Skip to content

feat(cli): make /models, /help and /effort say what they mean - #56

Merged
AetherAI3 merged 2 commits into
mainfrom
feat/cli-slash-ui-polish
Jul 28, 2026
Merged

feat(cli): make /models, /help and /effort say what they mean#56
AetherAI3 merged 2 commits into
mainfrom
feat/cli-slash-ui-polish

Conversation

@AetherAI3

Copy link
Copy Markdown
Owner

Three surfaces a user reads constantly, each losing information a different way.

/effort was missing a tier

The orchestrator's closed set is LOW/MED/HIGH/MAX/ULTRA/CODEPRO (lib/orchestrator/presets/contracts.py), and anything outside it is silently coerced to MED. The CLI dial had five entries — HIGH was unreachable from the CLI at all.

⚠️ Behaviour change worth a second opinion: adding it renumbers the shortcuts. /effort 5 is now ULTRA, not CODEPRO; the top of the dial is 6. Names are what travel on the wire, and the slider echoes the resolved tier on every set, so a mis-numbered entry is visible immediately — but it is a change to muscle memory. Easy to revert if you'd rather keep the old numbering and leave HIGH unreachable.

The slider also gained a legend naming what the dial actually moves — phases, sub-agent fan-out, repair passes, UVT ceiling — read off EffectiveEffortPolicy rather than invented, plus the two capabilities CODEPRO alone unlocks (System-2 review, unlimited context). It previously showed a position with no units.

/models columns drifted

Rows were tab-separated with a marker column mixing * (one column) against a lock emoji (two). Any id crossing a tab stop shifted every following column, so the lock — the one thing the eye needs to be steady — landed somewhere different on each row.

Columns now pad by visible width via ui/text.visibleWidth, grouped into MODELS and ORCHESTRATORS, and a locked row states the tier that unlocks it instead of only showing a padlock. --json output is unchanged.

/help dead-ended on anything but an exact name

renderRegistryHelp returned "Unknown command" for any target that wasn't an exact name or alias — so help vault or help git, a user describing what they want rather than naming it, hit a dead end standing next to a registry that could have answered.

Adds a substring search over names, summaries, sections and aliases, running after exact match and before did-you-mean, so both existing paths are untouched. Command detail now lists siblings in the same section. Output is styled (it was flat text), and the usage column pads to the widest entry present rather than a hard 42 columns — which previously let a long usage butt straight against its own summary.

Also: the slash footer read for detail ? Tab completes — a mangled · that shipped as a question mark and parsed as part of the sentence.

Test plan

  • npm run typecheck clean
  • 822 pass
  • The one failure (migration_guard's @types/node pin) is pre-existing — package.json is not in this diff and its last commit is HEAD, the dependabot bump that broke it
  • The registry arg-hint test is now tied to EFFORT_TIERS.length, so the hint can never again advertise a range the dial doesn't accept — which is how it went stale
  • Eyeball /models, /help, /help <word> and /effort in a real terminal

🤖 Generated with Claude Code

AetherAI3 and others added 2 commits July 27, 2026 18:14
Three surfaces a user reads constantly, each losing information a different way.

/models — rows were tab-separated with a marker column mixing "*" (one column)
with a lock emoji (two). Any id crossing a tab stop shifted every following
column, so the lock — the one thing the eye needs to be steady — landed
somewhere different on each row. Columns are now padded by VISIBLE width via
ui/text.visibleWidth, grouped into MODELS and ORCHESTRATORS, and a locked row
states the tier that unlocks it instead of only showing a padlock. --json output
is unchanged.

/help — renderRegistryHelp emitted flat, unstyled text, and any target that was
not an exact command name returned "Unknown command", so `help vault` or
`help git` (a user describing what they want rather than naming it) hit a dead
end next to a registry that could have answered. Adds a substring search over
names, summaries, sections and aliases, running AFTER exact match and BEFORE
did-you-mean so both existing paths are untouched. Command detail now lists
sibling commands in the same section. Section rows are styled, and the usage
column pads to the widest entry present rather than a hard 42 columns, which
previously let a long usage butt straight against its own summary.

The slash footer read "for detail ? Tab completes" — a mangled "·" that shipped
as a question mark and parsed as part of the sentence.

/effort — the dial was missing HIGH. The orchestrator's closed tier set is
LOW/MED/HIGH/MAX/ULTRA/CODEPRO (lib/orchestrator/presets/contracts.py), and
anything outside it is silently coerced to MED, so the CLI simply could not
reach a tier the backend accepts. Adding it shifts the numeric shortcuts: the
top of the dial is 6, and /effort 5 is now ULTRA rather than CODEPRO. Names are
what travel on the wire and the slider echoes the resolved tier on every set, so
a mis-numbered entry is visible immediately.

The slider also gained a legend naming what the dial moves — phases, sub-agent
fan-out, repair passes, UVT ceiling — taken from EffectiveEffortPolicy rather
than invented, plus the two capabilities CODEPRO alone unlocks (System-2 review,
unlimited context). It showed a position with no units before.

Tests: 822 pass. The one failure, migration_guard's @types/node pin, is
pre-existing — package.json is not in this diff and its last commit is HEAD
(the dependabot bump that broke it). The registry arg-hint test is now tied to
EFFORT_TIERS.length so the hint can never again advertise a range the dial
does not accept.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…floor

CI has been red on main since fc0fa41, which bumped @types/node to ^26.1.1.
The bump contradicts the package's own contract: engines.node is ">=24", so
typing the project against Node 26 lets tsc accept code using APIs that do not
exist on the Node 24 this package claims to support — a type error that only
shows up at a user's runtime.

test/migration_guard.test.ts asserts exactly that pairing and is the thing that
went red. The guard is correct and the dependency bump is not, so this restores
the ^24.0.0 range that was in place before it.

Unblocks the CI gate on this branch. Worth a dependabot ignore rule for
@types/node majors so the same bump does not land again.

Tests: 823 pass, 0 fail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@AetherAI3
AetherAI3 merged commit 20552a4 into main Jul 28, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant