From 152cdcabadc525808deba3781989953d2983340b Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 19 Jul 2026 01:39:15 +0200 Subject: [PATCH] fix(migrate): preserve Windows shell semantics --- .../sources/conductor/project-config.test.ts | 24 +++++++++++++++++ .../src/sources/conductor/project-config.ts | 26 ++++++++++++++++--- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/migrate/src/sources/conductor/project-config.test.ts b/packages/migrate/src/sources/conductor/project-config.test.ts index fde83c8bcc..24116057a2 100644 --- a/packages/migrate/src/sources/conductor/project-config.test.ts +++ b/packages/migrate/src/sources/conductor/project-config.test.ts @@ -179,6 +179,30 @@ cwd = "apps/web" }); }); +test("skips variable commands on Windows while preserving ordinary commands", () => { + const inspected = inspectConductorProjectConfig( + emptyRepo("windows-variables"), + { + scripts: { + setup: "cd $CONDUCTOR_WORKSPACE_PATH", + run: { + service: { command: "serve --port $CONDUCTOR_PORT" }, + plain: { command: "npm test" }, + }, + }, + }, + "win32", + ); + + expect(inspected.config).toEqual({ scripts: { plain: { command: "npm test" } } }); + expect(inspected.notices.map((notice) => notice.message)).toEqual( + expect.arrayContaining([ + "worktree.setup: Conductor variables use unsupported shell syntax on Windows: CONDUCTOR_WORKSPACE_PATH. Command was not imported.", + "scripts.service: Conductor variables use unsupported shell syntax on Windows: CONDUCTOR_PORT. Command was not imported.", + ]), + ); +}); + function fixtureRepo(name: "current" | "legacy"): string { const directory = mkdtempSync(path.join(os.tmpdir(), `paseo-migrate-${name}-`)); cleanup.push(directory); diff --git a/packages/migrate/src/sources/conductor/project-config.ts b/packages/migrate/src/sources/conductor/project-config.ts index c48988b0c8..c6dd4e124f 100644 --- a/packages/migrate/src/sources/conductor/project-config.ts +++ b/packages/migrate/src/sources/conductor/project-config.ts @@ -58,8 +58,8 @@ export function inspectConductorProjectConfig( notices.push(malformedSetting("scripts", "Expected a scripts table.")); } - mapLifecycle(scripts?.setup, "worktree.setup", "setup", config, notices); - mapLifecycle(scripts?.archive, "worktree.teardown", "teardown", config, notices); + mapLifecycle(scripts?.setup, "worktree.setup", "setup", config, notices, platform); + mapLifecycle(scripts?.archive, "worktree.teardown", "teardown", config, notices, platform); mapRunScripts(scripts?.run, config, notices, platform); mapMetadataPrompts(settings.prompts, config, notices); reportUnsupported(repoRoot, settings, notices); @@ -160,13 +160,14 @@ function mapLifecycle( target: "setup" | "teardown", config: PaseoConfigRaw, notices: MigrationNotice[], + platform: NodeJS.Platform, ): void { if (value === undefined) return; if (typeof value !== "string" || value.trim().length === 0) { notices.push(malformedSetting(key, "Expected a non-empty command string.")); return; } - const command = rewriteExactCommand(value, "lifecycle", key, notices); + const command = rewriteExactCommand(value, "lifecycle", key, notices, platform); if (!command) return; config.worktree = { ...config.worktree, [target]: command }; } @@ -337,7 +338,13 @@ function mapRunScript( } } - const rewritten = rewriteExactCommand(command, service ? "run" : "lifecycle", key, notices); + const rewritten = rewriteExactCommand( + command, + service ? "run" : "lifecycle", + key, + notices, + platform, + ); if (!rewritten) return; if (service) { const environmentName = scriptId.toUpperCase().replace(/[^A-Z0-9]+/g, "_"); @@ -353,7 +360,18 @@ function rewriteExactCommand( context: RewriteContext, key: string, notices: MigrationNotice[], + platform: NodeJS.Platform, ): string | null { + const sourceVariables = collectConductorVariables(command); + if (platform === "win32" && sourceVariables.length > 0) { + notices.push( + unsupportedSetting( + key, + `Conductor variables use unsupported shell syntax on Windows: ${sourceVariables.join(", ")}. Command was not imported.`, + ), + ); + return null; + } let rewritten = command; for (const [from, to] of [ ["CONDUCTOR_WORKSPACE_PATH", "PASEO_WORKTREE_PATH"],