diff --git a/genkit-tools/cli/src/utils/runtime-detector.ts b/genkit-tools/cli/src/utils/runtime-detector.ts index 63f104563d..b0fc861a71 100644 --- a/genkit-tools/cli/src/utils/runtime-detector.ts +++ b/genkit-tools/cli/src/utils/runtime-detector.ts @@ -124,7 +124,10 @@ export function detectRuntime(): RuntimeInfo { if (hasBunVersion || execMatchesBun || argv0MatchesBun) { // Check if this is a Bun-compiled binary // Bun compiled binaries have virtual paths like /$bunfs/root/... - if (argv1 && argv1.startsWith('/$bunfs/')) { + if ( + argv1 && + (argv1.startsWith('/$bunfs/') || /^[A-Za-z]:[\\/]+~BUN[\\/]+/.test(argv1)) + ) { // This is a Bun-compiled binary type = RUNTIME_COMPILED; scriptPath = undefined; diff --git a/genkit-tools/cli/src/utils/spawn-config.ts b/genkit-tools/cli/src/utils/spawn-config.ts index 28b52661a2..b4e0a89400 100644 --- a/genkit-tools/cli/src/utils/spawn-config.ts +++ b/genkit-tools/cli/src/utils/spawn-config.ts @@ -38,7 +38,10 @@ export interface SpawnConfig { */ export async function validateExecutablePath(path: string): Promise { try { - await access(path, constants.F_OK | constants.X_OK); + // Remove surrounding quotes if present (handle quotation) + const normalizedPath = + path.startsWith('"') && path.endsWith('"') ? path.slice(1, -1) : path; + await access(normalizedPath, constants.F_OK | constants.X_OK); return true; } catch { return false; @@ -91,7 +94,7 @@ export function buildServerHarnessSpawnConfig( throw new Error('Log path is required'); } - const command = runtime.execPath; + let command = runtime.execPath; let args: string[]; if (runtime.type === 'compiled-binary') { @@ -112,6 +115,12 @@ export function buildServerHarnessSpawnConfig( shell: runtime.platform === 'win32', }; + // Handles spaces in the command and arguments on Windows + if (runtime.platform === 'win32') { + command = `"${command}"`; + args = args.map((arg) => `"${arg}"`); + } + return { command, args, diff --git a/genkit-tools/cli/tests/utils/spawn-config_test.ts b/genkit-tools/cli/tests/utils/spawn-config_test.ts index 872eb37da0..a84c657442 100644 --- a/genkit-tools/cli/tests/utils/spawn-config_test.ts +++ b/genkit-tools/cli/tests/utils/spawn-config_test.ts @@ -79,12 +79,12 @@ describe('spawn-config', () => { mockLogPath ); - expect(config.command).toBe('C:\\Program Files\\nodejs\\node.exe'); + expect(config.command).toBe('"C:\\Program Files\\nodejs\\node.exe"'); expect(config.args).toEqual([ - 'C:\\Users\\dev\\AppData\\Roaming\\npm\\node_modules\\genkit-cli\\dist\\bin\\genkit.js', - SERVER_HARNESS_COMMAND, - '4000', - '/path/to/devui.log', + '"C:\\Users\\dev\\AppData\\Roaming\\npm\\node_modules\\genkit-cli\\dist\\bin\\genkit.js"', + '"' + SERVER_HARNESS_COMMAND + '"', + '"4000"', + '"/path/to/devui.log"', ]); expect(config.options.shell).toBe(true); // Shell enabled on Windows }); @@ -180,7 +180,7 @@ describe('spawn-config', () => { mockLogPath ); - expect(config.command).toBe('C:\\Program Files\\Bun\\bun.exe'); + expect(config.command).toBe('"C:\\Program Files\\Bun\\bun.exe"'); expect(config.options.shell).toBe(true); }); }); @@ -227,7 +227,7 @@ describe('spawn-config', () => { mockLogPath ); - expect(config.command).toBe('C:\\Tools\\genkit.exe'); + expect(config.command).toBe('"C:\\Tools\\genkit.exe"'); expect(config.options.shell).toBe(true); });