Repository navigation
Add Claude-Code-style slash command autosuggest to the main chat composer - #275
Merged
Merged
Conversation
…oser
Typing `/` at the start of the composer now opens a dropdown of matching
slash commands (currently just /model), narrowed as more is typed. Up/Down
moves the highlight, Tab or Enter accepts it (inserting the name plus a
trailing space), and Escape dismisses the dropdown. Enter still sends the
message once the typed name is already exact, so /model{Enter} keeps working
as before.
Builds on the registry and token-matching helpers added to slashCommand.ts,
which future slash commands join automatically.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR #266 added
/modelas a minimal client-side parser (slashCommand.ts) plus command logic (modelCommand.ts), but it only recognized a fully-typed command on submit — there was no autosuggest UI. This builds the autosuggest layer on top of that, without touching/model's own semantics.Registry.
slashCommand.tsnow exportsSLASH_COMMANDS, a{ name, summary }[]registry (currently just/model), plus two small pure helpers:matchSlashCommands(registry, query)(prefix match, case-insensitive) andactiveSlashToken(text, caret)(is the caret inside the leading/nametoken, and what's typed so far). A future slash command just needs an entry inSLASH_COMMANDSto show up in the dropdown.Dropdown. There's no existing combobox/dropdown component in the app to reuse (checked
web/src/components/uiand the chat/explorer features) — the closest patterns areExplorerTree's roving-highlight list andRowMenu's floating popover, so the new menu borrows their conventions:bg-popover/border-border/shadow-mdfor the floating surface andbg-accent text-accent-foregroundfor the highlighted row, withrole="listbox"/role="option"/aria-selected. It's a plain absolutely-positioned<ul>anchored to the composer's ownrelativeinput bar (bottom-full), not a portal, since it only ever needs to sit directly above that one box.Where it lives.
Composertakes an optionalcommandsprop; when set, it tracks the caret and offers the dropdown.ThreadBodyforwards the prop;ChatPagepassesSLASH_COMMANDS.SessionChatSlot(the session composer, which sharesThreadBody/Composer) doesn't pass it, so that composer is unaffected — matching today's behavior where/modelonly means anything on the main thread.Keyboard model, matching the task's spec:
/<name>and moves the caret just past the space./model{Enter}keeps working exactly as Add a /model slash command to the main chat composer #266 shipped it — verified by the existing/modeltests, which I didn't touch).preventDefaultonmousedown).Deviation from the CLI: in Claude Code's terminal, Enter always accepts an open suggestion menu, and you'd use a different key (or an empty line) to send. Here Enter is also the composer's send key, so I added the "already exact" escape hatch — if I hadn't,
/model{Enter}would re-accept a no-op completion instead of running the command, which is worse than the CLI's own behavior in a chat box. Tab remains the unambiguous accept-only key, same as the CLI.Scope cuts, per the task: no argument-level suggestions after
/model(nice-to-have, skipped to keep this to the command-name autosuggest), no new slash commands, no change to/model's behavior.Test plan
vitest run src/features/chat(344 tests) andsrc/features/sessions(100 tests, since they shareComposer/ThreadBody) — all green.slashCommand.test.tscases formatchSlashCommandsandactiveSlashToken.Composer.test.tsxcases: dropdown open/close on a leading slash vs. ordinary text, prefix narrowing, closing once the caret passes into arguments, Up/Down with wraparound, Tab-complete, the Enter exact-vs-suggestion split, Escape, mouse accept, and that plain typing/Enter-to-send is unaffected when commands are registered.tsc -bandeslintclean on the changed files;make lintclean (one formatting autofix applied).dev_syncfailed three times in a row on an unrelated backend-pod issue (copy to backend was interrupted ... container not found, backend pod at 9 restarts) that a frontend-only TS/React change cannot cause.dev_statusreports all podsRunning/ready. Flagging as an infra blocker rather than retrying further.🤖 Generated with Claude Code