Skip to content

fix: stabilize xterm session restore rendering#282

Merged
kbwo merged 4 commits intomainfrom
fix/xterm-rendering-glitch
Apr 13, 2026
Merged

fix: stabilize xterm session restore rendering#282
kbwo merged 4 commits intomainfrom
fix/xterm-rendering-glitch

Conversation

@kbwo
Copy link
Copy Markdown
Owner

@kbwo kbwo commented Apr 12, 2026

Summary

  • write serialized restore snapshots before re-disabling auto-wrap and buffer live PTY output until restore replay finishes
  • restore a bounded amount of normal-buffer scrollback on session re-entry while keeping alternate-screen restores viewport-only
  • preserve the cursor position for bounded range restores and reset scrollback replay after clear-screen sequences

Verification

  • npm run test -- src/services/sessionManager.test.ts src/services/sessionManager.effect.test.ts src/services/sessionManager.autoApproval.test.ts src/components/Session.test.tsx
  • npm run typecheck
  • npm run lint

Notes

  • local bun.lock changes are not included in this PR

kbwo added 4 commits April 12, 2026 17:55
Restore snapshots depend on xterm serialize semantics for wrapped lines. In upstream SerializeAddon, wrapped rows normally serialize with an empty row separator instead of an explicit CRLF, relying on DECAWM to overflow naturally; only fallback cases inject extra wrap-forcing sequences. That means writing CSI ? 7 l before replay can overlap wrapped restore content on a single row.

Also guard the restore/live-output boundary in SessionManager: when a session becomes active, buffer PTY chunks that arrive during snapshot replay and flush them only after the restore event completes. This preserves ordering and removes a race where live output could interleave with the serialized snapshot and corrupt the screen.

References:

- xterm.js SerializeAddon wrapped-row separator logic (pinned to the addon version bundled here): https://github.com/xtermjs/xterm.js/blob/f447274f430fd22513f6adbf9862d19524471c04/addons/addon-serialize/src/SerializeAddon.ts#L163-L170

- xterm.js SerializeAddon fallback wrap injection: https://github.com/xtermjs/xterm.js/blob/f447274f430fd22513f6adbf9862d19524471c04/addons/addon-serialize/src/SerializeAddon.ts#L210-L214

- xterm.js SerializeAddon mode serialization for wraparoundMode: https://github.com/xtermjs/xterm.js/blob/f447274f430fd22513f6adbf9862d19524471c04/addons/addon-serialize/src/SerializeAddon.ts#L495-L496
Restore up to 200 lines of normal-buffer scrollback on session re-entry while keeping alternate-screen restores viewport-only. Track a restore baseline after clear-screen sequences so stale pre-clear content is not replayed.

Also append an explicit CUP cursor reposition after bounded range restores. xterm's SerializeAddon omits the final cursor restoration when serializing an explicit range, so live input could resume at the wrong location without this correction.
…rm-rendering-glitch

# Conflicts:
#	src/components/Session.tsx
@kbwo kbwo marked this pull request as ready for review April 13, 2026 13:17
@kbwo kbwo merged commit 4a66528 into main Apr 13, 2026
1 check passed
@kbwo kbwo deleted the fix/xterm-rendering-glitch branch April 13, 2026 13:18
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.

1 participant