diff --git a/src/cli.ts b/src/cli.ts index 50d23e1..3ba9c36 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -403,15 +403,21 @@ function flushWriteStream(stream: NodeJS.WriteStream, timeoutMs: number): Promis const finishAfterDrain = () => { setImmediate(cleanup); }; + const finishWhenDrained = () => { + if (settled) { + return; + } + if (stream.destroyed || stream.writableEnded || (!stream.writableNeedDrain && stream.writableLength === 0)) { + cleanup(); + return; + } + setImmediate(finishWhenDrained); + }; timeout = setTimeout(cleanup, timeoutMs); stream.once('drain', finishAfterDrain); stream.once('error', cleanup); - setImmediate(() => { - if (stream.destroyed || stream.writableEnded || !stream.writableNeedDrain) { - cleanup(); - } - }); + setImmediate(finishWhenDrained); }); } diff --git a/tests/cli-force-exit-behavior.integration.test.ts b/tests/cli-force-exit-behavior.integration.test.ts index 7d8573e..24e120a 100644 --- a/tests/cli-force-exit-behavior.integration.test.ts +++ b/tests/cli-force-exit-behavior.integration.test.ts @@ -50,6 +50,7 @@ const [cliEntry, configPath] = process.argv.slice(2); process.env.MCPORTER_DISABLE_AUTORUN = '1'; let cleanupErrorListenerSeen = false; +let cleanupEmptyWriteSeen = false; let cliRunning = false; Object.defineProperty(process.stdout, 'writableNeedDrain', { configurable: true, @@ -70,6 +71,13 @@ process.stdout.once = (event, listener) => { } return result; }; +const originalWrite = process.stdout.write.bind(process.stdout); +process.stdout.write = (chunk, encoding, callback) => { + if (cliRunning && chunk === '') { + cleanupEmptyWriteSeen = true; + } + return originalWrite(chunk, encoding, callback); +}; const { runCli } = await import(pathToFileURL(cliEntry).href); cliRunning = true; @@ -78,6 +86,10 @@ if (!cleanupErrorListenerSeen) { console.error('expected force-exit cleanup to observe stdout errors'); process.exitCode = 1; } +if (cleanupEmptyWriteSeen) { + console.error('expected force-exit cleanup not to write to stdout'); + process.exitCode = 1; +} `; const scriptPath = path.join(tempDir, 'cleanup-stdout-error.mjs'); await fs.writeFile(scriptPath, script, 'utf8');