Skip to content

fix(path): add Windows PATH bootstrap dirs#44215

Open
aniruddhaadak80 wants to merge 2 commits intoopenclaw:mainfrom
aniruddhaadak80:fix/windows-path-bootstrap-dirs
Open

fix(path): add Windows PATH bootstrap dirs#44215
aniruddhaadak80 wants to merge 2 commits intoopenclaw:mainfrom
aniruddhaadak80:fix/windows-path-bootstrap-dirs

Conversation

@aniruddhaadak80
Copy link
Copy Markdown

Summary

  • Problem: PATH bootstrapping only seeded Unix-style directories, so minimal Windows environments could miss standard tool locations even when those directories existed.
  • Why it matters: Windows users can end up with shells that cannot find common executables like gh, node, or user-installed package manager shims.
  • What changed: added Windows-specific bootstrap candidates for pnpm, WindowsApps, roaming npm, Program Files nodejs, and SystemRoot paths, plus a focused regression test.
  • What did NOT change (scope boundary): no changes to explicit env.vars.PATH merging logic, process spawning, or non-Windows path ordering.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  • Windows PATH bootstrap now considers common native install locations instead of only Unix-oriented directories.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)

Repro + Verification

Environment

  • OS: Windows
  • Runtime/container: local Node/pnpm workspace
  • Model/provider: N/A
  • Integration/channel (if any): N/A
  • Relevant config (redacted): N/A

Steps

  1. Simulate a minimal Windows PATH environment.
  2. Ensure common Windows tool directories exist.
  3. Run ensureOpenClawCliOnPath.
  4. Verify those directories are prepended into PATH.

Expected

  • Windows bootstrap should include standard native tool directories when present.

Actual

  • The new regression test passes and the PATH helper now prepends those directories in the expected order.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: ran pnpm exec vitest run src/infra/path-env.test.ts src/agents/bash-tools.test.ts -t "PATH|prepends common Windows tool dirs when present".
  • Additional gate: ran pnpm build:plugin-sdk:dts.
  • What I did not verify: end-to-end Windows registry PATH import behavior remains out of scope for this PR.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)

Failure Recovery (if this breaks)

  • Revert the helper + test changes.
  • Known bad symptoms reviewers should watch for: unexpected PATH ordering on Windows minimal shells.

Copilot AI review requested due to automatic review settings March 12, 2026 16:19
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 12, 2026

Greptile Summary

This PR extends the PATH bootstrap helper (candidateBinDirs) with a win32 branch that seeds common Windows tool directories — pnpm shims, WindowsApps aliases, roaming npm, Program Files nodejs (64-bit and 32-bit), System32, and SystemRoot — guarded by null-checks on the corresponding env vars and silently filtered by the existing isDirectory check. The implementation is consistent with the macOS/Linux patterns already present and is backward-compatible.

  • path-env.ts: Logic is correct and clean. Each env-var is guarded, directory existence is verified via isDirectory, and the ordering (user package manager tools → system directories) mirrors the existing Unix behavior.
  • path-env.test.ts: Two minor test hygiene gaps — the ProgramFiles(x86)/nodejs branch is not exercised, and HOMEBREW_PREFIX / HOMEBREW_BREW_FILE / XDG_BIN_HOME are not cleared before the new test (unlike the Linuxbrew test), which could make the test non-deterministic on macOS/Linux CI runners where those vars are set. Assertions use arrayContaining so failures won't surface today, but the isolation is incomplete.

Confidence Score: 4/5

  • Safe to merge; the implementation is correct and the only gaps are minor test coverage holes that don't affect production behavior.
  • The production code change is small, well-guarded, and consistent with existing patterns. The two test hygiene issues (missing ProgramFiles(x86) coverage and un-cleared HOMEBREW vars) are low risk since the assertions use arrayContaining and non-existent directories are already filtered at runtime. No behavioral change on non-Windows platforms.
  • src/infra/path-env.test.ts — minor isolation gaps in the new Windows test case
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/infra/path-env.test.ts
Line: 250-255

Comment:
**`ProgramFiles(x86)` branch is not exercised**

The test sets `ProgramFiles` and `ProgramW6432` but never sets `ProgramFiles(x86)`. As a result, the `programFilesX86` branch in `path-env.ts` (line 115–117) has zero test coverage and `programFilesX86/nodejs` is never verified in the assertion. Consider adding the env-var and including its resolved dir in the `arrayContaining` check.

