Skip to content

fix: include version manager bins in expanded PATH#562

Open
brownmike wants to merge 4 commits intoRunMaestro:mainfrom
brownmike:fix/codex-version-manager-paths
Open

fix: include version manager bins in expanded PATH#562
brownmike wants to merge 4 commits intoRunMaestro:mainfrom
brownmike:fix/codex-version-manager-paths

Conversation

@brownmike
Copy link

@brownmike brownmike commented Mar 12, 2026

Packaged Maestro can detect Node-backed CLIs like Codex in nvm or fnm installations but still fail to launch them. Agent detection probes those locations directly, while child-process PATH expansion previously omitted the detected version manager bin directories.

Add detected version manager bins to the shared expanded PATH and preserve the intended precedence when prepending paths. This keeps nvm/current/bin ahead of versioned installs and prevents packaged launches from failing with 'env: node: No such file or directory'.

Add regression coverage for both the shared PATH builder and the child process environment builder so packaged-path resolution stays aligned with agent detection.

Resolves #561

Summary by CodeRabbit

  • New Features

    • Detects and prioritizes Node Version Manager (NVM) bin paths when assembling the runtime PATH.
  • Tests

    • Improved test coverage for environment PATH detection with NVM setups.
    • Expanded test environment OS utilities (tmpdir) and filesystem mocks to better simulate NVM-related scenarios.

Packaged Maestro can detect Node-backed CLIs like Codex in nvm or fnm
installations but still fail to launch them. Agent detection probes those
locations directly, while child-process PATH expansion previously omitted
the detected version manager bin directories.

Add detected version manager bins to the shared expanded PATH and preserve
the intended precedence when prepending paths. This keeps nvm/current/bin
ahead of versioned installs and prevents packaged launches from failing
with 'env: node: No such file or directory'.

Add regression coverage for both the shared PATH builder and the child
process environment builder so packaged-path resolution stays aligned with
agent detection.
@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fda98be7-fe4c-4148-aef6-51073703b158

📥 Commits

Reviewing files that changed from the base of the PR and between 548327e and 2f5be14.

📒 Files selected for processing (2)
  • src/__tests__/cli/services/agent-spawner.test.ts
  • src/__tests__/main/agents/session-storage.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/tests/main/agents/session-storage.test.ts

📝 Walkthrough

Walkthrough

Adds detection and inclusion of Node version-manager bin directories into PATH expansion and child-process environment building, fixes prepending order to preserve left-to-right precedence, and adds tests and test-mock adjustments to cover the behavior.

Changes

Cohort / File(s) Summary
Path utils
src/shared/pathUtils.ts
Detect Node version-manager bin paths and include them in Unix-like PATH assembly; change path-prepending loops to reverse iteration using unshift to preserve precedence.
Unit tests — path & env builders
src/__tests__/shared/pathUtils.test.ts, src/main/process-manager/utils/__tests__/envBuilder.test.ts
Added tests that create temporary NVM_DIR structures and assert current/bin is prepended ahead of versioned node bins in expanded PATH and child-process env.
Test mocks updates
src/__tests__/cli/services/agent-spawner.test.ts, src/__tests__/main/agents/session-storage.test.ts
Extended test mocks for fs and os to include existsSync, readdirSync, mkdirSync, createWriteStream, and tmpdir for improved test isolation and predictable tmpdir behavior.

Sequence Diagram(s)

(Skipped — changes are limited to PATH construction and tests and do not introduce multi-component sequential flows requiring visualization.)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: include version manager bins in expanded PATH' accurately summarizes the main change—adding Node version manager bin directories to the expanded PATH for child processes.
Linked Issues check ✅ Passed The PR fully addresses issue #561 by including version manager bins in expanded PATH, preserving precedence when prepending entries, and adding regression tests for both shared PATH builder and child-process environment builder.
Out of Scope Changes check ✅ Passed All changes are directly related to the PR objectives: version manager PATH detection in pathUtils.ts, PATH precedence fixes via reverse iteration, test coverage for PATH expansion and NVM detection, and necessary mock updates for test files.
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
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@brownmike brownmike changed the title Include version manager bins in expanded PATH fix: include version manager bins in expanded PATH Mar 12, 2026
@greptile-apps
Copy link

greptile-apps bot commented Mar 12, 2026

Greptile Summary

This PR fixes a gap where packaged Maestro could detect Node CLIs (e.g. Codex) inside nvm/fnm installations during agent-detection probes, but then fail to launch them because buildExpandedPath() — used by buildChildProcessEnv() — was not calling detectNodeVersionManagerBinPaths(). It aligns the shared PATH builder with the detection logic so both use the same version-manager bin directories.

