Skip to content

fix(terminal): inherit full parent env for Unix PTY to fix zsh#840

Merged
pedramamini merged 2 commits intoRunMaestro:rcfrom
chr1syy:fix/terminal-vi
Apr 16, 2026
Merged

fix(terminal): inherit full parent env for Unix PTY to fix zsh#840
pedramamini merged 2 commits intoRunMaestro:rcfrom
chr1syy:fix/terminal-vi

Conversation

@chr1syy
Copy link
Copy Markdown
Contributor

@chr1syy chr1syy commented Apr 15, 2026

Summary

  • Unix PTY terminal sessions used a minimal 6-variable environment (HOME, USER, SHELL, TERM, LANG, PATH) while Windows inherited the full parent env
  • zsh depends on inherited variables (FPATH, XDG_*, TMPDIR, etc.) for ZLE line editor and plugin initialization — without them, input becomes invisible and navigation breaks
  • Now inherits full parent environment on Unix (matching Windows), strips Electron/IDE vars, and overrides TERM/LANG/PATH with controlled values

Test plan

  • Existing envBuilder tests pass (41/41)
  • New tests verify Unix env inheritance and Electron var stripping
  • Type check, lint, and prettier clean
  • Manual: open Maestro terminal with zsh — verify input is visible, navigation works, vi/vim :q renders correctly
  • Manual: verify bash terminal still works as before

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests

    • Added unit tests validating terminal environment handling on Unix, including inheritance of user variables and removal of internal framework variables.
  • Bug Fixes

    • Terminal environment now inherits parent environment on Unix/macOS while explicitly removing internal/framework-specific variables for improved isolation and consistent TERM/LANG/PATH defaults.

The Unix PTY terminal env was a minimal 6-variable set (HOME, USER, SHELL,
TERM, LANG, PATH). While bash tolerates this, zsh depends on inherited
variables (FPATH, XDG_*, TMPDIR, etc.) for ZLE and plugin initialization.
Without them, zsh input becomes invisible and navigation breaks.

Inherit full parent env (matching Windows behavior), strip Electron/IDE
vars, and override TERM/LANG/PATH with controlled values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 15, 2026

📝 Walkthrough

Walkthrough

PTY environment construction now inherits the full parent process.env on Unix-like systems, forces TERM='xterm-256color', sets PATH via buildUnixBasePath(), and then removes Electron/IDE-related variables listed in STRIPPED_ENV_VARS. Tests added to validate inheritance and stripping with mocked process.platform.

Changes

Cohort / File(s) Summary
Environment Builder Implementation
src/main/process-manager/utils/envBuilder.ts
Unix PTY env now starts from full process.env, still forces TERM, defaults LANG, sets PATH via buildUnixBasePath(), then deletes keys in STRIPPED_ENV_VARS. Windows behavior unchanged.
Environment Builder Tests
src/main/process-manager/utils/__tests__/envBuilder.test.ts
Added two tests that mock process.platform to Unix: one asserts specific env vars (ZSH_CUSTOM_VAR, XDG_CONFIG_HOME) are preserved; the other asserts Electron/IDE-related vars and NODE_ENV are stripped.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

ready to merge

Poem

🐰 I hopped through envs at break of dawn,
Kept the home-grown vars, tossed the IDE's pawns,
TERM set bright, PATH snug and neat,
A tidy shell beneath my feet. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: inheriting the full parent environment for Unix PTY terminals to fix zsh compatibility issues.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 15, 2026

Greptile Summary

This PR fixes zsh breakage in Unix PTY terminal sessions by switching from a minimal 6-variable environment to inheriting the full parent process.env, while stripping Electron/IDE-specific variables and overriding TERM, LANG, and PATH with controlled values — matching the existing Windows behavior. New tests cover inheritance and Electron-var stripping on Unix.

Confidence Score: 5/5

Safe to merge — the logic change is well-scoped, Windows behaviour is untouched, and only two minor doc-comment inconsistencies remain.

