diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index a7fe14198..4ab3077b0 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -4,6 +4,7 @@ ### Fixed +- Fixed stdout/stderr write-stream failures from embedded terminal hosts, including Node's `errno -122` case, crashing Caveman Code with an unhandled `WriteStream` error. - Added missing `@sinclair/typebox` runtime dependency. Fixes `ERR_MODULE_NOT_FOUND` on `caveman-code` startup when installed globally ([#6](https://github.com/JuliusBrussee/caveman-code/issues/6)). - Fixed broken extensions-migration links in the hooks-folder warning — now point to `JuliusBrussee/caveman-code` instead of the renamed-away `caveman-cli` repo ([#8](https://github.com/JuliusBrussee/caveman-code/issues/8)). - Self-update check now queries the correct GitHub repo (`caveman-code`) for releases. diff --git a/packages/coding-agent/src/cli.ts b/packages/coding-agent/src/cli.ts index 6e78be1d7..270e3b475 100644 --- a/packages/coding-agent/src/cli.ts +++ b/packages/coding-agent/src/cli.ts @@ -11,6 +11,42 @@ process.emitWarning = (() => {}) as typeof process.emitWarning; import { EnvHttpProxyAgent, setGlobalDispatcher } from "undici"; import { main } from "./main.js"; +type StdioWriteError = Error & { + code?: string; + errno?: number | string; + syscall?: string; +}; + +function isClosedStdioWrite(error: StdioWriteError): boolean { + if (error.syscall !== "write") return false; + if (error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED") return true; + // Some embedded PTY hosts surface a failed output stream as libuv EDQUOT + // (errno -122) instead of a more specific stream error on recent Node versions. + return error.errno === -122 || error.errno === "-122" || error.code === "Unknown system error -122"; +} + +function getStdioWriteExitCode(error: StdioWriteError): number { + return error.errno === -122 || error.errno === "-122" || error.code === "Unknown system error -122" ? 1 : 0; +} + +function installStdioWriteErrorHandlers(): void { + let exiting = false; + const handleError = (error: Error) => { + if (!isClosedStdioWrite(error)) { + throw error; + } + if (exiting) return; + exiting = true; + const exitCode = getStdioWriteExitCode(error); + process.exitCode = exitCode; + setImmediate(() => process.exit(exitCode)); + }; + + process.stdout.on("error", handleError); + process.stderr.on("error", handleError); +} + setGlobalDispatcher(new EnvHttpProxyAgent()); +installStdioWriteErrorHandlers(); main(process.argv.slice(2));