Skip to content

Fix/panel scrollback leak 457 - #471

Open
ilijachrchev wants to merge 8 commits into
dcouple:mainfrom
ilijachrchev:fix/panel-scrollback-leak-457
Open

Fix/panel scrollback leak 457#471
ilijachrchev wants to merge 8 commits into
dcouple:mainfrom
ilijachrchev:fix/panel-scrollback-leak-457

Conversation

@ilijachrchev

Copy link
Copy Markdown
Contributor

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. sanitizeTerminalOutput only 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 — getTerminalState and agent-status detection both use the screen emulator instead. Three consumers shared the defective raw-log path:

  1. runpane panels outputgetPanelScrollback (main/src/ipc/runpane.ts) — the context-capture path; its output flows into --initial-input-file, prepended to the typed "continue"
  2. terminal:getScrollbackClean (main/src/ipc/panels.ts) — the UI @-terminal raw-copy feature
  3. terminal:save-scrollback (main/src/ipc/panels.ts) — the @-terminal embed-copy feature

The 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 limit
  • TerminalPanelManager.getCleanTerminalScrollback(panelId, maxLines): awaits emulator idle, returns clean text or null (no live emulator → caller falls back to persisted state)
  • Routed both panels.ts IPC handlers through the emulator, keeping the sanitized persisted-state fallback for lazy/inactive terminals
  • Routed runpane panels output through the emulator (made panelScrollbackOutput async)
  • Tests: emulator renders in-place cursor repaints as clean text, line-limit trimming, and a runpane integration test asserting the emulator source wins over the raw log

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Code refactoring

Checklist

  • I have read the CONTRIBUTING.md guidelines
  • My code follows the code style of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have run pnpm typecheck and pnpm lint locally
  • I have tested the Electron app locally with pnpm electron-dev

Critical Areas Modified

  • Session output handling (requires explicit permission)
  • Timestamp handling
  • State management/IPC events
  • Diff viewer CSS

Screenshots (if applicable)

N/A — the bug produces no visible UI change; the symptom is in the agent's session JSONL (first user message contains another panel's screen dump). The fix changes what text the scrollback readers return internally.

Additional Notes

  • pnpm run typecheck passes. OxLint exit 0, ESLint 0 errors in touched files.
  • terminalStateEmulator.test.ts (9), runpane.test.ts (60), terminalPanelManager.test.ts — all pass.
  • Two non-code failures (Knip's zod/mini resolution; daemonRegistryBindings minimatch CJS/ESM) reproduce identically on the base commit — pre-existing, not from this change.
  • Manual end-to-end testing was not performed — the dev Electron app shows "Open Pane from the desktop app" on both this branch and plain main (v2.4.62), a pre-existing Windows dev environment issue unrelated to this @fix.
  • One pre-existing typecheck error on the base commit (runpane.ts:475 PaneCommandValue) was fixed as part of the rebase cleanup (cast request as PaneCommandValue).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New Claude Code tab receives another panel's screen/scrollback as its first prompt (duplicate agent runs the same brief in the same worktree)

1 participant