cmux-next: compact composer row, folder/host strip on top, searchable folder picker (hq#1957 item 15)

Merged
TE
22d ago
+2397-679

Moves the composer's folder/host row out of the card into a Codex-style strip attached to the composer's top edge, in both the chat composer and the New Tab composer. The folder popover now tells duplicate projects apart (hq#1957 composer location strip; Leo via coordinator). This PR also lands #20443 (compact row, steady composer, edges); its description follows below. Leo approved both from the captures ("i like that composer after VERY much, MERGE MERGE MERGE"), so the native recording was waived.

  • Strip: "📁 project ⌄ · 💻 host ⌄ … branch ⌄". It is 30px tall in every state (no project, project chosen, host loading), uses the card's fill and edge, and is inset by the card's corner radius. Queued prompts stack above it. The card keeps a single bottom row: + · model · effort · access … mic · send.
  • Folder popover: a search field (the shared Combobox, with arrow-key navigation) and a check on the current project. A duplicate name gets the fewest trailing folders that tell it apart, e.g. "cmux · cg-lane-adopt", and the full path shows only on hover. New Worktree, Add project and Choose folder… are reachable by keyboard, and Escape returns focus to the strip.
  • Grey placeholder pills: already gone on this base. #20335 renders the per-harness cached values. A test now asserts that no placeholder renders while effort and access load, and that the controls do not move when the values arrive.

Verification

  • bun test test/project-suffix.test.ts: red (0 pass, 1 error), then green 8/8.
  • CMUX_BROWSER_TESTS=1 bun test test/composer-location-strip.test.ts: red 0/10, then green 10/10.
  • The 23 related composer and New Tab test files pass (116 tests), and bun run check passes.
  • Captures (before/after, chat, chat with a queue, New Tab and popover at 420/720px) are on big-red at /tmp/cg-lane-adopt-dogfood/strip-*.png.
  • Seam: under a strip, the card draws its rim (at rest, focused, shell mode, Increase Contrast) on ::before with the strip's stretch masked out. The strip uses the card's edge color, so borders = none clears it. test/composer-location-strip.test.ts -t seam was red at 1f56cbc4897 (0/2, the seam line 24 brightness levels off) and is green at d1de333b266.
  • Unverified: tested in Chromium only, not WebKit or the native app. The cached chip values were not checked in real use.
  • From feat-cmux-next, not this PR: check:layers is red on summary/summary.css (raw z-index, d77476fd812), and vp fmt flags App.tsx and three summary/subagent files.

From #20443

Fixes the agent composer's controls row and stops the composer from shifting during a turn (hq#1957 item 15; Leo: "this is super weird", "so much layout shift while a subagent runs").

Controls row

  • Before: the permission chip was a fixed 180px wide behind a flex spacer, so "Auto" floated in the middle of the row and left a big gap.
  • Now: plus, model, ring, effort and permission sit together on the left; mic and Send/Stop sit on the right. Free space appears only between the two groups.
  • In a narrow pane, labels give way in order: the permission label goes first (lock icon only), then effort, then model.
  • The footer row (folder, host, branch) can grow but never shrinks. It keeps 12px side and 10px bottom insets, so it is no longer clipped.

Layout shift during a turn

  • The context ring used to appear at turn start. It now holds its slot once a session exists, so a prewarmed new chat shows an inactive ring.
  • Steer (shown when you type during a turn) used to push the mic left. It now comes in to the left of the mic.
  • The queue, permission asks and PR dock already grow upward over the transcript. Send/Stop is the same 32px circle. A mode change moves no other control.
  • Exception: in a narrow (~420px) row, the left cluster may shift when Steer appears, because there is no spare room to reserve.
  • The labels/icons switch has hysteresis: it leaves icon mode only with 4px of clear room, so it cannot flip every frame.

Compact row (Leo: "tonka toys")

  • The left group is "+ · model · effort · access", with even 8px gaps between 28px controls. Hover is a light wash that sits tight to each control.
  • The context ring is no longer in the row. Context usage now shows in the model chip's tooltip ("Opus 5.5 · 42% of context used"). The context details popover and its Compact button are gone from the pane; /compact still works.
  • The "Trusted this chat's…" chip has no slot in the row (op-next-composer-footer-cx is removing it), so the row shows one lock at most.
  • Stop is the same 28px grey circle as Send, with a 7px square. It replaces the large white disc.

Edges (border hunt, op-next-theme)

  • #20303 added a glass shadow and a text-color rim to the composer card. Both are gone. The card keeps one thin Apple-like rim, the 0.5px --acpmux-composer-edge hairline, which appearance.borders = none clears (Leo: a thin Liquid Glass rim is good, don't strip it to zero).
  • Permission cards keep one 0.5px hairline in the same edge color, with no shadow. A test guards that the hairline stays.
  • The permission panel's gallery entry now loads the pane's stylesheets inside .acpmux-shell. Before this, its edge checks measured an unstyled card and passed without testing anything.
  • The New Tab box loses its drop shadow, both at rest and when focused.
  • Keyboard focus still shifts the card's edge toward the accent color. That is a focus state, not a border, so it stays under borders = none.

Verification

  • Edges: CMUX_BROWSER_TESTS=1 bun test test/composer-edges.test.ts was red at 4580bd4130c (0/5) and at acab5b5e9df (New Tab), and is green 6/6 at a585a87afeb. With the real permission card measured (600aa9e50b0), the CSS from before the fix fails 6 of 7 checks and the fix passes 7/7. Of the related composer, New Tab and permission suites, 132 pass and 1 fails: new-tab-chat-title-width, which fails the same way on the base.
  • Compact row: CMUX_BROWSER_TESTS=1 bun test test/composer-row-layout.test.ts test/composer-turn-cycle.test.ts was red at d5fa4a0de6a (3 pass, 30 fail) and green at 1bebce0ad46. bun test test/composer-*.test.ts passes 53/53. Captures are on big-red at /tmp/cg-lane-adopt-dogfood/compact-{before,after}-*.png.
  • CMUX_BROWSER_TESTS=1 bun test test/composer-row-layout.test.ts: red 0/12 on eddade242f3, green 12/12.
  • CMUX_BROWSER_TESTS=1 bun test test/composer-turn-cycle.test.ts: red 0/6 on 397913287ba, green 6/6. It checks that the input and every control stay within 0.5px through idle → running → 1 subagent → 3 subagents → asking → queued → finished.
  • bun test test/composer-row-fit.test.ts (switch hysteresis): red 1/3, green 3/3.
  • bun run check passes; a review subagent found no blockers, and its flip-flop finding is fixed above.
  • Unverified: Chromium only, not WebKit or the native app. I could not reproduce Leo's exact footer clipping outside the gallery.
  • Screenshots (before/after at 420, 720 and 1100px, plus the turn cycle) are on big-red at /tmp/cg-lane-adopt-dogfood/composer-*.png.

Changelog

Fixed: the agent composer's controls form one compact row (stop matches send, no spinner) and no longer shift while a turn or subagent runs.
Changed: the agent and New Tab composers show the folder and host in a strip on top of the composer, and the folder picker can be searched and tells worktrees apart.

🤖 Generated with Claude Code