From a8adc2c6b104734a65a27c9ad796e568140fdf58 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Wed, 14 Oct 2026 01:10:13 +0800 Subject: [PATCH] fix(setup): retain Codex per-tool approval maps --- src/application/ClientConfigurationDocument.ts | 8 ++++++-- src/application/ClientRegistrationShape.ts | 13 +++++++++++++ src/application/Setup.planning.test.ts | 2 +- .../filesystem/clientRegistrationFields.test.ts | 6 +++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/application/ClientConfigurationDocument.ts b/src/application/ClientConfigurationDocument.ts index bb3e8e42d..42d209030 100644 --- a/src/application/ClientConfigurationDocument.ts +++ b/src/application/ClientConfigurationDocument.ts @@ -1561,7 +1561,7 @@ const registrationManagedKey = ( Object.hasOwn(REGISTRATION_LAUNCHER_KEYS, key) || Object.hasOwn(REGISTRATION_REMOTE_KEYS, key) || !registrationFieldAccepted(dialect, key, value) || - (key === "tools" && !keepsCopilotTools(dialect)) || + (key === "tools" && dialect !== "toml" && !keepsCopilotTools(dialect)) || (key === "enabled" && value === false) || (key === "enable" && value === false && dialect === "zcode") || (key === "disabled" && value === true && !keepsGrokDisabledFlag(dialect)); @@ -1625,7 +1625,11 @@ export const describeClientRegistrationRetention = ( const removed = keepsGrokDisabledFlag(dialect) ? "Remote-server keys, an enabled: false switch, and registration fields that do not parse are removed. A boolean disabled value is kept." : "Remote-server keys, switches that turn the server off, and registration fields that do not parse are removed."; - const tools = keepsCopilotTools(dialect) ? "" : " A tools value is removed."; + const tools = keepsCopilotTools(dialect) + ? "" + : dialect === "toml" + ? " Invalid Codex tools values are removed; valid per-tool approval maps are kept." + : " A tools value is removed."; const replacement = replaced.length === 0 ? `${removed}${tools}` diff --git a/src/application/ClientRegistrationShape.ts b/src/application/ClientRegistrationShape.ts index 082da9082..0eaa0ff99 100644 --- a/src/application/ClientRegistrationShape.ts +++ b/src/application/ClientRegistrationShape.ts @@ -22,6 +22,19 @@ export const registrationSchema = z const codexRegistrationSchema = registrationSchema.extend({ tool_timeout_sec: z.number().optional(), + tools: z + .record( + z.string(), + z + .object({ + approval_mode: z + .enum(["auto", "prompt", "writes", "approve"]) + .optional(), + output_token_limit: z.number().int().positive().optional(), + }) + .strict(), + ) + .optional(), required: z.boolean().optional(), cwd: z.string().optional(), env_vars: z.array(z.string()).optional(), diff --git a/src/application/Setup.planning.test.ts b/src/application/Setup.planning.test.ts index 6ecf2c52b..0f6f34d32 100644 --- a/src/application/Setup.planning.test.ts +++ b/src/application/Setup.planning.test.ts @@ -160,7 +160,7 @@ describe("setup workflow", () => { "registration fields that do not parse are removed", ); expect(result.plannedActions[0]?.detail).toContain( - "A tools value is removed.", + "Invalid Codex tools values are removed; valid per-tool approval maps are kept.", ); expect(host.hopperInstalls).toBe(0); expect(host.configurations).toBe(0); diff --git a/tests/boundary/filesystem/clientRegistrationFields.test.ts b/tests/boundary/filesystem/clientRegistrationFields.test.ts index 52125b3b8..3e87288b8 100644 --- a/tests/boundary/filesystem/clientRegistrationFields.test.ts +++ b/tests/boundary/filesystem/clientRegistrationFields.test.ts @@ -59,7 +59,11 @@ it.each([ "codex", "toml", "toml", - { tool_timeout_sec: 900, enabled_tools: ["analyze_function"] }, + { + tool_timeout_sec: 900, + enabled_tools: ["analyze_function"], + tools: { binary_session: { approval_mode: "approve" } }, + }, ], ["grok_build", "grok", "grok", { tool_timeout_sec: 900 }], ["hermes", "hermes", "hermes", { timeout: 600, connect_timeout: 60 }],