From d45acfc4b1ba3c6564beb1985238eb7bd0797ef1 Mon Sep 17 00:00:00 2001 From: xianzuyang9-blip Date: Sun, 7 Jun 2026 21:05:25 +0800 Subject: [PATCH 1/2] Handle missing dist in CLI bin --- bin/excod.cjs | 6 +++++- tests/bin.test.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/bin.test.ts diff --git a/bin/excod.cjs b/bin/excod.cjs index 21e8382..e7e50e1 100755 --- a/bin/excod.cjs +++ b/bin/excod.cjs @@ -1,2 +1,6 @@ #!/usr/bin/env node -import('../dist/cli.js'); +import('../dist/cli.js').catch((error) => { + console.error('Error: dist/cli.js not found. Run `npm run build` first.'); + console.error(error.message); + process.exit(1); +}); diff --git a/tests/bin.test.ts b/tests/bin.test.ts new file mode 100644 index 0000000..06fccd3 --- /dev/null +++ b/tests/bin.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from 'vitest'; +import { spawnSync } from 'node:child_process'; +import { existsSync, renameSync } from 'node:fs'; + +describe('bin/excod.cjs', () => { + it('explains how to recover when dist/cli.js is missing', () => { + const distExists = existsSync('dist'); + if (distExists) { + renameSync('dist', 'dist-test-backup'); + } + + try { + const result = spawnSync(process.execPath, ['bin/excod.cjs'], { + encoding: 'utf8', + }); + + expect(result.status).toBe(1); + expect(result.stderr).toContain('Run `npm run build` first'); + expect(result.stderr).toContain('dist/cli.js'); + } finally { + if (distExists) { + renameSync('dist-test-backup', 'dist'); + } + } + }); +}); From 62848cc1644b292a772cf9739ce12e3a0a925f44 Mon Sep 17 00:00:00 2001 From: xianzuyang9-blip Date: Mon, 8 Jun 2026 03:36:50 +0800 Subject: [PATCH 2/2] Tighten CLI bin startup error handling --- bin/excod.cjs | 14 ++++++++++++-- tests/bin.test.ts | 43 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/bin/excod.cjs b/bin/excod.cjs index e7e50e1..081eebe 100755 --- a/bin/excod.cjs +++ b/bin/excod.cjs @@ -1,6 +1,16 @@ #!/usr/bin/env node import('../dist/cli.js').catch((error) => { - console.error('Error: dist/cli.js not found. Run `npm run build` first.'); - console.error(error.message); + const missingBuiltCli = + error?.code === 'ERR_MODULE_NOT_FOUND' && + typeof error?.message === 'string' && + /[\\/]dist[\\/]cli\.js/.test(error.message); + + if (missingBuiltCli) { + console.error('Error: dist/cli.js not found. Run `npm run build` first.'); + console.error(error.message); + } else { + console.error('Error: CLI startup failed.'); + console.error(error?.stack ?? error); + } process.exit(1); }); diff --git a/tests/bin.test.ts b/tests/bin.test.ts index 06fccd3..dff7ead 100644 --- a/tests/bin.test.ts +++ b/tests/bin.test.ts @@ -1,16 +1,19 @@ import { describe, expect, it } from 'vitest'; import { spawnSync } from 'node:child_process'; -import { existsSync, renameSync } from 'node:fs'; +import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; describe('bin/excod.cjs', () => { it('explains how to recover when dist/cli.js is missing', () => { - const distExists = existsSync('dist'); - if (distExists) { - renameSync('dist', 'dist-test-backup'); - } + const tempDir = mkdtempSync(join(tmpdir(), 'excod-bin-missing-dist-')); + const tempBin = join(tempDir, 'bin', 'excod.cjs'); + mkdirSync(dirname(tempBin), { recursive: true }); + copyFileSync('bin/excod.cjs', tempBin); try { - const result = spawnSync(process.execPath, ['bin/excod.cjs'], { + const result = spawnSync(process.execPath, [tempBin], { + cwd: tempDir, encoding: 'utf8', }); @@ -18,9 +21,31 @@ describe('bin/excod.cjs', () => { expect(result.stderr).toContain('Run `npm run build` first'); expect(result.stderr).toContain('dist/cli.js'); } finally { - if (distExists) { - renameSync('dist-test-backup', 'dist'); - } + rmSync(tempDir, { recursive: true, force: true }); + } + }); + + it('does not report missing dist for CLI runtime failures', () => { + const tempDir = mkdtempSync(join(tmpdir(), 'excod-bin-runtime-error-')); + const tempBin = join(tempDir, 'bin', 'excod.cjs'); + const tempCli = join(tempDir, 'dist', 'cli.js'); + mkdirSync(dirname(tempBin), { recursive: true }); + mkdirSync(dirname(tempCli), { recursive: true }); + copyFileSync('bin/excod.cjs', tempBin); + writeFileSync(tempCli, "throw new Error('boom from cli');\n", 'utf8'); + + try { + const result = spawnSync(process.execPath, [tempBin], { + cwd: tempDir, + encoding: 'utf8', + }); + + expect(result.status).toBe(1); + expect(result.stderr).toContain('CLI startup failed'); + expect(result.stderr).toContain('boom from cli'); + expect(result.stderr).not.toContain('Run `npm run build` first'); + } finally { + rmSync(tempDir, { recursive: true, force: true }); } }); });