-
-
Notifications
You must be signed in to change notification settings - Fork 64
fix(electron): inherit full login shell environment instead of PATH only #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
881e8a9
3efaf22
e327f12
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,37 +13,54 @@ import { resolveUserShell } from './user-shell.js'; | |
| const __filename = fileURLToPath(import.meta.url); | ||
| const __dirname = path.dirname(__filename); | ||
|
|
||
| // When launched from a .desktop file, PATH is minimal (/usr/bin:/bin). | ||
| // Resolve the user's full login-interactive shell PATH so spawned PTYs | ||
| // can find CLI tools like claude, codex, gemini, etc. | ||
| // When launched from a .desktop file (e.g. AppImage), the environment is | ||
| // minimal — often just PATH=/usr/bin:/bin. Resolve the user's full | ||
| // login-interactive shell environment and merge it into process.env so | ||
| // spawned PTYs can find CLI tools (claude, codex, gemini, etc.) and | ||
| // inherit other expected variables (SSH_AGENT_LAUNCHER, KUBECONFIG, etc.). | ||
| // | ||
| // Uses -ilc (interactive + login) to source both .zprofile/.profile AND | ||
| // .zshrc/.bashrc, where version managers (nvm, volta, fnm) add to PATH. | ||
| // Sentinel markers isolate PATH from noisy shell init output. | ||
| // A perl one-liner dumps every env var as null-delimited key=value pairs, | ||
| // bounded by sentinel markers to isolate the data from noisy shell init. | ||
| // | ||
| // Trade-off: -i (interactive) triggers .zshrc side effects (compinit, conda, | ||
| // welcome messages). Login-only (-lc) would be quieter but would miss tools | ||
| // that are only added to PATH in .bashrc/.zshrc (e.g. nvm). We accept the | ||
| // side effects since the sentinel-based parsing discards all other output. | ||
| function fixPath(): void { | ||
| // Another trade-off: inheriting the *full* environment (rather than just PATH) | ||
| // can pull in large variables (certificates, tokens, kubeconfig). We set a | ||
| // generous maxBuffer and fall back to the original environment on failure. | ||
| function fixEnv(): void { | ||
| if (process.platform === 'win32') return; | ||
| try { | ||
| const loginShell = resolveUserShell(); | ||
| const sentinel = '__PCODE_PATH__'; | ||
| const result = execFileSync(loginShell, ['-ilc', `printf "${sentinel}%s${sentinel}" "$PATH"`], { | ||
| encoding: 'utf8', | ||
| timeout: 5000, | ||
| }); | ||
| const match = result.match(new RegExp(`${sentinel}(.+?)${sentinel}`)); | ||
| if (match?.[1]) { | ||
| process.env.PATH = match[1]; | ||
| const sentinel = '__PCODE_ENV__'; | ||
| const result = execFileSync( | ||
| loginShell, | ||
| [ | ||
| '-ilc', | ||
| `printf '${sentinel}' && perl -e 'print "$_=$ENV{$_}\\0" for keys %ENV' && printf '${sentinel}'`, | ||
| ], | ||
| { encoding: 'utf8', timeout: 5000, maxBuffer: 10 * 1024 * 1024 }, | ||
| ); | ||
|
Comment on lines
+39
to
+46
|
||
| const startIdx = result.indexOf(sentinel); | ||
| const endIdx = result.lastIndexOf(sentinel); | ||
| if (startIdx === -1 || endIdx === -1 || startIdx === endIdx) return; | ||
|
|
||
| const envBlock = result.slice(startIdx + sentinel.length, endIdx); | ||
| for (const entry of envBlock.split('\0')) { | ||
| if (!entry) continue; | ||
| const eqIdx = entry.indexOf('='); | ||
| if (eqIdx <= 0) continue; | ||
| process.env[entry.slice(0, eqIdx)] = entry.slice(eqIdx + 1); | ||
| } | ||
| } catch (err) { | ||
| console.warn('[fixPath] Failed to resolve login shell PATH:', err); | ||
| console.warn('[fixEnv] Failed to resolve login shell environment:', err); | ||
| } | ||
| } | ||
|
|
||
| fixPath(); | ||
| fixEnv(); | ||
|
|
||
| // Verify that preload.cjs ALLOWED_CHANNELS stays in sync with the IPC enum. | ||
| // Logs a warning in dev if they drift — catches mismatches before they hit users. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment above this function still describes resolving only PATH and using sentinel-based parsing to isolate PATH output, but the implementation now captures and applies the full environment via
env -0. Please update the comment to match the new behavior (and any updated trade-offs).