@@ -753,7 +753,8 @@ export class AICodeUI {
753753 const actualInputLines = Math . min ( this . lineEditor . lines . length , maxInputLines ) ;
754754
755755 // Calculate available space for content (welcome box or conversation)
756- const availableContentLines = this . viewportHeight - chromeLines - actualInputLines ;
756+ // Clamp to 0 minimum to handle very small terminals
757+ const availableContentLines = Math . max ( 0 , this . viewportHeight - chromeLines - actualInputLines ) ;
757758
758759 // Show welcome box if no messages, otherwise show conversation
759760 if ( this . messages . length === 0 && ! this . isStreaming ) {
@@ -784,6 +785,16 @@ export class AICodeUI {
784785 const statusBar = this . renderStatusBar ( width ) ;
785786 lines . push ( statusBar ) ;
786787
788+ // INVARIANT: lines must be exactly viewportHeight
789+ // If too many lines, keep the bottom (input/status) - slice from end
790+ if ( lines . length > this . viewportHeight ) {
791+ lines . splice ( 0 , lines . length - this . viewportHeight ) ;
792+ }
793+ // If too few lines, pad at top
794+ while ( lines . length < this . viewportHeight ) {
795+ lines . unshift ( '' ) ;
796+ }
797+
787798 this . viewport . render ( { lines } ) ;
788799 }
789800
@@ -895,15 +906,19 @@ export class AICodeUI {
895906 }
896907 }
897908
909+ // Reserve 1 line for scroll indicator if needed
910+ const hasScrollIndicator = this . scrollOffset > 0 ;
911+ const effectiveMaxLines = hasScrollIndicator ? maxLines - 1 : maxLines ;
912+
898913 // Apply scroll offset and take last N lines
899- const startIdx = Math . max ( 0 , allLines . length - maxLines - this . scrollOffset ) ;
914+ const startIdx = Math . max ( 0 , allLines . length - effectiveMaxLines - this . scrollOffset ) ;
900915 const endIdx = allLines . length - this . scrollOffset ;
901916 const visibleLines = allLines . slice ( startIdx , endIdx ) ;
902917
903918 lines . push ( ...visibleLines ) ;
904919
905- // Show scroll indicator if needed
906- if ( this . scrollOffset > 0 ) {
920+ // Show scroll indicator if needed (already reserved space above)
921+ if ( hasScrollIndicator ) {
907922 lines . push ( dim ( ` [${ this . scrollOffset } more below - PageDown to scroll]` ) ) ;
908923 }
909924
0 commit comments