Skip to content

feat(desktop): resolve login-shell PATH for GUI launches (port of cline/cline#12429) - #69696

Merged
teknium1 merged 2 commits into
mainfrom
cline-port/login-shell-path
Aug 17, 2026
Merged

teknium1 merged 2 commits into
mainfrom
cline-port/login-shell-path

Conversation

@teknium1

Copy link
Copy Markdown
Collaborator

Summary

GUI-launched Hermes Desktop (Finder/Dock on macOS, desktop launchers on Linux) now resolves the user's login-shell PATH once at startup and merges it into process.env before the backend spawns — so the backend subtree and the Electron-side resolvers can find Homebrew-, nvm-, pyenv-, cargo-, and ~/.local/bin-installed CLIs.

Ported from cline/cline#12429 (same approach as VS Code's shell environment resolution), adapted to the desktop app's existing backend-env.ts PATH machinery.

Root cause: launchd/desktop launchers hand GUI apps a minimal PATH (/usr/bin:/bin:/usr/sbin:/sbin); shell profiles never run. backend-env.ts's static sane-entry list papers over Homebrew//usr/local, but anything only a profile adds stays invisible — breaking tool availability checks (shutil.which('cua-driver') → computer_use schema silently missing, #51249), stdio MCP server spawns (npx/uvx from nvm or ~/.local/bin), and the Electron-side git/gh/hermes resolvers (#48158). The Python terminal tool's login-shell snapshot covers agent terminal commands, but not the backend process env itself.

Changes

  • apps/desktop/electron/shell-path.ts (new): runs $SHELL -ilc (fallback -lc for the macOS system-bash-3.2 swallow documented in tests/tools/test_find_shell.py) printing $PATH between sentinel markers so profile banners/motd can't corrupt the capture. Merges login-shell entries first (Homebrew/version managers win), current-only entries appended, deduped via backend-env's appendUniquePathEntries. Single-flight, 5s-per-attempt timeout, stdin closed, never rejects — a broken shell profile never blocks boot. win32 no-op (Windows GUI apps get the user PATH from the registry env block).
  • apps/desktop/electron/main.ts: warm the resolution at app.whenReady; await the same single-flight promise in the local-backend start path before runtime resolution, with rememberLog breadcrumbs.
  • apps/desktop/electron/shell-path.test.ts (new): 12 tests — sentinel extraction under banner noise, last-marker poisoning guard, merge ordering/dedupe, -ilc→-lc fallback, failure/unchanged/win32 no-ops, single-flight memoization, never-rejects.

Validation

Check Result
vitest --project electron shell-path.test.ts 12/12 pass
vitest --project electron backend-env.test.ts 6/6 pass (module reused, no regression)
tsc -p tsconfig.electron.json --noEmit clean
eslint + prettier on changed files clean
Live E2E (real shell, GUI-minimal env PATH=/usr/bin:/bin:/usr/sbin:/sbin) enriched with ~/.local/bin, nvm node bin, ~/.cargo/bin, go bin; login entries first; deduped

Related

Infographic

login-shell-path-resolution

@github-actions

github-actions Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

૮ >ﻌ< ა ci review

ran on 8b3e136 — fix: resolve semantic merge conflict — startHermes update-wa

⚠️ Warnings

CI timings · View report · View job

Wall time 27m17s vs 8m (+241.0%). 7 job(s) slower, 12 faster,

  • Check no committed infographics / check-no-committed-infographics: +45.0s
  • JS & TS checks / apps/desktop / check:test:ui:shard-1of3: +44.0s
  • JS & TS checks / apps/desktop / check:test:ui:shard-2of3: -21.0s
  • JS & TS checks / web / check: -13.0s
  • JS & TS checks / apps/desktop / check:test:desktop:all: +11.0s

OSV vulnerability scan · View job

5 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.

@alt-glitch alt-glitch added type/feature New feature or request comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have labels Jul 23, 2026

Copy link
Copy Markdown

Thank you for the explicit credit and for carrying the diagnosis forward into the broader startup-level PATH solution. Resolving the login-shell PATH once for the backend is clearly stronger than my original point fix, and I appreciate you naming #43834 and the other contributors who independently mapped this bug family. I’m glad the investigation was useful.

@isak-ialogics

Copy link
Copy Markdown

Current main now conflicts in apps/desktop/electron/main.ts because local startup moved into runPrimaryBackendStartup; this needs a semantic rebase rather than choosing either conflict side. A narrow resolution is to retain main’s orchestrator and replace waitForLocalStart: waitForUpdateToFinish with an async callback that (1) awaits waitForUpdateToFinish(), then (2) awaits ensureLoginShellPath() and emits this PR’s applied/fallback log. That preserves main’s saved-remote fast path and guarantees the merged PATH is installed before prepareLocalBackend calls resolveHermesBackend. Keep this PR’s import and non-blocking app.whenReady() warmup; do not restore the old inline token/backend-resolution block.

@teknium1

teknium1 commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

Refreshed against current main: startHermes local startup moved into runPrimaryBackendStartup (which now owns the update-mutex wait via waitForLocalStart), so the branch's pre-existing top-level waitForUpdateToFinish() call became a duplicate — removed it in the merge resolution and kept ensureLoginShellPath() before backend resolve, matching the new startup seam (thanks @isak-ialogics for flagging the semantic conflict). Verified: tsc -p tsconfig.electron.json clean, vitest --project electron electron/shell-path.test.ts 12/12 passing.

…launched desktop (cline/cline#12429)

feat(desktop): resolve the user's login-shell PATH once at startup and
merge it into process.env before the backend spawns.

GUI launches (Finder/Dock on macOS, desktop launchers on Linux) inherit
a minimal PATH that never runs the user's shell profiles, so the
backend process — and everything it spawns or probes (shutil.which
availability checks like cua-driver, stdio MCP servers, Electron-side
git/gh/hermes resolvers) — cannot see Homebrew-, nvm-, pyenv-, cargo-,
or ~/.local/bin-installed tools. backend-env.ts's static sane-entry
list covers Homebrew//usr/local but not profile-added dirs.

Approach (ported from cline/cline#12429, mirrors VS Code's shell
environment resolution):
- new electron/shell-path.ts: run $SHELL -ilc (fallback -lc for the
  macOS system-bash-3.2 swallow) printing $PATH between sentinel
  markers so profile banners can't corrupt the capture
- merge login-shell entries first, current-only entries appended,
  deduped via backend-env's appendUniquePathEntries
- single-flight, timeout-bounded, failure-hardened: a broken or slow
  shell profile never blocks boot; win32 no-op
- warmed at app.whenReady, awaited before backend runtime resolution

12 unit tests + live E2E verified (GUI-minimal PATH enriched with
~/.local/bin, nvm, cargo, go entries on a real shell).
…into runPrimaryBackendStartup (waitForLocalStart); drop duplicated waitForUpdateToFinish call, keep login-shell PATH merge before backend resolve
@teknium1
teknium1 force-pushed the cline-port/login-shell-path branch from 4e4c7c0 to 8b3e136 Compare August 17, 2026 02:57
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists and removed type/feature New feature or request P3 Low — cosmetic, nice to have labels Aug 17, 2026
@teknium1
teknium1 merged commit 25851e6 into main Aug 17, 2026
41 checks passed
@teknium1
teknium1 deleted the cline-port/login-shell-path branch August 17, 2026 05:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Hermes Desktop backend PATH misses ~/.local/bin desktop: macOS resolvers ignore Homebrew PATH before backend spawn

4 participants