From df76aaef9611c91ef4769d13282690ed2201ad36 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Sat, 25 Apr 2026 22:47:20 -0300 Subject: [PATCH] fix(cli-tools): preserve TOML integer/boolean types in Codex config round-trip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The parseToml function was stripping all value quotes uniformly, turning every value into a JS string. When toToml re-serialized, unquoted integers like 2 were wrapped in quotes becoming "2" — a TOML string. This broke Codex CLI which expects u32 for tui.model_availability_nux: Error loading config.toml: invalid type: string "2", expected u32 Now parseToml detects booleans (true/false), integers, and floats, preserving their native JS types. formatTomlValue already handles number/boolean types correctly, so round-tripping no longer corrupts third-party config sections. --- src/app/api/cli-tools/codex-settings/route.ts | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/app/api/cli-tools/codex-settings/route.ts b/src/app/api/cli-tools/codex-settings/route.ts index f997aa5fb1..d904f73d3e 100644 --- a/src/app/api/cli-tools/codex-settings/route.ts +++ b/src/app/api/cli-tools/codex-settings/route.ts @@ -40,7 +40,7 @@ const parseToml = (content: string) => { const kvMatch = trimmed.match(/^([^=]+)\s*=\s*(.+)$/); if (kvMatch) { let key = kvMatch[1].trim(); - let value = kvMatch[2].trim(); + const rawValue = kvMatch[2].trim(); // Strip quotes from key (TOML quoted keys like "gpt-5.3-codex") if ( (key.startsWith('"') && key.endsWith('"')) || @@ -48,17 +48,30 @@ const parseToml = (content: string) => { ) { key = key.slice(1, -1); } - // Remove quotes from string values only (not arrays, booleans, numbers) - if ( - (value.startsWith('"') && value.endsWith('"')) || - (value.startsWith("'") && value.endsWith("'")) + // Parse value preserving TOML types (integers, floats, booleans) + let parsedValue: string | number | boolean = rawValue; + if (rawValue === "true") { + parsedValue = true; + } else if (rawValue === "false") { + parsedValue = false; + } else if ( + (rawValue.startsWith('"') && rawValue.endsWith('"')) || + (rawValue.startsWith("'") && rawValue.endsWith("'")) ) { - value = value.slice(1, -1); + // Quoted string — strip quotes, keep as string + parsedValue = rawValue.slice(1, -1); + } else if (/^-?\d+$/.test(rawValue)) { + // Integer literal (unquoted) + parsedValue = parseInt(rawValue, 10); + } else if (/^-?\d+\.\d+$/.test(rawValue)) { + // Float literal (unquoted) + parsedValue = parseFloat(rawValue); } + // Arrays and other complex values stay as raw strings if (currentSection === "_root") { - result._root[key] = value; + result._root[key] = parsedValue; } else { - result._sections[currentSection][key] = value; + result._sections[currentSection][key] = parsedValue; } } });