Skip to content

Commit 3300e3b

Browse files
committed
fix: CLI entry-point guard for npx/bunx invocation (closes #160)
Entry-point guard only matched aimock-cli.js/aimock-cli.ts but npx/bunx create a symlink named 'aimock', so the guard never fired and the CLI exited immediately without starting the server. Add basename match for 'aimock' alongside the existing suffix checks. Add integration test that invokes the CLI via an 'aimock' symlink.
1 parent 2839acf commit 3300e3b

2 files changed

Lines changed: 64 additions & 3 deletions

File tree

src/__tests__/aimock-cli.test.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
22
import { execFile, type ChildProcess } from "node:child_process";
3-
import { existsSync, mkdtempSync, writeFileSync, rmSync } from "node:fs";
3+
import { existsSync, mkdtempSync, writeFileSync, rmSync, symlinkSync, unlinkSync } from "node:fs";
44
import { tmpdir } from "node:os";
55
import { join, resolve } from "node:path";
66
import { runAimockCli, type AimockCliDeps } from "../aimock-cli.js";
@@ -189,6 +189,66 @@ describe.skipIf(!CLI_AVAILABLE)("aimock CLI: server lifecycle", () => {
189189
});
190190
});
191191

192+
describe.skipIf(!CLI_AVAILABLE)("aimock CLI: npx/bunx symlink invocation (#160)", () => {
193+
let tmpDir: string;
194+
let symlinkPath: string;
195+
196+
beforeEach(() => {
197+
tmpDir = makeTmpDir();
198+
symlinkPath = join(tmpDir, "aimock");
199+
symlinkSync(CLI_PATH, symlinkPath);
200+
});
201+
202+
afterEach(() => {
203+
try {
204+
unlinkSync(symlinkPath);
205+
} catch {
206+
/* already cleaned up */
207+
}
208+
rmSync(tmpDir, { recursive: true, force: true });
209+
});
210+
211+
it("starts when invoked as 'aimock' symlink (npx/bunx scenario)", async () => {
212+
const fixturePath = writeFixtureFile(tmpDir);
213+
const configPath = writeConfig(tmpDir, {
214+
llm: { fixtures: fixturePath },
215+
});
216+
217+
let out = "";
218+
let err = "";
219+
const cp = execFile("node", [symlinkPath, "--config", configPath]);
220+
cp.stdout?.on("data", (d: string) => {
221+
out += d;
222+
});
223+
cp.stderr?.on("data", (d: string) => {
224+
err += d;
225+
});
226+
227+
// Wait for "listening" output — proves the entry-point guard fired
228+
await new Promise<void>((resolve, reject) => {
229+
const deadline = setTimeout(() => {
230+
reject(new Error(`Timed out — stdout: ${out}, stderr: ${err}`));
231+
}, 5000);
232+
const check = () => {
233+
if (/listening on/i.test(out) || /listening on/i.test(err)) {
234+
clearTimeout(deadline);
235+
resolve();
236+
return;
237+
}
238+
setTimeout(check, 50);
239+
};
240+
check();
241+
});
242+
243+
expect(out).toContain("listening on");
244+
245+
cp.kill("SIGTERM");
246+
await new Promise<void>((resolve) => {
247+
cp.on("close", () => resolve());
248+
});
249+
});
250+
});
251+
192252
/* ================================================================== */
193253
/* Unit tests (exercise runAimockCli directly for coverage) */
194254
/* ================================================================== */

src/aimock-cli.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22
import { parseArgs } from "node:util";
3-
import { resolve } from "node:path";
3+
import { resolve, basename } from "node:path";
44
import { loadConfig, startFromConfig } from "./config-loader.js";
55
import { runConvertCli, type ConvertCliDeps } from "./convert.js";
66

@@ -137,7 +137,8 @@ export function runAimockCli(deps: AimockCliDeps = {}): void {
137137
// Run when executed as a script (not when imported for testing).
138138
/* v8 ignore start -- entry-point guard, exercised by integration tests */
139139
const scriptName = process.argv[1] ?? "";
140-
if (scriptName.endsWith("aimock-cli.js") || scriptName.endsWith("aimock-cli.ts")) {
140+
const base = basename(scriptName);
141+
if (base === "aimock" || base === "aimock-cli.js" || base === "aimock-cli.ts") {
141142
runAimockCli();
142143
}
143144
/* v8 ignore stop */

0 commit comments

Comments
 (0)