





















@@ -1,22 +1,23 @@
11import { spawnSync } from "node:child_process";
2-import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2+import { chmodSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
33import { tmpdir } from "node:os";
44import { join } from "node:path";
55import { describe, expect, it } from "vitest";
6677const SCRIPT_PATH = "scripts/install.sh";
889-function runInstallShell(script: string) {
9+function runInstallShell(script: string, env: NodeJS.ProcessEnv = {}) {
1010return spawnSync("bash", ["-c", script], {
1111encoding: "utf8",
1212env: {
1313 ...process.env,
1414OPENCLAW_INSTALL_SH_NO_RUN: "1",
15+ ...env,
1516},
1617});
1718}
181919-describe("install.sh apt behavior", () => {
20+describe("install.sh", () => {
2021const script = readFileSync(SCRIPT_PATH, "utf8");
21222223it("runs apt-get through noninteractive wrappers", () => {
@@ -41,6 +42,71 @@ describe("install.sh apt behavior", () => {
4142'run_quiet_step "Configuring NodeSource repository" sudo -E bash "$tmp"',
4243);
4344});
45+46+it("loads nvm before checking Node.js so stale system Node does not win", () => {
47+expect(script).toMatch(
48+/# Step 2: Node\.js\s+load_nvm_for_node_detection\s+if ! check_node; then/,
49+);
50+51+const tmp = mkdtempSync(join(tmpdir(), "openclaw-install-nvm-"));
52+const home = join(tmp, "home");
53+const systemBin = join(tmp, "system-bin");
54+const nvmBin = join(home, ".nvm/versions/node/v22.22.1/bin");
55+mkdirSync(systemBin, { recursive: true });
56+mkdirSync(nvmBin, { recursive: true });
57+mkdirSync(join(home, ".nvm"), { recursive: true });
58+59+const systemNode = join(systemBin, "node");
60+const nvmNode = join(nvmBin, "node");
61+writeFileSync(systemNode, "#!/bin/sh\necho v8.11.3\n");
62+writeFileSync(nvmNode, "#!/bin/sh\necho v22.22.1\n");
63+chmodSync(systemNode, 0o755);
64+chmodSync(nvmNode, 0o755);
65+writeFileSync(
66+join(home, ".nvm/nvm.sh"),
67+[
68+'NVM_DIR="${NVM_DIR:-$HOME/.nvm}"',
69+"export NVM_DIR",
70+"nvm() {",
71+' if [ "$1" = "use" ]; then',
72+' export PATH="$NVM_DIR/versions/node/v22.22.1/bin:$PATH"',
73+" return 0",
74+" fi",
75+" return 0",
76+"}",
77+"",
78+].join("\n"),
79+);
80+81+let result: ReturnType<typeof runInstallShell> | undefined;
82+try {
83+result = runInstallShell(
84+[
85+`cd ${JSON.stringify(process.cwd())}`,
86+`source ${JSON.stringify(SCRIPT_PATH)}`,
87+"set +e",
88+"load_nvm_for_node_detection",
89+"check_node",
90+"status=$?",
91+'printf "status=%s\\npath=%s\\nversion=%s\\n" "$status" "$(command -v node)" "$(node -v)"',
92+"exit $status",
93+].join("\n"),
94+{
95+HOME: home,
96+PATH: `${systemBin}:/usr/bin:/bin`,
97+TERM: "dumb",
98+},
99+);
100+} finally {
101+rmSync(tmp, { force: true, recursive: true });
102+}
103+104+expect(result?.status).toBe(0);
105+const output = result?.stdout ?? "";
106+expect(output).toContain("status=0");
107+expect(output).toContain(`path=${nvmNode}`);
108+expect(output).toContain("version=v22.22.1");
109+});
44110});
4511146112describe("install.sh macOS Homebrew Node behavior", () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。