Repository navigation
Agent chat: long lines in diff and command cards show a thin scrollbar at rest - #23967
Conversation
…t rest (red) Real Chromium and WebKit on the transcript gallery's long-line states (two new ones cut to the eight-line preview): the diff's and the Shell block's lines run past the edge, so each must draw a thin thumb on no track at rest, on a lane of 10px or less that the preview does not cut off, with no resize cursor over the block. The JSDOM sideways test checks the new mark on both kinds of scroller. Leo-ask: ask-d900f5acf9 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
…r at rest An unwrapped tool block whose lines run past its right edge (an edit's diff, a Shell block, a call's output) now keeps a thin thumb on no track under its lines at rest, in the shared thumb color, as long as its lines run past it. Before, the only sign at rest was the right-edge fade: the diff's thumb was transparent until it scrolled (and nearly invisible while it did), and the output had WebKit's overlay scroller, which shows only while scrolling. - scrollers.ts: SIDEWAYS_ATTRIBUTE (set by watchSideways while a box's lines run past it) gives Pierre's code rows their thumb at rest; the page side (SIDEWAYS_SCROLLER_ATTRIBUTE, on Shell and output bodies from their JSX, and SIDEWAYS_SCROLLER_CSS, installed with the page's other scroller rules) makes their scrollbar the thin one from the start, since WebKit keeps a scroller's kind once made. - A block cut to its eight-line preview ends with that lane: a cut diff cuts Pierre's code box with it (--cv-block-cut), so the scrollbar is no longer under the last line past the cut, and the bottom fade stops above the lane. Leo-ask: ask-d900f5acf9 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Gallery before/after for
States
Pick other states with a Passes: CI passes on CI passes on Written by red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on ea5f81f to compare; do not merge until green; see lane-rules Tour of |
|
Found 7 test failures on Blacksmith runners: Failures
|
Hiding every thumb with a late style sheet and diffing two screenshots read no thumb in Chromium even where one was drawn (a fleet run on the fix: the lane was there and thin, the diff empty). Read the lane itself: with the box scrolled to its start, a column that differs from the lane's right end, which shows the card under a colorless track, is drawn on. Log the measurements. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
|
Bead |
|
|
…orners On a diff card that fits its preview, the lane is the card's bottom edge, and its 12px rounded corners clip both ends of the lane to the page's color. The reading compared every column with the lane's right end, inside that corner, so it saw the whole lane as drawn (react-apps-check on fb97162: 702 of 702 columns, Chromium and WebKit). Read between the corners. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
|
Review (codex gpt-6.1-sol): BLOCK at b0d426c Blocking findings:
Non-blocking findings: none. Checked the nine-file diff, surrounding scroller and Pierre integrations, the new JSDOM and Chromium/WebKit tests, the gate-owned files, and the final GraphQL head SHA; no app build or test suite was run. |
… does not move the transcript Codex review of #23967: every streamed token re-walked the whole block (O(rows) per token), and a cut or open Shell/output body grew by the sideways scrollbar's lane when its lines started running past, so the transcript jumped. These fail on the current code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
…eep the sideways lane watchSideways walked the whole block (every element, and Pierre's shadow roots) on every change, so each streamed token cost O(rows). Now only mount walks the block: a change marks the code box it is in, takes in only the nodes it added, and the marked boxes are measured once a frame. Scroll and size changes still update at once. An unwrapped Shell or call-output body keeps its scrollbar's lane at its bottom whether or not its lines run past, as padding the bar takes when it comes, so the body (cut or open) is the same height with the bar and without it, and the transcript does not jump. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
Pierre, loaded by the earlier tests in the file, defines `diffs-container` and gives it a shadow root, so attaching another one threw before the test measured anything. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
|
|
|
|
|
|
|
Review (codex gpt-6.1-sol): BLOCK at 920fe51 Blocking findings:
Non-blocking findings:
Checked the full nine-file diff against base, the round-1 O(rows) and streaming-height fixes, the scroller scope, the mutation/rAF/Pierre shadow paths, and the new test assertions; the live head was re-read with GraphQL, and no app build or test suite was run. |
… no lane where none is needed Codex review round 2 of #23967. A Pierre host removed from a still-mounted block left its shadow root's code boxes watched and its root observed. A wrapped diff and a settled unwrapped Shell body whose lines fit still kept the sideways scrollbar's lane, an empty tail. These tests fail on the current code: the leak test counts what the watcher holds after six removals and after stop, and the browser tests check that a diff, a running command and a call output hold their height while lines start and stop running past, and that settled fitting and wrapped bodies keep no lane. New gallery states: a running unwrapped command (whole and cut) and an unwrapped call output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
…e only where a bar can come watchSideways keeps one change observer per root (the block and each shadow root in it), so a removed host's root, its code boxes, their size observations and their scroll listeners all go with it, and a host removed before its root came leaves the pending set too. The sideways scrollbar's lane: a wrapped diff keeps none. A call output's lane is its own bottom padding, so it is the same height with or without the bar. An unwrapped Shell body keeps its lane while its lines run past and, all the while its command runs, whether or not they do (`data-live` from the row's running state), so a streamed line that starts or stops running past does not move the transcript. When a command that fit ends, its body drops the 8px lane once, with the row's other end-of-run changes; a settled body whose lines fit has no tail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
|
|
…-up load A lone running call reads only on the turn's live line, so the running-command states put a later call after it and open its row directly. The gallery entry is warmed once, not per state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
|
Review (codex gpt-6.1-sol): SHIP at 0056f5e Blocking findings:
Non-blocking findings:
Checked the full diff against base, the per-root observer and unmount cleanup paths, streamed-token work, Chromium/WebKit scrollbar CSS and layout states, the round-1/2 regressions, and all gate-rules-owned files; no app build or test suite was run. |
…e-block-hscroll # Conflicts: # webviews/src/agent-session/acpmux/conversation/ToolRow.tsx
|
Review (codex gpt-6.1-sol): BLOCK at 5131157 Blocking findings
Non-blocking findings
Checked: full diff against merge-base |
…der them (red) Codex review round 4 of #23967: a non-shell call output past eight lines is cut at calc(8 * 18px) under border-box, so its 8px lane and top padding come out of the cut instead of being added. Adds the gallery state output-unwrapped-long-cut and puts it in the browser matrix (thumb at rest, steady height, settled), with a new check that the cut box's clientHeight less its padding is 8 line heights, with lines running past and with them fitting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
…g a line to it The cut preview of a non-shell call output was capped at calc(8 * 18px) under border-box, so its 8px top padding and its 8px scrollbar lane came out of the eight lines (about seven showed). The cap is now eight lines plus the top padding plus --cv-lane, as the Shell body's cut already is (Codex review round 4 of #23967). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
Conflict in webviews/src/agent-session/acpmux/conversation/ToolRow.tsx: the call output's <pre> took base's data-lang (JSON results) and this branch's SIDEWAYS_SCROLLER spread; both kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15cfc-5eec-7700-94d7-9a3a1f7d889a&host=Air-Blue
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
|
|
|
|
Review (codex gpt-6.1-sol): SHIP at 5dc8099 Blocking findings: None. Non-blocking findings:
Checked: the full diff from the merge base, ToolRow against both parents, Markdown and JSON result handling, scroller registration, cut sizing against the round-4 head, per-token observer work and cleanup, and the exact GraphQL head; no app build or test suite was run. |
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/39947108873 at 184fa32 failed: cmux-next generated files. |
|
base-red-watch: |
|
Shipped in:
|
…w under the scrollbar fade (red) Lawrence 2026-10-23 (msg 11494): scrollbars auto-fade and grow near the pointer. Under the scrollbar fade (data-cmux-scroller-fade, the agent pane's default), a diff's or command output's sideways thumb from #23967 must show none at rest, one while the lines scroll sideways, and a thicker one while the pointer is near the block's bottom edge. Fails before the fix: the thumb stays at rest, and nearBottomEdge does not exist.
… like the others #23967 (Leo) keeps a thin sideways thumb at rest under the lines of a diff, Shell block or call output that run past the edge. Under the scrollbar fade (data-cmux-scroller-fade, on by default in the agent pane since Lawrence 2026-10-23, msg 11494) that thumb now fades like every other scroller: none at rest (the right-edge fade still says the lines go on), shown while the box scrolls, and wider and darker while the pointer is near the block's bottom edge. nearScroller now also marks a sideways scroller whose bar is near the pointer (inside Pierre's shadow roots too). With the fade off (Debug Settings agentPane.debug.scrollerFade) the #23967 look stays: shown at rest.
|
Review (codex gpt-6.1-sol): BLOCK at 5dc8099 Blocking findings:
Non-blocking findings:
Checked the full diff from the current merge-base, the round-1 observer and height fixes, removed-host cleanup, Pierre's shadow-root CSS and gutter behavior, Shell/output lane states, scroller scope, and the gate-owned files. The live GraphQL head is unchanged at this SHA; no app build, gallery capture, or full-tree check was run. |
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Leo-ask: ask-d900f5acf9
In agent chat, an unwrapped diff, Shell block or call output whose lines run past the card's right edge now keeps a thin scrollbar thumb under its lines at rest, as long as there is more to scroll. Before this, the only sign at rest was the right-edge fade from #23413: the diff's thumb stayed transparent until you scrolled it (and was a 1.5 to 7.5% tint while you did), and Shell and output bodies used WebKit's overlay scroller, which only shows while scrolling. A card cut to its eight-line preview now ends with that scrollbar in view. Before, a cut diff's scrollbar sat under its last line, below the cut.
I picked "scroll with a visible thumb" over always wrapping. Prose files (
.md,.txt) and command output already wrap by default since #23413, so Leo'scodex-excursions.mdcard now wraps. Code stays unwrapped because wrapping breaks its shape, and the Wrap lines toggle covers anyone who wants it. The visible thumb follows Leo's newer call on the composer (#23854): "IF THERE ARE THINGS TO SCROLL, JUST KEEP THE SCROLLBAR". It is a thumb with no track, so SCROLLBARS-THIN's "never a permanent gray track" still holds.What changes
webviews/src/scrollers.tswatchSidewayssetsSIDEWAYS_ATTRIBUTEon a block's scroller while its lines run past it.--cmux-scroller-thumb. It keeps the same color while scrolling.SIDEWAYS_SCROLLER_ATTRIBUTEfrom their JSX.SIDEWAYS_SCROLLER_CSS, installed with the page's other scroller rules, makes their scrollbar the thin 8px one from the start. The attribute has to be there from the start because WebKit keeps a scroller's kind once it has made it.conversation.cssandsideways.ts--cv-lane) wherever it keeps one (see the review fixes below), and its bottom fade stops above the lane.--cv-block-cut), so the box's scrollbar sits at the cut instead of under the hidden lines.--diffs-scrollbar-gutter-overrideinside diff cards; the new browser test reads it as 6px there.edit-long-line-code-cutandshell-unwrapped-long-cut(and the review states below).The resize cursor
I found no resize cursor or
resize:property in any transcript card. The onlycol-resizein the agent pane's webview is the inspector's own edge (inspector/inspector.css:53), and it isn't over the chat column.The cause #23413 found is native.
DividerHandleView.resetCursorRectsadded its whole frame as a cursor rect, so a strip divider running under a docked chat kept its resize cursor over the chat. AppKit cursor rects ignore views stacked above them. #23413 fixed it withcursorClip(merged 2026-10-21 15:59 UTC, after this screenshot was taken on 10-20 21:57), and that fix is unchanged here. The new browser test adds a guard: across a grid over each card and its tool row, nothing shows a*-resizecursor or has aresizevalue.Tests
webviews/test/transcript-block-sideways-scrollbar.test.ts, in real Chromium (scrollbars on) and WebKit, on the long-line gallery states, cut and whole. For each block it checks:transcript-block-overflow.test.tsx(JSDOM) checks that the new attribute is on both kinds of scroller, stays after scrolling to the end, and is off when the lines fit. It also checks that the bottom fade ends above the lane.Focused command:
cmux-ci run --class light --script scripts/ci/run-webviews-tests.sh --env CMUX_BROWSER_TESTS=1 --env CMUX_WEB_TEST_FILES=<the two files, newline-separated>lane: 0) and the cut diff's lane below the cut (535.75 vs 427.75). The JSDOM test fails on base because the attribute doesn't exist. There is no red run of the final pixel (thumb-at-rest) check: the fleet's WebKit didn't launch (180 s timeout), and the last red/green pair sat queued for about 4 hours before it was cancelled. An earlier red for the diff thumb used a detection method that has since been fixed, so it isn't counted as evidence.Codex review fixes (rounds 1 and 2)
sideways.ts):sideways.ts): a removed Pierre host now takes everything under it with it: its shadow root's change observer, its code boxes, their size observations and their scroll listeners. A host removed before its shadow root arrived is dropped too.conversation.css):data-live, from the row's running state), it keeps the lane whether or not they do, so a streamed line that starts or stops running past doesn't move the transcript.shell-live-unwrapped-long-line,shell-live-unwrapped-long-cut,output-unwrapped-long-line.cc54a7b19da8c140501681faand on huge-blue (the leak test, the wrapped-diff tests and the settled-Shell tests fail); green on fleet stepb0fb5d3a6e488d7e4cb1e202and on huge-blue (both files pass).626a6ed87c59d17c9aa16244(old code measured during the stream; the Shell body shrank by 8px when its scrollbar went), green on6f03d1c010974893bc1e4cef.Codex review fix (round 4)
.cv-tool-output[data-preview="cut"]). Its cap wascalc(8 * 18px)underbox-sizing: border-box, so its 8px top padding and its 8px scrollbar lane came out of the eight lines: the box showed 128px of text, about seven lines, and the lane did not make the preview taller.conversation.css: the cap is nowcalc(8 * 18px + 8px + var(--cv-lane)), eight lines plus the top padding plus the lane, the same shape as the Shell body's cut (calc(8 * 18px + 8px + var(--cv-lane, 0px))).output-unwrapped-long-cut(a 14-line call output, unwrapped). It joins the browser matrix (thumb at rest, steady height, settled), and a new check reads the cut box'sclientHeightless its padding: it must be eight line heights (144px), both while its lines run past the edge and after they fit.51ffedc3fa3763c2100a4750on cmux12s: only the new check fails, in Chromium and WebKit,shown: 128againsteight: 144in both states; the other 36 tests pass.543b4b5589718161282a6142on cmux13s (both test files) and18280c8b7fbdc3ea3f5fbb24on cmux12s (the browser file), Chromium and WebKit.feat-cmux-next(ea5f81f): one conflict, inToolRow.tsx. Base addeddata-langto the call output's<pre>and this branch added theSIDEWAYS_SCROLLERspread on the same line; both are kept. Base's new Markdown result box (.cv-tool-output__markdown) is not a.cv-tool-output, so the lane and cut rules don't reach it.Observed / Not run
scripts/web-lint.shpassed;scripts/cmux-next/prepush-gate.pyfound no new violations;check-scrollbars.shreported nothing in webviews; the branch hasfeat-cmux-nextmerged in (it picks up ci: the agent pane page ships the Inspector's ContextSection.css (base red since #23789) #23935's ContextSection.css and the wave.css fixes).Native/OptChat/chief-turnhas no entry in.github/rust-workspaces.tomlon base; this PR touches no Cargo workspace), and fast gates' web lint, whose only "new finding" is vp lint's closing lineFinished in 7.6s on 2465 files with 162 rules using 4 threads.: the compare's noise rule (scripts/ci/fast_gate_webviews_checks.pyNOISE, Web checks: vp fmt's closing file count is not a finding the change adds #24436) matcheson N files using N threadsbut not thewith N rulesform, and the merge's file count differs from the base's. The base's own 4 lint findings are reported as base.HighlightedCode) still show their scrollbar only while scrolling; they're outside this change.No capture: webview-only change; the gallery advisory run captures the new and updated
agent-pane.transcriptstates (edit-long-line-code,edit-long-line-code-cut,shell-unwrapped-long-line,shell-unwrapped-long-cut,shell-live-unwrapped-long-line,shell-live-unwrapped-long-cut,output-unwrapped-long-line,output-unwrapped-long-cut).Changelog
Agent session: Air-Blue
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Agent chat diff, Shell and call-output cards whose lines run past the right edge now show a thin horizontal scrollbar at rest, not only while scrolling. Before, the only hint was the right-edge fade: the diff thumb was transparent until scrolled, and Shell and output bodies used WebKit's overlay scroller, which shows only while scrolling. A card cut to its eight-line preview now ends with the scrollbar in view; a cut diff no longer leaves it under the hidden last line.
Bug Fixes
SIDEWAYS_ATTRIBUTE(set bywatchSideways) shows the at-rest thumb on Pierre's diff rows; Shell and output bodies carrySIDEWAYS_SCROLLER_ATTRIBUTEfrom their JSX so WebKit makes their scrollbar the thin one from the start.Written for commit 5dc8099. Summary will update on new commits.