mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-22 16:25:58 +00:00
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:
parent
27a4e92802
commit
15d33d5ab1
5 changed files with 43 additions and 4 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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": {}}
|
||||
|
|
|
|||
|
|
@ -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] = []
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue