feat(desktop): searchable picker menu for the repository chip and the Start model menu; the plan toolbar back to one row

Merged
DA
11d ago
+1095-495

Base coding-agents. Dean's direction, relayed by the orchestrator, in three parts: the repository picker redesigned as a devtool picker, the Start chevron's model menu on the same component, and the plan toolbar back to one row level with the side panel's bar.

What Dean saw

Opening the composer's repository chip drew a giant magnifying glass over the composer, an empty first row, a "Repositories" heading, and then the list. The glyph had no size: .plan-compose-menu-row svg and .plan-compose-chip svg were sized, the search row's was not, and an SVG with a viewBox and no size fills the row it is in. The Start chevron's menu listed the whole catalog (about forty models) with no scrolling, running off the window.

One shared menu: renderer/searchable-menu.tsx

SearchableMenu, a command palette in a menu's clothes, used by the repository chip and the Start button (Settings' menus are another worker's and will adopt it on rebase):

  • First row: the search field (Search repositories / Search models), a 16px glyph, focused as the menu opens, filtering as you type by the row's label and any extra terms (a model's provider). Omit placeholder and the menu draws no field, for a short list: the list holds focus and reads the same keys.
  • The list: compact 32px rows, an icon, the name, a check on the chosen row (aria-current); max-height: 288px, overflow-y: auto, overscroll-behavior: contain. Quiet empty states: No repositories match / No models match, and the owner's own note (Reading your repositories…, a failure with Try again, Luke can't see any repository yet., Reading the models…).
  • The foot, pinned under the list behind a hairline, always on screen.
  • Keyboard: arrows move one highlight (aria-selected) and wrap, the caret staying in the field; Enter picks the highlighted row; Escape closes with stopPropagation, so it closes the menu and not the panel; focus returns to the trigger. A pointer over a row moves the same highlight, and a press on a row is kept from taking focus, so there is one highlight however it was reached.
  • The look is the existing plan-compose-menu surface (12px radius, hairline, overlay, shadow), entering on menu-enter over --duration-quick / --motion-exit (the old rule named a search-enter keyframe that no longer existed). No literal milliseconds.
  • API: id, label, placeholder?, rows: MenuRow[] ({ id, label, icon?, terms? }), value, note?, noMatch, onPick, onClose, onLeave, foot?, className?.

The repository picker

  • No heading. Rows are the recent repositories first, then every repository the App reaches as the service ordered them (most recently updated first), each once; a private repository wears a new LockIcon glyph, the rest the GitHub mark.
  • The last row reads GitHub ↗, pinned under the list, and opens the App's installationUrl (the page that chooses which repositories Luke sees, or the install page when it is installed nowhere). The chip still reads Install Luke on GitHub ↗ and opens that page directly when the App is installed nowhere and no repository is named.
  • Everything B4 built stands: choosing sets the composer's repository, the same menu serves Change repository… and a plan with no repository, refusals show under the card, the list is read on mount and on window focus.

The Start chevron's model menu

  • Search by name or provider; the list scrolls; the efforts and Start with <model> · <effort> stand in the pinned foot.
  • Models are grouped by provider, Anthropic first, and newest first within each: orderedModels in planning/coding-agent-model.ts (exported for Settings too). The catalog carries no release date and the server is out of scope, so the version in the id stands for one (5.5 before 5.1 before 5, 6 before 5.6), catalog order kept between models of one version.
  • The check: the menu lands on readDefault's answer, which the server fills with anthropic/claude-opus-5.5 · high when the account stores nothing (account-app.ts), never on the first row; the catalog in the test now lists an older Claude first so the test tells the two apart. A check on Claude Fable 5 is a stored default.

The toolbar: one row again

  • The repository line under the plan title is gone; the toolbar is title, then the actions. .desktop-toolbar and .side-panel-bar are both height: var(--desktop-bar-height) (they shared the token as a min-height since #1755; the second line B4 put in the heading is what pushed the toolbar past it).
  • A plan with no repository shows a compact Choose repository chip in the actions row, left of Start, at the toolbar buttons' height. A plan with one shows it in the sidebar's row and no chip; ⋯ › Change repository… opens the same picker hung from the actions row's right edge, and Escape hands focus back to the ⋯ button.

Tests

  • searchable-menu.test.ts loads desktop.css into jsdom: every icon in the menu resolves to a px size (the regression test for the giant glyph; it fails without the .plan-compose-menu-search svg rule), the list's bound and contained scrolling, the foot outside the list, the two bars' height from one token; highlight from the chosen row, arrows with the field keeping focus, Enter, Escape, pointer highlight and the prevented mousedown, matching by label and terms, and the search-off mode.
  • new-plan-form.test.ts: the search as the first row and focused, recent first, the lock, the check, GitHub pinned and opening the installation URL, filtering, the keyboard path (type, arrow, Enter), the reading and empty states, the failure with Try again, Escape.
  • start-agent-button.test.ts: search by name and provider, newest first, the check on the default rather than the first row, the pinned foot, the reading state.
  • plan-actions.test.ts: the heading holds the title alone, no subtitle, the chip left of Start for a plan without a repository and absent for one with, Change repository… opening the picker from the toolbar with focus in the search and back on ⋯ after Escape.
  • coding-agent-model.test.ts: orderedModels.
  • A shared fixture #testing/scroll-into-view gives jsdom the scrollIntoView it lacks.

./scripts/check.sh exits 0. CI could not verify the Mac: Dean waived verify.sh for this work, so the layout above is described rather than captured. docs/PLANNING.md updated (composer repository chip, header, Start).


Open workspace in Conductor


Devin Review