What happens
The moon strip is the one section of the TUI content column that does not reflow to the terminal width, so on a narrow terminal it is silently clipped - including the animated "active" moon that tells you the run is still working.
buildContentCells threads a contentWidth into the prompt wrap, the agent-message wrap and the banner, but renderMoonStripCells is not given a width. MOONS_PER_ROW is a fixed 30 and each moon glyph is 2 columns, so a full strip row is 60 columns - a value tuned for the fixed CONTENT_WIDTH of 63.
Once the content column narrows below that, centerLineCells -> clampCellsToWidth trims the row. Nothing corrupts - every frame row is still exactly terminalWidth columns - but moons fall off the end without any indication that they were dropped.
How to reproduce
- Run gnhf in a terminal narrower than about 60 columns (or resize one down mid-run).
- Let it accumulate more iterations than fit - at
terminalWidth 40 that is about 20.
- The strip is cut at the terminal width. The trailing moons disappear, and because the animated moon for the in-flight iteration is appended last, it is the first thing to go.
The practical cost is that the one live element of the display - the moon that animates while the agent is working - is the one most likely to be hidden, so a narrow terminal can look like a stalled run.
Suggested fix
Thread the same contentWidth that buildContentCells already computes into renderMoonStripCells and derive moons-per-row from it (Math.max(1, Math.floor(contentWidth / 2))) instead of the fixed MOONS_PER_ROW = 30. The strip then wraps onto more rows as the terminal narrows rather than being cut.
The height-constrained path in buildContentCells already handles a taller strip: it keeps the newest moon rows and drops the oldest, which is the right priority here too - the active moon stays visible.
Worth deciding alongside: whether a strip that still cannot fit should show an elision marker rather than dropping moons silently.
Context
Found during review of the fix for #166 and #161, which made the content column reflow to the terminal width. That change is what leaves the moon strip as the only section still tied to the old fixed width, so this is adjacent fallout rather than a regression - the fixed MOONS_PER_ROW predates it. Deliberately split out to keep that PR reviewable.
What happens
The moon strip is the one section of the TUI content column that does not reflow to the terminal width, so on a narrow terminal it is silently clipped - including the animated "active" moon that tells you the run is still working.
buildContentCellsthreads acontentWidthinto the prompt wrap, the agent-message wrap and the banner, butrenderMoonStripCellsis not given a width.MOONS_PER_ROWis a fixed30and each moon glyph is 2 columns, so a full strip row is 60 columns - a value tuned for the fixedCONTENT_WIDTHof 63.Once the content column narrows below that,
centerLineCells->clampCellsToWidthtrims the row. Nothing corrupts - every frame row is still exactlyterminalWidthcolumns - but moons fall off the end without any indication that they were dropped.How to reproduce
terminalWidth40 that is about 20.The practical cost is that the one live element of the display - the moon that animates while the agent is working - is the one most likely to be hidden, so a narrow terminal can look like a stalled run.
Suggested fix
Thread the same
contentWidththatbuildContentCellsalready computes intorenderMoonStripCellsand derive moons-per-row from it (Math.max(1, Math.floor(contentWidth / 2))) instead of the fixedMOONS_PER_ROW = 30. The strip then wraps onto more rows as the terminal narrows rather than being cut.The height-constrained path in
buildContentCellsalready handles a taller strip: it keeps the newest moon rows and drops the oldest, which is the right priority here too - the active moon stays visible.Worth deciding alongside: whether a strip that still cannot fit should show an elision marker rather than dropping moons silently.
Context
Found during review of the fix for #166 and #161, which made the content column reflow to the terminal width. That change is what leaves the moon strip as the only section still tied to the old fixed width, so this is adjacent fallout rather than a regression - the fixed
MOONS_PER_ROWpredates it. Deliberately split out to keep that PR reviewable.