diff --git a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts index d14defde9d9..92a5a2b5828 100644 --- a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts +++ b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts @@ -1534,6 +1534,9 @@ describe('pane terminal output scheduler', () => { expect(hasTerminalParseProgressSince(terminal, generation)).toBe(false) expect(recoveryReasons).toEqual(['write-stalled']) expect(isTerminalWritePipelineCertifiedDead(terminal)).toBe(true) + // Only the first rejection touches xterm; later PTY deliveries credit + // directly while recovery owns the certified-dead instance. + expect(terminal.write).toHaveBeenCalledTimes(1) expect(onParsed).not.toHaveBeenCalled() for (const ackCredit of ackCredits) { expect(ackCredit).toHaveBeenCalledTimes(1) diff --git a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.ts b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.ts index 4e1e08284cd..a641f0b0f81 100644 --- a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.ts +++ b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.ts @@ -21,6 +21,7 @@ import { armTerminalWriteStallWatch, cancelTerminalWriteStallWatch, failTerminalWriteStallWatch, + isTerminalWritePipelineCertifiedDead, settleTerminalWriteStallWatch } from './terminal-write-pipeline-health' import { @@ -1123,6 +1124,12 @@ export function writeTerminalOutput( options: WriteTerminalOutputOptions ): void { exposeDebugApi() + // Why: recovery may be budget-delayed while PTY output keeps flowing. Main + // owns the authoritative buffer; credit delivery without waking dead xterm. + if (isTerminalWritePipelineCertifiedDead(terminal)) { + options.ackCredit?.() + return + } if (!data) { // Why: an empty write still consumed its delivery — credit or main's // in-flight window leaks.