From 8a55473bb8857abe011c07fa53b42b80cc20a67e Mon Sep 17 00:00:00 2001 From: devv-eve Date: Wed, 15 Apr 2026 03:49:49 -0700 Subject: [PATCH] fix(desktop): evaluate daemon spawn env lazily to pick up PATH fix (#1088) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DESKTOP_SPAWN_ENV was a top-level const in daemon-manager.ts that snapshotted process.env at module load. Because ESM imports are hoisted and evaluated before main/index.ts runs fix-path, the snapshot captured launchd's minimal PATH — missing ~/.local/bin, Homebrew, etc. The main process then had the corrected PATH, but every spawned daemon inherited the stale one and failed with "no agent CLI found" on fresh GUI launches. Convert it to desktopSpawnEnv() so process.env is read at call time, after fix-path has already updated it. Co-authored-by: Devv Co-authored-by: Claude Opus 4.6 (1M context) --- apps/desktop/src/main/daemon-manager.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/desktop/src/main/daemon-manager.ts b/apps/desktop/src/main/daemon-manager.ts index 82ac270af..cc450f1cc 100644 --- a/apps/desktop/src/main/daemon-manager.ts +++ b/apps/desktop/src/main/daemon-manager.ts @@ -598,11 +598,12 @@ function profileArgs(active: ActiveProfile): string[] { // Env passed to every CLI child so the daemon process knows it was spawned // by the Desktop app. The server uses this to mark runtimes as managed and -// hide CLI self-update UI. -const DESKTOP_SPAWN_ENV = { - ...process.env, - MULTICA_LAUNCHED_BY: "desktop", -}; +// hide CLI self-update UI. Computed lazily so it picks up the PATH fix +// applied by fix-path in main/index.ts — as a top-level const it would +// snapshot process.env at import time, before that block runs. +function desktopSpawnEnv(): NodeJS.ProcessEnv { + return { ...process.env, MULTICA_LAUNCHED_BY: "desktop" }; +} async function startDaemon(): Promise<{ success: boolean; error?: string }> { const bin = await resolveCliBinary(); @@ -624,7 +625,7 @@ async function startDaemon(): Promise<{ success: boolean; error?: string }> { execFile( bin, args, - { timeout: 20_000, env: DESKTOP_SPAWN_ENV }, + { timeout: 20_000, env: desktopSpawnEnv() }, (err) => { if (err) { currentState = "stopped";