cmux-next composer: footer swaps whole units sooner, never an ellipsis (folds in #20548)

Merged
TE
17d ago
+2189-133

Summary

Leo's report showed the composer footer cutting labels ("Claude O…", "M.") and, around 290 px, the access chip running into the mic. This PR makes the footer swap whole units sooner, so fewer controls drop out:

  • Effort stays a chip of its own (Leo, 10-15: reasoning inside the model chip was weird). It's not folded in and not in the model menu. cg-composer's #20946, which made the reasoning chip clickable on its own before a session reports, is merged in. Its held chip gets the same short name ("Med"). The New Tab row's effort chip now steps at the same composer width instead of shrinking into "M…". The New Tab model chip still shrinks as #20548 left it.
  • As the pane narrows, each unit moves to a shorter whole form: the effort level's short name ("Med Fast"), the model's family ("Opus"), the access glyph alone, and the model's harness mark alone. The mic leaves only once nothing else can shrink. No label is cut and no ellipsis appears.
  • #20548 (fix/cx-narrow-layouts) is merged into this branch. Its composer container query on .acpmux-composer, .nt-composer replaces this PR's earlier pane container. Its 298 px row step is now the table's rowTight: 297. Its agent-pane.narrow gallery and narrow-layouts.test.ts come along, with checks adjusted for whole-unit forms. A comment on #20548 says it can close when this lands.

This PR covers the footer row only. The location strip's machine and folder steps belong to cg-composer.

Steps

COMPOSER_FIT_STEPS and ROW_FIT_STEPS in composerRowFit.ts hold every step. Widths are the composer's content width (about the pane width less 36 px), applied with @container composer queries. The measuring hook is a safety net for labels too long for their width (a long model name, or a long mode in another language). It applies the next steps in table order, and the mic goes last.

Composer widthWhat changes
> 470Opus 5.5 ⌄ · Medium Fast ⌄ · lock Auto ⌄ · mic · Send
≤ 470The effort chip shows its level's short name: Med Fast
≤ 440The model shows its family: Opus
≤ 420The access label goes. The glyph (warning color kept) and chevron stay
≤ 370The model shows its harness mark alone, with a tooltip naming "Claude Opus 5.5"
≤ 340The mic leaves (a listening mic stays so a click can stop it)
≤ 297Tighter group gaps (#20548's step)
≤ 260Tighter row edge and inset

At every width the row keeps +, the effort chip, the access glyph, Send/Stop and every chevron. No label is under 3 characters and no two hit targets overlap. test/composer-fit-steps.test.ts parses composerLocation.css and holds every @container composer width to the table.

References:

  • The compact-composer verdict (RESULTS.md, items 3 to 5): whole units, no ellipsis.
  • Borrowed from shadcn AI Elements (prompt input): short labels as the norm, and icon-only with an accessible name as the floor. The model's mark carries the full name in its tooltip and aria-label. I didn't take their left/right toolbar split or their spacing scale.

Testing

test/reasoning-chip-steps.test.ts covers the reasoning chip on the New Tab page (#20946's held chip, and an agent that reported "Medium Fast") and on a new chat, at 760, 400 and 300 px. Command: bun test test/reasoning-chip-steps.test.ts, on sbx.

  • Red at 46d47d84f548 (feat-cmux-next a4122f0c0fc7 merged, before the fix): 3 pass, 6 fail. The 400 and 300 px chips read "Medium". On New Tab at 300 px, "Medium Fast" overflows by 47 px and ends in an ellipsis.
  • Green on the head: 9 pass, 0 fail.

test/composer-row-steps.test.ts loads the real pane in the gallery (agent-pane.composer-row, variant leo-report: Claude Opus 5.5, Fast on, Medium, Auto) in Chromium at 760, 520, 500, 460, 440, 400, 360, 300 and 280 px. At each width it checks every control's visible label (text plus ::before), clipping, ellipses, labels under 3 characters, chevrons, the mark's tooltip, bar overflow and pairwise overlap. The command was the same on both sides: bun test test/composer-row-steps.test.ts, on sbx.

  • Red on base ba0ea8545abf plus the test and gallery variant: 0 pass, 9 fail. For example, "Medium Fast" overflows its box by up to 68 px, "Claude Opus 5.5" by up to 101 px, access overlaps the mic by 28 px and Send by 4 px, and the mic is still in the row.
  • Green on the head: 9 pass, 0 fail.
  • On the head (feat-cmux-next 3648305c9baa merged): bun run check is clean. 43 files (reasoning-own-control, reasoning-chip-steps, every composer-, model-picker-, the New Tab composer/menu/picker files, newtab-quiet-focus, narrow-layouts, tooltip-rules, ui-rules, pane-english, new-chat-effort-chip, claude-reasoning-default and agent-pane-bottom-stack): 292 pass, 1 fail. The 1 is tooltip-rules flagging pages/home-channels/LiveTyping.tsx:52, a base red that #21057 fixes; this PR doesn't touch that file. An earlier run before that merge, which also covered row-rhythm, bottom-stack, turn-cycle, location-strip, model-picker-picks and claude-reasoning-default, was green as well.
  • test/browser/composer-rim.html now gives each composer the width a pane gives it. With the composer as a size container (#20548), a shrink-to-fit flex item collapsed to its 36 px padding and the next composer covered the chip in #20792's new focus test. That test and composer-rim-hairline: 26 pass, 0 fail.
  • gen-strings.mjs --check passes. The new effort.short.* strings (High, Low, Med, Max, XHigh) are in all 21 locales, and the catalog is +660/−0 against base.
  • crash_ratchet.py passes.

Captures

Gallery stills, not the real app. They come from the real pane component (agent-pane.composer-row, variant leo-report) in Chromium at 2x, cropped to the composer. The before side is base ba0ea8545abf plus the gallery variant. Real-app stills are blocked by the DEV-build launch SIGTRAP (cx-qukj2). I didn't try the short-tag workaround.

WidthSchemeBefore (base)After (this PR)
760 pxlightbefore light 760after light 760
760 pxdarkbefore dark 760after dark 760
400 pxlightbefore light 400after light 400
400 pxdarkbefore dark 400after dark 400
300 pxlightbefore light 300after light 300
300 pxdarkbefore dark 300after dark 300

Before: "Claude O… ⌄ M. ⌄" at 400, and "C ⌄ M. ⌄" with the lock against the mic at 300. After: at 400, the mark, "Med Fast", the lock glyph, the mic and Send. At 300, the mark, "Med Fast", the lock glyph and Send, each with its chevron. There's no motion change, so there's no clip.

Changelog

  • Changed: The agent composer's footer, including New Tab's reasoning chip, shortens whole controls (short effort level, model family, then icons) in narrow panes instead of cutting labels with an ellipsis, and drops the mic only when nothing else can shrink.

Bead: cx-u5e2y

🤖 Generated with Claude Code