```suggestion
    process.env.PATH = nodejsDir;
    process.env.LOCALAPPDATA = localAppData;
    process.env.APPDATA = appData;
    process.env.ProgramFiles = programFiles;
    process.env.ProgramW6432 = programFiles;
    process.env["ProgramFiles(x86)"] = abs("C:/Program Files (x86)");
    process.env.SystemRoot = systemRoot;
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/infra/path-env.test.ts
Line: 256

Comment:
**HOMEBREW / XDG env vars not cleared before Windows test**

Every other test that cares about PATH ordering explicitly clears `HOMEBREW_PREFIX`, `HOMEBREW_BREW_FILE`, and `XDG_BIN_HOME` (see the Linuxbrew test at lines 206–208). This test skips those deletes. On a macOS/Linux CI runner where those variables are set, `resolveBrewPathDirs` could inject additional entries into `prepend`, making the actual PATH content non-deterministic and potentially masking ordering regressions. Since the assertion uses `arrayContaining`, failures won't surface today, but the test environment is not fully isolated.

Consider adding:
```suggestion
    delete process.env.OPENCLAW_PATH_BOOTSTRAPPED;
    delete process.env.HOMEBREW_PREFIX;
    delete process.env.HOMEBREW_BREW_FILE;
    delete process.env.XDG_BIN_HOME;
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 696dc61

Comment on lines +250 to +255
process.env.PATH = nodejsDir;
process.env.LOCALAPPDATA = localAppData;
process.env.APPDATA = appData;
process.env.ProgramFiles = programFiles;
process.env.ProgramW6432 = programFiles;
process.env.SystemRoot = systemRoot;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ProgramFiles(x86) branch is not exercised

The test sets ProgramFiles and ProgramW6432 but never sets ProgramFiles(x86). As a result, the programFilesX86 branch in path-env.ts (line 115–117) has zero test coverage and programFilesX86/nodejs is never verified in the assertion. Consider adding the env-var and including its resolved dir in the arrayContaining check.

Suggested change
process.env.PATH = nodejsDir;
process.env.LOCALAPPDATA = localAppData;
process.env.APPDATA = appData;
process.env.ProgramFiles = programFiles;
process.env.ProgramW6432 = programFiles;
process.env.SystemRoot = systemRoot;
process.env.PATH = nodejsDir;
process.env.LOCALAPPDATA = localAppData;
process.env.APPDATA = appData;
process.env.ProgramFiles = programFiles;
process.env.ProgramW6432 = programFiles;
process.env["ProgramFiles(x86)"] = abs("C:/Program Files (x86)");
process.env.SystemRoot = systemRoot;
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/path-env.test.ts
Line: 250-255

Comment:
**`ProgramFiles(x86)` branch is not exercised**

The test sets `ProgramFiles` and `ProgramW6432` but never sets `ProgramFiles(x86)`. As a result, the `programFilesX86` branch in `path-env.ts` (line 115–117) has zero test coverage and `programFilesX86/nodejs` is never verified in the assertion. Consider adding the env-var and including its resolved dir in the `arrayContaining` check.

```suggestion
    process.env.PATH = nodejsDir;
    process.env.LOCALAPPDATA = localAppData;
    process.env.APPDATA = appData;
    process.env.ProgramFiles = programFiles;
    process.env.ProgramW6432 = programFiles;
    process.env["ProgramFiles(x86)"] = abs("C:/Program Files (x86)");
    process.env.SystemRoot = systemRoot;
```

How can I resolve this? If you propose a fix, please make it concise.

process.env.ProgramFiles = programFiles;
process.env.ProgramW6432 = programFiles;
process.env.SystemRoot = systemRoot;
delete process.env.OPENCLAW_PATH_BOOTSTRAPPED;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

HOMEBREW / XDG env vars not cleared before Windows test

Every other test that cares about PATH ordering explicitly clears HOMEBREW_PREFIX, HOMEBREW_BREW_FILE, and XDG_BIN_HOME (see the Linuxbrew test at lines 206–208). This test skips those deletes. On a macOS/Linux CI runner where those variables are set, resolveBrewPathDirs could inject additional entries into prepend, making the actual PATH content non-deterministic and potentially masking ordering regressions. Since the assertion uses arrayContaining, failures won't surface today, but the test environment is not fully isolated.

Consider adding:

Suggested change
delete process.env.OPENCLAW_PATH_BOOTSTRAPPED;
delete process.env.OPENCLAW_PATH_BOOTSTRAPPED;
delete process.env.HOMEBREW_PREFIX;
delete process.env.HOMEBREW_BREW_FILE;
delete process.env.XDG_BIN_HOME;
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/path-env.test.ts
Line: 256

Comment:
**HOMEBREW / XDG env vars not cleared before Windows test**

