From a482082529e277690bd53b52485ff577c3933ac2 Mon Sep 17 00:00:00 2001 From: BenStullsBets Date: Fri, 26 Jun 2026 13:11:13 -0700 Subject: [PATCH] fix(#59): disable claude-code IDE auto-connect to stop spurious macOS Apple-Events prompt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The claude-code provider spawns the bundled `claude` CLI via @cline/sdk → ai-sdk-provider-claude-code → @anthropic-ai/claude-agent-sdk. On macOS, when that subprocess is launched from inside the VS Code extension host it performs IDE auto-connect, which shells out to `osascript` (`tell application …`) to identify/activate the editor — raising the macOS "control other applications" (Apple Events / Automation) permission prompt. There is no AppleScript/osascript anywhere in the JS dependency tree (the only match is the build-only `vite`); the Apple Event is sent by the spawned `claude` binary, which contains 26 osascript calls. Every one is user-action-gated (clipboard image, screenshot, terminal-setup, Claude-Desktop deep link, browser detection) except the IDE auto-connect path, which is the only one that fires without user action when launched inside an IDE — exactly the reported symptom (appears on use, harmless when declined, since we never use the connection). Fix: spawn the agent with the macOS IDE integration disabled via the provider's `options.env` passthrough — `CLAUDE_CODE_AUTO_CONNECT_IDE=0` hard-returns out of the binary's auto-connect gate (`mK("0") === true`), and `CLAUDE_CODE_IDE_SKIP_AUTO_INSTALL=1` skips the extension-install deep link. `options.env` is seeded with the full `process.env` so the default environment inheritance is unchanged (login under HOME, proxy/CA vars preserved) — only the two switches are added. The env flows end to end into the spawned child (verified through the provider's getBaseProcessEnv merge and the agent SDK's spawn). runEditTurn is the sole agent-spawn site, so this covers every flow. Unit test asserts the agent is constructed with the two switches set and the rest of the environment preserved. 250 unit + typecheck + build green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/liveTurn.ts | 19 +++++++++++++++++++ test/liveTurn.test.ts | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/liveTurn.ts b/src/liveTurn.ts index 3edac9e..a6b7a5d 100644 --- a/src/liveTurn.ts +++ b/src/liveTurn.ts @@ -64,6 +64,25 @@ export async function runEditTurn( providerId: "claude-code", modelId, systemPrompt: SYSTEM_PROMPT, + // The claude-code provider spawns the bundled `claude` CLI. On macOS, when + // that process is launched from inside VS Code it performs IDE auto-connect, + // which shells out to `osascript` (`tell application …`) to identify/activate + // the editor — raising the macOS "control other applications" (Apple Events) + // permission prompt (#59). We only consume the turn's text result and never + // use the IDE connection, so we disable it: `CLAUDE_CODE_AUTO_CONNECT_IDE=0` + // hard-returns out of the auto-connect path in the binary, and + // `CLAUDE_CODE_IDE_SKIP_AUTO_INSTALL=1` skips the extension-install deep link. + // Seeding with the full `process.env` keeps the default inheritance intact + // (login under HOME, proxy/CA vars) — we only add the two switches. The + // provider forwards `options.env` into the spawned child (verified end to end + // through @cline/sdk → ai-sdk-provider-claude-code → @anthropic-ai/claude-agent-sdk). + options: { + env: { + ...process.env, + CLAUDE_CODE_AUTO_CONNECT_IDE: "0", + CLAUDE_CODE_IDE_SKIP_AUTO_INSTALL: "1", + }, + }, }); // Stream reduced progress snapshots out (INV-44 additive) and wire cancellation diff --git a/test/liveTurn.test.ts b/test/liveTurn.test.ts index 32f022d..290abec 100644 --- a/test/liveTurn.test.ts +++ b/test/liveTurn.test.ts @@ -52,6 +52,44 @@ describe("extractReplacement", () => { }); }); +describe("runEditTurn macOS automation prompt (#59)", () => { + // The claude-code provider spawns the bundled `claude` CLI, which on macOS + // performs IDE auto-connect when launched inside VS Code — sending Apple Events + // that raise the "control other applications" prompt. The extension only + // consumes the text result and never needs that connection, so we disable it. + it("spawns the agent with IDE auto-connect + auto-install disabled, preserving the rest of the environment", async () => { + vi.resetModules(); + const cfgs: any[] = []; + vi.doMock("@cline/sdk", () => ({ + Agent: class { + constructor(cfg: any) { + cfgs.push(cfg); + } + subscribe() { + return () => {}; + } + abort() {} + async run() { + return { status: "completed", outputText: "X", runId: "r" }; + } + }, + })); + process.env.__WGL_TEST_SENTINEL__ = "keep-me"; + await runEditTurn("do it", "old"); + const cfg = cfgs[0]; + // mK("0") === true in the claude binary → hard-disables IDE auto-connect, + // so no osascript / Apple Event fires. + expect(cfg.options?.env?.CLAUDE_CODE_AUTO_CONNECT_IDE).toBe("0"); + // Belt-and-suspenders: skip the IDE-extension auto-install (deep-link path). + expect(cfg.options?.env?.CLAUDE_CODE_IDE_SKIP_AUTO_INSTALL).toBe("1"); + // The full process environment must survive (login under HOME, proxy/CA vars). + expect(cfg.options?.env?.__WGL_TEST_SENTINEL__).toBe("keep-me"); + delete process.env.__WGL_TEST_SENTINEL__; + vi.doUnmock("@cline/sdk"); + vi.resetModules(); + }); +}); + describe("runEditTurn progress + cancel", () => { it("emits progress snapshots and returns the replacement unchanged (INV-44)", async () => { vi.resetModules(); -- 2.39.5