























@@ -1,6 +1,14 @@
1-import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
1+import {
2+chmodSync,
3+copyFileSync,
4+mkdtempSync,
5+readFileSync,
6+rmSync,
7+writeFileSync,
8+} from "node:fs";
29import { tmpdir } from "node:os";
3-import { join } from "node:path";
10+import { delimiter, join } from "node:path";
11+import { pathToFileURL } from "node:url";
412import { describe, expect, it } from "vitest";
513import { execNodeEvalSync, spawnNodeEvalSync } from "../../src/test-utils/node-process.js";
614@@ -49,6 +57,27 @@ function runTsEval(source: string, env: Record<string, string> = {}) {
4957return execNodeEvalSync(source, { env: { ...process.env, ...env }, imports: ["tsx"] });
5058}
515960+function fakePrlctlEnv(tempDir: string): Record<string, string> {
61+const pathValue = `${tempDir}${delimiter}${process.env.Path ?? process.env.PATH ?? ""}`;
62+const fakeBootstrap = pathToFileURL(join(tempDir, "prlctl-bootstrap.mjs")).href;
63+const nodeOptions = [process.env.NODE_OPTIONS, `--import=${fakeBootstrap}`]
64+.filter(Boolean)
65+.join(" ");
66+return { NODE_OPTIONS: nodeOptions, PATH: pathValue, Path: pathValue };
67+}
68+69+function writeFakePrlctl(
70+tempDir: string,
71+posixScript: string,
72+windowsBootstrap: string,
73+): void {
74+const prlctlPath = join(tempDir, "prlctl");
75+writeFileSync(prlctlPath, posixScript);
76+chmodSync(prlctlPath, 0o755);
77+copyFileSync(process.execPath, join(tempDir, "prlctl.exe"));
78+writeFileSync(join(tempDir, "prlctl-bootstrap.mjs"), windowsBootstrap);
79+}
80+5281function resolveProviderAuth(
5382provider: string,
5483options: {
@@ -161,9 +190,8 @@ console.log(result);
161190162191it("quotes shell args and resolves fuzzy snapshot hints through the shared TypeScript helper", () => {
163192const tempDir = mkdtempSync(join(tmpdir(), "openclaw-parallels-helper-"));
164-const prlctlPath = join(tempDir, "prlctl");
165-writeFileSync(
166-prlctlPath,
193+writeFakePrlctl(
194+tempDir,
167195`#!/usr/bin/env bash
168196set -euo pipefail
169197if [[ "$1" == "snapshot-list" ]]; then
@@ -177,9 +205,24 @@ JSON
177205 exit 0
178206fi
179207exit 1
208+`,
209+`import { basename } from "node:path";
210+const isPrlctl = [process.argv0, process.execPath].some((value) =>
211+ basename(value).toLowerCase() === "prlctl.exe",
212+);
213+if (isPrlctl) {
214+ if (process.argv.some((arg) => arg.includes("snapshot-list"))) {
215+ console.log(JSON.stringify({
216+ "{older}": { name: "fresh", state: "running" },
217+ "{wanted}": { name: "fresh-poweroff-2026-04-01", state: "poweroff" },
218+ "{other}": { name: "unrelated", state: "poweroff" },
219+ }));
220+ process.exit(0);
221+ }
222+ process.exit(1);
223+}
180224`,
181225);
182-chmodSync(prlctlPath, 0o755);
183226184227try {
185228const output = runTsEval(
@@ -189,7 +232,7 @@ console.log(shellQuote("it's ok"));
189232const snapshot = resolveSnapshot("vm", "fresh");
190233console.log([snapshot.id, snapshot.state, snapshot.name].join("\\t"));
191234`,
192-{ PATH: `${tempDir}:${process.env.PATH ?? ""}` },
235+fakePrlctlEnv(tempDir),
193236);
194237195238expect(output.split("\n")[0]).toBe("'it'\"'\"'s ok'");
@@ -201,9 +244,8 @@ console.log([snapshot.id, snapshot.state, snapshot.name].join("\\t"));
201244202245it("uses one Ubuntu VM fallback resolver for Linux lanes", () => {
203246const tempDir = mkdtempSync(join(tmpdir(), "openclaw-parallels-vm-helper-"));
204-const prlctlPath = join(tempDir, "prlctl");
205-writeFileSync(
206-prlctlPath,
247+writeFakePrlctl(
248+tempDir,
207249`#!/usr/bin/env bash
208250set -euo pipefail
209251if [[ "$1" == "list" ]]; then
@@ -217,17 +259,32 @@ JSON
217259 exit 0
218260fi
219261exit 1
262+`,
263+`import { basename } from "node:path";
264+const isPrlctl = [process.argv0, process.execPath].some((value) =>
265+ basename(value).toLowerCase() === "prlctl.exe",
266+);
267+if (isPrlctl) {
268+ if (process.argv.some((arg) => arg.includes("list"))) {
269+ console.log(JSON.stringify([
270+ { name: "Ubuntu 25.10" },
271+ { name: "Ubuntu 23.10" },
272+ { name: "Ubuntu 24.04.3 ARM64" },
273+ ]));
274+ process.exit(0);
275+ }
276+ process.exit(1);
277+}
220278`,
221279);
222-chmodSync(prlctlPath, 0o755);
223280224281try {
225282const output = runTsEval(
226283`
227284import { resolveUbuntuVmName } from "./${TS_PATHS.common}";
228285console.log(resolveUbuntuVmName("Ubuntu missing"));
229286`,
230-{ PATH: `${tempDir}:${process.env.PATH ?? ""}` },
287+fakePrlctlEnv(tempDir),
231288);
232289233290expect(output.trim()).toBe("Ubuntu 24.04.3 ARM64");
@@ -428,6 +485,15 @@ console.log(JSON.stringify(result));
428485expect(script).toContain("OPENCLAW_PARALLELS_LINUX_DISABLE_BONJOUR");
429486});
430487488+it("keeps the Windows update config scrub compatible with PowerShell 5.1", () => {
489+const script = readFileSync(TS_PATHS.npmUpdateScripts, "utf8");
490+491+expect(script).not.toContain("ConvertFrom-Json -AsHashtable");
492+expect(script).toContain("function Get-OpenClawJsonProperty");
493+expect(script).toContain("function Remove-OpenClawJsonProperty");
494+expect(script).toContain("Remove-OpenClawJsonProperty $entries $pluginId");
495+});
496+431497it("keeps aggregate update guest scripts isolated from the npm-update orchestrator", () => {
432498const orchestrator = readFileSync(TS_PATHS.npmUpdate, "utf8");
433499const updateScripts = readFileSync(TS_PATHS.npmUpdateScripts, "utf8");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。