diff --git a/src/web/public/app.js b/src/web/public/app.js index 84ad39a5..ac0076ba 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -1386,7 +1386,7 @@ class CodemanApp { // remaining segments to the next frame to prevent terminal.write() from blocking // the main thread. 141KB single-frame writes have been observed to freeze Chrome // for 2+ minutes even with the canvas renderer. - const MAX_FRAME_BYTES = 49152; // 48KB budget per frame + const MAX_FRAME_BYTES = 65536; // 64KB budget per frame let bytesThisFrame = 0; let deferred = false; @@ -1815,6 +1815,16 @@ class CodemanApp { _onSessionTerminal(data) { if (data.id === this.activeSessionId) { if (data.data.length > 32768) _crashDiag.log(`TERMINAL: ${(data.data.length/1024).toFixed(0)}KB`); + + // Hard cap: track total bytes queued across ALL buffers (pendingWrites + + // flickerFilterBuffer + loadBufferQueue). When rAF is throttled (tab + // backgrounded, GPU busy), data accumulates with no flush, reaching + // 889KB+ and freezing Chrome for minutes. Drop data beyond 96KB — + // the server sends session:needsRefresh to recover. + const queued = (this.pendingWrites?.reduce((s, w) => s + w.length, 0) || 0) + + (this.flickerFilterBuffer?.length || 0); + if (queued > 131072) return; // 128KB — drop to prevent accumulation + this.batchTerminalWrite(data.data); } } diff --git a/src/web/public/constants.js b/src/web/public/constants.js index cc8f80a4..f7f37803 100644 --- a/src/web/public/constants.js +++ b/src/web/public/constants.js @@ -52,8 +52,8 @@ const TITLE_FLASH_INTERVAL_MS = 1500; // Title flash rate const BROWSER_NOTIF_RATE_LIMIT_MS = 3000; // Rate limit for browser notifications const AUTO_CLOSE_NOTIFICATION_MS = 8000; // Auto-close browser notifications const THROTTLE_DELAY_MS = 100; // General UI throttle delay -const TERMINAL_CHUNK_SIZE = 32 * 1024; // 32KB chunks for terminal data (smaller to avoid WebGL GPU stalls) -const TERMINAL_TAIL_SIZE = 256 * 1024; // 256KB tail for initial load +const TERMINAL_CHUNK_SIZE = 32 * 1024; // 32KB chunks for terminal buffer loading +const TERMINAL_TAIL_SIZE = 128 * 1024; // 128KB tail for initial load const SYNC_WAIT_TIMEOUT_MS = 50; // Wait timeout for terminal sync const STATS_POLLING_INTERVAL_MS = 2000; // System stats polling