Skip to content

Commit f444c6a

Browse files
authored
Merge pull request #33 from OasAIStudio/fix/global-cli-entry
Fix global CLI entrypoint
2 parents e196c24 + 8026128 commit f444c6a

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

src/cli/main.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#!/usr/bin/env node
22

3+
import { realpathSync } from "node:fs";
34
import { resolve } from "node:path";
4-
import { pathToFileURL } from "node:url";
5+
import { fileURLToPath, pathToFileURL } from "node:url";
56

67
import { resolveWorkflowConfig } from "../config/config-resolver.js";
78
import { WORKFLOW_FILENAME } from "../config/defaults.js";
@@ -220,6 +221,23 @@ export async function main(): Promise<void> {
220221
process.exitCode = exitCode;
221222
}
222223

224+
export function shouldRunAsCli(
225+
importMetaUrl: string,
226+
entryPath: string | undefined,
227+
): boolean {
228+
if (!entryPath) {
229+
return false;
230+
}
231+
232+
try {
233+
return (
234+
realpathSync(fileURLToPath(importMetaUrl)) === realpathSync(entryPath)
235+
);
236+
} catch {
237+
return importMetaUrl === pathToFileURL(entryPath).href;
238+
}
239+
}
240+
223241
function readValueFlag(
224242
argv: readonly string[],
225243
index: number,
@@ -268,9 +286,6 @@ function renderUsage(): string {
268286
].join("\n");
269287
}
270288

271-
if (
272-
process.argv[1] &&
273-
import.meta.url === pathToFileURL(process.argv[1]).href
274-
) {
289+
if (shouldRunAsCli(import.meta.url, process.argv[1])) {
275290
void main();
276291
}

tests/cli/main.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { mkdtemp, writeFile } from "node:fs/promises";
1+
import { mkdtemp, symlink, writeFile } from "node:fs/promises";
22
import { tmpdir } from "node:os";
33
import { join } from "node:path";
4+
import { pathToFileURL } from "node:url";
45

56
import { describe, expect, it, vi } from "vitest";
67

@@ -9,6 +10,7 @@ import {
910
applyCliOverrides,
1011
parseCliArgs,
1112
runCli,
13+
shouldRunAsCli,
1214
} from "../../src/cli/main.js";
1315
import type { ResolvedWorkflowConfig } from "../../src/config/types.js";
1416

@@ -61,6 +63,30 @@ describe("cli", () => {
6163
expect(runtime.logsRoot).toBe("/repo/runtime-logs");
6264
});
6365

66+
it("treats symlinked executables as the CLI entrypoint", async () => {
67+
const workspace = await mkdtemp(join(tmpdir(), "symphony-task-cli-link-"));
68+
const cliPath = join(workspace, "main.js");
69+
const symlinkPath = join(workspace, "symphony");
70+
71+
await writeFile(cliPath, "#!/usr/bin/env node\n", "utf8");
72+
await symlink(cliPath, symlinkPath);
73+
74+
expect(shouldRunAsCli(pathToFileURL(cliPath).href, symlinkPath)).toBe(true);
75+
});
76+
77+
it("returns false when the resolved entrypoint differs from the module path", async () => {
78+
const workspace = await mkdtemp(
79+
join(tmpdir(), "symphony-task-cli-mismatch-"),
80+
);
81+
const cliPath = join(workspace, "main.js");
82+
const otherPath = join(workspace, "other.js");
83+
84+
await writeFile(cliPath, "#!/usr/bin/env node\n", "utf8");
85+
await writeFile(otherPath, "#!/usr/bin/env node\n", "utf8");
86+
87+
expect(shouldRunAsCli(pathToFileURL(cliPath).href, otherPath)).toBe(false);
88+
});
89+
6490
it("defaults to loading ./WORKFLOW.md from cwd when no workflow path is given", async () => {
6591
const workspace = await mkdtemp(join(tmpdir(), "symphony-task16-cli-"));
6692
const workflowPath = join(workspace, "WORKFLOW.md");

0 commit comments

Comments
 (0)