fix(desktop): surface skill & quick-command slash commands in the palette (#38531)

The desktop chat app's slash curation (desktop-slash-commands.ts) only
suggested the ~19 curated built-ins. isDesktopSlashSuggestion required
membership in DESKTOP_COMMANDS, so every skill-derived command and user
quick_command was silently dropped from both completion paths
(commands.catalog empty-query + complete.slash typed-query) and from
filterDesktopCommandsCatalog — even though isDesktopSlashCommand let them
EXECUTE when typed in full. The tui_gateway backend already includes skills
in both RPCs; the gap was purely renderer-side.

Add isDesktopSlashExtensionCommand() (= not-a-known-Hermes-built-in, the
same predicate that already gates execution) and let extensions through the
suggestion path. The catalog filter routes through isDesktopSlashSuggestion,
so skill/quick-command categories and pairs are kept automatically.
This commit is contained in:
Teknium
2026-06-03 16:24:06 -07:00
committed by GitHub
parent 96f0ddc6a9
commit 5c0a1fec0c
3 changed files with 52 additions and 5 deletions
@@ -17,8 +17,9 @@ describe('desktop slash command curation', () => {
expect(isDesktopSlashSuggestion('/usage')).toBe(true)
})
it('lets explicitly typed extension commands run without suggesting them', () => {
expect(isDesktopSlashSuggestion('/my-skill')).toBe(false)
it('surfaces skill and quick commands (extensions) in suggestions and lets them run', () => {
expect(isDesktopSlashSuggestion('/my-skill')).toBe(true)
expect(isDesktopSlashSuggestion('/gif-search')).toBe(true)
expect(isDesktopSlashCommand('/my-skill')).toBe(true)
})
@@ -38,7 +39,7 @@ describe('desktop slash command curation', () => {
expect(isDesktopSlashCommand('/reset')).toBe(true)
})
it('filters command catalogs down to core desktop commands', () => {
it('filters built-in catalog noise but keeps skill / quick-command extensions', () => {
const filtered = filterDesktopCommandsCatalog({
categories: [
{
@@ -61,8 +62,14 @@ describe('desktop slash command curation', () => {
skill_count: 2
})
expect(filtered.categories).toEqual([{ name: 'Session', pairs: [['/new', 'Start a new desktop chat']] }])
expect(filtered.pairs).toEqual([['/new', 'Start a new desktop chat']])
expect(filtered.categories).toEqual([
{ name: 'Session', pairs: [['/new', 'Start a new desktop chat']] },
{ name: 'User commands', pairs: [['/ship-it', 'Run release checklist']] }
])
expect(filtered.pairs).toEqual([
['/new', 'Start a new desktop chat'],
['/ship-it', 'Run release checklist']
])
expect(filtered.skill_count).toBe(2)
})
@@ -150,10 +150,35 @@ export function isDesktopSlashCommand(command: string): boolean {
return DESKTOP_COMMANDS.has(canonical) || !isKnownHermesSlashCommand(normalized)
}
/**
* An "extension" command is anything the backend surfaces that is NOT one of
* Hermes' built-in slash commands — i.e. skill commands (`/gif-search`,
* `/codex`, …) and user-defined quick commands. These are user-activated, so
* they should appear in the desktop slash palette even though they aren't in
* the curated `DESKTOP_COMMANDS` allow-list. This mirrors the predicate in
* `isDesktopSlashCommand` that already lets them EXECUTE when typed.
*/
export function isDesktopSlashExtensionCommand(command: string): boolean {
const normalized = normalizeCommand(command)
if (!normalized || normalized === '/') {
return false
}
return !isKnownHermesSlashCommand(normalized)
}
export function isDesktopSlashSuggestion(command: string): boolean {
const normalized = normalizeCommand(command)
const canonical = canonicalDesktopSlashCommand(normalized)
// Surface skill / quick commands (extensions the backend provides) alongside
// the curated built-ins. Built-in aliases stay hidden so the popover isn't
// cluttered with duplicates.
if (isDesktopSlashExtensionCommand(normalized)) {
return true
}
return DESKTOP_COMMANDS.has(canonical) && !DESKTOP_ALIASES.has(normalized)
}