fix(daemon): prefer current node (process.execPath) and add macOS version manager paths to service PATH

On macOS, `openclaw gateway install` hardcodes the system node
(/opt/homebrew/bin/node) in the launchd plist, ignoring the node from
version managers (fnm/nvm/volta). This causes the Gateway to run a
different node version than the user's shell environment.

Two fixes:

1. `resolvePreferredNodePath` now checks `process.execPath` first.
   If the currently running node is a supported version, use it directly.
   This respects the user's active version manager selection.

2. `buildMinimalServicePath` now includes version manager bin directories
   on macOS (fnm, nvm, volta, pnpm, bun), matching the existing Linux
   behavior.

Fixes #18090
Related: #6061, #6064
This commit is contained in:
Yao
2026-02-16 22:03:53 +08:00
committed by Peter Steinberger
parent 59eac34c2b
commit 1a8548df18
4 changed files with 188 additions and 11 deletions

View File

@@ -96,21 +96,66 @@ describe("getMinimalServicePathParts - Linux user directories", () => {
expect(result).toContain("/opt/fnm/current/bin");
});
it("does not include Linux user directories on macOS", () => {
it("includes version manager directories on macOS when HOME is set", () => {
const result = getMinimalServicePathParts({
platform: "darwin",
home: "/Users/testuser",
});
// Should not include Linux-specific user dirs even with HOME set
expect(result.some((p) => p.includes(".npm-global"))).toBe(false);
expect(result.some((p) => p.includes(".nvm"))).toBe(false);
// Should include common user bin directories
expect(result).toContain("/Users/testuser/.local/bin");
expect(result).toContain("/Users/testuser/.npm-global/bin");
expect(result).toContain("/Users/testuser/bin");
// Should only include macOS system directories
// Should include version manager paths (macOS specific)
// Note: nvm has no stable default path, relies on user's shell config
expect(result).toContain("/Users/testuser/Library/Application Support/fnm/aliases/default/bin"); // fnm default on macOS
expect(result).toContain("/Users/testuser/.fnm/aliases/default/bin"); // fnm if customized to ~/.fnm
expect(result).toContain("/Users/testuser/.volta/bin");
expect(result).toContain("/Users/testuser/.asdf/shims");
expect(result).toContain("/Users/testuser/Library/pnpm"); // pnpm default on macOS
expect(result).toContain("/Users/testuser/.local/share/pnpm"); // pnpm XDG fallback
expect(result).toContain("/Users/testuser/.bun/bin");
// Should also include macOS system directories
expect(result).toContain("/opt/homebrew/bin");
expect(result).toContain("/usr/local/bin");
});
it("includes env-configured version manager dirs on macOS", () => {
const result = getMinimalServicePathPartsFromEnv({
platform: "darwin",
env: {
HOME: "/Users/testuser",
FNM_DIR: "/Users/testuser/Library/Application Support/fnm",
NVM_DIR: "/Users/testuser/.nvm",
PNPM_HOME: "/Users/testuser/Library/pnpm",
},
});
// fnm uses aliases/default/bin (not current)
expect(result).toContain("/Users/testuser/Library/Application Support/fnm/aliases/default/bin");
// nvm: relies on NVM_DIR env var (no stable default path)
expect(result).toContain("/Users/testuser/.nvm");
// pnpm: binary is directly in PNPM_HOME
expect(result).toContain("/Users/testuser/Library/pnpm");
});
it("places version manager dirs before system dirs on macOS", () => {
const result = getMinimalServicePathParts({
platform: "darwin",
home: "/Users/testuser",
});
// fnm on macOS defaults to ~/Library/Application Support/fnm
const fnmIndex = result.indexOf("/Users/testuser/Library/Application Support/fnm/aliases/default/bin");
const homebrewIndex = result.indexOf("/opt/homebrew/bin");
expect(fnmIndex).toBeGreaterThan(-1);
expect(homebrewIndex).toBeGreaterThan(-1);
expect(fnmIndex).toBeLessThan(homebrewIndex);
});
it("does not include Linux user directories on Windows", () => {
const result = getMinimalServicePathParts({
platform: "win32",