From 729d3bd2287b5813b35885e9070b6086043b7f20 Mon Sep 17 00:00:00 2001 From: leechenghsiu Date: Sun, 6 Sep 2026 22:37:43 +0800 Subject: [PATCH] fix(npm): mirror the binary's exit status instead of throwing a Node stack trace `npx zeabur ...` runs npm/index.js, which spawned the Go binary with execFileSync and never caught the throw on a non-zero exit. Two things went wrong every time the CLI failed: Node printed an uncaught-exception stack trace whose error object carried `stdout: null, stderr: null` (stdio is inherited, so the real output had already gone to the terminal), and the process exit code became 1 regardless of what the binary returned. An agent reading that saw "exec produced nothing" instead of psql's actual `role "postgres" does not exist` (exit 2). The wrapper now exits with the binary's status; a signal death maps to the shell convention 128+signal; a spawn failure (e.g. missing binary) prints one line and exits 1. Refs DES-909 Co-Authored-By: Claude Fable 5.1 --- npm/index.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/npm/index.js b/npm/index.js index 370f309..1466335 100755 --- a/npm/index.js +++ b/npm/index.js @@ -40,5 +40,21 @@ function getArch() { const pathToBinary = fileURLToPath(new URL(`./zeabur_${platform}_${arch}/zeabur${platform === "windows" ? ".exe" : ""}`, import.meta.url)); const args = process.argv.slice(2); - execFileSync(pathToBinary, args, { stdio: "inherit" }); + // This wrapper must be transparent: the binary already wrote its own + // stdout/stderr (stdio: "inherit"), so on failure we only mirror its exit + // status. Letting execFileSync throw would print a Node stack trace with + // `stdout: null, stderr: null` and replace the real exit code with 1. + try { + execFileSync(pathToBinary, args, { stdio: "inherit" }); + } catch (e) { + if (typeof e.status === "number") { + process.exit(e.status); + } + if (e.signal) { + // Shell convention for a process killed by a signal. + process.exit(128 + (os.constants.signals[e.signal] ?? 0)); + } + console.error(e.message ?? String(e)); + process.exit(1); + } })()