Key changes:

  • src/shared/pathUtils.ts: Calls detectNodeVersionManagerBinPaths() at the top of buildExpandedPath() and spreads the result at the front of the Unix additionalPaths array. Also fixes both path-prepending loops from forward-iteration to reverse-iteration so that unshift preserves the intended array order (previously customPaths[0] and versionManagerPaths[0] would end up last due to repeated unshift in forward order; now they correctly end up first).
  • Two new regression tests using real temp-directory fixtures confirm that nvm/current/bin appears at index 0 of the PATH and ahead of versioned installs, covering both buildExpandedPath and buildChildProcessEnv.
  • One minor inconsistency: the new test in pathUtils.test.ts uses a hardcoded /tmp/ prefix for mkdtempSync, while the equivalent test in envBuilder.test.ts uses the more portable path.join(os.tmpdir(), ...).

Confidence Score: 5/5

  • Safe to merge — the fix is a straightforward additive change to PATH construction with good regression coverage and no risk of breaking existing behavior.
  • The core logic change (adding versionManagerPaths to the Unix additionalPaths array and fixing loop direction) is correct and well-scoped. The reverse-loop fix ensures the intended ordering is preserved when prepending via unshift. The new tests validate both the ordering invariant and end-to-end inclusion in child-process environments. The only finding is a minor portability nit in one test (/tmp hardcoded vs os.tmpdir()), which does not affect correctness on the primary CI targets (Linux/macOS).
  • No files require special attention.

Important Files Changed

Filename Overview
src/shared/pathUtils.ts Adds versionManagerPaths to the Unix additionalPaths array and fixes the loop direction (forward → reverse) so that unshift preserves the input array order rather than reversing it. Logic is correct: nvm/current/bin ends up first in PATH, versioned bins follow, then standard paths.
src/tests/shared/pathUtils.test.ts Adds regression test verifying that detected NVM bin directories are prepended and in the correct priority order. Uses real filesystem ops (mkdtempSync / mkdirSync / rmSync) with proper try/finally cleanup. Minor: hardcoded /tmp/ prefix should use os.tmpdir() for cross-platform consistency, matching envBuilder.test.ts.
src/main/process-manager/utils/tests/envBuilder.test.ts Adds a parallel regression test for buildChildProcessEnv ensuring version manager bins appear in the spawned-process PATH. Uses os.tmpdir() portably, cleans up properly in finally, and asserts both presence and precedence ordering.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["buildExpandedPath(customPaths?)"] --> B["detectNodeVersionManagerBinPaths()"]
    B --> C{isWindows?}
    C -- Yes --> D["return []"]
    C -- No --> E["Probe NVM_DIR → current/bin + versions/node/**/bin"]
    E --> F["Probe fnm aliases/default + node-versions/**/bin"]
    F --> G["Probe volta, mise, asdf, n shims"]
    G --> H["return versionManagerPaths[]"]

    H --> I["Build additionalPaths\n[...versionManagerPaths, homebrew, local, ...]"]
    D --> J["Build Windows additionalPaths\n[npm, git, dotnet, ...]"]

    A --> K["pathParts = process.env.PATH.split(':')"]
    I --> L["Reverse-iterate additionalPaths\nunshift each into pathParts"]
    J --> L
    K --> L

    A --> M{customPaths?}
    M -- Yes --> N["Reverse-iterate customPaths\nunshift each into pathParts"]
    M -- No --> L

    N --> L
    L --> O["return pathParts.join(':')"]

    O --> P["buildChildProcessEnv()\nenv.PATH = buildExpandedPath()"]
    O --> Q["buildExpandedEnv()\nenv.PATH = buildExpandedPath()"]
Loading

Last reviewed commit: f2ba473

Copy link

@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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/shared/pathUtils.ts (1)

391-407: Comment at line 391 is misleading.

The comment says "Add custom paths first" but due to the order of operations (customPaths processed before additionalPaths, both using unshift), additionalPaths (including version manager paths) actually end up before customPaths in the final PATH. This appears intentional based on the test expectations (version manager paths should be first), but the comment doesn't reflect the actual behavior.

📝 Suggested comment fix
-	// Add custom paths first (if provided)
+	// Add custom paths (if provided) - these will appear after additionalPaths in final PATH
 	if (customPaths && customPaths.length > 0) {
 		for (let i = customPaths.length - 1; i >= 0; i--) {
 			const p = customPaths[i];
 			if (!pathParts.includes(p)) {
 				pathParts.unshift(p);
 			}
 		}
 	}