All findings are P2 documentation-only issues. The runtime behaviour is correct: full parent env is inherited on Unix, Electron/IDE vars are stripped, and TERM/LANG/PATH are overridden with controlled values. Platform detection reads process.platform at call time, so test mocking is reliable. Existing 41/41 tests pass plus two new targeted tests.

No files require special attention

Important Files Changed

Filename Overview
src/main/process-manager/utils/envBuilder.ts buildPtyTerminalEnv now spreads full process.env and applies STRIPPED_ENV_VARS on Unix; one stale @note docstring remains after the change
src/main/process-manager/utils/tests/envBuilder.test.ts New tests added for Unix env inheritance and Electron-var stripping; platform mocking is safe because isWindows() reads process.platform at call time

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[buildPtyTerminalEnv called] --> B{isWindows?}
    B -- Yes --> C["env = { ...process.env, TERM: 'xterm-256color' }"]
    B -- No --> D["env = { ...process.env, TERM, LANG, PATH: buildUnixBasePath() }"]
    D --> E[Delete each key in STRIPPED_ENV_VARS\nELECTRON_*, CLAUDECODE, NODE_ENV…]
    C --> F{env.VIMINIT set?}
    E --> F
    F -- No --> G["env.VIMINIT = process.env.VIMINIT || 'set nocompatible | set esckeys'"]
    F -- Yes --> H[Keep inherited VIMINIT]
    G --> I{shellEnvVars provided?}
    H --> I
    I -- Yes --> J[Merge shellEnvVars with ~/ expansion]
    I -- No --> K[Return env]
    J --> K
Loading

Comments Outside Diff (2)

  1. src/main/process-manager/utils/envBuilder.ts, line 62 (link)

    P2 Stale @note in JSDoc

    The note still says "Terminal sessions do NOT strip Electron/IDE variables" but the new Unix branch now deletes all STRIPPED_ENV_VARS (including ELECTRON_RUN_AS_NODE, CLAUDECODE, etc.). It should be updated to reflect the current behaviour.

  2. src/main/process-manager/utils/envBuilder.ts, line 119-133 (link)

    P2 @see comment is now incomplete

    The JSDoc on STRIPPED_ENV_VARS only points to buildChildProcessEnv(), but buildPtyTerminalEnv() now also iterates over this list. A reader looking at this constant won't know it affects PTY sessions too.

Reviews (1): Last reviewed commit: "fix(terminal): inherit full parent env f..." | Re-trigger Greptile

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/main/process-manager/utils/__tests__/envBuilder.test.ts (1)

481-500: Consider testing all STRIPPED_ENV_VARS for completeness.

This test verifies 4 of 8 variables in STRIPPED_ENV_VARS. For consistency with the comprehensive test at lines 196-215 (which tests buildChildProcessEnv), consider adding the missing variables: ELECTRON_EXTRA_LAUNCH_ARGS, CLAUDE_CODE_ENTRYPOINT, CLAUDE_AGENT_SDK_VERSION, and CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING.

