@@ -381,6 +381,50 @@ test("CliRenderer flushes captured output before switching to passthrough in spl
381381 splitCommitSpy . mockRestore ( )
382382} )
383383
384+ test ( "CliRenderer preserves split render offset when switching to passthrough" , async ( ) => {
385+ const result = await createTestRenderer ( {
386+ width : 40 ,
387+ height : 10 ,
388+ screenMode : "split-footer" ,
389+ footerHeight : 4 ,
390+ externalOutputMode : "capture-stdout" ,
391+ consoleMode : "disabled" ,
392+ } )
393+
394+ renderer = result . renderer
395+ ; ( renderer as any ) . stdout . write ( "seed\n" )
396+ await result . renderOnce ( )
397+
398+ const before = ( renderer as any ) . renderOffset
399+ const pinned = ( renderer as any ) . _terminalHeight - ( renderer as any ) . _splitHeight
400+
401+ renderer . externalOutputMode = "passthrough"
402+
403+ expect ( before ) . toBeGreaterThan ( 0 )
404+ expect ( before ) . toBeLessThanOrEqual ( pinned )
405+ expect ( ( renderer as any ) . renderOffset ) . toBe ( before )
406+ } )
407+
408+ test ( "CliRenderer does not force split repaint when switching to passthrough with no pending output" , async ( ) => {
409+ const result = await createTestRenderer ( {
410+ screenMode : "split-footer" ,
411+ footerHeight : 6 ,
412+ externalOutputMode : "capture-stdout" ,
413+ consoleMode : "disabled" ,
414+ } )
415+
416+ renderer = result . renderer
417+ const lib = ( renderer as any ) . lib
418+ const repaintSpy = spyOn ( lib , "repaintSplitFooter" )
419+
420+ expect ( ( renderer as any ) . externalOutputQueue . size ) . toBe ( 0 )
421+
422+ renderer . externalOutputMode = "passthrough"
423+
424+ expect ( repaintSpy ) . toHaveBeenCalledTimes ( 0 )
425+ repaintSpy . mockRestore ( )
426+ } )
427+
384428test ( "CliRenderer flushes pending split output before resize applies new geometry" , async ( ) => {
385429 const result = await createTestRenderer ( {
386430 width : 40 ,
0 commit comments