Bug Description
After resizing the terminal window (shrink then enlarge, or vice versa), the Hermes TUI enters an infinite render loop:
- The status bar line duplicates/scrolls repeatedly
- Screen flickers as fullReset is called every frame
- The only escape is Ctrl+C to kill the process
Reproduction Steps
- Start
hermes in macOS Terminal (or iTerm2)
- Wait for the welcome banner + prompt to appear
- Shrink the terminal window (drag edge to reduce height)
- Enlarge it back to original size
- Observe: status bar lines start stacking, screen flickers, prompt becomes unusable
Environment
- Hermes version: v0.12.0 (2026.4.30), upstream 5d3be89
- OS: macOS 15.x on MacBook Air
- Terminal: macOS Terminal.app and iTerm2 (both reproduce)
- Shell: zsh 5.9
Root Cause Analysis
The root cause is in ui-tui/packages/hermes-ink/src/ink/log-update.ts around line 230:
if (prev.screen.height >= prev.viewport.height && prev.screen.height > 0 && cursorAtBottom && !isGrowing) {
// scrollback-diff check
if (scrollbackChangeY >= 0) {
return fullResetSequence_CAUSES_FLICKER(next, "offscreen", stylePool, ...)
}
}
This block detects changes in scrollback rows (off-screen rows above the viewport) and triggers fullResetSequence_CAUSES_FLICKER. The loop:
- Resize triggers fullReset (line ~150,
viewport.height < prev.viewport.height) — expected and correct.
- fullReset clears the entire terminal and repaints. After repaint, cursor-restore LF may push rows into scrollback differently than before.
- Next frame: scrollback-diff block detects that scrollback rows changed (because fullReset repositioned the cursor), triggers another fullReset.
- Infinite loop: each fullReset causes scrollback changes that trigger the next fullReset.
The loop is especially triggered when:
- A spinner/timer/progress element updates in a scrollback row
- The status bar content changes between frames (e.g. timer display
⏲ Ns)
- Any dynamic content exists in what the renderer considers scrollback
The scrollback-diff block at line ~230 has NO altScreen guard, so it fires in main-screen mode too, where scrollback rows are truly off-screen and invisible.
Suggested Fix
Option A: Gate the scrollback-diff fullReset behind altScreen mode. In main-screen mode, scrollback row changes are invisible to the user (above the visible viewport), so incremental diff of visible rows is sufficient.
Option B: After a resize-triggered fullReset, add a one-frame cooldown that suppresses the scrollback-diff check, preventing the immediate re-trigger.
Additional Context
This affects daily usability — any terminal resize during a session makes the TUI unusable until restart. Confirmed with debug logging showing repeated fullReset(offscreen) calls triggered by scrollback-diff matching spinner/status-bar row changes.
Debug log evidence:
- Every frame:
[SCROLL-DBG] resize fullReset followed by fullReset(offscreen) on next frame
- The
offscreen trigger shows scrollback rows differing due to previous frame fullReset repositioning content
- Loop continues until process is killed
Workaround
No known workaround other than avoiding terminal resize while Hermes TUI is running.
Bug Description
After resizing the terminal window (shrink then enlarge, or vice versa), the Hermes TUI enters an infinite render loop:
Reproduction Steps
hermesin macOS Terminal (or iTerm2)Environment
Root Cause Analysis
The root cause is in
ui-tui/packages/hermes-ink/src/ink/log-update.tsaround line 230:This block detects changes in scrollback rows (off-screen rows above the viewport) and triggers
fullResetSequence_CAUSES_FLICKER. The loop:viewport.height < prev.viewport.height) — expected and correct.The loop is especially triggered when:
⏲ Ns)The scrollback-diff block at line ~230 has NO
altScreenguard, so it fires in main-screen mode too, where scrollback rows are truly off-screen and invisible.Suggested Fix
Option A: Gate the scrollback-diff fullReset behind
altScreenmode. In main-screen mode, scrollback row changes are invisible to the user (above the visible viewport), so incremental diff of visible rows is sufficient.Option B: After a resize-triggered fullReset, add a one-frame cooldown that suppresses the scrollback-diff check, preventing the immediate re-trigger.
Additional Context
This affects daily usability — any terminal resize during a session makes the TUI unusable until restart. Confirmed with debug logging showing repeated
fullReset(offscreen)calls triggered by scrollback-diff matching spinner/status-bar row changes.Debug log evidence:
[SCROLL-DBG] resize fullResetfollowed byfullReset(offscreen)on next frameoffscreentrigger shows scrollback rows differing due to previous frame fullReset repositioning contentWorkaround
No known workaround other than avoiding terminal resize while Hermes TUI is running.