release: v0.4.1#16
Conversation
Remove <Static> which permanently wrote rows to stdout and caused uncontrolled terminal scrolling when long responses completed. Render rows in the dynamic region with viewport-capped visibility so only the rows that fit above the input box are shown. Add a spacer to pin the input box + status bar at the bottom when content is short. Cap streaming text with tailForHeight() which accounts for line wrapping so it never pushes the input box off-screen.
There was a problem hiding this comment.
🧪 PR Review is completed: Viewport management system is well-structured but has a height estimation gap for tool diffs and a potential regression in reasoning expand functionality.
Skipped files
CHANGELOG.md: Skipped file pattern
⬇️ Low Priority Suggestions (2)
src/ui/App.tsx (2 suggestions)
Location:
src/ui/App.tsx(Lines 1685-1685)🟡 Logic Error
Issue: The
estimateRowLinesfunction for the "tool" case withrow.diffcounts raw newline-delimited lines (row.diff.split(" ").length) without accounting for terminal line wrapping. The function's own JSDoc states it "Intentionally slightly conservative (overestimates)" but this case actually underestimates height when diff lines are longer thanwrapWidth. Long diff lines (e.g., minified code, long URLs) will wrap to multiple terminal rows, causing more rows to be displayed thanavailableHeightallows and potentially pushing the input box off-screen.Fix: Use the already-defined
wrapped()helper instead of raw line counting to account for line wrapping, while keeping the 62-line cap.Impact: Ensures the viewport height estimation remains conservative as documented, preventing the input box from being pushed off-screen by long diff content.
- h += Math.min(62, row.diff.split("\n").length) + 1; + h += Math.min(62, wrapped(row.diff)) + 1;Location:
src/ui/App.tsx(Lines 1376-1378)🟡 Potential Regression
Issue: The old code displayed streaming reasoning with
tail(streamingReasoning, expandReasoningRef.current ? 30 : 3), respecting the user's expand/collapse toggle. The newstreamingReasoningDisplayalways uses 3 lines viatailForHeight(streamingReasoning, 3, wrapWidth), ignoringexpandReasoningRef.current. If the expand toggle is still wired to user input (e.g., a keypress), the user will press it but see no effect — a silent regression. Additionally,middleHeightat line 1344 hardcodes+= 4for reasoning, which would also need to change if expand is restored.Fix: Restore the expand-aware line count in
streamingReasoningDisplay, and updatemiddleHeightat line 1344 to1 + (expandReasoningRef.current ? 30 : 3)to reserve the correct vertical space.Impact: Restores the reasoning expand/collapse UX and keeps viewport calculations consistent.
- const streamingReasoningDisplay = streamingReasoning - ? tailForHeight(streamingReasoning, 3, wrapWidth) - : ""; + const streamingReasoningDisplay = streamingReasoning + ? tailForHeight(streamingReasoning, expandReasoningRef.current ? 30 : 3, wrapWidth) + : "";
Release v0.4.1
Patch release — fixes the CLI viewport scrolling issue.
Fixed
<Static>(which permanently wrote rows to stdout and caused the whole view to scroll up when a long response completed). Rows are now rendered in the dynamic region with viewport-capped visibility — only the rows that fit above the input box are shown. A spacer fills the gap when content is short so the input box + status bar are always at the bottom. Streaming text is capped withtailForHeight()(accounting for line wrapping) so it never grows tall enough to push the input box off-screen.Checklist
npm run typecheckandnpm run buildpass0.4.1inpackage.jsonCHANGELOG.mdupdatedrelease/v0.4.1(matches version)