-	// Add standard additional paths
+	// Add standard additional paths (these will be prepended, appearing first in final PATH)
 	for (let i = additionalPaths.length - 1; i >= 0; i--) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/shared/pathUtils.ts` around lines 391 - 407, The inline comment "Add
custom paths first (if provided)" is misleading because the code processes
customPaths then additionalPaths with unshift, causing additionalPaths to appear
before customPaths in the final path; update the comment near the loop handling
customPaths/additionalPaths in pathUtils.ts to accurately state that
additionalPaths (e.g., version manager paths) will take precedence and will be
placed before any customPaths in pathParts, or adjust wording to clarify the
intended ordering semantics involving customPaths, additionalPaths, and
pathParts.
src/__tests__/shared/pathUtils.test.ts (1)

281-308: Use os.tmpdir() instead of hardcoded /tmp for cross-platform compatibility.

Line 284 uses a hardcoded /tmp/maestro-nvm- prefix. While this test runs under a mocked darwin platform, using os.tmpdir() is more consistent with the pattern used in envBuilder.test.ts and avoids potential issues if the test setup changes.

♻️ Suggested fix
 		it('should prepend detected Node version manager bin paths', () => {
 			process.env.PATH = '/usr/bin';
 			const originalNvmDir = process.env.NVM_DIR;
-			const tempNvmDir = fs.mkdtempSync('/tmp/maestro-nvm-');
+			const tempNvmDir = fs.mkdtempSync(path.join(os.tmpdir(), 'maestro-nvm-'));
 			process.env.NVM_DIR = tempNvmDir;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/__tests__/shared/pathUtils.test.ts` around lines 281 - 308, Replace the
hardcoded '/tmp/maestro-nvm-' prefix passed to fs.mkdtempSync with a prefix
based on os.tmpdir() so the temp directory is created in the OS temp location;
specifically import/use os.tmpdir() (or require('os')) and call
fs.mkdtempSync(path.join(os.tmpdir(), 'maestro-nvm-')) when creating tempNvmDir
in the test that exercises buildExpandedPath(), leaving the rest of the temp
cleanup and NVM_DIR restore logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/process-manager/utils/__tests__/envBuilder.test.ts`:
- Around line 309-335: The test in envBuilder.test.ts is platform-dependent
because detectNodeVersionManagerBinPaths (in pathUtils.ts) returns empty on
Windows, causing assertions in the buildChildProcessEnv() test to fail; fix by
either (A) mocking process.platform to a Unix-like value (e.g., set
process.platform to 'darwin' for the duration of the test and restore it
afterward) so detectNodeVersionManagerBinPaths yields the expected paths before
calling buildChildProcessEnv(), or (B) skip the test on Windows by checking
process.platform and using test.skip or conditional logic to not run the
assertions on 'win32'. Restore any mutated state (process.platform,
process.env.NVM_DIR) in finally blocks.

---

Nitpick comments:
In `@src/__tests__/shared/pathUtils.test.ts`:
- Around line 281-308: Replace the hardcoded '/tmp/maestro-nvm-' prefix passed
to fs.mkdtempSync with a prefix based on os.tmpdir() so the temp directory is
created in the OS temp location; specifically import/use os.tmpdir() (or
require('os')) and call fs.mkdtempSync(path.join(os.tmpdir(), 'maestro-nvm-'))
when creating tempNvmDir in the test that exercises buildExpandedPath(), leaving
the rest of the temp cleanup and NVM_DIR restore logic unchanged.

In `@src/shared/pathUtils.ts`:
- Around line 391-407: The inline comment "Add custom paths first (if provided)"
is misleading because the code processes customPaths then additionalPaths with
unshift, causing additionalPaths to appear before customPaths in the final path;
update the comment near the loop handling customPaths/additionalPaths in
pathUtils.ts to accurately state that additionalPaths (e.g., version manager
paths) will take precedence and will be placed before any customPaths in
pathParts, or adjust wording to clarify the intended ordering semantics
involving customPaths, additionalPaths, and pathParts.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a9fe5869-7a8c-49bc-869a-ad596d347a36

📥 Commits

Reviewing files that changed from the base of the PR and between 9ff6839 and f2ba473.

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

Use os.tmpdir() in the pathUtils regression test instead of a
hardcoded temporary directory path, and clarify the PATH-prepend
comment to explain why the arrays are iterated in reverse.

These changes keep the implementation the same while addressing the
review notes on portability and code clarity.
Force the regression test to run under a Unix-like platform value so
it exercises version manager path detection consistently across local
runs and CI, including Windows.

This addresses the remaining review concern without changing the
production code path.
@chr1syy
Copy link
Collaborator

chr1syy commented Mar 12, 2026

didnt manage to finish #535 yet, so closing it for this PR

Copy link

@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 (3)
docs/releases.md (3)

201-201: Minor: Capitalize "GitHub" properly.

Per static analysis, "Github" should be "GitHub" (capital H).

📝 Suggested fix
-🌳 Github Worktree support was added. Any agent bound to a Git repository has the option to enable worktrees, each of which show up as a sub-agent with their own write-lock and Auto Run capability. Now you can truly develop in parallel on the same project and issue PRs when you're ready, all from within Maestro. Huge improvement, major thanks to `@petersilberman`.
+🌳 GitHub Worktree support was added. Any agent bound to a Git repository has the option to enable worktrees, each of which show up as a sub-agent with their own write-lock and Auto Run capability. Now you can truly develop in parallel on the same project and issue PRs when you're ready, all from within Maestro. Huge improvement, major thanks to `@petersilberman`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/releases.md` at line 201, The release note contains the incorrect
capitalization "Github Worktree support"; update the string in docs/releases.md
to "GitHub Worktree support" (replace "Github" with "GitHub") so the release
entry uses the proper product casing.

