Skip to content

Commit 696dc61

Browse files
fix(path): add Windows PATH bootstrap dirs
1 parent 0a8fa0e commit 696dc61

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

src/infra/path-env.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ describe("ensureOpenClawCliOnPath", () => {
4444
"HOMEBREW_PREFIX",
4545
"HOMEBREW_BREW_FILE",
4646
"XDG_BIN_HOME",
47+
"LOCALAPPDATA",
48+
"APPDATA",
49+
"ProgramFiles",
50+
"ProgramW6432",
51+
"ProgramFiles(x86)",
52+
"SystemRoot",
53+
"WINDIR",
4754
] as const;
4855
let envSnapshot: Record<(typeof envKeys)[number], string | undefined>;
4956

@@ -212,4 +219,53 @@ describe("ensureOpenClawCliOnPath", () => {
212219
expect(parts[0]).toBe(linuxbrewBin);
213220
expect(parts[1]).toBe(linuxbrewSbin);
214221
});
222+
223+
it("prepends common Windows tool dirs when present", () => {
224+
const homeDir = abs("C:/Users/TestUser");
225+
const execDir = path.join(homeDir, "AppData", "Local", "Programs", "OpenClaw");
226+
const localAppData = path.join(homeDir, "AppData", "Local");
227+
const appData = path.join(homeDir, "AppData", "Roaming");
228+
const programFiles = abs("C:/Program Files");
229+
const systemRoot = abs("C:/Windows");
230+
231+
const pnpmDir = path.join(localAppData, "pnpm");
232+
const windowsAppsDir = path.join(localAppData, "Microsoft", "WindowsApps");
233+
const npmDir = path.join(appData, "npm");
234+
const nodejsDir = path.join(programFiles, "nodejs");
235+
const system32Dir = path.join(systemRoot, "System32");
236+
237+
setDir(homeDir);
238+
setDir(execDir);
239+
setDir(localAppData);
240+
setDir(path.join(localAppData, "Microsoft"));
241+
setDir(pnpmDir);
242+
setDir(windowsAppsDir);
243+
setDir(appData);
244+
setDir(npmDir);
245+
setDir(programFiles);
246+
setDir(nodejsDir);
247+
setDir(systemRoot);
248+
setDir(system32Dir);
249+
250+
process.env.PATH = nodejsDir;
251+
process.env.LOCALAPPDATA = localAppData;
252+
process.env.APPDATA = appData;
253+
process.env.ProgramFiles = programFiles;
254+
process.env.ProgramW6432 = programFiles;
255+
process.env.SystemRoot = systemRoot;
256+
delete process.env.OPENCLAW_PATH_BOOTSTRAPPED;
257+
258+
ensureOpenClawCliOnPath({
259+
execPath: path.join(execDir, "node.exe"),
260+
cwd: homeDir,
261+
homeDir,
262+
platform: "win32",
263+
});
264+
265+
const parts = (process.env.PATH ?? "").split(path.delimiter);
266+
expect(parts).toEqual(
267+
expect.arrayContaining([pnpmDir, windowsAppsDir, npmDir, nodejsDir, system32Dir, systemRoot]),
268+
);
269+
expect(parts.indexOf(pnpmDir)).toBeLessThan(parts.indexOf(nodejsDir));
270+
});
215271
});

src/infra/path-env.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,32 @@ function candidateBinDirs(opts: EnsureOpenClawPathOpts): { prepend: string[]; ap
9393
if (platform === "darwin") {
9494
prepend.push(path.join(homeDir, "Library", "pnpm"));
9595
}
96+
if (platform === "win32") {
97+
const localAppData = process.env.LOCALAPPDATA;
98+
const roamingAppData = process.env.APPDATA;
99+
const systemRoot = process.env.SystemRoot ?? process.env.WINDIR;
100+
const programFiles = process.env.ProgramW6432 ?? process.env.ProgramFiles;
101+
const programFilesX86 = process.env["ProgramFiles(x86)"];
102+
103+
if (localAppData) {
104+
prepend.push(
105+
path.join(localAppData, "pnpm"),
106+
path.join(localAppData, "Microsoft", "WindowsApps"),
107+
);
108+
}
109+
if (roamingAppData) {
110+
prepend.push(path.join(roamingAppData, "npm"));
111+
}
112+
if (programFiles) {
113+
prepend.push(path.join(programFiles, "nodejs"));
114+
}
115+
if (programFilesX86) {
116+
prepend.push(path.join(programFilesX86, "nodejs"));
117+
}
118+
if (systemRoot) {
119+
prepend.push(path.join(systemRoot, "System32"), systemRoot);
120+
}
121+
}
96122
if (process.env.XDG_BIN_HOME) {
97123
prepend.push(process.env.XDG_BIN_HOME);
98124
}

0 commit comments

Comments
 (0)