= ({
)}
)
+ case ContextMenuOptionType.Command:
+ return (
+
+ {option.label}
+ {option.description && (
+
+ {option.description}
+
+ )}
+
+ )
case ContextMenuOptionType.Problems:
return Problems
case ContextMenuOptionType.Terminal:
@@ -163,6 +196,8 @@ const ContextMenu: React.FC = ({
switch (option.type) {
case ContextMenuOptionType.Mode:
return "symbol-misc"
+ case ContextMenuOptionType.Command:
+ return "play"
case ContextMenuOptionType.OpenedFile:
return "window"
case ContextMenuOptionType.File:
diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx
index ff1ce31c53c..cb51fe9c9a3 100644
--- a/webview-ui/src/context/ExtensionStateContext.tsx
+++ b/webview-ui/src/context/ExtensionStateContext.tsx
@@ -10,7 +10,7 @@ import {
ORGANIZATION_ALLOW_ALL,
} from "@roo-code/types"
-import { ExtensionMessage, ExtensionState, MarketplaceInstalledMetadata } from "@roo/ExtensionMessage"
+import { ExtensionMessage, ExtensionState, MarketplaceInstalledMetadata, Command } from "@roo/ExtensionMessage"
import { findLastIndex } from "@roo/array"
import { McpServer } from "@roo/mcp"
import { checkExistKey } from "@roo/checkExistApiConfig"
@@ -33,6 +33,7 @@ export interface ExtensionStateContextType extends ExtensionState {
currentCheckpoint?: string
filePaths: string[]
openedTabs: Array<{ label: string; isActive: boolean; path?: string }>
+ commands: Command[]
organizationAllowList: OrganizationAllowList
cloudIsAuthenticated: boolean
sharingEnabled: boolean
@@ -242,6 +243,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
const [theme, setTheme] = useState(undefined)
const [filePaths, setFilePaths] = useState([])
const [openedTabs, setOpenedTabs] = useState>([])
+ const [commands, setCommands] = useState([])
const [mcpServers, setMcpServers] = useState([])
const [currentCheckpoint, setCurrentCheckpoint] = useState()
const [extensionRouterModels, setExtensionRouterModels] = useState(undefined)
@@ -308,6 +310,10 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
setOpenedTabs(tabs)
break
}
+ case "commands": {
+ setCommands(message.commands ?? [])
+ break
+ }
case "messageUpdated": {
const clineMessage = message.clineMessage!
setState((prevState) => {
@@ -372,6 +378,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
currentCheckpoint,
filePaths,
openedTabs,
+ commands,
soundVolume: state.soundVolume,
ttsSpeed: state.ttsSpeed,
fuzzyMatchThreshold: state.fuzzyMatchThreshold,
diff --git a/webview-ui/src/i18n/locales/ca/chat.json b/webview-ui/src/i18n/locales/ca/chat.json
index 8865da01c24..ace10191cfc 100644
--- a/webview-ui/src/i18n/locales/ca/chat.json
+++ b/webview-ui/src/i18n/locales/ca/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Edita el teu missatge..."
+ },
+ "command": {
+ "triggerDescription": "Activa la comanda {{name}}"
}
}
diff --git a/webview-ui/src/i18n/locales/de/chat.json b/webview-ui/src/i18n/locales/de/chat.json
index c28a41aabd8..692f3c3afb1 100644
--- a/webview-ui/src/i18n/locales/de/chat.json
+++ b/webview-ui/src/i18n/locales/de/chat.json
@@ -344,6 +344,9 @@
"description": "Führe Remote-Agenten in der Cloud aus, greife von überall auf deine Aufgaben zu, arbeite mit anderen zusammen und vieles mehr.",
"joinWaitlist": "Tritt der Warteliste bei, um frühen Zugang zu erhalten."
},
+ "command": {
+ "triggerDescription": "Starte den {{name}} Befehl"
+ },
"editMessage": {
"placeholder": "Bearbeite deine Nachricht..."
}
diff --git a/webview-ui/src/i18n/locales/en/chat.json b/webview-ui/src/i18n/locales/en/chat.json
index b5e9c1da16b..441dad589d3 100644
--- a/webview-ui/src/i18n/locales/en/chat.json
+++ b/webview-ui/src/i18n/locales/en/chat.json
@@ -346,5 +346,8 @@
"title": "Roo Code Cloud is coming soon!",
"description": "Run Roomote agents in the cloud, access your tasks from anywhere, collaborate with others, and more.",
"joinWaitlist": "Join the waitlist to get early access."
+ },
+ "command": {
+ "triggerDescription": "Trigger the {{name}} command"
}
}
diff --git a/webview-ui/src/i18n/locales/es/chat.json b/webview-ui/src/i18n/locales/es/chat.json
index da2973027c0..a379f4cfe07 100644
--- a/webview-ui/src/i18n/locales/es/chat.json
+++ b/webview-ui/src/i18n/locales/es/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Edita tu mensaje..."
+ },
+ "command": {
+ "triggerDescription": "Activar el comando {{name}}"
}
}
diff --git a/webview-ui/src/i18n/locales/fr/chat.json b/webview-ui/src/i18n/locales/fr/chat.json
index 1153dea6c01..09ac5da79b1 100644
--- a/webview-ui/src/i18n/locales/fr/chat.json
+++ b/webview-ui/src/i18n/locales/fr/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Modifiez votre message..."
+ },
+ "command": {
+ "triggerDescription": "Déclencher la commande {{name}}"
}
}
diff --git a/webview-ui/src/i18n/locales/hi/chat.json b/webview-ui/src/i18n/locales/hi/chat.json
index 114384da18c..99699335c0d 100644
--- a/webview-ui/src/i18n/locales/hi/chat.json
+++ b/webview-ui/src/i18n/locales/hi/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "अपना संदेश संपादित करें..."
+ },
+ "command": {
+ "triggerDescription": "{{name}} कमांड को ट्रिगर करें"
}
}
diff --git a/webview-ui/src/i18n/locales/id/chat.json b/webview-ui/src/i18n/locales/id/chat.json
index e272ba3fa20..e40ca9c7f70 100644
--- a/webview-ui/src/i18n/locales/id/chat.json
+++ b/webview-ui/src/i18n/locales/id/chat.json
@@ -352,5 +352,8 @@
},
"editMessage": {
"placeholder": "Edit pesan Anda..."
+ },
+ "command": {
+ "triggerDescription": "Jalankan perintah {{name}}"
}
}
diff --git a/webview-ui/src/i18n/locales/it/chat.json b/webview-ui/src/i18n/locales/it/chat.json
index 4a0b58180bf..97329b4c750 100644
--- a/webview-ui/src/i18n/locales/it/chat.json
+++ b/webview-ui/src/i18n/locales/it/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Modifica il tuo messaggio..."
+ },
+ "command": {
+ "triggerDescription": "Attiva il comando {{name}}"
}
}
diff --git a/webview-ui/src/i18n/locales/ja/chat.json b/webview-ui/src/i18n/locales/ja/chat.json
index 1db33759d57..c6de5224fcf 100644
--- a/webview-ui/src/i18n/locales/ja/chat.json
+++ b/webview-ui/src/i18n/locales/ja/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "メッセージを編集..."
+ },
+ "command": {
+ "triggerDescription": "{{name}}コマンドをトリガー"
}
}
diff --git a/webview-ui/src/i18n/locales/ko/chat.json b/webview-ui/src/i18n/locales/ko/chat.json
index 9af867fe7a2..132e8a19ea4 100644
--- a/webview-ui/src/i18n/locales/ko/chat.json
+++ b/webview-ui/src/i18n/locales/ko/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "메시지 편집..."
+ },
+ "command": {
+ "triggerDescription": "{{name}} 명령 트리거"
}
}
diff --git a/webview-ui/src/i18n/locales/nl/chat.json b/webview-ui/src/i18n/locales/nl/chat.json
index 0c95429b553..62cbad798d5 100644
--- a/webview-ui/src/i18n/locales/nl/chat.json
+++ b/webview-ui/src/i18n/locales/nl/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Bewerk je bericht..."
+ },
+ "command": {
+ "triggerDescription": "Activeer de {{name}} opdracht"
}
}
diff --git a/webview-ui/src/i18n/locales/pl/chat.json b/webview-ui/src/i18n/locales/pl/chat.json
index c2cb70a05d3..371e81e77ae 100644
--- a/webview-ui/src/i18n/locales/pl/chat.json
+++ b/webview-ui/src/i18n/locales/pl/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Edytuj swoją wiadomość..."
+ },
+ "command": {
+ "triggerDescription": "Uruchom polecenie {{name}}"
}
}
diff --git a/webview-ui/src/i18n/locales/pt-BR/chat.json b/webview-ui/src/i18n/locales/pt-BR/chat.json
index 64a6b4a067a..61d28acaffe 100644
--- a/webview-ui/src/i18n/locales/pt-BR/chat.json
+++ b/webview-ui/src/i18n/locales/pt-BR/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Edite sua mensagem..."
+ },
+ "command": {
+ "triggerDescription": "Acionar o comando {{name}}"
}
}
diff --git a/webview-ui/src/i18n/locales/ru/chat.json b/webview-ui/src/i18n/locales/ru/chat.json
index a860c9e94e1..4cfbb368057 100644
--- a/webview-ui/src/i18n/locales/ru/chat.json
+++ b/webview-ui/src/i18n/locales/ru/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Редактировать сообщение..."
+ },
+ "command": {
+ "triggerDescription": "Запустить команду {{name}}"
}
}
diff --git a/webview-ui/src/i18n/locales/tr/chat.json b/webview-ui/src/i18n/locales/tr/chat.json
index 6ddca0a6256..1a5d1438b5e 100644
--- a/webview-ui/src/i18n/locales/tr/chat.json
+++ b/webview-ui/src/i18n/locales/tr/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Mesajını düzenle..."
+ },
+ "command": {
+ "triggerDescription": "{{name}} komutunu tetikle"
}
}
diff --git a/webview-ui/src/i18n/locales/vi/chat.json b/webview-ui/src/i18n/locales/vi/chat.json
index 61b11998ade..4195845279d 100644
--- a/webview-ui/src/i18n/locales/vi/chat.json
+++ b/webview-ui/src/i18n/locales/vi/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "Chỉnh sửa tin nhắn của bạn..."
+ },
+ "command": {
+ "triggerDescription": "Kích hoạt lệnh {{name}}"
}
}
diff --git a/webview-ui/src/i18n/locales/zh-CN/chat.json b/webview-ui/src/i18n/locales/zh-CN/chat.json
index a19d7af5f01..c3787cce0ee 100644
--- a/webview-ui/src/i18n/locales/zh-CN/chat.json
+++ b/webview-ui/src/i18n/locales/zh-CN/chat.json
@@ -344,6 +344,9 @@
"description": "在云端运行远程代理,随时随地访问任务,与他人协作等更多功能。",
"joinWaitlist": "加入等待列表获取早期访问权限。"
},
+ "command": {
+ "triggerDescription": "触发 {{name}} 命令"
+ },
"editMessage": {
"placeholder": "编辑消息..."
}
diff --git a/webview-ui/src/i18n/locales/zh-TW/chat.json b/webview-ui/src/i18n/locales/zh-TW/chat.json
index 45053a4493e..27c53f8ed67 100644
--- a/webview-ui/src/i18n/locales/zh-TW/chat.json
+++ b/webview-ui/src/i18n/locales/zh-TW/chat.json
@@ -346,5 +346,8 @@
},
"editMessage": {
"placeholder": "編輯訊息..."
+ },
+ "command": {
+ "triggerDescription": "觸發 {{name}} 命令"
}
}
diff --git a/webview-ui/src/utils/__tests__/context-mentions.spec.ts b/webview-ui/src/utils/__tests__/context-mentions.spec.ts
index 50fb1b1c504..f0266cc07f6 100644
--- a/webview-ui/src/utils/__tests__/context-mentions.spec.ts
+++ b/webview-ui/src/utils/__tests__/context-mentions.spec.ts
@@ -194,8 +194,16 @@ describe("getContextMenuOptions", () => {
{ path: "/Users/test/project/assets/", type: "folder", label: "assets/" },
]
+ // Mock translation function
+ const mockT = (key: string, options?: { name?: string }) => {
+ if (key === "chat:command.triggerDescription" && options?.name) {
+ return `Trigger command: ${options.name}`
+ }
+ return key
+ }
+
it("should return all option types for empty query", () => {
- const result = getContextMenuOptions("", "", null, [])
+ const result = getContextMenuOptions("", "", mockT, null, [])
expect(result).toHaveLength(6)
expect(result.map((item) => item.type)).toEqual([
ContextMenuOptionType.Problems,
@@ -208,7 +216,7 @@ describe("getContextMenuOptions", () => {
})
it("should filter by selected type when query is empty", () => {
- const result = getContextMenuOptions("", "", ContextMenuOptionType.File, mockQueryItems)
+ const result = getContextMenuOptions("", "", mockT, ContextMenuOptionType.File, mockQueryItems)
expect(result).toHaveLength(2)
expect(result.map((item) => item.type)).toContain(ContextMenuOptionType.File)
expect(result.map((item) => item.type)).toContain(ContextMenuOptionType.OpenedFile)
@@ -217,19 +225,19 @@ describe("getContextMenuOptions", () => {
})
it("should match git commands", () => {
- const result = getContextMenuOptions("git", "git", null, mockQueryItems)
+ const result = getContextMenuOptions("git", "git", mockT, null, mockQueryItems)
expect(result[0].type).toBe(ContextMenuOptionType.Git)
expect(result[0].label).toBe("Git Commits")
})
it("should match git commit hashes", () => {
- const result = getContextMenuOptions("abc1234", "abc1234", null, mockQueryItems)
+ const result = getContextMenuOptions("abc1234", "abc1234", mockT, null, mockQueryItems)
expect(result[0].type).toBe(ContextMenuOptionType.Git)
expect(result[0].value).toBe("abc1234")
})
it("should return NoResults when no matches found", () => {
- const result = getContextMenuOptions("nonexistent", "nonexistent", null, mockQueryItems)
+ const result = getContextMenuOptions("nonexistent", "nonexistent", mockT, null, mockQueryItems)
expect(result).toHaveLength(1)
expect(result[0].type).toBe(ContextMenuOptionType.NoResults)
})
@@ -250,7 +258,7 @@ describe("getContextMenuOptions", () => {
},
]
- const result = getContextMenuOptions("test", "test", null, testItems, mockDynamicSearchResults)
+ const result = getContextMenuOptions("test", "test", mockT, null, testItems, mockDynamicSearchResults)
// Check if opened files and dynamic search results are included
expect(result.some((item) => item.type === ContextMenuOptionType.OpenedFile)).toBe(true)
@@ -259,7 +267,7 @@ describe("getContextMenuOptions", () => {
it("should maintain correct result ordering according to implementation", () => {
// Add multiple item types to test ordering
- const result = getContextMenuOptions("t", "t", null, mockQueryItems, mockDynamicSearchResults)
+ const result = getContextMenuOptions("t", "t", mockT, null, mockQueryItems, mockDynamicSearchResults)
// Find the different result types
const fileResults = result.filter(
@@ -290,7 +298,7 @@ describe("getContextMenuOptions", () => {
})
it("should include opened files when dynamic search results exist", () => {
- const result = getContextMenuOptions("open", "open", null, mockQueryItems, mockDynamicSearchResults)
+ const result = getContextMenuOptions("open", "open", mockT, null, mockQueryItems, mockDynamicSearchResults)
// Verify opened files are included
expect(result.some((item) => item.type === ContextMenuOptionType.OpenedFile)).toBe(true)
@@ -299,7 +307,7 @@ describe("getContextMenuOptions", () => {
})
it("should include git results when dynamic search results exist", () => {
- const result = getContextMenuOptions("commit", "commit", null, mockQueryItems, mockDynamicSearchResults)
+ const result = getContextMenuOptions("commit", "commit", mockT, null, mockQueryItems, mockDynamicSearchResults)
// Verify git results are included
expect(result.some((item) => item.type === ContextMenuOptionType.Git)).toBe(true)
@@ -320,7 +328,7 @@ describe("getContextMenuOptions", () => {
},
]
- const result = getContextMenuOptions("test", "test", null, mockQueryItems, duplicateSearchResults)
+ const result = getContextMenuOptions("test", "test", mockT, null, mockQueryItems, duplicateSearchResults)
// Count occurrences of src/test.ts in results
const duplicateCount = result.filter(
@@ -340,6 +348,7 @@ describe("getContextMenuOptions", () => {
const result = getContextMenuOptions(
"nonexistentquery123456",
"nonexistentquery123456",
+ mockT,
null,
mockQueryItems,
[], // Empty dynamic search results
@@ -387,7 +396,7 @@ describe("getContextMenuOptions", () => {
]
// Get results for "test" query
- const result = getContextMenuOptions(testQuery, testQuery, null, testItems, testSearchResults)
+ const result = getContextMenuOptions(testQuery, testQuery, mockT, null, testItems, testSearchResults)
// Verify we have results
expect(result.length).toBeGreaterThan(0)
@@ -433,7 +442,7 @@ describe("getContextMenuOptions", () => {
},
]
- const result = getContextMenuOptions("/co", "/co", null, [], [], mockModes)
+ const result = getContextMenuOptions("/co", "/co", mockT, null, [], [], mockModes)
// Verify mode results are returned
expect(result[0].type).toBe(ContextMenuOptionType.Mode)
@@ -443,7 +452,7 @@ describe("getContextMenuOptions", () => {
it("should not process slash commands when query starts with slash but inputValue doesn't", () => {
// Use a completely non-matching query to ensure we get NoResults
// and provide empty query items to avoid any matches
- const result = getContextMenuOptions("/nonexistentquery", "Hello /code", null, [], [])
+ const result = getContextMenuOptions("/nonexistentquery", "Hello /code", mockT, null, [], [])
// Should not process as a mode command
expect(result[0].type).not.toBe(ContextMenuOptionType.Mode)
@@ -453,7 +462,7 @@ describe("getContextMenuOptions", () => {
// --- Tests for Escaped Spaces (Focus on how paths are presented) ---
it("should return search results with correct labels/descriptions (no escaping needed here)", () => {
- const options = getContextMenuOptions("@search", "search", null, mockQueryItems, mockSearchResults)
+ const options = getContextMenuOptions("@search", "search", mockT, null, mockQueryItems, mockSearchResults)
const fileResult = options.find((o) => o.label === "search result spaces.ts")
expect(fileResult).toBeDefined()
// Value should be the normalized path, description might be the same or label
@@ -466,7 +475,7 @@ describe("getContextMenuOptions", () => {
})
it("should return query items (like opened files) with correct labels/descriptions", () => {
- const options = getContextMenuOptions("open", "@open", null, mockQueryItems, [])
+ const options = getContextMenuOptions("open", "@open", mockT, null, mockQueryItems, [])
const openedFile = options.find((o) => o.label === "open file.ts")
expect(openedFile).toBeDefined()
expect(openedFile?.value).toBe("src/open file.ts")
@@ -483,7 +492,7 @@ describe("getContextMenuOptions", () => {
]
// The formatting happens in getContextMenuOptions when converting search results to menu items
- const formattedItems = getContextMenuOptions("spaces", "@spaces", null, [], searchResults)
+ const formattedItems = getContextMenuOptions("spaces", "@spaces", mockT, null, [], searchResults)
// Verify we get some results back that aren't "No Results"
expect(formattedItems.length).toBeGreaterThan(0)
diff --git a/webview-ui/src/utils/context-mentions.ts b/webview-ui/src/utils/context-mentions.ts
index 889dca9dbea..50ab3cf12b3 100644
--- a/webview-ui/src/utils/context-mentions.ts
+++ b/webview-ui/src/utils/context-mentions.ts
@@ -1,6 +1,7 @@
import { Fzf } from "fzf"
import type { ModeConfig } from "@roo-code/types"
+import type { Command } from "@roo/ExtensionMessage"
import { mentionRegex } from "@roo/context-mentions"
@@ -105,6 +106,7 @@ export enum ContextMenuOptionType {
Git = "git",
NoResults = "noResults",
Mode = "mode", // Add mode type
+ Command = "command", // Add command type
}
export interface ContextMenuQueryItem {
@@ -118,43 +120,83 @@ export interface ContextMenuQueryItem {
export function getContextMenuOptions(
query: string,
inputValue: string,
+ t: (key: string, options?: { name?: string }) => string,
selectedType: ContextMenuOptionType | null = null,
queryItems: ContextMenuQueryItem[],
dynamicSearchResults: SearchResult[] = [],
modes?: ModeConfig[],
+ commands?: Command[],
): ContextMenuQueryItem[] {
- // Handle slash commands for modes
+ // Handle slash commands for modes and commands
if (query.startsWith("/") && inputValue.startsWith("/")) {
- const modeQuery = query.slice(1)
- if (!modes?.length) return [{ type: ContextMenuOptionType.NoResults }]
-
- // Create searchable strings array for fzf
- const searchableItems = modes.map((mode) => ({
- original: mode,
- searchStr: mode.name,
- }))
-
- // Initialize fzf instance for fuzzy search
- const fzf = new Fzf(searchableItems, {
- selector: (item) => item.searchStr,
- })
+ const slashQuery = query.slice(1)
+ const results: ContextMenuQueryItem[] = []
+
+ // Add mode suggestions
+ if (modes?.length) {
+ // Create searchable strings array for fzf
+ const searchableItems = modes.map((mode) => ({
+ original: mode,
+ searchStr: mode.name,
+ }))
+
+ // Initialize fzf instance for fuzzy search
+ const fzf = new Fzf(searchableItems, {
+ selector: (item) => item.searchStr,
+ })
- // Get fuzzy matching items
- const matchingModes = modeQuery
- ? fzf.find(modeQuery).map((result) => ({
- type: ContextMenuOptionType.Mode,
- value: result.item.original.slug,
- label: result.item.original.name,
- description: getModeDescription(result.item.original),
- }))
- : modes.map((mode) => ({
- type: ContextMenuOptionType.Mode,
- value: mode.slug,
- label: mode.name,
- description: getModeDescription(mode),
- }))
+ // Get fuzzy matching items
+ const matchingModes = slashQuery
+ ? fzf.find(slashQuery).map((result) => ({
+ type: ContextMenuOptionType.Mode,
+ value: result.item.original.slug,
+ label: result.item.original.name,
+ description: getModeDescription(result.item.original),
+ }))
+ : modes.map((mode) => ({
+ type: ContextMenuOptionType.Mode,
+ value: mode.slug,
+ label: mode.name,
+ description: getModeDescription(mode),
+ }))
+
+ results.push(...matchingModes)
+ }
+
+ // Add command suggestions
+ if (commands?.length) {
+ // Create searchable strings array for fzf
+ const searchableCommands = commands.map((command) => ({
+ original: command,
+ searchStr: command.name,
+ }))
+
+ // Initialize fzf instance for fuzzy search
+ const fzf = new Fzf(searchableCommands, {
+ selector: (item) => item.searchStr,
+ })
+
+ // Get fuzzy matching commands
+ const matchingCommands = slashQuery
+ ? fzf.find(slashQuery).map((result) => ({
+ type: ContextMenuOptionType.Command,
+ value: result.item.original.name,
+ label: result.item.original.name,
+ description: t("chat:command.triggerDescription", { name: result.item.original.name }),
+ icon: "$(play)",
+ }))
+ : commands.map((command) => ({
+ type: ContextMenuOptionType.Command,
+ value: command.name,
+ label: command.name,
+ description: t("chat:command.triggerDescription", { name: command.name }),
+ icon: "$(play)",
+ }))
+
+ results.push(...matchingCommands)
+ }
- return matchingModes.length > 0 ? matchingModes : [{ type: ContextMenuOptionType.NoResults }]
+ return results.length > 0 ? results : [{ type: ContextMenuOptionType.NoResults }]
}
const workingChanges: ContextMenuQueryItem = {