fix(desktop,tui,docs): dedup commands.catalog, route desktop /compact to /compress, update README

- tui_gateway commands.catalog: skip _TUI_EXTRA entries that collide with a
  registry command or alias (the /compact class of bug, #57133; also removes
  the pre-existing /sessions duplicate) — registry entry is canonical.
- apps/desktop: /compact now dispatches as an alias of /compress (matching
  the registry's canonical alias) instead of dead-ending; /density (the
  renamed TUI display toggle) is marked terminal-only so the desktop palette
  doesn't advertise a command its dispatcher can't run.
- ui-tui/README.md: document /density instead of the old /compact toggle.
- tests: commands.catalog regression test asserting no duplicate advertised
  names and no command shadowing another command's alias; desktop routing test.
This commit is contained in:
Teknium 2026-07-22 04:43:29 -07:00
parent 27a4e92802
commit 15d33d5ab1
5 changed files with 43 additions and 4 deletions

View file

@ -31,7 +31,7 @@ describe('desktop slash command curation', () => {
it('hides terminal, messaging, and dedicated-UI commands from suggestions', () => {
expect(isDesktopSlashSuggestion('/clear')).toBe(false)
expect(isDesktopSlashSuggestion('/compact')).toBe(false)
expect(isDesktopSlashSuggestion('/density')).toBe(false)
expect(isDesktopSlashSuggestion('/redraw')).toBe(false)
expect(isDesktopSlashSuggestion('/approve')).toBe(false)
expect(isDesktopSlashSuggestion('/model')).toBe(false)
@ -40,6 +40,14 @@ describe('desktop slash command curation', () => {
expect(isDesktopSlashSuggestion('/curator')).toBe(false)
})
it('routes /compact to /compress (context compression), not the TUI display toggle', () => {
expect(resolveDesktopCommand('/compact')?.name).toBe('/compress')
expect(isDesktopSlashCommand('/compact')).toBe(true)
// Alias stays out of the popover so /compress is the single visible entry.
expect(isDesktopSlashSuggestion('/compact')).toBe(false)
expect(isDesktopSlashSuggestion('/compress')).toBe(true)
})
it('surfaces /tools, /save, and /personality on the desktop', () => {
expect(isDesktopSlashSuggestion('/tools')).toBe(true)
expect(isDesktopSlashSuggestion('/save')).toBe(true)

View file

@ -148,7 +148,7 @@ const DESKTOP_COMMAND_SPECS: readonly DesktopCommandSpec[] = [
surface: exec()
},
{ name: '/background', description: 'Run a prompt in the background', aliases: ['/bg', '/btw'], surface: exec() },
{ name: '/compress', description: 'Compress this conversation context', surface: exec() },
{ name: '/compress', description: 'Compress this conversation context', aliases: ['/compact'], surface: exec() },
{ name: '/debug', description: 'Create a debug report', surface: exec() },
{ name: '/goal', description: 'Manage the standing goal for this session', surface: exec() },
{ name: '/personality', description: 'Switch personality for this session', surface: exec(), args: true },
@ -187,10 +187,10 @@ const NO_DESKTOP_SURFACE: Record<DesktopUnavailableReason, readonly string[]> =
terminal: [
'/busy',
'/clear',
'/compact',
'/config',
'/copy',
'/cron',
'/density',
'/details',
'/exit',
'/footer',

View file

@ -6418,6 +6418,30 @@ def test_commands_catalog_includes_tui_mouse_command():
assert "/mouse" in tui_pairs
def test_commands_catalog_has_no_duplicate_or_alias_colliding_names():
"""No command may be advertised twice, and no advertised command may
shadow an alias of a different command (e.g. the historical /compact
collision where the registry aliased compact -> compress while the TUI
also registered its own /compact display toggle; see #57133)."""
resp = server.handle_request(
{"id": "1", "method": "commands.catalog", "params": {}}
)
names = [name for name, _ in resp["result"]["pairs"]]
dupes = {n for n in names if names.count(n) > 1}
assert not dupes, f"duplicate commands advertised in catalog: {sorted(dupes)}"
canon = resp["result"]["canon"]
colliding = {
name
for name in names
if canon.get(name.lower(), name) != name
}
assert not colliding, (
f"catalog commands shadow aliases of other commands: {sorted(colliding)}"
)
def test_commands_catalog_filters_gateway_only_commands_and_keeps_status_visible():
resp = server.handle_request(
{"id": "1", "method": "commands.catalog", "params": {}}

View file

@ -13342,6 +13342,13 @@ def _(rid, params: dict) -> dict:
cat_map[cat].append([c, desc])
for name, desc, cat in _TUI_EXTRA:
# Dedup guard: skip TUI extras that collide with a registry
# command or one of its aliases (e.g. the historical /compact
# collision, #57133, or /sessions which the registry also
# advertises). The registry entry is canonical.
if name.lower() in canon:
continue
canon[name.lower()] = name
all_pairs.append([name, desc])
if cat not in cat_map:
cat_map[cat] = []

View file

@ -225,7 +225,7 @@ The following commands are handled directly by the TUI client. Unrecognized comm
### Core (`core.ts`)
`/help`, `/quit` (alias `/exit`), `/update`, `/clear` (alias `/new`),
`/compact`, `/copy`, `/paste`, `/details` (alias `/detail`),
`/density`, `/copy`, `/paste`, `/details` (alias `/detail`),
`/statusbar` (alias `/sb`), `/queue` (alias `/q`), `/logs`, `/history`,
`/save`, `/undo`, `/retry`, `/steer`, `/mouse` (alias `/scroll`),
`/status`, `/title`, `/fortune`, `/redraw`, `/terminal-setup`