Skip to content

connect: full-width composer that wraps, readline shortcuts, and a live model list#79

Merged
hbrooks merged 1 commit into
mainfrom
connect-composer-polish
Jul 25, 2026
Merged

connect: full-width composer that wraps, readline shortcuts, and a live model list#79
hbrooks merged 1 commit into
mainfrom
connect-composer-polish

Conversation

@hbrooks

@hbrooks hbrooks commented Jul 25, 2026

Copy link
Copy Markdown
Member

Summary

Seven papercuts in the multi-session UI's new-session pane and nav bar.

  • Heading now asks "What are we shipping today?" instead of "What would you like to do?"
  • Full-width input: the pane carried a paddingLeft={1} that inset the composer's rules one column from the header's and the nav's. Removed; the rows inside carry their own indents.
  • Wrapping: a long prompt truncated and ran off the right edge. Now wrap="wrap" against an explicit width, so it flows onto the next row and the box grows downward into the spacer above.
  • Model list from the API: the picker's options were hardcoded and had gone stale (no Opus 5, and "Default" still claimed Opus 4.8). Now fetched from GET /v1/models, so it tracks the server registry instead of drifting each time we enable a model. An older server without that route falls back to a built-in list.
  • Readline shortcuts in both text inputs (the chat composer and the new-session prompt) via a new shared src/lib/editing.ts: option/ctrl+arrows and meta+b/f hop a word, ctrl+a/e reach the line edges, option+backspace and ctrl+w kill a word, ctrl+u/k kill to the line edges. cmd+arrows never reach the process (macOS terminals keep the command modifier for themselves), so ctrl+a/e stand in for it.
  • Nav dividers: vertical rules between session cells, so the bar reads as discrete sessions rather than one run of text.
  • Nav new-session button is pinned at its full label width ("+ New session", never a truncated "+ Ne…"). A crowded bar drops session cells instead, which the "N more" tail already accounts for.

Depends on a backend change

GET /v1/models does not exist yet. /models exists but is a dashboard-cookie route the CLI's bearer token cannot call, so this PR needs the companion v1_router.py change (reusing the models router's supported_models()) before the picker reads live data. Until then the fallback list applies; I verified it matches the server registry exactly, Opus 5 and the default flag included.

Test plan

  • vitest run — 298 pass, including new coverage for composerModelOptions (server order, default naming, empty fallback) and all of applyEditShortcut
  • tsc --noEmit clean
  • Drove the TUI in tmux: heading, full-width rules, nav dividers, and the model picker selecting Opus 5
  • Typed a 130-char prompt and watched it wrap rather than run off-screen
  • Confirmed option+left, ctrl+a, ctrl+e, and ctrl+w move and kill text (caret position read from capture-pane -e)
  • Nav checked at 40/60/80/120/160 columns: the new-session button stays whole and cells drop; 40 previously wrapped the bar onto an extra row
  • Not UI-verified: the chat composer's shortcuts. Every session in my list is watch-only (laptop-synced or Slack-owned), so no composer was reachable. It calls the same helper driven live in the new-session pane, and the helper is unit-tested, but I did not observe it there.

…ve model list

The new-session pane had grown several papercuts that made it read as a
prototype rather than the place you start work:

- the heading asked "What would you like to do?"; it now asks what we are
  shipping today
- the prompt input sat one column in from the edge, so its rules did not
  line up with the header's or the nav's
- a long prompt truncated and ran off the right edge instead of wrapping
- neither text input honored the readline bindings a terminal actually
  delivers (option+arrows, ctrl+a/e/w/u/k), so a typo mid-prompt meant
  holding down the left arrow
- the model picker's list was hardcoded and had gone stale, missing Opus 5
- the session nav ran its cells together as one strip of text, and its
  new-session button truncated to "+ Ne…" once the bar got crowded

The model list now comes from GET /v1/models, so the picker tracks the
server's registry instead of drifting from it every time we enable a model.
An older server without that route falls back to the built-in list.

The nav gains vertical rules between cells and pins the new-session button
at its full label width, dropping session cells (which the "› N more" tail
already accounts for) when the terminal is too narrow for both.
@hbrooks
hbrooks merged commit d0e1fa5 into main Jul 25, 2026
1 check 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