22-22: Minor: Hyphenate compound adjectives.

Per static analysis, "open source projects" should be "open-source projects" when used as a compound adjective.

📝 Suggested fix
-🎶 **Maestro Symphony** — Contribute to open source with AI assistance! Browse curated issues from projects with the `runmaestro.ai` label, clone repos with one click, and automatically process the relevant Auto Run playbooks. Track your contributions, streaks, and stats. You're contributing CPU and tokens towards your favorite open source projects and features.
+🎶 **Maestro Symphony** — Contribute to open-source with AI assistance! Browse curated issues from projects with the `runmaestro.ai` label, clone repos with one click, and automatically process the relevant Auto Run playbooks. Track your contributions, streaks, and stats. You're contributing CPU and tokens towards your favorite open-source projects and features.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/releases.md` at line 22, In the "Maestro Symphony" release blurb replace
the compound adjective "open source projects" with the hyphenated form
"open-source projects" in the sentence that begins with "Contribute to open
source with AI assistance!" to satisfy the static analysis rule; update that
exact phrase in the diffed line so the text reads "Browse curated issues from
projects with the `runmaestro.ai` label, clone repos with one click, and
automatically process the relevant Auto Run playbooks." using "open-source
projects" where applicable.

176-176: Minor: Hyphenate "built-in".

Per static analysis, "built in updater" should be "built-in updater".

📝 Suggested fix
-🎯 Added [GitHub Spec-Kit](https://github.com/github/spec-kit) commands into Maestro with a built in updater to grab the latest prompts from the repository. We do override `/speckit-implement` (the final step) to create Auto Run docs and guide the user through their execution, which thanks to Wortrees from v0.11.x allows us to run in parallel!
+🎯 Added [GitHub Spec-Kit](https://github.com/github/spec-kit) commands into Maestro with a built-in updater to grab the latest prompts from the repository. We do override `/speckit-implement` (the final step) to create Auto Run docs and guide the user through their execution, which thanks to Worktrees from v0.11.x allows us to run in parallel!
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/releases.md` at line 176, Update the phrase "built in updater" to the
correct hyphenated form "built-in updater" in the release notes sentence
referencing GitHub Spec-Kit so the line now reads that Maestro includes a
"built-in updater" to grab the latest prompts; edit the string in the release
notes paragraph containing "GitHub Spec-Kit" / "Maestro" / "/speckit-implement"
to apply this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/releases.md`:
- Line 201: The release note contains the incorrect capitalization "Github
Worktree support"; update the string in docs/releases.md to "GitHub Worktree
support" (replace "Github" with "GitHub") so the release entry uses the proper
product casing.
- Line 22: In the "Maestro Symphony" release blurb replace the compound
adjective "open source projects" with the hyphenated form "open-source projects"
in the sentence that begins with "Contribute to open source with AI assistance!"
to satisfy the static analysis rule; update that exact phrase in the diffed line
so the text reads "Browse curated issues from projects with the `runmaestro.ai`
label, clone repos with one click, and automatically process the relevant Auto
Run playbooks." using "open-source projects" where applicable.
- Line 176: Update the phrase "built in updater" to the correct hyphenated form
"built-in updater" in the release notes sentence referencing GitHub Spec-Kit so
the line now reads that Maestro includes a "built-in updater" to grab the latest
prompts; edit the string in the release notes paragraph containing "GitHub
Spec-Kit" / "Maestro" / "/speckit-implement" to apply this change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c29fd465-357a-4939-9c6c-85540e245ea8

📥 Commits

Reviewing files that changed from the base of the PR and between 8bf9f7d and 548327e.

📒 Files selected for processing (3)
  • docs/releases.md
  • src/__tests__/cli/services/agent-spawner.test.ts
  • src/__tests__/main/agents/session-storage.test.ts

@brownmike brownmike force-pushed the fix/codex-version-manager-paths branch from 548327e to 2f5be14 Compare March 12, 2026 22:41
@brownmike
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chr1syy
Copy link
Collaborator

chr1syy commented Mar 13, 2026

manual test working, also fixed agents not being able to run node or npm without sourcing nvm

chr1syy added a commit to chr1syy/Maestro that referenced this pull request Mar 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Packaged app can detect Codex in nvm/fnm, but child-process PATH omits version manager bins

2 participants