Fix/panel scrollback leak 457 - #471
Conversation
…ngled repaint dumps
… stop mangled context dumps
…ToolPanelState changes
parsakhaz
left a comment
There was a problem hiding this comment.
Verdict: Request changes: preserve bounded scrollback when disposal races a read.
Counts: Must Fix: 1 (security: 0) · Should Fix: 0 · pass 1/1
Must Fix
- MF-1:
getScrollbackText(maxLines)falls back to viewport-onlyfinalScreenTextafter disposal and ignoresmaxLines·main/src/services/terminalStateEmulator.ts:121· snapshot full rendered scrollback before disposal and apply the same limit on both live and disposed paths · violates the new method contract- Evidence:
TerminalPanelManager.getCleanTerminalScrollbackcaptures the emulator and then awaitswaitForIdle()atmain/src/services/terminalPanelManager.ts:2004-2010.dispose()resolves those idle waiters during terminal teardown, after storing onlygetScreenText(). The resumed reader therefore enters the disposed branch at line 122 and receives only the viewport, even when older history exists; a smaller requested limit is also ignored. - Failure scenario: a panel exits while pending writes drain and
runpane panels output, raw@copy, or embed-copy is reading it. The read resumes after disposal and silently returns only the last viewport instead of the requested recent scrollback, or returns more rows than requested when the terminal viewport is taller than the limit.
- Evidence:
Praise
- The new emulator-backed path correctly avoids ANSI-stripped repaint fragments, and the
limit + 1integration inmain/src/ipc/runpane.ts:1610-1614preserveshasMorefor live reads.
Checks
- Inspected all six changed files against PR #471 and issue #457 intent.
- Security review covered IPC input boundaries, output handling, filesystem effects, and terminal escape processing. No PR-introduced security defect found.
- Targeted main Vitest suite passed through the changed terminal emulator, RunPane IPC, and terminal panel manager tests.
5d650b1 to
33adc2d
Compare
parsakhaz
left a comment
There was a problem hiding this comment.
Re-review: MF-1 is fixed in 1d3ef4b with disposed-scrollback regression coverage. The final head also removes the remaining raw live-log fallback and validates line bounds. Typecheck, lint, 116 focused tests, and the isolated RunPane repaint probe pass.
|
All three passes are complete and pushed at REVIEW
SIMPLIFY
REFACTOR
Verification
Follow-ups
Left for parsa
Automated manual QA passed on isolated Pane data at |
Description
Fixes #457 — new Claude Code tab receives another panel's mangled screen buffer as its first prompt.
Panel-scrollback readers sourced text from the raw PTY append log (
terminal.scrollbackBuffer) and merely ANSI-stripped it. The append log accumulates every repaint frame — agents and tools update in place via cursor-motion escapes (\x1b[nD,\x1b[K, column addressing), not carriage returns.sanitizeTerminalOutputonly collapses\r-based overwrites, so cursor-motion fragments concatenate into the reported garbage ("Workingorking•rking•king•ingngg"). The default 500-line copy preset ≈ the reported 9–12 KB.The codebase already knew the raw log is unreliable —
getTerminalStateand agent-status detection both use the screen emulator instead. Three consumers shared the defective raw-log path:runpane panels output→getPanelScrollback(main/src/ipc/runpane.ts) — the context-capture path; its output flows into--initial-input-file, prepended to the typed "continue"terminal:getScrollbackClean(main/src/ipc/panels.ts) — the UI @-terminal raw-copy featureterminal:save-scrollback(main/src/ipc/panels.ts) — the @-terminal embed-copy featureThe fix routes all three through a new
getScrollbackText()method on the screen emulator, which renders clean plain text from the already-correct rendered buffer.Changes:
TerminalStateEmulator.getScrollbackText(maxLines?): clean plain text from the rendered buffer (scrollback history + viewport), trimming trailing blanks before applying the line limitTerminalPanelManager.getCleanTerminalScrollback(panelId, maxLines): awaits emulator idle, returns clean text or null (no live emulator → caller falls back to persisted state)panels.tsIPC handlers through the emulator, keeping the sanitized persisted-state fallback for lazy/inactive terminalsrunpane panels outputthrough the emulator (madepanelScrollbackOutputasync)Type of Change
Checklist
pnpm typecheckandpnpm lintlocallypnpm electron-devCritical Areas Modified
Screenshots (if applicable)
N/A — the bug produces no visible UI change; the symptom is in the agent's session JSONL (first
usermessage contains another panel's screen dump). The fix changes what text the scrollback readers return internally.Additional Notes
pnpm run typecheckpasses. OxLint exit 0, ESLint 0 errors in touched files.terminalStateEmulator.test.ts(9),runpane.test.ts(60),terminalPanelManager.test.ts— all pass.runpane.ts:475 PaneCommandValue) was fixed as part of the rebase cleanup (castrequest as PaneCommandValue).Automated QA
Status: passed at
33adc2d7. An isolated Electron dev app and local RunPane wrapper returned cleanWorking...andqa-sentineltext from bothpanels screenandpanels output, with no repaint fragments. Typecheck, lint, and 116 focused tests pass. No screenshots were needed because this PR changes terminal text plumbing, not layout. Remaining human check: optional raw and embed@terminal copy in a packaged app.