agent transcript: toggle holds last a fixed minimum, a sideways wheel keeps them, and a stale press is never reused (follow-up to #28780)

Merged
TE
6d ago
+58-36

Leo's words:

why the f*** did you guys ff***ing ellipsis EVERYTHING WITH NO WAY TO EXPAND WHAT WAS SAID TO SEE

AND IT'S SO F***ING AWKWARD TO SEE THEM THERE AT THE BOTTOM SINCE WHEN I EXPAND THEM IT JUMPS ME DOWN AND WHEN I COLLAPSE IT JUMPS ME UP

#28780 carried this PR's earlier head (5e59e449) to feat-cmux-next: every cut row opens to its whole text, every toggle holds its place, and the collapse room. This PR is now the remainder. It holds the toggle-hold fixes made after that head, merged with the current base. Its diff against base is about 60 lines.

What this changes

  • A fixed minimum hold, not one that keeps extending (foldAnchor.ts). Base extends a hold by 150 ms every time its line moves, up to 1.5 s. While the view was scrolled to a tall prompt, that kept re-placing the prompt under the pointer, and its Show less missed the click (transcript-fold-anchor-browser: "Show less on a prompt several screens tall, with motion off" failed with it). Every hold now lasts max(foldMs + FOLD_SETTLE_MS, FOLD_HOLD_MIN_MS = 400 ms). A toggle with no fold under Reduce Motion, which used to get 150 ms, is still held while what it opened is measured and placed.
  • A sideways wheel keeps the hold in both release paths (App.tsx cancelProgrammatic). Base exempted a horizontal wheel only in release. The user-scroll intent listener cleared the hold first, so scrolling a code block sideways still let go.
  • The press place is never stale (App.tsx). A keyboard click (detail === 0) does not reuse an earlier, abandoned press, and pointercancel drops it. The row's own anchored-collapse event (holdAsked) keeps the click's pressed place instead of replacing it with where the line is now.
  • A file link inside a tool line is not a toggle (NESTED_CONTROL gains [role="link"], the role WriteLabel's file name uses).
  • No dangling aria-controls (ToolRow.tsx). Since every call opens, an opened call with no output names a body only when one is drawn.
  • DiagramBlock's toggle carries data-fold-toggle too, like Wrap lines and Raw.

Stop and cleanup

Nothing new animates. A hold is a timestamp checked on each placement pass, with no timer. It ends at max(foldMs + FOLD_SETTLE_MS, FOLD_HOLD_MIN_MS) after the click, or at once on a vertical wheel, a key, a touch or a drag. The pointercancel listener is added and removed with the pointerdown and click listeners. Nothing runs per streamed token.

Tests

  • conversation/foldAnchor.test.ts:
    • a toggle with no fold is held at least FOLD_HOLD_MIN_MS
    • a hold that puts its line back does not outlast its time
    • press, click, then the row's anchored-collapse event keeps the pressed place
    • a file link inside a tool line is not held
  • conversation/TruncatedRowsReachable.test.tsx: an opened call's aria-controls names a body that exists, and a call with no output names none.
  • Verified with cmux-ci on Linux Chromium:
    • typecheck, check:browser-lanes, check:fixed-waits, vp fmt
    • the acpmux conversation unit suites
    • 13 transcript browser suites: fold-keeps-place, fold-anchor-browser, follow-live, reading-place, queue-scroll-bottom, find-position, tool-group scroll, alignment and overlap, no-blank-space, incoming and received message disclosure, transcript-follow

Media

Linux Chromium gallery, agent-pane.tool-row-column (variant column), with the tool group opened. Captured through cmux-ci using a public gallery fixture. It shows what #28780 shipped and this PR keeps: every call row opens. This PR changes no layout.

Tool rows before

Tool rows after

Risk

Low. Hold timing only:

  • Holds no longer extend while their line moves; they last at least 400 ms instead.
  • A sideways wheel no longer releases a hold.
  • A file link inside a toggle no longer starts one.

Performance

metricbeforeafterdeltaharness
work per streamed token in the transcript path0 new0 new0code read: the changes run only on clicks, presses, wheel events and placement passes, O(1) each

Follow-ups from review (not in this PR)

  • Fold-room follow release when the transcript is shorter than the view: a no-output toggle can leave room above rowsEnd and stop following.
  • outputSummary no longer caps text for briefs, steer and dispatch, not only reports.

Agent session: agent session

šŸ¤– Generated with Claude Code