From 8854cd4c3bbe9d8f35eff45dad63530491e5169a Mon Sep 17 00:00:00 2001 From: "paseo-bot[bot]" <266920839+paseo-bot[bot]@users.noreply.github.com> Date: Mon, 2 Nov 2026 15:08:07 +0000 Subject: [PATCH] fix(claude): preserve configured env through current launch handling Keep the finalized provider environment when applying the launch-only client identity. Cover configured runtime controls in actual diagnostic and SDK child processes. Co-authored-by: Okan YILDIRIM <63511519+ragokan@users.noreply.github.com> --- .../src/server/agent/plugin-provider.test.ts | 45 ++++++++++++++++++- .../agent/providers/claude/agent.env.test.ts | 12 ++++- .../server/agent/providers/claude/query.ts | 8 ++-- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/packages/server/src/server/agent/plugin-provider.test.ts b/packages/server/src/server/agent/plugin-provider.test.ts index 2a0cf36b54..65893bae10 100644 --- a/packages/server/src/server/agent/plugin-provider.test.ts +++ b/packages/server/src/server/agent/plugin-provider.test.ts @@ -4,7 +4,8 @@ import { join } from "node:path"; import { AgentStorage } from "./agent-storage.js"; import { createIdleRuntimeCleanup } from "./idle-runtime-cleanup/index.js"; import { relative } from "node:path"; -import { execFileSync } from "node:child_process"; +import { promisify } from "node:util"; +import { execFile, execFileSync } from "node:child_process"; import { fileURLToPath } from "node:url"; import type { ProviderConnection, @@ -1858,6 +1859,48 @@ describe("pending provider responses", () => { }); describe("plugin provider launch and status", () => { + test("passes configured Electron mode to a real diagnostic child process", async () => { + const logger = createTestLogger(); + const registry = new PluginAgentClientRegistry(logger); + registry.replace([ + { + id: "environment-probe", + label: "Environment probe", + command: [ + process.execPath, + "-e", + "console.log(JSON.stringify({ mode: process.env.ELECTRON_RUN_AS_NODE ?? null, internal: process.env.PASEO_NODE_ENV ?? null, parent: process.env.CLAUDECODE ?? null }))", + ], + async status({ launch }) { + if (!launch) throw new Error("Missing provider launch"); + const { stdout } = await promisify(execFile)(launch.command, launch.args, { + env: launch.env, + timeout: 5000, + }); + return { available: true, diagnostic: stdout.trim() }; + }, + async connect() { + throw new Error("A diagnostic does not need a provider connection"); + }, + }, + ]); + const definition = registry.definitions()["environment-probe"]!; + const client = definition.createClient( + logger, + ProviderOverrideSchema.parse({ env: { ELECTRON_RUN_AS_NODE: "1" } }), + ); + try { + const diagnostic = await client.getDiagnostic!(); + expect(JSON.parse(diagnostic.diagnostic)).toEqual({ + mode: "1", + internal: null, + parent: null, + }); + } finally { + await registry.shutdown(); + } + }); + test("resolves the executable against the provider's PATH override", async () => { const harness = createProviderHarness(); const registration: ProviderRegistration = { ...harness.registration, command: ["node"] }; diff --git a/packages/server/src/server/agent/providers/claude/agent.env.test.ts b/packages/server/src/server/agent/providers/claude/agent.env.test.ts index 6d268e932c..c905dd6fa8 100644 --- a/packages/server/src/server/agent/providers/claude/agent.env.test.ts +++ b/packages/server/src/server/agent/providers/claude/agent.env.test.ts @@ -42,7 +42,13 @@ describe("Claude SDK env", () => { const query = claudeQuery( { prompt: "", options: {} }, { - runtimeSettings: { env: { CLAUDE_CODE_ENTRYPOINT: "sdk-ts" } }, + runtimeSettings: { + env: { + CLAUDE_CODE_ENTRYPOINT: "sdk-ts", + ELECTRON_RUN_AS_NODE: "1", + ESBUILD_BINARY_PATH: "/configured/esbuild", + }, + }, launchEnv: entrypoint === undefined ? {} : { CLAUDE_CODE_ENTRYPOINT: entrypoint }, queryFactory: ({ options }) => { if (!options.spawnClaudeCodeProcess) { @@ -52,7 +58,7 @@ describe("Claude SDK env", () => { command, args: [ "-e", - "process.stdout.write(JSON.stringify({ entrypoint: process.env.CLAUDE_CODE_ENTRYPOINT, parentSession: process.env.CLAUDECODE ?? null }))", + "process.stdout.write(JSON.stringify({ entrypoint: process.env.CLAUDE_CODE_ENTRYPOINT, parentSession: process.env.CLAUDECODE ?? null, electronMode: process.env.ELECTRON_RUN_AS_NODE ?? null, esbuild: process.env.ESBUILD_BINARY_PATH ?? null }))", ], cwd: process.cwd(), env: { ...process.env, CLAUDE_CODE_ENTRYPOINT: "sdk-ts", CLAUDECODE: "1" }, @@ -72,6 +78,8 @@ describe("Claude SDK env", () => { expect(JSON.parse(output)).toEqual({ ...(entrypoint === undefined ? {} : { entrypoint }), parentSession: null, + electronMode: "1", + esbuild: "/configured/esbuild", }); } finally { query.close(); diff --git a/packages/server/src/server/agent/providers/claude/query.ts b/packages/server/src/server/agent/providers/claude/query.ts index 0f9525d5b1..7b05351f09 100644 --- a/packages/server/src/server/agent/providers/claude/query.ts +++ b/packages/server/src/server/agent/providers/claude/query.ts @@ -5,7 +5,7 @@ import { createProviderEnvSpec, type ProviderRuntimeSettings, } from "../../provider-launch-config.js"; -import { buildSelfNodeCommand, createExternalProcessEnv } from "../../../paseo-env.js"; +import { buildSelfNodeCommand } from "../../../paseo-env.js"; import { spawnProcess } from "../../../../utils/spawn.js"; // Keep the raw SDK query import in this module only. Claude process launch behavior @@ -75,8 +75,10 @@ function applyRuntimeSettingsToClaudeOptions( }); // Session-open hooks may explicitly supply a client identity. Keep inherited // SDK/parent identities cleared while honoring this launch-only contribution. - providerEnvSpec.envOverlay.CLAUDE_CODE_ENTRYPOINT = launchEnv?.CLAUDE_CODE_ENTRYPOINT; - const providerEnv = createExternalProcessEnv(spawnOptions.env, providerEnvSpec.envOverlay); + const providerEnv = providerEnvSpec.env; + if (launchEnv?.CLAUDE_CODE_ENTRYPOINT !== undefined) { + providerEnv.CLAUDE_CODE_ENTRYPOINT = launchEnv.CLAUDE_CODE_ENTRYPOINT; + } const selfNodeCommand = isDefaultRuntime ? buildSelfNodeCommand(resolved.args, providerEnv) : null;