cmux NEXT transcript: one row grammar for send, command and subagent rows (carry #28291)

TE
5d ago
+45-0

This carries #28291 with its commits and authorship kept, merged up to feat-cmux-next, and fixes the review's BLOCK.

What this carry fixed

  • BLOCK: a duplicate aria-hidden control. "Subagent finished"'s chevron was a second clickable element (aria-hidden, onClick) beside the line's real open button, so it was hidden from assistive tech. Now the chevron only draws: no handler, no tab stop, not a button. The open button is the line's one control, and its hit area spans the row under the words (.cv-subagent-done::before). The duration and chevron pass clicks through to it (pointer-events: none), so clicking the chevron still opens the subagent. Restart, Retry and ⋯ stay their own buttons above it. The status words and chevrons still sit on one x.
  • The same pattern on message rows. This PR also moved AgentMessageRow's chevron out of the toggle as a clickable aria-hidden span. It gets the same fix: the toggle's hit area reaches the status and the chevron.
  • Base merge. One conflict, in SubsessionCallCard.css. Base's #463e538 ("the arrow over every button") had restyled .cv-sent__target, which this PR replaces with the recipient chip, so the chip's rules are kept. This PR's new cursor: pointer rules become cursor: default, per that base change.
  • Not changed: the received report row ("grid-lane …"), whose chevron sits off the column at x≈485 in the old after still. It is IncomingMessageCard's DisclosureRow, not a component this PR touches, so it is a follow-up.

Test: RowGrammar.test.tsx adds two tests. One asserts a done line has exactly one focusable control, and that its chevron (aria-hidden, no tab stop, no handler) opens nothing when clicked on its own while the button does. The other asserts a message row's chevron does not toggle it. RUNS_PLACEHOLDER

MEDIA_PLACEHOLDER


Original body of #28291:

Leo, 2026-10-29: "this ui isn't consistent :(" and "this rendering can be better for sent stuff".

Every tool row in the transcript now follows one row grammar (design/chat-transcript.md, "One row grammar", teamleaderleo/leo-workspace#1663):

  • Verb pattern. A shell acpmux send or sub-session send_message row now reads "Sent to " ("Sending to" while it goes out), as SendMessage rows already did, instead of "Sent message to".
  • One recipient style. Both send rows show the recipient as the same chip (.cv-agentmsg__name). The underlined link is gone. The chip still opens the recipient's chat when the session list knows it.
  • Fixed trailing column. Status ("Queued", "Delivered"), then duration, sit in grid column 3, right before the chevron in column 4 of the shared .cv-tool grid. AgentMessageRow used to be a flex row that put the chevron before its optional meta, so the chevron moved depending on whether a status was present. It is now the shared grid. The shell send's "· queued" moves out of the sentence into that column, and "Subagent finished: … · 2m 28s" moves its duration there too and gains the chevron its rows lacked. Rows with no status keep the column empty, so every chevron sits on one x.
  • One truncation rule. The sentence column ends in one ellipsis, and the preview (.cv-agentmsg__preview) is the span that takes the cut.
  • Sent rows are compact. Shut, a send shows its first line once. Open, the line drops it and the message shows once below, with Raw still under it.
  • No narration (transcript audit, cmuxterm-hq#5154): the started sub-session row drops its "Started sub-session" prefix. It is now the session's name next to its harness mark, per the transcript rule that the icon names the type.

Kept: colours, fonts and glass; expanding still shows the full message; Raw stays; the hover row (Copy, Reply) stays; Restart and Retry on subagent lines stay. Not touched: the composer, Session Info, the sidebar and menus.

Gallery

New entry agent-pane.transcript-row-grammar shows the four rows side by side (SendMessage, acpmux send, Ran 2 commands, Subagent finished) in four variants: chip (shipped), link, plain, and open. I picked the chip: it already marks a recipient in received rows, it stays legible next to a muted preview, and unlike a link it doesn't suggest navigation when the recipient opens nothing. Before/after comes from this PR's gallery advisory run (run 41087816263, agent-pane.agent-message-row, 420 px, Chromium). I viewed both pairs: in the after shots, every status word and chevron sits on one x, the failed send's reason moves out from under its chevron, and "Subagent stopped" gains its duration and chevron.

BeforeAfter
Sends (dark)before sent darkafter sent dark
Sends (light)before sent lightafter sent light
Outcomes (dark)before outcomes darkafter outcomes dark

The run flags one play check, a layout shift when a sent row opens (sent-opened, 0.0945). The base gives 0.0951 for the same check, so this PR doesn't introduce it.

Tests

RowGrammar.test.tsx renders the four row kinds side by side and checks:

  • the column order (icon first, trailing column right before the chevron, chevron last);
  • "Sent to" on both sends, with exactly one recipient chip;
  • "Queued" in the trailing column and not in the sentence;
  • one preview span, cut by the shared rule;
  • the subagent duration in the trailing column;
  • an opened send not repeating its first line;
  • the grid columns in the stylesheet;
  • the narration prefix being gone.

SentMessageLine.test.tsx is updated for the new words.

Observed / Not run

  • Ran pr-overlap against feat-cmux-next: no overlapping open PRs (the search fell back to a 29-minute-old list).
  • Strict fast-checks dispatch (16 focused bun files, then bun run check, under set -o pipefail) at b7a49f1 (run 41083915458): 139 pass, 0 fail. check:design-tokens flagged the gallery's 20px padding, which f6f8ef1 fixed by moving it to 16px on the spacing scale. check:fixed-waits reports 8 findings that the base has too.

Performance

metricbeforeafterdeltaharness or run link
per-token work in transcript rowsnone addednone added0no new timers, observers or effects; same components, CSS grid only

Risk: normal. CSS and markup for the message rows, plus one subagent row layout. The Home ledger keeps its own .lg-run-messages .cv-agentmsg__line flex override.

Changelog

Changed: transcript message, command and subagent rows share one layout; sends read "Sent to" with the recipient as a chip and status before the chevron.

#28291 closes once this lands.

Agent session: agent session

🤖 Generated with Claude Code