From 2646df346ee8bdf451beda7f0885a87f9c3da6c4 Mon Sep 17 00:00:00 2001 From: zrq8 <36910740+zrq8@users.noreply.github.com> Date: Thu, 8 Jan 2026 10:44:01 +0800 Subject: [PATCH] fix: start codex on Windows by using shell; keep mcp args parseable (#40) Windows global installs expose codex as codex.cmd; spawning 'codex' without shell hits ENOENT. Enable shell to align with Claude's Windows behavior and resolve PATH lookup. Shell spawn makes cmd.exe strip TOML double quotes in -c arrays, so args become a string. Switch mcp args to TOML literal (single-quoted) arrays to preserve types; update tests. --- cli/src/codex/codexLocal.ts | 3 ++- cli/src/codex/utils/codexMcpConfig.test.ts | 2 +- cli/src/codex/utils/codexMcpConfig.ts | 21 +++++++++++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/cli/src/codex/codexLocal.ts b/cli/src/codex/codexLocal.ts index bc494a84..c4940b89 100644 --- a/cli/src/codex/codexLocal.ts +++ b/cli/src/codex/codexLocal.ts @@ -80,7 +80,8 @@ export async function codexLocal(opts: { spawnName: 'codex', installHint: 'Codex CLI', includeCause: true, - logExit: true + logExit: true, + shell: process.platform === 'win32' }); } finally { process.stdin.resume(); diff --git a/cli/src/codex/utils/codexMcpConfig.test.ts b/cli/src/codex/utils/codexMcpConfig.test.ts index 621dd8e3..286c739b 100644 --- a/cli/src/codex/utils/codexMcpConfig.test.ts +++ b/cli/src/codex/utils/codexMcpConfig.test.ts @@ -15,7 +15,7 @@ describe('codexMcpConfig', () => { expect(args).toEqual([ '-c', 'mcp_servers.hapi.command="hapi"', - '-c', 'mcp_servers.hapi.args=["mcp","--url","http://localhost:3000"]' + '-c', "mcp_servers.hapi.args=['mcp','--url','http://localhost:3000']" ]); }); diff --git a/cli/src/codex/utils/codexMcpConfig.ts b/cli/src/codex/utils/codexMcpConfig.ts index 623f2ad6..a4648670 100644 --- a/cli/src/codex/utils/codexMcpConfig.ts +++ b/cli/src/codex/utils/codexMcpConfig.ts @@ -20,12 +20,25 @@ function escapeTomlString(value: string): string { .replace(/\t/g, '\\t'); } +/** + * Escape a string value for use in a TOML single-quoted literal string. + * Only single quotes need escaping (by doubling them). + */ +function escapeTomlLiteralString(value: string): string { + return value.replace(/'/g, "''"); +} + +function buildTomlLiteralArray(values: string[]): string { + const items = values.map((value) => `'${escapeTomlLiteralString(value)}'`); + return `[${items.join(',')}]`; +} + /** * Build -c arguments for MCP server configuration. * * Generates arguments like: * -c 'mcp_servers.hapi.command="hapi"' - * -c 'mcp_servers.hapi.args=["mcp", "--url", "http://..."]' + * -c 'mcp_servers.hapi.args=['mcp', '--url', 'http://...']' * * @param mcpServers - Map of server name to server config * @returns Array of CLI arguments to pass to codex @@ -39,9 +52,9 @@ export function buildMcpServerConfigArgs( // -c 'mcp_servers..command=""' configArgs.push('-c', `mcp_servers.${name}.command="${escapeTomlString(server.command)}"`); - // -c 'mcp_servers..args=["arg1", "arg2"]' - // JSON.stringify produces valid TOML array syntax for simple string arrays - const argsToml = JSON.stringify(server.args); + // -c 'mcp_servers..args=['arg1','arg2']' + // Use TOML literal strings to avoid shell-quote mangling on Windows. + const argsToml = buildTomlLiteralArray(server.args); configArgs.push('-c', `mcp_servers.${name}.args=${argsToml}`); }