fix(cli): preserve startup banner on terminal resize#23048
Conversation
Recover from SIGWINCH without clearing the physical screen or scrollback buffer. The startup banner and tool summary are printed before prompt_toolkit owns the live chrome, so they live in normal terminal scrollback. Calling erase_screen() + \x1b[3J] on every resize removed that UI permanently — _replay_output_history cannot reconstruct it because the banner was never added to _OUTPUT_HISTORY. Instead, just reset prompt_toolkit's renderer cache and invalidate so the next incremental redraw starts from a clean slate, then let the original on_resize handler recalculate layout for the new terminal size. This matches the behaviour of bash/zsh/fish on SIGWINCH. Fixes NousResearch#22999
|
This PR addresses one specific symptom of a broader issue: the CLI/TUI does not reflow content on terminal resize. There are 34+ open bugs about various manifestations of this problem. I've opened a tracking feature request (#24164) that proposes a comprehensive solution — a SIGWINCH handler triggering full re-render at new viewport dimensions, comparable to how opencode and Claude Code handle resize smoothly. If this PR gets merged, please consider whether the underlying architecture supports full reflow, or if we still need a systematic fix. The tracking issue consolidates all related work: |
|
Salvaged onto current main via #25227 (your branch was 219 commits behind; cherry-picked with your authorship preserved in git log). Commit e2b2d48 on main, author vominh1919 vominh1919@gmail.com. Thanks for the fix — and to @Dc-j0e for the well-diagnosed bug report. |
Problem
After starting the classic CLI in a small terminal window and then maximizing/resizing, the startup banner and right-side tool summary disappear. Only the bottom input prompt area remains visible.
Root cause:
_recover_after_resize()calls_clear_prompt_toolkit_screen(app, rebuild_scrollback=True)which sendserase_screen()+�[3J](clear scrollback). The startup banner was printed before prompt_toolkit owned the chrome, so it lives in normal terminal scrollback — clearing it removes the banner permanently._replay_output_historycannot reconstruct it because the banner was never added to_OUTPUT_HISTORY.Fix
Replace the aggressive screen/scrollback clear with a minimal renderer reset:
app.renderer.reset(leave_alternate_screen=False)— drops prompt_toolkit's cached screen + cursor state so the next redraw starts cleanapp.invalidate()— schedules a repaintoriginal_on_resize()— recalculates layout for the new terminal sizeThis matches how bash/zsh/fish/vim/htop handle SIGWINCH — they never clear scrollback on resize.
Before vs After
_force_full_redraw(Ctrl+L)_clear_prompt_toolkit_screenwrapped in try/exceptTests
Updated
test_resize_rebuilds_scrollback_before_prompt_toolkit_redraw→test_resize_preserves_scrollback_and_resets_rendererto verify:renderer.reset()+invalidate()+original_on_resize()called in ordererase_screen,write_raw,cursor_gotoNOT called (scrollback preserved)All 9 tests in
tests/cli/test_cli_force_redraw.pypass.Fixes #22999