From 252702326b7eb7bba984f4965df40bc2cc1c1b33 Mon Sep 17 00:00:00 2001
From: Hannes Rudolph
Date: Mon, 8 Dec 2025 10:08:08 -0700
Subject: [PATCH 1/3] feat: add slash commands support to marketplace
- Add 'command' type to marketplace item schema with content and argumentHint
- Implement command detection in MarketplaceManager for project and global directories
- Add fetchCommands() to RemoteConfigLoader for API integration
- Add installCommand() and removeCommand() to SimpleInstaller
- Add 'Slash Commands' tab to marketplace UI with 3-tab navigation
- Update install modal and item card components for command type
- Add translations for all 18 locales
- Include comprehensive test coverage for new functionality
---
packages/types/src/marketplace.ts | 13 ++-
.../marketplace/MarketplaceManager.ts | 28 +++++
.../marketplace/RemoteConfigLoader.ts | 38 ++++++-
src/services/marketplace/SimpleInstaller.ts | 49 +++++++++
.../__tests__/RemoteConfigLoader.spec.ts | 92 ++++++++++++++--
.../__tests__/SimpleInstaller.spec.ts | 103 ++++++++++++++++++
.../marketplace/MarketplaceListView.tsx | 6 +-
.../marketplace/MarketplaceView.tsx | 24 +++-
.../MarketplaceViewStateManager.ts | 2 +-
.../MarketplaceViewStateManager.spec.ts | 41 +++++++
.../components/MarketplaceInstallModal.tsx | 20 ++--
.../components/MarketplaceItemCard.tsx | 7 +-
.../src/i18n/locales/ca/marketplace.json | 15 ++-
.../src/i18n/locales/de/marketplace.json | 19 +++-
.../src/i18n/locales/en/marketplace.json | 15 ++-
.../src/i18n/locales/es/marketplace.json | 15 ++-
.../src/i18n/locales/fr/marketplace.json | 15 ++-
.../src/i18n/locales/hi/marketplace.json | 15 ++-
.../src/i18n/locales/id/marketplace.json | 15 ++-
.../src/i18n/locales/it/marketplace.json | 15 ++-
.../src/i18n/locales/ja/marketplace.json | 15 ++-
.../src/i18n/locales/ko/marketplace.json | 15 ++-
.../src/i18n/locales/nl/marketplace.json | 15 ++-
.../src/i18n/locales/pl/marketplace.json | 19 +++-
.../src/i18n/locales/pt-BR/marketplace.json | 15 ++-
.../src/i18n/locales/ru/marketplace.json | 15 ++-
.../src/i18n/locales/tr/marketplace.json | 15 ++-
.../src/i18n/locales/vi/marketplace.json | 15 ++-
.../src/i18n/locales/zh-CN/marketplace.json | 15 ++-
.../src/i18n/locales/zh-TW/marketplace.json | 15 ++-
30 files changed, 612 insertions(+), 89 deletions(-)
diff --git a/packages/types/src/marketplace.ts b/packages/types/src/marketplace.ts
index f2821e1b742..22dcfeba7fe 100644
--- a/packages/types/src/marketplace.ts
+++ b/packages/types/src/marketplace.ts
@@ -27,7 +27,7 @@ export type McpInstallationMethod = z.infer
/**
* Component type validation
*/
-export const marketplaceItemTypeSchema = z.enum(["mode", "mcp"] as const)
+export const marketplaceItemTypeSchema = z.enum(["mode", "mcp", "command"] as const)
export type MarketplaceItemType = z.infer
@@ -61,6 +61,13 @@ export const mcpMarketplaceItemSchema = baseMarketplaceItemSchema.extend({
export type McpMarketplaceItem = z.infer
+export const commandMarketplaceItemSchema = baseMarketplaceItemSchema.extend({
+ content: z.string().min(1), // Markdown content for slash command
+ argumentHint: z.string().optional(),
+})
+
+export type CommandMarketplaceItem = z.infer
+
/**
* Unified marketplace item schema using discriminated union
*/
@@ -73,6 +80,10 @@ export const marketplaceItemSchema = z.discriminatedUnion("type", [
mcpMarketplaceItemSchema.extend({
type: z.literal("mcp"),
}),
+ // Command marketplace item
+ commandMarketplaceItemSchema.extend({
+ type: z.literal("command"),
+ }),
])
export type MarketplaceItem = z.infer
diff --git a/src/services/marketplace/MarketplaceManager.ts b/src/services/marketplace/MarketplaceManager.ts
index dfde5600b9a..231793f61fa 100644
--- a/src/services/marketplace/MarketplaceManager.ts
+++ b/src/services/marketplace/MarketplaceManager.ts
@@ -284,6 +284,20 @@ export class MarketplaceManager {
} catch (error) {
// File doesn't exist or can't be read, skip
}
+
+ // Check commands in .roo/commands
+ const projectCommandsDir = path.join(workspaceFolder.uri.fsPath, ".roo", "commands")
+ try {
+ const entries = await fs.readdir(projectCommandsDir, { withFileTypes: true })
+ for (const entry of entries) {
+ if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
+ const commandName = entry.name.slice(0, -3)
+ metadata[commandName] = { type: "command" }
+ }
+ }
+ } catch (error) {
+ // Directory doesn't exist or can't be read, skip
+ }
} catch (error) {
console.error("Error checking project installations:", error)
}
@@ -329,6 +343,20 @@ export class MarketplaceManager {
} catch (error) {
// File doesn't exist or can't be read, skip
}
+
+ // Check global commands
+ const globalCommandsDir = path.join(globalSettingsPath, "commands")
+ try {
+ const entries = await fs.readdir(globalCommandsDir, { withFileTypes: true })
+ for (const entry of entries) {
+ if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
+ const commandName = entry.name.slice(0, -3)
+ metadata[commandName] = { type: "command" }
+ }
+ }
+ } catch (error) {
+ // Directory doesn't exist or can't be read, skip
+ }
} catch (error) {
console.error("Error checking global installations:", error)
}
diff --git a/src/services/marketplace/RemoteConfigLoader.ts b/src/services/marketplace/RemoteConfigLoader.ts
index b5851ae854d..a44d7b0b783 100644
--- a/src/services/marketplace/RemoteConfigLoader.ts
+++ b/src/services/marketplace/RemoteConfigLoader.ts
@@ -3,10 +3,11 @@ import * as yaml from "yaml"
import { z } from "zod"
import {
- type MarketplaceItem,
- type MarketplaceItemType,
+ commandMarketplaceItemSchema,
modeMarketplaceItemSchema,
mcpMarketplaceItemSchema,
+ type MarketplaceItem,
+ type MarketplaceItemType,
} from "@roo-code/types"
import { getRooCodeApiUrl } from "@roo-code/cloud"
@@ -18,6 +19,10 @@ const mcpMarketplaceResponse = z.object({
items: z.array(mcpMarketplaceItemSchema),
})
+const commandMarketplaceResponse = z.object({
+ items: z.array(commandMarketplaceItemSchema),
+})
+
export class RemoteConfigLoader {
private apiBaseUrl: string
private cache: Map = new Map()
@@ -32,10 +37,11 @@ export class RemoteConfigLoader {
const modesPromise = this.fetchModes()
const mcpsPromise = hideMarketplaceMcps ? Promise.resolve([]) : this.fetchMcps()
+ const commandsPromise = this.fetchCommands()
- const [modes, mcps] = await Promise.all([modesPromise, mcpsPromise])
+ const [modes, mcps, commands] = await Promise.all([modesPromise, mcpsPromise, commandsPromise])
- items.push(...modes, ...mcps)
+ items.push(...modes, ...mcps, ...commands)
return items
}
@@ -83,6 +89,30 @@ export class RemoteConfigLoader {
return items
}
+ private async fetchCommands(): Promise {
+ const cacheKey = "commands"
+ const cached = this.getFromCache(cacheKey)
+
+ if (cached) {
+ return cached
+ }
+
+ const data = await this.fetchWithRetry(`${this.apiBaseUrl}/api/marketplace/commands`)
+
+ // The commands endpoint returns Markdown list (yaml frontmatter + markdown body per item)
+ // The test server sample is plain Markdown with YAML frontmatter; parse as plain text list.
+ const yamlData = yaml.parse(data)
+ const validated = commandMarketplaceResponse.parse(yamlData)
+
+ const items: MarketplaceItem[] = validated.items.map((item) => ({
+ type: "command" as const,
+ ...item,
+ }))
+
+ this.setCache(cacheKey, items)
+ return items
+ }
+
private async fetchWithRetry(url: string, maxRetries = 3): Promise {
let lastError: Error
diff --git a/src/services/marketplace/SimpleInstaller.ts b/src/services/marketplace/SimpleInstaller.ts
index be002e2f1d5..9d4467fda7c 100644
--- a/src/services/marketplace/SimpleInstaller.ts
+++ b/src/services/marketplace/SimpleInstaller.ts
@@ -6,6 +6,7 @@ import type { MarketplaceItem, MarketplaceItemType, InstallMarketplaceItemOption
import { GlobalFileNames } from "../../shared/globalFileNames"
import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
import type { CustomModesManager } from "../../core/config/CustomModesManager"
+import { getGlobalRooDirectory, getProjectRooDirectoryForCwd } from "../roo-config"
export interface InstallOptions extends InstallMarketplaceItemOptions {
target: "project" | "global"
@@ -26,11 +27,30 @@ export class SimpleInstaller {
return await this.installMode(item, target)
case "mcp":
return await this.installMcp(item, target, options)
+ case "command":
+ return await this.installCommand(item, target)
default:
throw new Error(`Unsupported item type: ${(item as any).type}`)
}
}
+ private async installCommand(
+ item: MarketplaceItem,
+ target: "project" | "global",
+ ): Promise<{ filePath: string; line?: number }> {
+ if (!item.content || Array.isArray(item.content)) {
+ throw new Error("Command item missing content")
+ }
+
+ const dirPath = await this.getCommandDirPath(target)
+ await fs.mkdir(dirPath, { recursive: true })
+
+ const filePath = path.join(dirPath, `${item.id}.md`)
+ await fs.writeFile(filePath, item.content, "utf-8")
+
+ return { filePath }
+ }
+
private async installMode(
item: MarketplaceItem,
target: "project" | "global",
@@ -288,11 +308,28 @@ export class SimpleInstaller {
case "mcp":
await this.removeMcp(item, target)
break
+ case "command":
+ await this.removeCommand(item, target)
+ break
default:
throw new Error(`Unsupported item type: ${(item as any).type}`)
}
}
+ private async removeCommand(item: MarketplaceItem, target: "project" | "global"): Promise {
+ const dirPath = await this.getCommandDirPath(target)
+ const filePath = path.join(dirPath, `${item.id}.md`)
+
+ try {
+ await fs.unlink(filePath)
+ } catch (error: any) {
+ if (error.code === "ENOENT") {
+ return
+ }
+ throw error
+ }
+ }
+
private async removeMode(item: MarketplaceItem, target: "project" | "global"): Promise {
if (!this.customModesManager) {
throw new Error("CustomModesManager is not available")
@@ -381,4 +418,16 @@ export class SimpleInstaller {
return path.join(globalSettingsPath, GlobalFileNames.mcpSettings)
}
}
+
+ private async getCommandDirPath(target: "project" | "global"): Promise {
+ if (target === "project") {
+ const workspaceFolder = vscode.workspace.workspaceFolders?.[0]
+ if (!workspaceFolder) {
+ throw new Error("No workspace folder found")
+ }
+ return path.join(getProjectRooDirectoryForCwd(workspaceFolder.uri.fsPath), "commands")
+ }
+
+ return path.join(getGlobalRooDirectory(), "commands")
+ }
}
diff --git a/src/services/marketplace/__tests__/RemoteConfigLoader.spec.ts b/src/services/marketplace/__tests__/RemoteConfigLoader.spec.ts
index 61740ab5fbd..32a046455f8 100644
--- a/src/services/marketplace/__tests__/RemoteConfigLoader.spec.ts
+++ b/src/services/marketplace/__tests__/RemoteConfigLoader.spec.ts
@@ -24,7 +24,7 @@ describe("RemoteConfigLoader", () => {
})
describe("loadAllItems", () => {
- it("should fetch and combine modes and MCPs from API", async () => {
+ it("should fetch and combine modes, MCPs, and commands from API", async () => {
const mockModesYaml = `items:
- id: "test-mode"
name: "Test Mode"
@@ -38,6 +38,13 @@ describe("RemoteConfigLoader", () => {
url: "https://github.com/test/test-mcp"
content: '{"command": "test"}'`
+ const mockCommandsYaml = `items:
+ - id: "explain"
+ name: "Explain"
+ description: "Get a detailed explanation"
+ author: "@roo"
+ content: "# Explain\\n\\nExplain the following: {args}"`
+
mockedAxios.get.mockImplementation((url: string) => {
if (url.includes("/modes")) {
return Promise.resolve({ data: mockModesYaml })
@@ -45,12 +52,15 @@ describe("RemoteConfigLoader", () => {
if (url.includes("/mcps")) {
return Promise.resolve({ data: mockMcpsYaml })
}
+ if (url.includes("/commands")) {
+ return Promise.resolve({ data: mockCommandsYaml })
+ }
return Promise.reject(new Error("Unknown URL"))
})
const items = await loader.loadAllItems()
- expect(mockedAxios.get).toHaveBeenCalledTimes(2)
+ expect(mockedAxios.get).toHaveBeenCalledTimes(3)
expect(mockedAxios.get).toHaveBeenCalledWith(
"https://test.api.com/api/marketplace/modes",
expect.objectContaining({
@@ -71,8 +81,18 @@ describe("RemoteConfigLoader", () => {
},
}),
)
+ expect(mockedAxios.get).toHaveBeenCalledWith(
+ "https://test.api.com/api/marketplace/commands",
+ expect.objectContaining({
+ timeout: 10000,
+ headers: {
+ Accept: "application/json",
+ "Content-Type": "application/json",
+ },
+ }),
+ )
- expect(items).toHaveLength(2)
+ expect(items).toHaveLength(3)
expect(items[0]).toEqual({
type: "mode",
id: "test-mode",
@@ -88,6 +108,14 @@ describe("RemoteConfigLoader", () => {
url: "https://github.com/test/test-mcp",
content: '{"command": "test"}',
})
+ expect(items[2]).toEqual({
+ type: "command",
+ id: "explain",
+ name: "Explain",
+ description: "Get a detailed explanation",
+ author: "@roo",
+ content: "# Explain\n\nExplain the following: {args}",
+ })
})
it("should use cache on subsequent calls", async () => {
@@ -104,6 +132,8 @@ describe("RemoteConfigLoader", () => {
url: "https://github.com/test/test-mcp"
content: "test content"`
+ const mockCommandsYaml = `items: []`
+
mockedAxios.get.mockImplementation((url: string) => {
if (url.includes("/modes")) {
return Promise.resolve({ data: mockModesYaml })
@@ -111,16 +141,19 @@ describe("RemoteConfigLoader", () => {
if (url.includes("/mcps")) {
return Promise.resolve({ data: mockMcpsYaml })
}
+ if (url.includes("/commands")) {
+ return Promise.resolve({ data: mockCommandsYaml })
+ }
return Promise.reject(new Error("Unknown URL"))
})
// First call - should hit API
const items1 = await loader.loadAllItems()
- expect(mockedAxios.get).toHaveBeenCalledTimes(2)
+ expect(mockedAxios.get).toHaveBeenCalledTimes(3)
// Second call - should use cache
const items2 = await loader.loadAllItems()
- expect(mockedAxios.get).toHaveBeenCalledTimes(2) // Still 2, not 4
+ expect(mockedAxios.get).toHaveBeenCalledTimes(3) // Still 3, not 6
expect(items1).toEqual(items2)
})
@@ -133,6 +166,7 @@ describe("RemoteConfigLoader", () => {
content: "test content"`
const mockMcpsYaml = `items: []`
+ const mockCommandsYaml = `items: []`
// Mock modes endpoint to fail twice then succeed
let modesCallCount = 0
@@ -147,6 +181,9 @@ describe("RemoteConfigLoader", () => {
if (url.includes("/mcps")) {
return Promise.resolve({ data: mockMcpsYaml })
}
+ if (url.includes("/commands")) {
+ return Promise.resolve({ data: mockCommandsYaml })
+ }
return Promise.reject(new Error("Unknown URL"))
})
@@ -185,6 +222,8 @@ describe("RemoteConfigLoader", () => {
url: "https://github.com/test/test-mcp"
content: "test content"`
+ const validCommandsYaml = `items: []`
+
mockedAxios.get.mockImplementation((url: string) => {
if (url.includes("/modes")) {
return Promise.resolve({ data: invalidModesYaml })
@@ -192,6 +231,9 @@ describe("RemoteConfigLoader", () => {
if (url.includes("/mcps")) {
return Promise.resolve({ data: validMcpsYaml })
}
+ if (url.includes("/commands")) {
+ return Promise.resolve({ data: validCommandsYaml })
+ }
return Promise.reject(new Error("Unknown URL"))
})
@@ -215,6 +257,13 @@ describe("RemoteConfigLoader", () => {
url: "https://github.com/test/test-mcp"
content: "test content"`
+ const mockCommandsYaml = `items:
+ - id: "target-command"
+ name: "Target Command"
+ description: "The command we want"
+ author: "@roo"
+ content: "# Command content"`
+
mockedAxios.get.mockImplementation((url: string) => {
if (url.includes("/modes")) {
return Promise.resolve({ data: mockModesYaml })
@@ -222,11 +271,15 @@ describe("RemoteConfigLoader", () => {
if (url.includes("/mcps")) {
return Promise.resolve({ data: mockMcpsYaml })
}
+ if (url.includes("/commands")) {
+ return Promise.resolve({ data: mockCommandsYaml })
+ }
return Promise.reject(new Error("Unknown URL"))
})
const modeItem = await loader.getItem("target-mode", "mode" as MarketplaceItemType)
const mcpItem = await loader.getItem("target-mcp", "mcp" as MarketplaceItemType)
+ const commandItem = await loader.getItem("target-command", "command" as MarketplaceItemType)
const notFound = await loader.getItem("nonexistent", "mode" as MarketplaceItemType)
expect(modeItem).toEqual({
@@ -246,6 +299,15 @@ describe("RemoteConfigLoader", () => {
content: "test content",
})
+ expect(commandItem).toEqual({
+ type: "command",
+ id: "target-command",
+ name: "Target Command",
+ description: "The command we want",
+ author: "@roo",
+ content: "# Command content",
+ })
+
expect(notFound).toBeNull()
})
})
@@ -259,6 +321,7 @@ describe("RemoteConfigLoader", () => {
content: "test content"`
const mockMcpsYaml = `items: []`
+ const mockCommandsYaml = `items: []`
mockedAxios.get.mockImplementation((url: string) => {
if (url.includes("/modes")) {
@@ -267,23 +330,26 @@ describe("RemoteConfigLoader", () => {
if (url.includes("/mcps")) {
return Promise.resolve({ data: mockMcpsYaml })
}
+ if (url.includes("/commands")) {
+ return Promise.resolve({ data: mockCommandsYaml })
+ }
return Promise.reject(new Error("Unknown URL"))
})
// First call
await loader.loadAllItems()
- expect(mockedAxios.get).toHaveBeenCalledTimes(2)
+ expect(mockedAxios.get).toHaveBeenCalledTimes(3)
// Second call - should use cache
await loader.loadAllItems()
- expect(mockedAxios.get).toHaveBeenCalledTimes(2)
+ expect(mockedAxios.get).toHaveBeenCalledTimes(3)
// Clear cache
loader.clearCache()
// Third call - should hit API again
await loader.loadAllItems()
- expect(mockedAxios.get).toHaveBeenCalledTimes(4)
+ expect(mockedAxios.get).toHaveBeenCalledTimes(6)
})
})
@@ -296,6 +362,7 @@ describe("RemoteConfigLoader", () => {
content: "test content"`
const mockMcpsYaml = `items: []`
+ const mockCommandsYaml = `items: []`
mockedAxios.get.mockImplementation((url: string) => {
if (url.includes("/modes")) {
@@ -304,6 +371,9 @@ describe("RemoteConfigLoader", () => {
if (url.includes("/mcps")) {
return Promise.resolve({ data: mockMcpsYaml })
}
+ if (url.includes("/commands")) {
+ return Promise.resolve({ data: mockCommandsYaml })
+ }
return Promise.reject(new Error("Unknown URL"))
})
@@ -315,18 +385,18 @@ describe("RemoteConfigLoader", () => {
// First call
await loader.loadAllItems()
- expect(mockedAxios.get).toHaveBeenCalledTimes(2)
+ expect(mockedAxios.get).toHaveBeenCalledTimes(3)
// Second call immediately - should use cache
await loader.loadAllItems()
- expect(mockedAxios.get).toHaveBeenCalledTimes(2)
+ expect(mockedAxios.get).toHaveBeenCalledTimes(3)
// Advance time by 6 minutes (360,000 ms)
currentTime += 6 * 60 * 1000
// Third call - cache should be expired
await loader.loadAllItems()
- expect(mockedAxios.get).toHaveBeenCalledTimes(4)
+ expect(mockedAxios.get).toHaveBeenCalledTimes(6)
// Restore original Date.now
Date.now = originalDateNow
diff --git a/src/services/marketplace/__tests__/SimpleInstaller.spec.ts b/src/services/marketplace/__tests__/SimpleInstaller.spec.ts
index 94684056d47..08a0c234432 100644
--- a/src/services/marketplace/__tests__/SimpleInstaller.spec.ts
+++ b/src/services/marketplace/__tests__/SimpleInstaller.spec.ts
@@ -15,6 +15,7 @@ vi.mock("fs/promises", () => ({
writeFile: vi.fn(),
mkdir: vi.fn(),
rm: vi.fn(),
+ unlink: vi.fn(),
}))
vi.mock("os")
vi.mock("vscode", () => ({
@@ -346,4 +347,106 @@ describe("SimpleInstaller", () => {
)
})
})
+
+ describe("installCommand", () => {
+ const mockCommandItem: MarketplaceItem = {
+ id: "explain",
+ name: "Explain",
+ description: "Get a detailed explanation of code, concepts, or errors",
+ type: "command",
+ content: `---
+description: "Get a detailed explanation of code, concepts, or errors"
+argument-hint: ""
+---
+
+# Explain Request
+
+Please provide a comprehensive explanation of the following:
+
+**Input:** {args}`,
+ }
+
+ it("should install command to project .roo/commands/ directory", async () => {
+ mockFs.writeFile.mockResolvedValueOnce(undefined as any)
+
+ const result = await installer.installItem(mockCommandItem, { target: "project" })
+
+ expect(result.filePath).toBe(path.join("/test/workspace", ".roo", "commands", "explain.md"))
+ expect(mockFs.mkdir).toHaveBeenCalledWith(expect.stringContaining(path.join(".roo", "commands")), {
+ recursive: true,
+ })
+ expect(mockFs.writeFile).toHaveBeenCalledWith(result.filePath, mockCommandItem.content, "utf-8")
+ })
+
+ it("should install command to global commands directory", async () => {
+ mockFs.writeFile.mockResolvedValueOnce(undefined as any)
+
+ const result = await installer.installItem(mockCommandItem, { target: "global" })
+
+ expect(result.filePath).toContain("commands")
+ expect(result.filePath).toContain("explain.md")
+ expect(mockFs.mkdir).toHaveBeenCalledWith(expect.any(String), { recursive: true })
+ expect(mockFs.writeFile).toHaveBeenCalledWith(result.filePath, mockCommandItem.content, "utf-8")
+ })
+
+ it("should throw error for missing content", async () => {
+ const noContentCommand: MarketplaceItem = {
+ ...mockCommandItem,
+ content: undefined as any,
+ }
+
+ await expect(installer.installItem(noContentCommand, { target: "project" })).rejects.toThrow(
+ "Command item missing content",
+ )
+ })
+
+ it("should throw error for array content in command", async () => {
+ const arrayContentCommand: MarketplaceItem = {
+ ...mockCommandItem,
+ content: ["content1", "content2"] as any,
+ }
+
+ await expect(installer.installItem(arrayContentCommand, { target: "project" })).rejects.toThrow(
+ "Command item missing content",
+ )
+ })
+ })
+
+ describe("removeCommand", () => {
+ const mockCommandItem: MarketplaceItem = {
+ id: "explain",
+ name: "Explain",
+ description: "Get a detailed explanation of code, concepts, or errors",
+ type: "command",
+ content: "# Explain\n\nContent here",
+ }
+
+ it("should remove command file from project directory", async () => {
+ mockFs.unlink.mockResolvedValueOnce(undefined as any)
+
+ await installer.removeItem(mockCommandItem, { target: "project" })
+
+ expect(mockFs.unlink).toHaveBeenCalledWith(
+ expect.stringContaining(path.join(".roo", "commands", "explain.md")),
+ )
+ })
+
+ it("should not throw error if command file does not exist", async () => {
+ const notFoundError = new Error("File not found") as any
+ notFoundError.code = "ENOENT"
+ mockFs.unlink.mockRejectedValueOnce(notFoundError)
+
+ await expect(installer.removeItem(mockCommandItem, { target: "project" })).resolves.not.toThrow()
+ })
+
+ it("should throw error for other file system errors", async () => {
+ const permissionError = new Error("Permission denied") as any
+ permissionError.code = "EPERM"
+ mockFs.unlink.mockRejectedValueOnce(permissionError)
+
+ await expect(installer.removeItem(mockCommandItem, { target: "project" })).rejects.toThrow(
+ "Permission denied",
+ )
+ })
+ })
})
diff --git a/webview-ui/src/components/marketplace/MarketplaceListView.tsx b/webview-ui/src/components/marketplace/MarketplaceListView.tsx
index c3c497ccfed..760445d17b0 100644
--- a/webview-ui/src/components/marketplace/MarketplaceListView.tsx
+++ b/webview-ui/src/components/marketplace/MarketplaceListView.tsx
@@ -16,7 +16,7 @@ export interface MarketplaceListViewProps {
stateManager: MarketplaceViewStateManager
allTags: string[]
filteredTags: string[]
- filterByType?: "mcp" | "mode"
+ filterByType?: "mcp" | "mode" | "command"
}
export function MarketplaceListView({ stateManager, allTags, filteredTags, filterByType }: MarketplaceListViewProps) {
@@ -48,7 +48,9 @@ export function MarketplaceListView({ stateManager, allTags, filteredTags, filte
? t("marketplace:filters.search.placeholderMcp")
: filterByType === "mode"
? t("marketplace:filters.search.placeholderMode")
- : t("marketplace:filters.search.placeholder")
+ : filterByType === "command"
+ ? t("marketplace:filters.search.placeholderCommand")
+ : t("marketplace:filters.search.placeholder")
}
value={state.filters.search}
onChange={(e) =>
diff --git a/webview-ui/src/components/marketplace/MarketplaceView.tsx b/webview-ui/src/components/marketplace/MarketplaceView.tsx
index 0d66be48afd..4acc0115e5b 100644
--- a/webview-ui/src/components/marketplace/MarketplaceView.tsx
+++ b/webview-ui/src/components/marketplace/MarketplaceView.tsx
@@ -13,7 +13,7 @@ import { ExtensionStateContext } from "@/context/ExtensionStateContext"
interface MarketplaceViewProps {
onDone?: () => void
stateManager: MarketplaceViewStateManager
- targetTab?: "mcp" | "mode"
+ targetTab?: "mcp" | "mode" | "command"
}
export function MarketplaceView({ stateManager, onDone, targetTab }: MarketplaceViewProps) {
const { t } = useAppTranslation()
@@ -43,7 +43,7 @@ export function MarketplaceView({ stateManager, onDone, targetTab }: Marketplace
}, [state.allItems, hasReceivedInitialState])
useEffect(() => {
- if (targetTab && (targetTab === "mcp" || targetTab === "mode")) {
+ if (targetTab && (targetTab === "mcp" || targetTab === "mode" || targetTab === "command")) {
manager.transition({ type: "SET_ACTIVE_TAB", payload: { tab: targetTab } })
}
}, [targetTab, manager])
@@ -117,10 +117,11 @@ export function MarketplaceView({ stateManager, onDone, targetTab }: Marketplace
@@ -130,6 +131,13 @@ export function MarketplaceView({ stateManager, onDone, targetTab }: Marketplace
onClick={() => manager.transition({ type: "SET_ACTIVE_TAB", payload: { tab: "mcp" } })}>
MCP
+
@@ -365,11 +369,13 @@ export const MarketplaceInstallModal: React.FC = (
-
+ {item.type !== "command" && (
+
+ )}
>
) : (
<>
diff --git a/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx b/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx
index e4bbdbcfde6..822191c4e20 100644
--- a/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx
+++ b/webview-ui/src/components/marketplace/components/MarketplaceItemCard.tsx
@@ -68,6 +68,7 @@ export const MarketplaceItemCard: React.FC = ({ item,
const labels: Partial> = {
mode: t("marketplace:filters.type.mode"),
mcp: t("marketplace:filters.type.mcpServer"),
+ command: t("marketplace:filters.type.slashCommand"),
}
return labels[item.type] ?? "N/A"
}, [item.type, t])
@@ -210,7 +211,9 @@ export const MarketplaceItemCard: React.FC = ({ item,
{item.type === "mode"
? t("marketplace:removeConfirm.mode.title")
- : t("marketplace:removeConfirm.mcp.title")}
+ : item.type === "command"
+ ? t("marketplace:removeConfirm.command.title")
+ : t("marketplace:removeConfirm.mcp.title")}
{item.type === "mode" ? (
@@ -220,6 +223,8 @@ export const MarketplaceItemCard: React.FC = ({ item,
{t("marketplace:removeConfirm.mode.rulesWarning")}
>
+ ) : item.type === "command" ? (
+ t("marketplace:removeConfirm.command.message", { commandName: item.name })
) : (
t("marketplace:removeConfirm.mcp.message", { mcpName: item.name })
)}
diff --git a/webview-ui/src/i18n/locales/ca/marketplace.json b/webview-ui/src/i18n/locales/ca/marketplace.json
index cd4612ae36e..17cbe0a19fb 100644
--- a/webview-ui/src/i18n/locales/ca/marketplace.json
+++ b/webview-ui/src/i18n/locales/ca/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Instal·lat",
"settings": "Configuració",
- "browse": "Navegar"
+ "browse": "Navegar",
+ "slashCommands": "Comandes Slash"
},
"done": "Fet",
"refresh": "Actualitzar",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Cercar elements del marketplace...",
"placeholderMcp": "Cercar MCPs...",
- "placeholderMode": "Cercar modes..."
+ "placeholderMode": "Cercar modes...",
+ "placeholderCommand": "Cercar comandes Slash..."
},
"installed": {
"label": "Filtra per estat",
@@ -23,7 +25,8 @@
"label": "Filtrar per tipus:",
"all": "Tots els tipus",
"mode": "Mode",
- "mcpServer": "Servidor MCP"
+ "mcpServer": "Servidor MCP",
+ "slashCommand": "Comanda Slash"
},
"sort": {
"label": "Ordenar per:",
@@ -91,6 +94,7 @@
"title": "Instal·lar {{name}}",
"titleMode": "Instal·lar mode {{name}}",
"titleMcp": "Instal·lar MCP {{name}}",
+ "titleCommand": "Instal·lar la comanda Slash {{name}}",
"scope": "Àmbit d'instal·lació",
"project": "Projecte (espai de treball actual)",
"global": "Global (tots els espais de treball)",
@@ -103,6 +107,7 @@
"installed": "Instal·lat amb èxit!",
"whatNextMcp": "Ara pots configurar i utilitzar aquest servidor MCP. Feu clic a la icona MCP de la barra lateral per canviar de pestanya.",
"whatNextMode": "Ara pots utilitzar aquest mode. Feu clic a la icona Modes de la barra lateral per canviar de pestanya.",
+ "whatNextCommand": "Ara pots utilitzar aquesta comanda slash escrivint /{{name}} al xat.",
"done": "Fet",
"goToMcp": "Anar a la pestanya MCP",
"goToModes": "Anar a la configuració de Modes",
@@ -149,6 +154,10 @@
"title": "Eliminar el servidor MCP",
"message": "Estàs segur que vols eliminar el servidor MCP \"{{mcpName}}\"?"
},
+ "command": {
+ "title": "Eliminar comanda Slash",
+ "message": "Estàs segur que vols eliminar la comanda slash \"{{commandName}}\"?"
+ },
"cancel": "Cancel·lar",
"confirm": "Eliminar"
},
diff --git a/webview-ui/src/i18n/locales/de/marketplace.json b/webview-ui/src/i18n/locales/de/marketplace.json
index 545e86bc910..06826d3d1ca 100644
--- a/webview-ui/src/i18n/locales/de/marketplace.json
+++ b/webview-ui/src/i18n/locales/de/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Installiert",
"settings": "Einstellungen",
- "browse": "Durchsuchen"
+ "browse": "Durchsuchen",
+ "slashCommands": "Slash Commands"
},
"done": "Fertig",
"refresh": "Aktualisieren",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Marketplace-Elemente durchsuchen...",
"placeholderMcp": "MCPs durchsuchen...",
- "placeholderMode": "Modi durchsuchen..."
+ "placeholderMode": "Modi durchsuchen...",
+ "placeholderCommand": "Slash Commands durchsuchen..."
},
"installed": {
"label": "Nach Status filtern",
@@ -23,7 +25,8 @@
"label": "Nach Typ filtern:",
"all": "Alle Typen",
"mode": "Modus",
- "mcpServer": "MCP-Server"
+ "mcpServer": "MCP-Server",
+ "slashCommand": "Slash Command"
},
"sort": {
"label": "Sortieren nach:",
@@ -91,6 +94,7 @@
"title": "{{name}} installieren",
"titleMode": "{{name}} Modus installieren",
"titleMcp": "{{name}} MCP installieren",
+ "titleCommand": "{{name}} Slash Command installieren",
"scope": "Installationsbereich",
"project": "Projekt (aktueller Arbeitsbereich)",
"global": "Global (alle Arbeitsbereiche)",
@@ -103,6 +107,7 @@
"installed": "Erfolgreich installiert!",
"whatNextMcp": "Du kannst diesen MCP-Server jetzt konfigurieren und verwenden. Klicke auf das MCP-Symbol in der Seitenleiste, um die Tabs zu wechseln.",
"whatNextMode": "Du kannst diesen Modus jetzt verwenden. Klicke auf das Modi-Symbol in der Seitenleiste, um die Tabs zu wechseln.",
+ "whatNextCommand": "Du kannst diesen Slash Command jetzt verwenden, indem du /{{name}} im Chat eingibst.",
"done": "Fertig",
"goToMcp": "Zum MCP-Tab gehen",
"goToModes": "Zu den Modi-Einstellungen gehen",
@@ -142,12 +147,16 @@
"removeConfirm": {
"mode": {
"title": "Modus entfernen",
- "message": "Bist du sicher, dass du den Modus „{{modeName}}“ entfernen möchtest?",
+ "message": "Bist du sicher, dass du den Modus \"{{modeName}}\" entfernen möchtest?",
"rulesWarning": "Dadurch werden auch alle zugehörigen Regeldateien für diesen Modus entfernt."
},
"mcp": {
"title": "MCP-Server entfernen",
- "message": "Bist du sicher, dass du den MCP-Server „{{mcpName}}“ entfernen möchtest?"
+ "message": "Bist du sicher, dass du den MCP-Server \"{{mcpName}}\" entfernen möchtest?"
+ },
+ "command": {
+ "title": "Slash Command entfernen",
+ "message": "Bist du sicher, dass du den Slash Command \"{{commandName}}\" entfernen möchtest?"
},
"cancel": "Abbrechen",
"confirm": "Entfernen"
diff --git a/webview-ui/src/i18n/locales/en/marketplace.json b/webview-ui/src/i18n/locales/en/marketplace.json
index dae9dd26116..b3f1ac3b27b 100644
--- a/webview-ui/src/i18n/locales/en/marketplace.json
+++ b/webview-ui/src/i18n/locales/en/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Installed",
"settings": "Settings",
- "browse": "Browse"
+ "browse": "Browse",
+ "slashCommands": "Slash Commands"
},
"done": "Done",
"refresh": "Refresh",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Search marketplace items...",
"placeholderMcp": "Search MCPs...",
- "placeholderMode": "Search Modes..."
+ "placeholderMode": "Search Modes...",
+ "placeholderCommand": "Search Slash Commands..."
},
"installed": {
"label": "Filter by status",
@@ -23,7 +25,8 @@
"label": "Filter by type:",
"all": "All types",
"mode": "Mode",
- "mcpServer": "MCP Server"
+ "mcpServer": "MCP Server",
+ "slashCommand": "Slash Command"
},
"sort": {
"label": "Sort by:",
@@ -89,6 +92,7 @@
"title": "Install {{name}}",
"titleMode": "Install {{name}} Mode",
"titleMcp": "Install {{name}} MCP",
+ "titleCommand": "Install {{name}} Slash Command",
"scope": "Installation Scope",
"project": "Project (current workspace)",
"global": "Global (all workspaces)",
@@ -102,6 +106,7 @@
"installed": "Successfully installed!",
"whatNextMcp": "You can now configure and use this MCP server. Click the MCP icon in the sidebar to switch tabs.",
"whatNextMode": "You can now use this mode. Click the Modes icon in the sidebar to switch tabs.",
+ "whatNextCommand": "You can now use this slash command by typing /{{name}} in the chat.",
"done": "Done",
"goToMcp": "Go to MCP Tab",
"goToModes": "Go to Modes Settings",
@@ -147,6 +152,10 @@
"title": "Remove MCP Server",
"message": "Are you sure you want to remove the MCP server \"{{mcpName}}\"?"
},
+ "command": {
+ "title": "Remove Slash Command",
+ "message": "Are you sure you want to remove the slash command \"{{commandName}}\"?"
+ },
"cancel": "Cancel",
"confirm": "Remove"
},
diff --git a/webview-ui/src/i18n/locales/es/marketplace.json b/webview-ui/src/i18n/locales/es/marketplace.json
index 2d4b257c93f..af5a0cdd13f 100644
--- a/webview-ui/src/i18n/locales/es/marketplace.json
+++ b/webview-ui/src/i18n/locales/es/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Instalado",
"settings": "Configuración",
- "browse": "Explorar"
+ "browse": "Explorar",
+ "slashCommands": "Comandos Slash"
},
"done": "Hecho",
"refresh": "Actualizar",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Buscar elementos del marketplace...",
"placeholderMcp": "Buscar MCPs...",
- "placeholderMode": "Buscar modos..."
+ "placeholderMode": "Buscar modos...",
+ "placeholderCommand": "Buscar comandos Slash..."
},
"installed": {
"label": "Filtrar por estado",
@@ -23,7 +25,8 @@
"label": "Filtrar por tipo:",
"all": "Todos los tipos",
"mode": "Modo",
- "mcpServer": "Servidor MCP"
+ "mcpServer": "Servidor MCP",
+ "slashCommand": "Comando Slash"
},
"sort": {
"label": "Ordenar por:",
@@ -91,6 +94,7 @@
"title": "Instalar {{name}}",
"titleMode": "Instalar modo {{name}}",
"titleMcp": "Instalar MCP {{name}}",
+ "titleCommand": "Instalar comando Slash {{name}}",
"scope": "Ámbito de instalación",
"project": "Proyecto (espacio de trabajo actual)",
"global": "Global (todos los espacios de trabajo)",
@@ -103,6 +107,7 @@
"installed": "¡Instalado exitosamente!",
"whatNextMcp": "Ahora puedes configurar y usar este servidor MCP. Haz clic en el icono MCP en la barra lateral para cambiar de pestaña.",
"whatNextMode": "Ahora puedes usar este modo. Haz clic en el icono Modos en la barra lateral para cambiar de pestaña.",
+ "whatNextCommand": "Ahora puedes usar este comando slash escribiendo /{{name}} en el chat.",
"done": "Hecho",
"goToMcp": "Ir a la pestaña MCP",
"goToModes": "Ir a la configuración de Modos",
@@ -149,6 +154,10 @@
"title": "Eliminar servidor MCP",
"message": "¿Estás seguro de que quieres eliminar el servidor MCP \"{{mcpName}}\"?"
},
+ "command": {
+ "title": "Eliminar comando Slash",
+ "message": "¿Estás seguro de que quieres eliminar el comando slash \"{{commandName}}\"?"
+ },
"cancel": "Cancelar",
"confirm": "Eliminar"
},
diff --git a/webview-ui/src/i18n/locales/fr/marketplace.json b/webview-ui/src/i18n/locales/fr/marketplace.json
index aa0ce5b718d..8d488a13a23 100644
--- a/webview-ui/src/i18n/locales/fr/marketplace.json
+++ b/webview-ui/src/i18n/locales/fr/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Installé",
"settings": "Paramètres",
- "browse": "Parcourir"
+ "browse": "Parcourir",
+ "slashCommands": "Commandes Slash"
},
"done": "Terminé",
"refresh": "Actualiser",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Rechercher des éléments du marketplace...",
"placeholderMcp": "Rechercher des MCPs...",
- "placeholderMode": "Rechercher des modes..."
+ "placeholderMode": "Rechercher des modes...",
+ "placeholderCommand": "Rechercher des commandes Slash..."
},
"installed": {
"label": "Filtrer par statut",
@@ -23,7 +25,8 @@
"label": "Filtrer par type :",
"all": "Tous les types",
"mode": "Mode",
- "mcpServer": "Serveur MCP"
+ "mcpServer": "Serveur MCP",
+ "slashCommand": "Commande Slash"
},
"sort": {
"label": "Trier par :",
@@ -91,6 +94,7 @@
"title": "Installer {{name}}",
"titleMode": "Installer le mode {{name}}",
"titleMcp": "Installer le MCP {{name}}",
+ "titleCommand": "Installer la commande Slash {{name}}",
"scope": "Portée d'installation",
"project": "Projet (espace de travail actuel)",
"global": "Global (tous les espaces de travail)",
@@ -103,6 +107,7 @@
"installed": "Installé avec succès !",
"whatNextMcp": "Vous pouvez maintenant configurer et utiliser ce serveur MCP. Cliquez sur l'icône MCP dans la barre latérale pour changer d'onglet.",
"whatNextMode": "Vous pouvez maintenant utiliser ce mode. Cliquez sur l'icône Modes dans la barre latérale pour changer d'onglet.",
+ "whatNextCommand": "Tu peux maintenant utiliser cette commande slash en tapant /{{name}} dans le chat.",
"done": "Terminé",
"goToMcp": "Aller à l'onglet MCP",
"goToModes": "Aller aux paramètres des Modes",
@@ -149,6 +154,10 @@
"title": "Supprimer le serveur MCP",
"message": "Êtes-vous sûr de vouloir supprimer le serveur MCP « {{mcpName}} » ?"
},
+ "command": {
+ "title": "Supprimer la commande Slash",
+ "message": "Es-tu sûr de vouloir supprimer la commande slash \"{{commandName}}\" ?"
+ },
"cancel": "Annuler",
"confirm": "Supprimer"
},
diff --git a/webview-ui/src/i18n/locales/hi/marketplace.json b/webview-ui/src/i18n/locales/hi/marketplace.json
index f50ca8b701e..50c60f3ffcf 100644
--- a/webview-ui/src/i18n/locales/hi/marketplace.json
+++ b/webview-ui/src/i18n/locales/hi/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "इंस्टॉल किया गया",
"settings": "सेटिंग्स",
- "browse": "ब्राउज़ करें"
+ "browse": "ब्राउज़ करें",
+ "slashCommands": "Slash Commands"
},
"done": "पूर्ण",
"refresh": "रिफ्रेश करें",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Marketplace आइटम खोजें...",
"placeholderMcp": "MCP खोजें...",
- "placeholderMode": "मोड खोजें..."
+ "placeholderMode": "मोड खोजें...",
+ "placeholderCommand": "Slash Commands खोजें..."
},
"installed": {
"label": "स्थिति के अनुसार फ़िल्टर करें",
@@ -23,7 +25,8 @@
"label": "प्रकार के अनुसार फ़िल्टर करें:",
"all": "सभी प्रकार",
"mode": "मोड",
- "mcpServer": "MCP सर्वर"
+ "mcpServer": "MCP सर्वर",
+ "slashCommand": "Slash Command"
},
"sort": {
"label": "इसके अनुसार क्रमबद्ध करें:",
@@ -89,6 +92,7 @@
"title": "{{name}} इंस्टॉल करें",
"titleMode": "{{name}} मोड इंस्टॉल करें",
"titleMcp": "{{name}} MCP इंस्टॉल करें",
+ "titleCommand": "{{name}} Slash Command इंस्टॉल करें",
"scope": "इंस्टॉलेशन स्कोप",
"project": "प्रोजेक्ट (वर्तमान वर्कस्पेस)",
"global": "ग्लोबल (सभी वर्कस्पेस)",
@@ -101,6 +105,7 @@
"installed": "सफलतापूर्वक इंस्टॉल किया गया!",
"whatNextMcp": "अब आप इस MCP सर्वर को कॉन्फ़िगर और उपयोग कर सकते हैं। टैब स्विच करने के लिए साइडबार में MCP आइकन पर क्लिक करें।",
"whatNextMode": "अब आप इस मोड का उपयोग कर सकते हैं। टैब स्विच करने के लिए साइडबार में मोड आइकन पर क्लिक करें।",
+ "whatNextCommand": "अब तुम चैट में /{{name}} टाइप करके इस slash command का उपयोग कर सकते हो।",
"done": "पूर्ण",
"goToMcp": "MCP टैब पर जाएं",
"goToModes": "मोड सेटिंग्स पर जाएं",
@@ -147,6 +152,10 @@
"title": "MCP सर्वर हटाएं",
"message": "क्या आप वाकई MCP सर्वर \"{{mcpName}}\" को हटाना चाहते हैं?"
},
+ "command": {
+ "title": "Slash Command हटाएं",
+ "message": "क्या तुम निश्चित हो कि तुम \"{{commandName}}\" slash command को हटाना चाहते हो?"
+ },
"cancel": "रद्द करें",
"confirm": "हटाएं"
},
diff --git a/webview-ui/src/i18n/locales/id/marketplace.json b/webview-ui/src/i18n/locales/id/marketplace.json
index f91a75ebbe2..76ea4b975c0 100644
--- a/webview-ui/src/i18n/locales/id/marketplace.json
+++ b/webview-ui/src/i18n/locales/id/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Terinstal",
"settings": "Pengaturan",
- "browse": "Jelajahi"
+ "browse": "Jelajahi",
+ "slashCommands": "Perintah Slash"
},
"done": "Selesai",
"refresh": "Refresh",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Cari item marketplace...",
"placeholderMcp": "Cari MCP...",
- "placeholderMode": "Cari Mode..."
+ "placeholderMode": "Cari Mode...",
+ "placeholderCommand": "Cari perintah Slash..."
},
"installed": {
"label": "Filter berdasarkan status",
@@ -23,7 +25,8 @@
"label": "Filter berdasarkan tipe:",
"all": "Semua tipe",
"mode": "Mode",
- "mcpServer": "Server MCP"
+ "mcpServer": "Server MCP",
+ "slashCommand": "Perintah Slash"
},
"sort": {
"label": "Urutkan berdasarkan:",
@@ -89,6 +92,7 @@
"title": "Instal {{name}}",
"titleMode": "Instal Mode {{name}}",
"titleMcp": "Instal MCP {{name}}",
+ "titleCommand": "Pasang Perintah Slash {{name}}",
"scope": "Cakupan Instalasi",
"project": "Proyek (workspace saat ini)",
"global": "Global (semua workspace)",
@@ -102,6 +106,7 @@
"installed": "Berhasil diinstal!",
"whatNextMcp": "Anda sekarang dapat mengkonfigurasi dan menggunakan server MCP ini. Klik ikon MCP di sidebar untuk beralih tab.",
"whatNextMode": "Anda sekarang dapat menggunakan mode ini. Klik ikon Mode di sidebar untuk beralih tab.",
+ "whatNextCommand": "Kamu sekarang bisa menggunakan perintah slash ini dengan mengetik /{{name}} di chat.",
"done": "Selesai",
"goToMcp": "Ke Tab MCP",
"goToModes": "Ke Pengaturan Mode",
@@ -147,6 +152,10 @@
"title": "Hapus Server MCP",
"message": "Apakah Anda yakin ingin menghapus server MCP \"{{mcpName}}\"?"
},
+ "command": {
+ "title": "Hapus Perintah Slash",
+ "message": "Apakah Anda yakin ingin menghapus perintah slash \"{{commandName}}\"?"
+ },
"cancel": "Batal",
"confirm": "Hapus"
},
diff --git a/webview-ui/src/i18n/locales/it/marketplace.json b/webview-ui/src/i18n/locales/it/marketplace.json
index 3c132848664..ba30de7caac 100644
--- a/webview-ui/src/i18n/locales/it/marketplace.json
+++ b/webview-ui/src/i18n/locales/it/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Installati",
"settings": "Impostazioni",
- "browse": "Sfoglia"
+ "browse": "Sfoglia",
+ "slashCommands": "Comandi Slash"
},
"done": "Fatto",
"refresh": "Aggiorna",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Cerca elementi del Marketplace...",
"placeholderMcp": "Cerca MCP...",
- "placeholderMode": "Cerca modalità..."
+ "placeholderMode": "Cerca modalità...",
+ "placeholderCommand": "Cerca comandi Slash..."
},
"installed": {
"label": "Filtra per stato",
@@ -23,7 +25,8 @@
"label": "Filtra per tipo:",
"all": "Tutti i tipi",
"mode": "Modalità",
- "mcpServer": "Server MCP"
+ "mcpServer": "Server MCP",
+ "slashCommand": "Comando Slash"
},
"sort": {
"label": "Ordina per:",
@@ -89,6 +92,7 @@
"title": "Installa {{name}}",
"titleMode": "Installa modalità {{name}}",
"titleMcp": "Installa MCP {{name}}",
+ "titleCommand": "Installa comando Slash {{name}}",
"scope": "Ambito di installazione",
"project": "Progetto (area di lavoro corrente)",
"global": "Globale (tutte le aree di lavoro)",
@@ -101,6 +105,7 @@
"installed": "Installato con successo!",
"whatNextMcp": "Ora puoi configurare e utilizzare questo server MCP. Clicca sull'icona MCP nella barra laterale per cambiare scheda.",
"whatNextMode": "Ora puoi utilizzare questa modalità. Clicca sull'icona delle modalità nella barra laterale per cambiare scheda.",
+ "whatNextCommand": "Ora puoi usare questo comando slash digitando /{{name}} nella chat.",
"done": "Fatto",
"goToMcp": "Vai alla scheda MCP",
"goToModes": "Vai alle impostazioni Modalità",
@@ -147,6 +152,10 @@
"title": "Rimuovi server MCP",
"message": "Sei sicuro di voler rimuovere il server MCP \"{{mcpName}}\"?"
},
+ "command": {
+ "title": "Rimuovi comando Slash",
+ "message": "Sei sicuro di voler rimuovere il comando slash \"{{commandName}}\"?"
+ },
"cancel": "Annulla",
"confirm": "Rimuovi"
},
diff --git a/webview-ui/src/i18n/locales/ja/marketplace.json b/webview-ui/src/i18n/locales/ja/marketplace.json
index 6a2ac9f9541..ac1477ccd0f 100644
--- a/webview-ui/src/i18n/locales/ja/marketplace.json
+++ b/webview-ui/src/i18n/locales/ja/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "インストール済み",
"settings": "設定",
- "browse": "参照"
+ "browse": "参照",
+ "slashCommands": "スラッシュコマンド"
},
"done": "完了",
"refresh": "更新",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Marketplaceアイテムを検索...",
"placeholderMcp": "MCPを検索...",
- "placeholderMode": "モードを検索..."
+ "placeholderMode": "モードを検索...",
+ "placeholderCommand": "スラッシュコマンドを検索..."
},
"installed": {
"label": "ステータスで絞り込む",
@@ -23,7 +25,8 @@
"label": "タイプでフィルター:",
"all": "すべてのタイプ",
"mode": "モード",
- "mcpServer": "MCPサーバー"
+ "mcpServer": "MCPサーバー",
+ "slashCommand": "スラッシュコマンド"
},
"sort": {
"label": "並び順:",
@@ -89,6 +92,7 @@
"title": "{{name}}をインストール",
"titleMode": "{{name}}モードをインストール",
"titleMcp": "{{name}} MCPをインストール",
+ "titleCommand": "{{name}}スラッシュコマンドをインストール",
"scope": "インストール範囲",
"project": "プロジェクト(現在のワークスペース)",
"global": "グローバル(すべてのワークスペース)",
@@ -101,6 +105,7 @@
"installed": "正常にインストールされました!",
"whatNextMcp": "このMCPサーバーを設定して使用できるようになりました。サイドバーのMCPアイコンをクリックしてタブを切り替えてください。",
"whatNextMode": "このモードを使用できるようになりました。サイドバーのモードアイコンをクリックしてタブを切り替えてください。",
+ "whatNextCommand": "チャットで /{{name}} と入力することで、このスラッシュコマンドを使用できるようになりました。",
"done": "完了",
"goToMcp": "MCPタブに移動",
"goToModes": "モード設定に移動",
@@ -147,6 +152,10 @@
"title": "MCPサーバーを削除",
"message": "MCPサーバー「{{mcpName}}」を本当に削除しますか?"
},
+ "command": {
+ "title": "スラッシュコマンドを削除",
+ "message": "スラッシュコマンド「{{commandName}}」を削除してもよろしいですか?"
+ },
"cancel": "キャンセル",
"confirm": "削除"
},
diff --git a/webview-ui/src/i18n/locales/ko/marketplace.json b/webview-ui/src/i18n/locales/ko/marketplace.json
index fd7d91c10e1..e1d8fabadef 100644
--- a/webview-ui/src/i18n/locales/ko/marketplace.json
+++ b/webview-ui/src/i18n/locales/ko/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "설치됨",
"settings": "설정",
- "browse": "찾아보기"
+ "browse": "찾아보기",
+ "slashCommands": "슬래시 명령어"
},
"done": "완료",
"refresh": "새로고침",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Marketplace 아이템 검색...",
"placeholderMcp": "MCP 검색...",
- "placeholderMode": "모드 검색..."
+ "placeholderMode": "모드 검색...",
+ "placeholderCommand": "슬래시 명령어 검색..."
},
"installed": {
"label": "상태별로 필터링",
@@ -23,7 +25,8 @@
"label": "유형별 필터:",
"all": "모든 유형",
"mode": "모드",
- "mcpServer": "MCP 서버"
+ "mcpServer": "MCP 서버",
+ "slashCommand": "슬래시 명령어"
},
"sort": {
"label": "정렬 기준:",
@@ -89,6 +92,7 @@
"title": "{{name}} 설치",
"titleMode": "{{name}} 모드 설치",
"titleMcp": "{{name}} MCP 설치",
+ "titleCommand": "{{name}} 슬래시 명령어 설치",
"scope": "설치 범위",
"project": "프로젝트 (현재 워크스페이스)",
"global": "전역 (모든 워크스페이스)",
@@ -101,6 +105,7 @@
"installed": "성공적으로 설치되었습니다!",
"whatNextMcp": "이제 이 MCP 서버를 설정하고 사용할 수 있습니다. 사이드바의 MCP 아이콘을 클릭하여 탭을 전환하세요.",
"whatNextMode": "이제 이 모드를 사용할 수 있습니다. 사이드바의 모드 아이콘을 클릭하여 탭을 전환하세요.",
+ "whatNextCommand": "이제 채팅에서 /{{name}}을 입력하여 이 슬래시 명령어를 사용할 수 있습니다.",
"done": "완료",
"goToMcp": "MCP 탭으로 이동",
"goToModes": "모드 설정으로 이동",
@@ -147,6 +152,10 @@
"title": "MCP 서버 제거",
"message": "정말로 '{{mcpName}}' MCP 서버를 제거하시겠습니까?"
},
+ "command": {
+ "title": "슬래시 명령어 제거",
+ "message": "슬래시 명령어 \"{{commandName}}\"을 제거하시겠습니까?"
+ },
"cancel": "취소",
"confirm": "제거"
},
diff --git a/webview-ui/src/i18n/locales/nl/marketplace.json b/webview-ui/src/i18n/locales/nl/marketplace.json
index b94c6294401..292c7aa4993 100644
--- a/webview-ui/src/i18n/locales/nl/marketplace.json
+++ b/webview-ui/src/i18n/locales/nl/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Geïnstalleerd",
"settings": "Instellingen",
- "browse": "Bladeren"
+ "browse": "Bladeren",
+ "slashCommands": "Slash-commando's"
},
"done": "Gereed",
"refresh": "Vernieuwen",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Marketplace-items zoeken...",
"placeholderMcp": "MCP's zoeken...",
- "placeholderMode": "Modi zoeken..."
+ "placeholderMode": "Modi zoeken...",
+ "placeholderCommand": "Zoek slash-commando's..."
},
"installed": {
"label": "Filteren op status",
@@ -23,7 +25,8 @@
"label": "Filteren op type:",
"all": "Alle types",
"mode": "Modus",
- "mcpServer": "MCP-server"
+ "mcpServer": "MCP-server",
+ "slashCommand": "Slash-commando"
},
"sort": {
"label": "Sorteren op:",
@@ -89,6 +92,7 @@
"title": "{{name}} installeren",
"titleMode": "{{name}} modus installeren",
"titleMcp": "{{name}} MCP installeren",
+ "titleCommand": "Slash-commando {{name}} installeren",
"scope": "Installatiebereik",
"project": "Project (huidige werkruimte)",
"global": "Globaal (alle werkruimtes)",
@@ -101,6 +105,7 @@
"installed": "Succesvol geïnstalleerd!",
"whatNextMcp": "Je kunt deze MCP-server nu configureren en gebruiken. Klik op het MCP-pictogram in de zijbalk om van tabblad te wisselen.",
"whatNextMode": "Je kunt deze modus nu gebruiken. Klik op het modi-pictogram in de zijbalk om van tabblad te wisselen.",
+ "whatNextCommand": "Je kunt dit slash-commando nu gebruiken door /{{name}} in de chat te typen.",
"done": "Gereed",
"goToMcp": "Ga naar MCP-tabblad",
"goToModes": "Ga naar Modi-instellingen",
@@ -147,6 +152,10 @@
"title": "MCP-server verwijderen",
"message": "Weet je zeker dat je de MCP-server \"{{mcpName}}\" wilt verwijderen?"
},
+ "command": {
+ "title": "Slash-commando verwijderen",
+ "message": "Weet je zeker dat je het slash-commando \"{{commandName}}\" wilt verwijderen?"
+ },
"cancel": "Annuleren",
"confirm": "Verwijderen"
},
diff --git a/webview-ui/src/i18n/locales/pl/marketplace.json b/webview-ui/src/i18n/locales/pl/marketplace.json
index d48dc34429c..e56c86ff80a 100644
--- a/webview-ui/src/i18n/locales/pl/marketplace.json
+++ b/webview-ui/src/i18n/locales/pl/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Zainstalowane",
"settings": "Ustawienia",
- "browse": "Przeglądaj"
+ "browse": "Przeglądaj",
+ "slashCommands": "Polecenia Slash"
},
"done": "Gotowe",
"refresh": "Odśwież",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Szukaj elementów marketplace...",
"placeholderMcp": "Szukaj MCPs...",
- "placeholderMode": "Szukaj trybów..."
+ "placeholderMode": "Szukaj trybów...",
+ "placeholderCommand": "Szukaj poleceń Slash..."
},
"installed": {
"label": "Filtruj według statusu",
@@ -23,7 +25,8 @@
"label": "Filtruj według typu:",
"all": "Wszystkie typy",
"mode": "Tryb",
- "mcpServer": "Serwer MCP"
+ "mcpServer": "Serwer MCP",
+ "slashCommand": "Polecenie Slash"
},
"sort": {
"label": "Sortuj według:",
@@ -89,6 +92,7 @@
"title": "Zainstaluj {{name}}",
"titleMode": "Zainstaluj tryb {{name}}",
"titleMcp": "Zainstaluj MCP {{name}}",
+ "titleCommand": "Zainstaluj polecenie Slash {{name}}",
"scope": "Zakres instalacji",
"project": "Projekt (bieżący obszar roboczy)",
"global": "Globalnie (wszystkie obszary robocze)",
@@ -101,6 +105,7 @@
"installed": "Zainstalowano pomyślnie!",
"whatNextMcp": "Możesz teraz skonfigurować i używać tego serwera MCP. Kliknij ikonę MCP na pasku bocznym, aby przełączyć zakładki.",
"whatNextMode": "Możesz teraz używać tego trybu. Kliknij ikonę Tryby na pasku bocznym, aby przełączyć zakładki.",
+ "whatNextCommand": "Możesz teraz używać tego polecenia slash, wpisując /{{name}} w czacie.",
"done": "Gotowe",
"goToMcp": "Przejdź do zakładki MCP",
"goToModes": "Przejdź do ustawień Trybów",
@@ -140,12 +145,16 @@
"removeConfirm": {
"mode": {
"title": "Usuń tryb",
- "message": "Czy na pewno chcesz usunąć tryb „{{modeName}}”?",
+ "message": "Czy na pewno chcesz usunąć tryb \"{{modeName}}\"?",
"rulesWarning": "Spowoduje to również usunięcie wszelkich powiązanych plików reguł dla tego trybu."
},
"mcp": {
"title": "Usuń serwer MCP",
- "message": "Czy na pewno chcesz usunąć serwer MCP „{{mcpName}}”?"
+ "message": "Czy na pewno chcesz usunąć serwer MCP \"{{mcpName}}\"?"
+ },
+ "command": {
+ "title": "Usuń polecenie Slash",
+ "message": "Czy na pewno chcesz usunąć polecenie slash \"{{commandName}}\"?"
},
"cancel": "Anuluj",
"confirm": "Usuń"
diff --git a/webview-ui/src/i18n/locales/pt-BR/marketplace.json b/webview-ui/src/i18n/locales/pt-BR/marketplace.json
index 80e47572506..511763e827a 100644
--- a/webview-ui/src/i18n/locales/pt-BR/marketplace.json
+++ b/webview-ui/src/i18n/locales/pt-BR/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Instalado",
"settings": "Configurações",
- "browse": "Navegar"
+ "browse": "Navegar",
+ "slashCommands": "Comandos Slash"
},
"done": "Concluído",
"refresh": "Atualizar",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Buscar itens do marketplace...",
"placeholderMcp": "Buscar MCPs...",
- "placeholderMode": "Buscar modos..."
+ "placeholderMode": "Buscar modos...",
+ "placeholderCommand": "Buscar comandos Slash..."
},
"installed": {
"label": "Filtrar por status",
@@ -23,7 +25,8 @@
"label": "Filtrar por tipo:",
"all": "Todos os tipos",
"mode": "Modo",
- "mcpServer": "Servidor MCP"
+ "mcpServer": "Servidor MCP",
+ "slashCommand": "Comando Slash"
},
"sort": {
"label": "Ordenar por:",
@@ -89,6 +92,7 @@
"title": "Instalar {{name}}",
"titleMode": "Instalar modo {{name}}",
"titleMcp": "Instalar MCP {{name}}",
+ "titleCommand": "Instalar comando Slash {{name}}",
"scope": "Escopo da instalação",
"project": "Projeto (workspace atual)",
"global": "Global (todos os workspaces)",
@@ -101,6 +105,7 @@
"installed": "Instalado com sucesso!",
"whatNextMcp": "Agora você pode configurar e usar este servidor MCP. Clique no ícone MCP na barra lateral para trocar de aba.",
"whatNextMode": "Agora você pode usar este modo. Clique no ícone Modos na barra lateral para trocar de aba.",
+ "whatNextCommand": "Agora você pode usar este comando slash digitando /{{name}} no chat.",
"done": "Concluído",
"goToMcp": "Ir para aba MCP",
"goToModes": "Ir para configurações de Modos",
@@ -147,6 +152,10 @@
"title": "Remover Servidor MCP",
"message": "Tem certeza de que deseja remover o servidor MCP \"{{mcpName}}\"?"
},
+ "command": {
+ "title": "Remover comando Slash",
+ "message": "Tem certeza de que deseja remover o comando slash \"{{commandName}}\"?"
+ },
"cancel": "Cancelar",
"confirm": "Remover"
},
diff --git a/webview-ui/src/i18n/locales/ru/marketplace.json b/webview-ui/src/i18n/locales/ru/marketplace.json
index 6c054a6b22e..95e95eed432 100644
--- a/webview-ui/src/i18n/locales/ru/marketplace.json
+++ b/webview-ui/src/i18n/locales/ru/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Установлено",
"settings": "Настройки",
- "browse": "Обзор"
+ "browse": "Обзор",
+ "slashCommands": "Slash-команды"
},
"done": "Готово",
"refresh": "Обновить",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Поиск элементов marketplace...",
"placeholderMcp": "Поиск MCPs...",
- "placeholderMode": "Поиск режимов..."
+ "placeholderMode": "Поиск режимов...",
+ "placeholderCommand": "Искать Slash-команды..."
},
"installed": {
"label": "Фильтр по статусу",
@@ -23,7 +25,8 @@
"label": "Фильтр по типу:",
"all": "Все типы",
"mode": "Режим",
- "mcpServer": "MCP сервер"
+ "mcpServer": "MCP сервер",
+ "slashCommand": "Slash-команда"
},
"sort": {
"label": "Сортировать по:",
@@ -89,6 +92,7 @@
"title": "Установить {{name}}",
"titleMode": "Установить режим {{name}}",
"titleMcp": "Установить MCP {{name}}",
+ "titleCommand": "Установить Slash-команду {{name}}",
"scope": "Область установки",
"project": "Проект (текущая рабочая область)",
"global": "Глобально (все рабочие области)",
@@ -101,6 +105,7 @@
"installed": "Успешно установлено!",
"whatNextMcp": "Теперь вы можете настроить и использовать этот MCP сервер. Нажмите на иконку MCP в боковой панели для переключения вкладок.",
"whatNextMode": "Теперь вы можете использовать этот режим. Нажмите на иконку Режимы в боковой панели для переключения вкладок.",
+ "whatNextCommand": "Теперь ты можешь использовать эту slash-команду, набрав /{{name}} в чате.",
"done": "Готово",
"goToMcp": "Перейти во вкладку MCP",
"goToModes": "Перейти в настройки Режимов",
@@ -147,6 +152,10 @@
"title": "Удалить сервер MCP",
"message": "Вы уверены, что хотите удалить сервер MCP «{{mcpName}}»?"
},
+ "command": {
+ "title": "Удалить Slash-команду",
+ "message": "Ты уверен, что хочешь удалить slash-команду \"{{commandName}}\"?"
+ },
"cancel": "Отмена",
"confirm": "Удалить"
},
diff --git a/webview-ui/src/i18n/locales/tr/marketplace.json b/webview-ui/src/i18n/locales/tr/marketplace.json
index 5b5a83a204a..59790448fcf 100644
--- a/webview-ui/src/i18n/locales/tr/marketplace.json
+++ b/webview-ui/src/i18n/locales/tr/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Yüklü",
"settings": "Ayarlar",
- "browse": "Gözat"
+ "browse": "Gözat",
+ "slashCommands": "Slash Komutları"
},
"done": "Tamamlandı",
"refresh": "Yenile",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Marketplace öğelerini ara...",
"placeholderMcp": "MCP'leri ara...",
- "placeholderMode": "Modları ara..."
+ "placeholderMode": "Modları ara...",
+ "placeholderCommand": "Slash komutlarını ara..."
},
"installed": {
"label": "Duruma göre filtrele",
@@ -23,7 +25,8 @@
"label": "Türe göre filtrele:",
"all": "Tüm türler",
"mode": "Mod",
- "mcpServer": "MCP Sunucusu"
+ "mcpServer": "MCP Sunucusu",
+ "slashCommand": "Slash Komutu"
},
"sort": {
"label": "Sırala:",
@@ -89,6 +92,7 @@
"title": "{{name}} Yükle",
"titleMode": "{{name}} Modunu Yükle",
"titleMcp": "{{name}} MCP'sini Yükle",
+ "titleCommand": "{{name}} Slash Komutunu Yükle",
"scope": "Yükleme Kapsamı",
"project": "Proje (mevcut çalışma alanı)",
"global": "Global (tüm çalışma alanları)",
@@ -101,6 +105,7 @@
"installed": "Başarıyla yüklendi!",
"whatNextMcp": "Artık bu MCP sunucusunu yapılandırabilir ve kullanabilirsiniz. Sekmeleri değiştirmek için kenar çubuğundaki MCP simgesine tıklayın.",
"whatNextMode": "Artık bu modu kullanabilirsiniz. Sekmeleri değiştirmek için kenar çubuğundaki Modlar simgesine tıklayın.",
+ "whatNextCommand": "Artık sohbette /{{name}} yazarak bu slash komutunu kullanabilirsin.",
"done": "Tamamlandı",
"goToMcp": "MCP Sekmesine Git",
"goToModes": "Modlar Ayarlarına Git",
@@ -147,6 +152,10 @@
"title": "MCP Sunucusunu Kaldır",
"message": "\"{{mcpName}}\" MCP sunucusunu kaldırmak istediğinizden emin misiniz?"
},
+ "command": {
+ "title": "Slash Komutunu Kaldır",
+ "message": "\"{{commandName}}\" slash komutunu kaldırmak istediğine emin misin?"
+ },
"cancel": "İptal",
"confirm": "Kaldır"
},
diff --git a/webview-ui/src/i18n/locales/vi/marketplace.json b/webview-ui/src/i18n/locales/vi/marketplace.json
index 29283bbfa28..8671841c693 100644
--- a/webview-ui/src/i18n/locales/vi/marketplace.json
+++ b/webview-ui/src/i18n/locales/vi/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "Đã cài đặt",
"settings": "Cài đặt",
- "browse": "Duyệt"
+ "browse": "Duyệt",
+ "slashCommands": "Lệnh Slash"
},
"done": "Hoàn thành",
"refresh": "Làm mới",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "Tìm kiếm các mục marketplace...",
"placeholderMcp": "Tìm kiếm MCP...",
- "placeholderMode": "Tìm kiếm Chế độ..."
+ "placeholderMode": "Tìm kiếm Chế độ...",
+ "placeholderCommand": "Tìm kiếm lệnh Slash..."
},
"installed": {
"label": "Lọc theo trạng thái",
@@ -23,7 +25,8 @@
"label": "Lọc theo loại:",
"all": "Tất cả loại",
"mode": "Chế độ",
- "mcpServer": "Máy chủ MCP"
+ "mcpServer": "Máy chủ MCP",
+ "slashCommand": "Lệnh Slash"
},
"sort": {
"label": "Sắp xếp theo:",
@@ -89,6 +92,7 @@
"title": "Cài đặt {{name}}",
"titleMode": "Cài đặt Chế độ {{name}}",
"titleMcp": "Cài đặt MCP {{name}}",
+ "titleCommand": "Cài đặt lệnh Slash {{name}}",
"scope": "Phạm vi cài đặt",
"project": "Dự án (không gian làm việc hiện tại)",
"global": "Toàn cục (tất cả không gian làm việc)",
@@ -101,6 +105,7 @@
"installed": "Cài đặt thành công!",
"whatNextMcp": "Bây giờ bạn có thể cấu hình và sử dụng máy chủ MCP này. Nhấp vào biểu tượng MCP trong thanh bên để chuyển tab.",
"whatNextMode": "Bây giờ bạn có thể sử dụng chế độ này. Nhấp vào biểu tượng Chế độ trong thanh bên để chuyển tab.",
+ "whatNextCommand": "Bây giờ bạn có thể sử dụng lệnh slash này bằng cách gõ /{{name}} trong trò chuyện.",
"done": "Hoàn thành",
"goToMcp": "Đi đến Tab MCP",
"goToModes": "Đi đến Cài đặt Chế độ",
@@ -147,6 +152,10 @@
"title": "Xóa máy chủ MCP",
"message": "Bạn có chắc chắn muốn xóa máy chủ MCP \"{{mcpName}}\" không?"
},
+ "command": {
+ "title": "Xóa lệnh Slash",
+ "message": "Bạn có chắc chắn muốn xóa lệnh slash \"{{commandName}}\" không?"
+ },
"cancel": "Hủy",
"confirm": "Xóa"
},
diff --git a/webview-ui/src/i18n/locales/zh-CN/marketplace.json b/webview-ui/src/i18n/locales/zh-CN/marketplace.json
index 34e2099aa53..43415c0b3da 100644
--- a/webview-ui/src/i18n/locales/zh-CN/marketplace.json
+++ b/webview-ui/src/i18n/locales/zh-CN/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "已安装",
"settings": "设置",
- "browse": "浏览"
+ "browse": "浏览",
+ "slashCommands": "Slash 命令"
},
"done": "完成",
"refresh": "刷新",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "搜索 Marketplace 项目...",
"placeholderMcp": "搜索 MCP...",
- "placeholderMode": "搜索模式..."
+ "placeholderMode": "搜索模式...",
+ "placeholderCommand": "搜索 Slash 命令..."
},
"installed": {
"label": "按状态筛选",
@@ -23,7 +25,8 @@
"label": "按类型筛选:",
"all": "所有类型",
"mode": "模式",
- "mcpServer": "MCP 服务"
+ "mcpServer": "MCP 服务",
+ "slashCommand": "Slash 命令"
},
"sort": {
"label": "排序方式:",
@@ -89,6 +92,7 @@
"title": "安装 {{name}}",
"titleMode": "安装 {{name}} 模式",
"titleMcp": "安装 {{name}} MCP",
+ "titleCommand": "安装 {{name}} Slash 命令",
"scope": "安装范围",
"project": "项目(当前工作区)",
"global": "全局(所有工作区)",
@@ -101,6 +105,7 @@
"installed": "安装成功!",
"whatNextMcp": "现在您可以配置和使用此 MCP 服务。点击侧边栏中的 MCP 图标切换标签页。",
"whatNextMode": "现在您可以使用此模式。点击侧边栏中的模式图标切换标签页。",
+ "whatNextCommand": "你现在可以在聊天中输入 /{{name}} 来使用这个 slash 命令。",
"done": "完成",
"goToMcp": "转到 MCP 标签页",
"goToModes": "转到模式设置",
@@ -147,6 +152,10 @@
"title": "删除 MCP 服务器",
"message": "您确定要删除 MCP 服务器\"{{mcpName}}\"吗?"
},
+ "command": {
+ "title": "移除 Slash 命令",
+ "message": "确定要移除 slash 命令\"{{commandName}}\"吗?"
+ },
"cancel": "取消",
"confirm": "删除"
},
diff --git a/webview-ui/src/i18n/locales/zh-TW/marketplace.json b/webview-ui/src/i18n/locales/zh-TW/marketplace.json
index a358c6efdd4..16e97ba2924 100644
--- a/webview-ui/src/i18n/locales/zh-TW/marketplace.json
+++ b/webview-ui/src/i18n/locales/zh-TW/marketplace.json
@@ -3,7 +3,8 @@
"tabs": {
"installed": "已安裝",
"settings": "設定",
- "browse": "瀏覽"
+ "browse": "瀏覽",
+ "slashCommands": "Slash 指令"
},
"done": "完成",
"refresh": "重新整理",
@@ -11,7 +12,8 @@
"search": {
"placeholder": "搜尋市集項目...",
"placeholderMcp": "搜尋 MCP...",
- "placeholderMode": "搜尋模式..."
+ "placeholderMode": "搜尋模式...",
+ "placeholderCommand": "搜尋 Slash 指令..."
},
"installed": {
"label": "按狀態篩選",
@@ -23,7 +25,8 @@
"label": "依類型篩選:",
"all": "所有類型",
"mode": "模式",
- "mcpServer": "MCP 伺服器"
+ "mcpServer": "MCP 伺服器",
+ "slashCommand": "Slash 指令"
},
"sort": {
"label": "排序方式:",
@@ -89,6 +92,7 @@
"title": "安裝 {{name}}",
"titleMode": "安裝 {{name}} 模式",
"titleMcp": "安裝 {{name}} MCP",
+ "titleCommand": "安裝 {{name}} Slash 指令",
"scope": "安裝範圍",
"project": "專案(目前工作區)",
"global": "全域(所有工作區)",
@@ -102,6 +106,7 @@
"installed": "安裝成功!",
"whatNextMcp": "您現在可以設定和使用此 MCP 伺服器。點選側邊欄的 MCP 圖示來切換分頁。",
"whatNextMode": "您現在可以使用此模式。點選側邊欄的模式圖示來切換分頁。",
+ "whatNextCommand": "你現在可以在聊天中輸入 /{{name}} 來使用這個 slash 指令。",
"done": "完成",
"goToMcp": "前往 MCP 分頁",
"goToModes": "前往模式設定",
@@ -147,6 +152,10 @@
"title": "移除 MCP 伺服器",
"message": "您確定要移除 MCP 伺服器「{{mcpName}}」嗎?"
},
+ "command": {
+ "title": "移除 Slash 指令",
+ "message": "確定要移除 slash 指令「{{commandName}}」嗎?"
+ },
"cancel": "取消",
"confirm": "移除"
},
From 774c095d5b8c91efa7086525f16d543a549e6753 Mon Sep 17 00:00:00 2001
From: Hannes Rudolph
Date: Mon, 8 Dec 2025 10:27:25 -0700
Subject: [PATCH 2/3] fix: use correct global commands path and add missing
i18n parameter
- MarketplaceManager: Use getGlobalRooDirectory() instead of extension settings path
for global commands detection, matching SimpleInstaller behavior
- MarketplaceInstallModal: Pass name parameter to whatNextCommand translation
---
src/services/marketplace/MarketplaceManager.ts | 3 ++-
.../marketplace/components/MarketplaceInstallModal.tsx | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/services/marketplace/MarketplaceManager.ts b/src/services/marketplace/MarketplaceManager.ts
index 231793f61fa..c192f60f716 100644
--- a/src/services/marketplace/MarketplaceManager.ts
+++ b/src/services/marketplace/MarketplaceManager.ts
@@ -12,6 +12,7 @@ import { GlobalFileNames } from "../../shared/globalFileNames"
import { ensureSettingsDirectoryExists } from "../../utils/globalContext"
import { t } from "../../i18n"
import type { CustomModesManager } from "../../core/config/CustomModesManager"
+import { getGlobalRooDirectory } from "../roo-config"
import { RemoteConfigLoader } from "./RemoteConfigLoader"
import { SimpleInstaller } from "./SimpleInstaller"
@@ -345,7 +346,7 @@ export class MarketplaceManager {
}
// Check global commands
- const globalCommandsDir = path.join(globalSettingsPath, "commands")
+ const globalCommandsDir = path.join(getGlobalRooDirectory(), "commands")
try {
const entries = await fs.readdir(globalCommandsDir, { withFileTypes: true })
for (const entry of entries) {
diff --git a/webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx b/webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx
index d7ef844f370..96237ed54fd 100644
--- a/webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx
+++ b/webview-ui/src/components/marketplace/components/MarketplaceInstallModal.tsx
@@ -246,7 +246,7 @@ export const MarketplaceInstallModal: React.FC = (
{item.type === "mcp"
? t("marketplace:install.whatNextMcp")
: item.type === "command"
- ? t("marketplace:install.whatNextCommand")
+ ? t("marketplace:install.whatNextCommand", { name: item.id })
: t("marketplace:install.whatNextMode")}
From 0b9214c1f6366166e088a524af6b275eb38deaf6 Mon Sep 17 00:00:00 2001
From: Hannes Rudolph
Date: Mon, 8 Dec 2025 10:52:03 -0700
Subject: [PATCH 3/3] fix: address i18n consistency issues in ca, ru, zh-TW
locales
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Capitalize 'Slash' consistently in Catalan message
- Use formal 'Вы/хотите' instead of informal 'Ты/хочешь' in Russian
- Use formal '您' instead of informal '你' in Traditional Chinese
- Capitalize 'Slash' consistently in Traditional Chinese messages
---
webview-ui/src/i18n/locales/ca/marketplace.json | 2 +-
webview-ui/src/i18n/locales/ru/marketplace.json | 2 +-
webview-ui/src/i18n/locales/zh-TW/marketplace.json | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/webview-ui/src/i18n/locales/ca/marketplace.json b/webview-ui/src/i18n/locales/ca/marketplace.json
index 17cbe0a19fb..cacd0b98502 100644
--- a/webview-ui/src/i18n/locales/ca/marketplace.json
+++ b/webview-ui/src/i18n/locales/ca/marketplace.json
@@ -156,7 +156,7 @@
},
"command": {
"title": "Eliminar comanda Slash",
- "message": "Estàs segur que vols eliminar la comanda slash \"{{commandName}}\"?"
+ "message": "Estàs segur que vols eliminar la comanda Slash \"{{commandName}}\"?"
},
"cancel": "Cancel·lar",
"confirm": "Eliminar"
diff --git a/webview-ui/src/i18n/locales/ru/marketplace.json b/webview-ui/src/i18n/locales/ru/marketplace.json
index 95e95eed432..5c63830d4d0 100644
--- a/webview-ui/src/i18n/locales/ru/marketplace.json
+++ b/webview-ui/src/i18n/locales/ru/marketplace.json
@@ -154,7 +154,7 @@
},
"command": {
"title": "Удалить Slash-команду",
- "message": "Ты уверен, что хочешь удалить slash-команду \"{{commandName}}\"?"
+ "message": "Вы уверены, что хотите удалить Slash-команду \"{{commandName}}\"?"
},
"cancel": "Отмена",
"confirm": "Удалить"
diff --git a/webview-ui/src/i18n/locales/zh-TW/marketplace.json b/webview-ui/src/i18n/locales/zh-TW/marketplace.json
index 16e97ba2924..b790692c70e 100644
--- a/webview-ui/src/i18n/locales/zh-TW/marketplace.json
+++ b/webview-ui/src/i18n/locales/zh-TW/marketplace.json
@@ -106,7 +106,7 @@
"installed": "安裝成功!",
"whatNextMcp": "您現在可以設定和使用此 MCP 伺服器。點選側邊欄的 MCP 圖示來切換分頁。",
"whatNextMode": "您現在可以使用此模式。點選側邊欄的模式圖示來切換分頁。",
- "whatNextCommand": "你現在可以在聊天中輸入 /{{name}} 來使用這個 slash 指令。",
+ "whatNextCommand": "您現在可以在聊天中輸入 /{{name}} 來使用這個 Slash 指令。",
"done": "完成",
"goToMcp": "前往 MCP 分頁",
"goToModes": "前往模式設定",
@@ -154,7 +154,7 @@
},
"command": {
"title": "移除 Slash 指令",
- "message": "確定要移除 slash 指令「{{commandName}}」嗎?"
+ "message": "您確定要移除 Slash 指令「{{commandName}}」嗎?"
},
"cancel": "取消",
"confirm": "移除"