Repository navigation
feat(composer): effort shortcuts, palette sub-options and status announcements - #844
Merged
Merged
Conversation
Two shell chords, unbound by default, step the composer's reasoning effort one level through the selected model's levels. They read the starting effort, the levels and the choice path from the model picker itself (`resolveSelectedModelEffort`, `stepModelEffort`, `persistModelPickerPreferences`), so the shortcut and the picker cannot disagree. A step stops at either end instead of wrapping, and does nothing for Stave Auto, a model without levels, a task an agent runs, or while an approval or question owns the composer. Assign a letter under Settings -> Command Palette -> Shell chords; the shortcut list and docs show them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…f task search While a query is typed, the command palette offers up to three options from inside commands: "Theme: <name>", "Appearance: Light/Dark/System" and "New task in <repository>". An option whose own name matches the query exactly ranks first; nothing is offered for an empty query. Options are built once per palette context and ranked per keystroke, outside store selectors, and are not pinned or kept in Recent. Tasks created by another task's delegation no longer get their own "Switch task" entry or appear in the search across repositories; they are reached through their parent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One hidden polite live region, mounted once in the app shell, speaks the open task's state when it changes: Working, Needs your input, Needs approval, Done, Failed or Stopped. Opening or switching to a task is silent because its first known state is the baseline; a transcript that is still loading has no state, and a turn's end is spoken only after the task was seen in a turn, so loading history never sounds like news. The state comes from the same classification Fleet uses and is read through one primitive store selector cached per message list, so the region re-renders only when the state changes and the timeline is never re-rendered by it. The composer run line no longer carries its own live region, so each change is spoken once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e commands A query that brings suggested options highlights the first one, so Enter runs it. The pin action follows only a command that is on screen; before, a command the query had filtered away could stay selected and be pinned with Alt+P. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
astyfx
requested review from
heath-s and
schang124
and removed request for
a team
October 27, 2026 14:31
|
| Commit | Scanned at | New | Resolved | Net |
|---|---|---|---|---|
9f3599e |
2026-10-27 14:31 UTC | 0 | 0 | 0 |
aed6de7 < |
2026-10-27 23:58 UTC | 0 | 0 | 0 |
Last scanned: aed6de7 · 2026-10-27 23:58 UTC
schang124
approved these changes
Oct 27, 2026
…wn hooks The effort command wiring and the existing Enter/Tab approval shortcut both answer window-level keys for the active task's composer. They now live in `use-composer-window-shortcuts.ts` as two hooks with unchanged behavior, which brings `ChatInputComposer.tsx` back under its max-lines ratchet; the ratchet entry drops to the new size. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The palette steered its selection through `Command.value`, which only moves the drawn `data-selected` row, while Enter runs the list's own highlight. With All repositories, an option could be drawn as selected while Enter opened a task from an older search that was still on screen. The list's highlight is now the only selection: it is drawn, run by Enter and pinned by Alt+P. Suggested options sit above task results, so a new query starts on them, and they are offered on a word, prefix or substring match only, not on scattered letters. The command palette preview can hold search responses back (`searchDelay=<ms>`) and records what it runs; an end-to-end test covers the delayed-search case, the first search result, and arrow keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opening another repository waits for it to load, and the person may go to another workspace meanwhile; the task was then created wherever they had gone. The request is now pinned to the chosen repository: after the open it creates the task only if the app is still in that repository and no newer "New task in" request was made, and otherwise creates nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An error a provider recovers from (it retries inside the running turn) made the task read as failed in the attention vocabulary, so the announcer said "Failed" while the turn was still working. An error while the turn runs now stays "Working"; "Failed" is spoken once the turn has ended on the failure (a failed receipt, or an error the turn stopped on). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The announcer stored the translated words, so after a language switch the region kept the old language. It now stores which state was announced and words it at render time, in a small region component the test renders in English and Korean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
astyfx
enabled auto-merge (squash)
October 28, 2026 01:31
astyfx
added a commit
that referenced
this pull request
Oct 28, 2026
Bring in #839, #840, #841, #842, #844 and #846. - Placeholder: one resolver. Main's `resolvePromptPlaceholder` now also takes `approvalRedirect` and returns the decline-and-steer or decline-and-queue keys. The duplicate `resolvePromptInputPlaceholder` is removed, and its tests now go through `resolvePromptPlaceholder`. - Approval keys: main's `useComposerApprovalShortcuts` now returns the Enter/Tab handler the empty editor uses. `use-approval-window-shortcuts.ts` is removed. - The composer's redirect-mode derivation moves into `resolveComposerApprovalRedirectMode`, which keeps `ChatInputComposer.tsx` and `prompt-input.tsx` within main's lowered line limits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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
Cmd/Ctrl+Kunder Settings → Command Palette → Shell chords (they appear there and in the shortcut list). They reuse the model picker's own logic for the starting effort, the levels and the choice path, so the two cannot drift.Theme: <name>,Appearance: Light/Dark/System,New task in <repository>. An option whose own name matches the query exactly ranks first. Nothing is suggested for an empty query.Changes
Effort
ai-elements/model-effort-step.tsholds three functions that the picker and the shortcuts both call:resolveSelectedModelEffort: the effort the picker marks as selected.stepModelEffort: the next level. Levels come from the model's catalog row, the same list the picker grid shows.persistModelPickerPreferences: what the picker remembers when you choose.session/use-composer-window-shortcuts.tsholds the composer's window-level keys as two hooks:useComposerEffortShortcut: the new effort commands.useComposerApprovalShortcuts: the existing Enter/Tab approval keys, moved out ofChatInputComposer.tsxwith no behavior change.agentChoice.selectModel, the same path a picker click takes. A step does nothing when:ChatInputComposer.tsxgoes from 1898 to 1844 lines. Its entry inconfig/max-lines-ratchet.jsonis lowered from 1899 to 1845.lib/app-shortcuts.ts,keybinding-registry.tsanduseAppKeybindings.tsadd two shell chords with an empty default key.docs/features/keyboard-shortcuts.mdlists them.Palette
layout/command-palette-leaves.tsbuilds options once per palette context and ranks them on each keystroke. It is pure, runs outside store selectors, and is memoized in the palette.Command.valueis no longer passed, and the effects that set the selection by hand are gone.startTaskInRepositorypins the request to the chosen repository. After the repository opens, the task is created only if the app is still in that repository (its active workspace belongs to it) and no newer "New task in" request was made. Otherwise nothing is created.CommandPaletteTaskSummary.isDelegatedskips a delegated task's "Switch task" entry; the active task stays known for context.electron/persistence/task-search.tsskipsisDelegatedTaskrows.docs/features/command-palette.mdis updated.searchDelay=<ms>holds search responses back.window.__stavePalettePreviewrecords what the palette runs.Announcements
lib/task-status-announcement.ts:resolveTaskAnnouncementStatemaps the Fleet classification (classifyTaskStatus) and the last turn's receipt or stop reason to an announcement state. An error while the turn is still running stays "Working". "Failed" is spoken only once the turn has ended on the failure (a failed receipt, or an error the turn stopped on). The transcript does not record whether an error is recoverable, so "the turn is still running" is the signal used.advanceTaskAnnouncementdecides what to speak. The first state after opening or switching a task is the baseline. A transcript that is still loading has no state. Done, Failed and Stopped are spoken only after the task was seen in a turn. Idle is never spoken.layout/TaskStatusAnnouncer.tsxis mounted once inAppShelland subscribes to one primitive state string. The state is cached per message list, so the component re-renders only when the state changes, and the timeline never re-renders because of it.TaskStatusAnnouncerRegionwords it at render time, so the text follows the app language.composer-shelf/TurnRunLine.tsxno longer has its own live announcement, so each change is spoken once. The agent run lines keep theirs.i18n: every new string is in en and ko (
shell:appShortcuts.*Effort*,shell:commandPaletteLeaves.*,shell:taskStatusAnnouncer.*).Verification
Run locally on the current head:
bun run check:licenses,check:reliability-gates,check:temporary-migrations,check:i18n(29 namespaces, en/ko),check:doc-paths,check:design-system,build:pages,check:max-lines-ratchet(64 files),check:switch-exhaustiveness,lint,typecheck,typecheck:lens-main.i18n.languagememo-dependency pattern, which rebuilds option titles when the language changes.bun test(19 files): 231 pass, 0 fail.command-palette-leaves,task-status-announcement,model-effort-step,app-shortcuts,keybinding-docs,keybinding-registry,app-keybinding-dispatch,model-effort-selector-utils,model-selector-effort,agent-model-selector,command-palette,command-palette-navigation,command-palette-scripts,task-search,composer-shelf-render,chat-input-approval-queue,chat-input.utils,chat-input-utils,custom-theme.PLAYWRIGHT_WEB_PORT=4891 bunx --bun playwright test tests/e2e/command-palette-options.e2e.ts: 3 pass. It runs against the command palette preview with delayed search responses.customThemeId: dracula; no task opened). This test failed before the selection fix: the highlight was on the stale task row.tests/e2e/base-ui-migration.e2e.ts: the same 4 tests fail on this branch and onorigin/main. They need the full app with the dev bridge.bun run test:isolated: 8927 pass, 1 fail. The failure isclaude-sdk-runtime.test.ts› "keeps the generic rate limit wording when the window is unknown". The expected time string now includes the date, so it depends on the run date; it is unrelated to this PR.bun test testsrun fails the same 187 tests on this branch and onorigin/main(process-spawn, ACP, git and provider-runtime suites).Screenshots (headless Chrome, 1280x900, not committed)
command-palette, "dracula" (dark): before, "No command matches 'dracula'". After, an Options group with "Theme: Dracula", highlighted.command-palette, "dark" (light): after, "Appearance: Dark" (marked Current) first, then two dark themes, then the usual results. Exactly three options.command-palette, "new task" (dark, Korean): after, "shop에서 새 작업" (subtitle "현재 저장소") above the existing "새 작업" command.command-palettewith an empty query: the same as before, with no Options group.composer-framewith the model picker open (light and dark): the same as before. Claude Opus 5.5 · Medium is still the selected cell after the picker moved to the shared effort helpers.These were taken before the later selection and option-matching fixes. The "dracula", "dark" and empty-query cases are covered again by the end-to-end test above.
Not verified / risks
ChatInputComposer. Coverage comes from the shared step, preference and ownership functions, plus typecheck. I did not press the chord in the running desktop app.🤖 Generated with Claude Code