1- import { mkdtemp , writeFile } from "node:fs/promises" ;
1+ import { mkdtemp , symlink , writeFile } from "node:fs/promises" ;
22import { tmpdir } from "node:os" ;
33import { join } from "node:path" ;
4+ import { pathToFileURL } from "node:url" ;
45
56import { 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" ;
1315import 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