Every other test that cares about PATH ordering explicitly clears `HOMEBREW_PREFIX`, `HOMEBREW_BREW_FILE`, and `XDG_BIN_HOME` (see the Linuxbrew test at lines 206–208). This test skips those deletes. On a macOS/Linux CI runner where those variables are set, `resolveBrewPathDirs` could inject additional entries into `prepend`, making the actual PATH content non-deterministic and potentially masking ordering regressions. Since the assertion uses `arrayContaining`, failures won't surface today, but the test environment is not fully isolated.

Consider adding:
```suggestion
    delete process.env.OPENCLAW_PATH_BOOTSTRAPPED;
    delete process.env.HOMEBREW_PREFIX;
    delete process.env.HOMEBREW_BREW_FILE;
    delete process.env.XDG_BIN_HOME;
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 696dc61097

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +104 to +107
prepend.push(
path.join(localAppData, "pnpm"),
path.join(localAppData, "Microsoft", "WindowsApps"),
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid prepending WindowsApps ahead of existing PATH

Adding %LOCALAPPDATA%\\Microsoft\\WindowsApps to the prepend list can change command resolution in non-minimal Windows setups, because mergePath places all prepend entries before the existing PATH. On machines where Windows App Execution Aliases are enabled (for example python.exe in WindowsApps) and a real interpreter already exists later in PATH, this change causes OpenClaw subprocesses to resolve the alias/stub instead of the intended executable, which can break tool execution unexpectedly.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends PATH bootstrapping in ensureOpenClawCliOnPath to better support Windows environments by adding common Windows tool locations to the candidate directories, and adds a Vitest case to validate the new behavior.

Changes:

  • Add Windows-specific PATH candidate directories (LOCALAPPDATA pnpm/WindowsApps, APPDATA npm, Program Files nodejs, SystemRoot/System32).
  • Extend the PATH-bootstrapping test suite to cover Windows tool directory prepending.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/infra/path-env.ts Adds Windows-specific candidate PATH entries to the bootstrap logic.
src/infra/path-env.test.ts Adds a Windows-focused test and snapshots additional Windows env vars.

expect(parts).toEqual(
expect.arrayContaining([pnpmDir, windowsAppsDir, npmDir, nodejsDir, system32Dir, systemRoot]),
);
expect(parts.indexOf(pnpmDir)).toBeLessThan(parts.indexOf(nodejsDir));
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

This test claims to verify that common Windows tool dirs are prepended, but it only asserts ordering for pnpmDir vs nodejsDir. Because arrayContaining ignores order, the test would still pass if some of the other Windows dirs (e.g. windowsAppsDir, npmDir, system32Dir, systemRoot) were appended after nodejsDir. Consider asserting that each of these expected directories appears before the original PATH entry (and optionally that System32 comes before SystemRoot).

Suggested change
expect(parts.indexOf(pnpmDir)).toBeLessThan(parts.indexOf(nodejsDir));
const originalPathIndex = parts.indexOf(nodejsDir);
expect(originalPathIndex).toBeGreaterThanOrEqual(0);
const pnpmIndex = parts.indexOf(pnpmDir);
const windowsAppsIndex = parts.indexOf(windowsAppsDir);
const npmIndex = parts.indexOf(npmDir);
const system32Index = parts.indexOf(system32Dir);
const systemRootIndex = parts.indexOf(systemRoot);
expect(pnpmIndex).toBeGreaterThanOrEqual(0);
expect(windowsAppsIndex).toBeGreaterThanOrEqual(0);
expect(npmIndex).toBeGreaterThanOrEqual(0);
expect(system32Index).toBeGreaterThanOrEqual(0);
expect(systemRootIndex).toBeGreaterThanOrEqual(0);
// All common tool dirs should be prepended before the original PATH entry.
expect(pnpmIndex).toBeLessThan(originalPathIndex);
expect(windowsAppsIndex).toBeLessThan(originalPathIndex);
expect(npmIndex).toBeLessThan(originalPathIndex);
expect(system32Index).toBeLessThan(originalPathIndex);
expect(systemRootIndex).toBeLessThan(originalPathIndex);
// Optionally, ensure System32 comes before SystemRoot.
expect(system32Index).toBeLessThan(systemRootIndex);

Copilot uses AI. Check for mistakes.
@katoue

This comment was marked as spam.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 09fb203251

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

platform: "win32",
});

const parts = (process.env.PATH ?? "").split(path.delimiter);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Parse simulated Windows PATH with semicolon delimiter

This test case forces platform: "win32", and ensureOpenClawCliOnPath now merges PATH entries with ";" on that platform (src/infra/path-env.ts:151), but the assertion still splits using path.delimiter. In the Ubuntu checks lane (.github/workflows/ci.yml), path.delimiter is ":", so Windows-style entries like C:/... get split at the drive colon and the expected directories cannot be found, making this regression test fail on non-Windows CI.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants