From bd6139878cfc1d7caf3468e08dbb3a3cdc49649d Mon Sep 17 00:00:00 2001 From: AIEPhoenix Date: Fri, 22 May 2026 15:12:54 +0800 Subject: [PATCH] fix(daemon): strip Electron node flag from PTYs Strip ELECTRON_RUN_AS_NODE from daemon-spawned PTY environments so user shells do not inherit Electron's internal Node-mode flag. Adds regression coverage for the daemon PTY env boundary. Fixes #2414. --- src/main/daemon/pty-subprocess.test.ts | 22 ++++++++++++++++++++++ src/main/daemon/pty-subprocess.ts | 7 +++++++ 2 files changed, 29 insertions(+) diff --git a/src/main/daemon/pty-subprocess.test.ts b/src/main/daemon/pty-subprocess.test.ts index 97d760397..b18e60ac1 100644 --- a/src/main/daemon/pty-subprocess.test.ts +++ b/src/main/daemon/pty-subprocess.test.ts @@ -214,6 +214,28 @@ describe('createPtySubprocess', () => { expect(env.ORCA_WORKTREE_ID).toBe('child-worktree') }) + it('does not inherit ELECTRON_RUN_AS_NODE from the daemon process env', () => { + // Why: the daemon is forked with ELECTRON_RUN_AS_NODE=1. If that flag + // reaches user shells, nested Electron commands run as plain Node. + const proc = mockPtyProcess() + spawnMock.mockReturnValue(proc) + const previous = process.env.ELECTRON_RUN_AS_NODE + process.env.ELECTRON_RUN_AS_NODE = '1' + + try { + createPtySubprocess({ sessionId: 'test', cols: 80, rows: 24 }) + } finally { + if (previous === undefined) { + delete process.env.ELECTRON_RUN_AS_NODE + } else { + process.env.ELECTRON_RUN_AS_NODE = previous + } + } + + const env = spawnMock.mock.calls.at(-1)?.[2].env + expect(env.ELECTRON_RUN_AS_NODE).toBeUndefined() + }) + it('does not inherit parent agent hook endpoint for development hook env', () => { const proc = mockPtyProcess() spawnMock.mockReturnValue(proc) diff --git a/src/main/daemon/pty-subprocess.ts b/src/main/daemon/pty-subprocess.ts index 4060b7580..84e52f0bf 100644 --- a/src/main/daemon/pty-subprocess.ts +++ b/src/main/daemon/pty-subprocess.ts @@ -79,6 +79,12 @@ function removeInheritedDevAgentHookEndpoint( } } +function removeInheritedElectronRunAsNode(env: Record): void { + // Why: the daemon needs ELECTRON_RUN_AS_NODE=1 internally, but user shells + // must not inherit it or nested Electron commands run as plain Node. + delete env.ELECTRON_RUN_AS_NODE +} + function formatMissingDaemonPathError(kind: 'helper' | 'cwd', path: string): DaemonProtocolError { const detailName = kind === 'helper' ? 'helper' : 'cwd' const step = kind === 'helper' ? 'posix_spawn' : 'daemon_cwd' @@ -182,6 +188,7 @@ export function createPtySubprocess(opts: PtySubprocessOptions): SubprocessHandl // of the terminal that launched `pn dev`; each PTY must opt into its own. removeUnspecifiedPaneIdentityEnv(env, opts.env) removeInheritedDevAgentHookEndpoint(env, opts.env) + removeInheritedElectronRunAsNode(env) removeInheritedNoColor(env) env.LANG ??= 'en_US.UTF-8'