@@ -56,15 +56,26 @@ function exitFullScreen(): void {
5656 process . stdout . write ( ANSI . exitAltScreen ) ;
5757}
5858
59- // Render content at top of screen, truncating to fit terminal height
59+ // Track how many lines the last render wrote so we can clear stale lines
60+ let lastRenderedLineCount = 0 ;
61+
62+ // Render content at top of screen by overwriting lines in place.
63+ // This avoids the flicker caused by clearing the entire screen each frame.
6064function renderScreen ( lines : string [ ] ) : void {
61- process . stdout . write ( ANSI . moveTo ( 1 , 1 ) ) ;
62- process . stdout . write ( ANSI . clearScreen ) ;
63- const maxLines = ( process . stdout . rows || 24 ) - 1 ; // Leave 1 line buffer
65+ const maxLines = ( process . stdout . rows || 24 ) - 1 ;
6466 const truncatedLines = lines . slice ( 0 , maxLines ) ;
67+
68+ let buf = ANSI . moveTo ( 1 , 1 ) ;
6569 for ( const line of truncatedLines ) {
66- console . log ( line ) ;
70+ buf += ANSI . clearLine + line + "\n" ;
6771 }
72+ // Clear any leftover lines from the previous (longer) render
73+ for ( let i = truncatedLines . length ; i < lastRenderedLineCount ; i ++ ) {
74+ buf += ANSI . clearLine + "\n" ;
75+ }
76+ lastRenderedLineCount = truncatedLines . length ;
77+
78+ process . stdout . write ( buf ) ;
6879}
6980
7081// Format percentage
@@ -509,7 +520,7 @@ export async function watchBenchmarkJob(id: string) {
509520 }
510521
511522 const jobName = job . name || job . id ;
512- const startTime = Date . now ( ) ;
523+ const jobStartMs = job . create_time_ms ;
513524
514525 // Enter full-screen mode and set up cleanup
515526 enterFullScreen ( ) ;
@@ -542,7 +553,7 @@ export async function watchBenchmarkJob(id: string) {
542553 const SPINNER_INTERVAL_MS = 100 ;
543554 const UPDATES_PER_POLL = Math . floor ( POLL_INTERVAL_MS / SPINNER_INTERVAL_MS ) ;
544555
545- // Handle terminal resize - clear screen to prevent artifacts
556+ // Handle terminal resize - force a full redraw to clear stale content
546557 let needsFullRedraw = false ;
547558 const handleResize = ( ) => {
548559 needsFullRedraw = true ;
@@ -555,7 +566,7 @@ export async function watchBenchmarkJob(id: string) {
555566
556567 while ( ! COMPLETED_STATES . includes ( job . state || "" ) ) {
557568 // Check timeout
558- if ( Date . now ( ) - startTime > MAX_WAIT_MS ) {
569+ if ( Date . now ( ) - jobStartMs > MAX_WAIT_MS ) {
559570 cleanup ( ) ;
560571 outputError (
561572 `Timeout waiting for job completion after ${ MAX_WAIT_MS / 1000 / 60 } minutes` ,
@@ -566,8 +577,7 @@ export async function watchBenchmarkJob(id: string) {
566577 const progressLines = formatWatchProgress ( progressList , tick ) ;
567578
568579 // Build screen content
569- const elapsed = Math . floor ( ( Date . now ( ) - startTime ) / 1000 ) ;
570- const elapsedStr = `${ Math . floor ( elapsed / 60 ) } m ${ elapsed % 60 } s` ;
580+ const elapsedStr = formatDuration ( Date . now ( ) - jobStartMs ) ;
571581
572582 const screenLines : string [ ] = [ ] ;
573583 screenLines . push (
@@ -588,9 +598,9 @@ export async function watchBenchmarkJob(id: string) {
588598 screenLines . push ( "" ) ;
589599 screenLines . push ( chalk . dim ( "Press Ctrl+C to exit" ) ) ;
590600
591- // Force full clear on resize to prevent artifacts
601+ // On resize, bump the line count so renderScreen clears the full area
592602 if ( needsFullRedraw ) {
593- process . stdout . write ( ANSI . clearScreen ) ;
603+ lastRenderedLineCount = process . stdout . rows || 24 ;
594604 needsFullRedraw = false ;
595605 }
596606
@@ -614,9 +624,8 @@ export async function watchBenchmarkJob(id: string) {
614624 cleanup ( ) ;
615625 }
616626
617- // Calculate total elapsed time
618- const totalElapsed = Date . now ( ) - startTime ;
619- const totalElapsedStr = formatDuration ( totalElapsed ) ;
627+ // Calculate total elapsed time from job creation
628+ const totalElapsedStr = formatDuration ( Date . now ( ) - jobStartMs ) ;
620629
621630 // Show completion message
622631 console . log ( chalk . green . bold ( "Benchmark job completed!" ) ) ;
0 commit comments