Switch CLI rendering to alternate screen buffer#151
Merged
Conversation
Replaces main-buffer rendering with the alternate screen buffer. The alternate buffer gives the CLI full screen ownership: no scrollback to corrupt, absolute positioning works without caveats, and resize is clear and redraw. This replaces the position tracking, resize heuristics, and scrollback corruption workarounds from prior fixes. Changes: - Screen: add enterAltBuffer/exitAltBuffer to interface and StdoutScreen - MockScreen: dual-buffer model with save/restore on switch, remove readonly from cells, add assertInAltBuffer/assertInMainBuffer/getMainRow - Renderer: remove lastVisibleCursorRow, lastFrame, pendingResize, zoneHeight, notifyResize, writeHistoryLine, writeHistory. Simplified stateless render() always starts with cursorAt(1,1) - Terminal: remove notifyResize, add enterAltBuffer/exitAltBuffer, historyBuffer and inAltBuffer fields. writeHistory accumulates in historyBuffer when in alt buffer, writes directly to screen otherwise - ClaudeCli: enter alt buffer after startup messages, before first redraw. Exit alt buffer as first operation in cleanup. Add SIGTERM and uncaughtException handlers that exit alt buffer before process exit. Remove notifyResize call from resize handler. - Tests: replace main-buffer Renderer tests with alt-buffer equivalents, add MockScreen buffer-switch tests, update terminal-integration tests
Completed responses accumulate in historyBuffer during alt buffer rendering. flushHistory() exits the alt buffer, writes accumulated lines to main buffer scrollback, then re-enters alt buffer and redraws. Called in sendQuery() after showSkills() so every completed response is permanently visible in scrollback.
bananabot9000
approved these changes
Mar 29, 2026
Collaborator
bananabot9000
left a comment
There was a problem hiding this comment.
Clean implementation. The Phase 0 design in the session log is thorough and the code follows it precisely.
What I like:
- Renderer is now stateless. No
lastVisibleCursorRow, nopendingResize, nozoneHeight, nolastFrame.render()is a pure function of its input pluscursorAt(1,1). That's a massive simplification Screeninterface extended cleanly --enterAltBuffer()/exitAltBuffer()keeps escape sequences centralised. MockScreen's dual-buffer model with save/restore is the right testing abstractionflushHistory()usesscreen.exitAltBuffer/enterAltBufferdirectly (bypassingTerminal.inAltBuffer) so the logical state stays consistent. Subtle but correct- Cleanup handler ordering:
exitAltBuffer()FIRST incleanup(), before kitty keyboard protocol restore. If the process dies mid-cleanup, the user at least sees their main buffer writeHistory()routing based oninAltBuffer-- main buffer writes go direct, alt buffer writes accumulate. Clean dual-path- Tests replaced, not just removed. The new
MockScreen dual-bufferandHistory flushdescribe blocks cover the new contracts.assertInAltBuffer()/assertInMainBuffer()assertions are a nice touch
Observations (not blocking):
flushHistory()callsthis.screen.exitAltBuffer()/enterAltBuffer()but doesn't touchthis.inAltBuffer. The flag staystruethroughout the flush, which is the correct choice (the flush is transparent to the rest of Terminal). Worth a comment if it's not already documented- The SIGTERM handler exits with code 0. If the process was asked to terminate, 0 is fine. Some prefer 128+SIGNUM (143) for signal exits but it doesn't matter in practice
cursorUpandcursorToconsts removed entirely. The only positioning primitive iscursorAt. Clean
191 tests pass per the session log. Ship it.
This was referenced Mar 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Related Issues
Closes #149
Co-Authored-By: Claude noreply@anthropic.com