fix(agent): stop phantom desktop app boots from agent subprocesses#3239
fix(agent): stop phantom desktop app boots from agent subprocesses#3239gantoine wants to merge 6 commits into
Conversation
Generated-By: PostHog Code Task-Id: c7c785f3-12d4-4e51-ba0f-8c39056461da
Generated-By: PostHog Code Task-Id: c7c785f3-12d4-4e51-ba0f-8c39056461da
Generated-By: PostHog Code Task-Id: c7c785f3-12d4-4e51-ba0f-8c39056461da
Codex spawns the local-tools MCP helper as process.execPath, which in packaged desktop installs is the app binary, while codex's own env has ELECTRON_RUN_AS_NODE stripped (spawn.ts). Without the var the helper boots the full desktop app instead of running the script. Ports the old-adapter fix from #3108 to the app-server adapter. Generated-By: PostHog Code Task-Id: c7c785f3-12d4-4e51-ba0f-8c39056461da
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
|
Reviews (1): Last reviewed commit: "fix(agent): carry ELECTRON_RUN_AS_NODE o..." | Re-trigger Greptile |
|
Reviews (2): Last reviewed commit: "fix(agent): carry ELECTRON_RUN_AS_NODE o..." | Re-trigger Greptile |
|
note to all: this needs careful review |
The workspace-server inherits both ELECTRON_RUN_AS_NODE=1 and POSTHOG_CODE_INTERNAL_CHILD=1 from apps/code (service.ts). We already dropped the former from user terminals; the latter leaked through, so a direct invocation of the packaged app binary from an integrated terminal would hit the bootstrap guard (app.isPackaged && POSTHOG_CODE_INTERNAL_CHILD) and exit(1) with a confusing error, even when the user meant to launch a second instance. Drop both markers. Generated-By: PostHog Code Task-Id: c7c785f3-12d4-4e51-ba0f-8c39056461da
🖥️ macOS test build (Apple Silicon)A signed macOS build for this PR is ready to download and run. ⬇️ Open this run and download the Unzip it, then open the
Built from 787b983 · rebuilds on each push while the |
Problem
Users sometimes see dozens of empty dark windows cascade onto the screen with dozens of hung "node" processes in Activity Monitor (hit again today — screenshots in the internal thread). Root cause was established in #3108: the agent host puts a
node -> app binaryshim on PATH that only behaves as node whileELECTRON_RUN_AS_NODE=1survives the caller's environment. Claude's Bash tool replays commands under a login-shell snapshot of the user's dotfiles, so direnv/mise/flox or a strayunsetstrips the var, and everynodeinvocation then boots a full desktop app instance: while the real app runs, phantoms lose the single-instance lock and exit invisibly; when the lock is free (quit, crash, update restart) each spawn opens an empty window and never exits.#3108 and its follow-up #3113 were closed unmerged, so main is still exposed (#3114 remains open). This PR re-lands the #3108 scope, rebased onto current main.
Changes
Cherry-picked from
feat/vendored-node-runtime(original work by @charlesvien):nodeshim is now a self-contained wrapper script that exportsELECTRON_RUN_AS_NODE=1itself before exec'ing the app binary (POSIX; Windows keeps the symlink). Also heals stale shims pointing at a moved binary, which the old EEXIST-skip never did. (node-shim.ts)POSTHOG_CODE_INTERNAL_CHILD=1, andbootstrap.tsrefuses to boot the packaged app when the marker is present withoutELECTRON_RUN_AS_NODE, failing fast on stderr instead of racing the single-instance lock.ELECTRON_RUN_AS_NODE, so Electron-based CLIs launched from app terminals don't silently run as node. (shell.ts)Adapted to current main (the old
adapters/codexwas replaced bycodex-app-serverin #2723):command: process.execPath— the app binary in packaged installs — while codex's own env has the var deleted. Its server config now carriesELECTRON_RUN_AS_NODE=1explicitly, porting the old-adapter fix. Inert on real node (cloud runs).Not included: the #3113 vendored Node runtime (tracked in #3114).
How did you test this?
node-shim.test.ts(7),agent.test.ts(25),shell.test.ts(5) in workspace-server;local-tools-mcp.test.ts(4, incl. new env assertion),spawn.test.ts(7),codex-app-server-agent.test.ts(57) in agent.pnpm typecheckand biome on all changed files pass.Closes #3108-scope; refs #3114.
Created with PostHog Code