📝 Proposed test enhancement
 it('should strip Electron/IDE variables from PTY environment on Unix', () => {
   const originalPlatform = process.platform;
   Object.defineProperty(process, 'platform', { value: 'linux' });

   try {
     process.env.ELECTRON_RUN_AS_NODE = '1';
     process.env.ELECTRON_NO_ASAR = '1';
+    process.env.ELECTRON_EXTRA_LAUNCH_ARGS = '--enable-features=something';
     process.env.CLAUDECODE = 'true';
+    process.env.CLAUDE_CODE_ENTRYPOINT = '/path/to/entrypoint';
+    process.env.CLAUDE_AGENT_SDK_VERSION = '1.0.0';
+    process.env.CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING = 'true';
     process.env.NODE_ENV = 'test';

     const env = buildPtyTerminalEnv({});

     expect(env.ELECTRON_RUN_AS_NODE).toBeUndefined();
     expect(env.ELECTRON_NO_ASAR).toBeUndefined();
+    expect(env.ELECTRON_EXTRA_LAUNCH_ARGS).toBeUndefined();
     expect(env.CLAUDECODE).toBeUndefined();
+    expect(env.CLAUDE_CODE_ENTRYPOINT).toBeUndefined();
+    expect(env.CLAUDE_AGENT_SDK_VERSION).toBeUndefined();
+    expect(env.CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING).toBeUndefined();
     expect(env.NODE_ENV).toBeUndefined();
   } finally {
     Object.defineProperty(process, 'platform', { value: originalPlatform });
   }
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/process-manager/utils/__tests__/envBuilder.test.ts` around lines 481
- 500, The test for buildPtyTerminalEnv currently asserts only half of the
entries from STRIPPED_ENV_VARS; update the test in envBuilder.test.ts to include
assertions for the remaining variables ELECTRON_EXTRA_LAUNCH_ARGS,
CLAUDE_CODE_ENTRYPOINT, CLAUDE_AGENT_SDK_VERSION, and
CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING (set them on process.env before
calling buildPtyTerminalEnv and assert they are undefined on the returned env).
Ensure you still toggle the platform to 'linux' and restore it in the finally
block, and reference the STRIPPED_ENV_VARS concept to match the comprehensive
coverage done for buildChildProcessEnv.
src/main/process-manager/utils/envBuilder.ts (1)

62-62: Docstring is now inconsistent with Unix behavior.

Line 62 states "Terminal sessions do NOT strip Electron/IDE variables" but the Unix code path at lines 80-82 now strips STRIPPED_ENV_VARS. This docstring should be updated to reflect the platform-specific difference.

📝 Proposed docstring update
- * `@note` Terminal sessions do NOT strip Electron/IDE variables (full environment inherited on Windows)
+ * `@note` On Windows, the full environment is inherited without stripping. On Unix/Linux/macOS, Electron/IDE variables are stripped to avoid zsh/plugin issues.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/process-manager/utils/envBuilder.ts` at line 62, Update the top
docstring to reflect platform-specific behavior: state that on Windows terminal
sessions inherit the full environment (Electron/IDE vars are not stripped) but
on Unix-like systems the code path removes variables listed in
STRIPPED_ENV_VARS; mention the symbol STRIPPED_ENV_VARS and the env-building
function (e.g., envBuilder / the function that performs the Unix code path) so
readers know the docstring matches the actual behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/process-manager/utils/__tests__/envBuilder.test.ts`:
- Around line 481-500: The test for buildPtyTerminalEnv currently asserts only
half of the entries from STRIPPED_ENV_VARS; update the test in
envBuilder.test.ts to include assertions for the remaining variables
ELECTRON_EXTRA_LAUNCH_ARGS, CLAUDE_CODE_ENTRYPOINT, CLAUDE_AGENT_SDK_VERSION,
and CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING (set them on process.env before
calling buildPtyTerminalEnv and assert they are undefined on the returned env).
Ensure you still toggle the platform to 'linux' and restore it in the finally
block, and reference the STRIPPED_ENV_VARS concept to match the comprehensive
coverage done for buildChildProcessEnv.

In `@src/main/process-manager/utils/envBuilder.ts`:
- Line 62: Update the top docstring to reflect platform-specific behavior: state
that on Windows terminal sessions inherit the full environment (Electron/IDE
vars are not stripped) but on Unix-like systems the code path removes variables
listed in STRIPPED_ENV_VARS; mention the symbol STRIPPED_ENV_VARS and the
env-building function (e.g., envBuilder / the function that performs the Unix
code path) so readers know the docstring matches the actual behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2fdb3c6e-3ead-457b-8593-ea43bbdd3e7a

📥 Commits

Reviewing files that changed from the base of the PR and between 03eb4ba and 289421e.

📒 Files selected for processing (2)
  • src/main/process-manager/utils/__tests__/envBuilder.test.ts
  • src/main/process-manager/utils/envBuilder.ts

…ge, fix stale docstring

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pedramamini
Copy link
Copy Markdown
Collaborator

Thanks for the contribution, @chr1syy! This is a well-scoped and well-motivated fix.

Review notes:

  • The spread-then-override pattern (...process.env → override TERM/LANG/PATH → strip Electron vars) is clean and correctly aligns Unix behavior with Windows, which already inherited the full parent env.
  • Test coverage is thorough — all 8 STRIPPED_ENV_VARS are verified, and the platform mock cleanup in finally blocks is solid.
  • JSDoc updates accurately reflect the new behavior.

One truly minor nit (not blocking): the @see comment on the STRIPPED_ENV_VARS constant (line ~109) still only references buildChildProcessEnv() — now that buildPtyTerminalEnv() also uses it on Unix, you could add a second @see there. Totally optional.

Looks good to merge! 🎉

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/main/process-manager/utils/envBuilder.ts (1)

81-83: Re-apply stripping after custom env merge (or narrow the doc contract).

At Line 81-83, stripping happens before shellEnvVars are applied (Line 94+), so stripped keys can be reintroduced. That conflicts with the wording at Line 62-63 unless the intent is “strip inherited parent vars only.”

♻️ Proposed adjustment
 	} else {
 		const basePath = buildUnixBasePath();
 		env = {
 			...process.env,
 			TERM: 'xterm-256color',
 			LANG: process.env.LANG || 'en_US.UTF-8',
 			PATH: basePath,
 		};
-		for (const key of STRIPPED_ENV_VARS) {
-			delete env[key];
-		}
 	}
@@
 	if (shellEnvVars && Object.keys(shellEnvVars).length > 0) {
 		const homeDir = os.homedir();
 		for (const [key, value] of Object.entries(shellEnvVars)) {
 			env[key] = value.startsWith('~/') ? path.join(homeDir, value.slice(2)) : value;
 		}
 	}
+
+	// Ensure stripped vars never leak into Unix PTY sessions, even via custom merges.
+	if (!isWindows()) {
+		for (const key of STRIPPED_ENV_VARS) {
+			delete env[key];
+		}
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/process-manager/utils/envBuilder.ts` around lines 81 - 83, Stripping
of inherited vars is performed too early: STRIPPED_ENV_VARS are deleted from env
before shellEnvVars are merged, so those keys can be reintroduced; either move
the deletion loop that iterates STRIPPED_ENV_VARS to after the merge with
shellEnvVars (or delete those keys from shellEnvVars before merging) so they
cannot be reintroduced, and update the doc/comment if the intent is to only
strip parent vars; look for the env variable and the merge with shellEnvVars in
envBuilder.ts and apply the deletion after that merge (or adjust the contract).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/process-manager/utils/envBuilder.ts`:
- Around line 81-83: Stripping of inherited vars is performed too early:
STRIPPED_ENV_VARS are deleted from env before shellEnvVars are merged, so those
keys can be reintroduced; either move the deletion loop that iterates
STRIPPED_ENV_VARS to after the merge with shellEnvVars (or delete those keys
from shellEnvVars before merging) so they cannot be reintroduced, and update the
doc/comment if the intent is to only strip parent vars; look for the env
variable and the merge with shellEnvVars in envBuilder.ts and apply the deletion
after that merge (or adjust the contract).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 25038c1a-f7d1-426f-9b2f-2097654c161f

📥 Commits

Reviewing files that changed from the base of the PR and between 289421e and 35740c0.

📒 Files selected for processing (2)
  • src/main/process-manager/utils/__tests__/envBuilder.test.ts
  • src/main/process-manager/utils/envBuilder.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/process-manager/utils/tests/envBuilder.test.ts

@chr1syy chr1syy added the ready to merge This PR is ready to merge label Apr 15, 2026
Copy link
Copy Markdown
Contributor

@ksylvan ksylvan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@pedramamini pedramamini merged commit c1add6d into RunMaestro:rc Apr 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved ready to merge This PR is ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants