cmux NEXT composer: queued prompts are compact muted lines, actions on hover
Leo, on nightly 331e2e9: "WHY CAN'T I CLICK THESE BUTTONS. ALSO 'Sends after this turn'... the styling is a bit shit".
Now: each queued prompt is one compact, muted line, as in ChatGPT's and Codex's queues. There is no "Queued / Sends after this turn" header and no 1, 2 index. The text is cut to one line with an ellipsis, and a hairline separates rows. ↪ Steer, the trash can and ⋯ show only while the pointer is on the row or focus is in it, so the keyboard still reaches them. They stay visible while the ⋯ menu is open, and always on a pointer that cannot hover. The list keeps its name, "Queued prompts (n)".
Builds on #23753 (merged as 6faf4de8896), with these review nits fixed:
- The Steer and ⋯ buttons show the soft hover pill on keyboard focus instead of the old 1.5px ring. Increase Contrast still gets the shared ring.
- The queued editor's hairline brightens to
--acpmux-composer-edge-focuswhile it is focused. - The unused
composer.queueSendNow,composer.queueRemove,composer.queueAfterTurnandcomposer.queueHeldstrings are removed. A grep of the whole repo found no other use.
The dead clicks (P0): root cause found and fixed. menuPressGuard.ts:14-18, 55-57 (at e4593d5f990, unchanged since 331e2e9) swallowed every primary press outside an open composer menu unless it landed on a menu button ([aria-haspopup]). With the model or access (Mode) menu open, a press on Steer or the trash can reached only the menu's dismiss: the guard stopped its mousedown and click on the target, so the button never ran and the first press only closed the chip. ⋯ worked because it is a menu button. The model and access chips sit right under the queue, so that state is common. Codex's review found it; the tests below reproduce it.
The guard came from 9acd655e095 ("an outside press only closes a menu"): a press outside a menu must not start dictation from the mic or put a caret in the field, as macOS and Codex menus swallow the dismissing click. That stays. The fix lets a queued prompt's own controls through (.acpmux-composer-queue button, .acpmux-queue-foldbar button join PASSES): one press closes the menu and runs Steer, Delete, ⋯, the prompt's text toggle, the fold or Resume. The mic and the prompt field still take nothing from the dismissing press (composer-menu-dismiss, 60 pass).
Without a menu open, every action was always the top hit at its centre and worked, in Chromium and WebKit, on 331e2e9 and on this head. No native overlay sits over the row: CEFHostView.swift:105 and WindowController.swift:508 occlude only divider lines, the sidebar and the strip scrollbar thumb.
Changelog
- Fixed: With the model or access menu open, a click on a queued prompt's Steer or Delete closes the menu and does what it says, instead of only closing the menu.
- Changed: Queued prompts show as one compact, muted line each, with no header or number. Steer, Delete and More show on hover or keyboard focus.
Regression test
cd webviews && CMUX_BROWSER_TESTS=1 bun test test/agent-pane-queue-row-click.test.ts && bun test test/menu-press-guard.test.ts (Chromium and WebKit, real pointer presses at each control's on-screen centre)
- Open-chip cases ("queued row with a chip's menu open": the access menu, then Steer, trash or ⋯; the model menu, then trash or ⋯; the model menu's Effort row covers Steer, and the context card covers all three, so a press there is the menu's own):
- Red at the test-only commit 329fca62a44 (on e4593d5f990): 8 fail, 2 pass. In both engines Steer and the trash can only close the menu, and no
queue_editorqueue_removeis sent. The two passes are WebKit's ⋯ cases: ⋯ is a menu button, so the guard let it through. The Chromium ⋯ cases failed fast after a 120 s timeout earlier in the run left its page broken. menu-press-guard: its new case ("a press on a queued prompt's control closes the menu and still reaches the control") is red at 329fca62a44 (6 pass, 1 fail).- Green at 72f3f7f78be: 18 pass, 0 fail (row-click); 7 pass (menu-press-guard).
- Red at the test-only commit 329fca62a44 (on e4593d5f990): 8 fail, 2 pass. In both engines Steer and the trash can only close the menu, and no
- The rest case ("rests as one muted line"): red at f847a1ad0a6 (header count 1), green since.
Observed / Not run
- Observed on huge-blue at 72f3f7f78be, all passing:
agent-pane-queue-row-click: 18 pass.agent-pane-queue-steer: 7 pass.agent-pane-queue-collapse: 13 pass.composer-menu-dismiss: 60 pass.menu-pointer-close-focus: 10 pass.composer-field-menu: 1 pass.composer-chip-press: 52 pass.menu-press-guard,ComposerQueue.test.tsx,queue-row-actions,queue-paused-whyandqueue-agent-message: 28 pass.
bun run checkfails only on formatting inwebviews/src/gallery/ENTRIES.md. That file has the same bytes as feat-cmux-next (from 1a88ee69750), so it is not this PR's red.composer-top-strip-variantsfails on its gallery warmup (warmGalleryFrame: agent-pane.composer-striptimeout). It fails the same way at d2d4ffec61d.cmux-ci compile-check --apppassed at 72f3f7f78be: job f6fb87a6e38406f480e3a307, 62 s.- Not run: the real app. I could not drive Leo's nightly page, and agents don't build the Mac app on Leo's Macs.
- The merge with feat-cmux-next carries #23872's paused note (it keeps its ellipsis in the two-column grid) and #23825's queued agent message line (it now spans the row).
No capture: webview-only change; gallery compare https://cmux-lawrences-mac-mini.tail137216.ts.net:18796/compare/composer-look-queue-click/
Agent session: cosmic-gray
🤖 Generated with Claude Code