cyberine
UsageRun recipes

The chat REPL is a bottom-anchored column (kntve)

The conversation grows UPWARD off the input, the way every good REPL does. Before this the transcript was a fixed-height box with no justifyContent, so on a 50-row terminal two messages sat at the TOP with roughly 32 blank rows between them and the input pinned at the bottom.

Prose is clamped to MAX_MEASURE (80 columns) and the surplus falls right as margin, so a 200-column terminal no longer wraps a sentence at ~199 cells. Tabular content keeps its own, looser cap (MAX_TABLE_W, 140) — a diff or a code fence is read by structure, not by sweep.

Assistant body text no longer changes colour when streaming ends. The streaming branch used the role colour while the finalized markdown render used TONE.text, so the body visibly re-tinted the instant the response completed, which reads as a re-render glitch rather than a state change. Liveness is carried by the spinner and the role glyph, which is where role colour belongs; command output keeps its deliberately calmer MUTED_STRONG treatment.

The input is separated from the conversation by REGION_GAP. That costs one terminal row, and it is reserved as CHROME (INPUT_REGION_GAP_ROWS in src/tui/chatLayout.ts) rather than taken out of the transcript — otherwise the transcript would silently lose a row. npm run selftest:tui-chat-composition asserts that, plus the anchoring and the measure clamp.

Known Limitations and Deferred Work. Only the input's region gap was converted to the marginTop-on-the-following-sibling form. The remaining paddingBottom / marginBottom / blank <Text> spacers in the chat tree still express spacing the old way, so one gap value still carries more than one level of hierarchy in places. That normalisation is a broad visual change best judged on a real TTY, which no headless check can stand in for.