





















@@ -37,13 +37,14 @@ import {
3737} from "./common.ts";
3838import { runWindowsBackgroundPowerShell } from "./guest-transports.ts";
3939import { linuxUpdateScript, macosUpdateScript, windowsUpdateScript } from "./npm-update-scripts.ts";
40-import { ensureVmRunning, resolveUbuntuVmName } from "./parallels-vm.ts";
40+import { ensureVmRunning, resolveMacosVmName, resolveUbuntuVmName } from "./parallels-vm.ts";
4141import { runTimedUpdateJob } from "./update-job-timeout.ts";
42424343interface NpmUpdateOptions {
4444betaValidation?: string;
4545freshTargetSpec?: string;
4646hostIp?: string;
47+macosVm?: string;
4748packageSpec: string;
4849targetTarball?: string;
4950updateTarget: string;
@@ -111,7 +112,7 @@ interface NpmUpdateSummary {
111112}>;
112113}
113114114-const macosVm = "macOS Tahoe";
115+const macosVmDefault = "macOS Tahoe";
115116const windowsVm = "Windows 11";
116117const linuxVmDefault = "Ubuntu 26.04";
117118const updateTimeoutSeconds = readPositiveIntEnv("OPENCLAW_PARALLELS_NPM_UPDATE_TIMEOUT_S", 1200);
@@ -298,6 +299,7 @@ Options:
298299 Aliases like beta3 resolve to the latest *-beta.3 version.
299300 --platform <list> Comma-separated platforms to run: all, macos, windows, linux.
300301 Default: all
302+ --macos-vm <name> Explicit Parallels macOS VM name.
301303 --provider <openai|anthropic|minimax>
302304 --model <provider/model> Override the model used for agent-turn smoke checks.
303305 --host-ip <ip> Override Parallels host IP.
@@ -315,6 +317,7 @@ export function parseArgs(argv: string[]): NpmUpdateOptions {
315317betaValidation: undefined,
316318freshTargetSpec: undefined,
317319json: false,
320+macosVm: undefined,
318321modelId: undefined,
319322packageSpec: "",
320323targetTarball: undefined,
@@ -358,6 +361,10 @@ export function parseArgs(argv: string[]): NpmUpdateOptions {
358361options.platforms = parsePlatformList(ensureValue(args, i, arg));
359362i++;
360363break;
364+case "--macos-vm":
365+options.macosVm = ensureValue(args, i, arg);
366+i++;
367+break;
361368case "--provider":
362369options.provider = parseProvider(ensureValue(args, i, arg));
363370i++;
@@ -455,6 +462,7 @@ export class NpmUpdateSmoke {
455462private targetTarballPath = "";
456463private targetTarballBuildCommit = "";
457464private targetTarballVersion = "";
465+private macosVm = macosVmDefault;
458466private linuxVm = linuxVmDefault;
459467460468private freshStatus = platformRecord("skip");
@@ -507,6 +515,12 @@ export class NpmUpdateSmoke {
507515if (this.options.platforms.has("linux")) {
508516this.linuxVm = resolveUbuntuVmName(linuxVmDefault);
509517}
518+if (this.options.platforms.has("macos")) {
519+this.macosVm = resolveMacosVmName(
520+this.options.macosVm ?? macosVmDefault,
521+Boolean(this.options.macosVm),
522+);
523+}
510524this.preflightRegistryUpdateTarget();
511525512526say(`Run fresh npm baseline: ${this.packageSpec}`);
@@ -535,7 +549,7 @@ export class NpmUpdateSmoke {
535549private async runFreshBaselines(): Promise<void> {
536550const jobs: Job[] = [];
537551if (this.options.platforms.has("macos")) {
538-jobs.push(this.spawnFresh("macOS", "macos", []));
552+jobs.push(this.spawnFresh("macOS", "macos", ["--vm", this.macosVm]));
539553}
540554if (this.options.platforms.has("windows")) {
541555jobs.push(this.spawnFresh("Windows", "windows", []));
@@ -563,7 +577,16 @@ export class NpmUpdateSmoke {
563577private async runFreshTargetInstalls(): Promise<void> {
564578const jobs: Job[] = [];
565579if (this.options.platforms.has("macos")) {
566-jobs.push(this.spawnFresh("macOS", "macos", [], {}, this.freshTargetSpec, "fresh-target"));
580+jobs.push(
581+this.spawnFresh(
582+"macOS",
583+"macos",
584+["--vm", this.macosVm],
585+{},
586+this.freshTargetSpec,
587+"fresh-target",
588+),
589+);
567590}
568591if (this.options.platforms.has("windows")) {
569592jobs.push(
@@ -768,7 +791,7 @@ export class NpmUpdateSmoke {
768791private async runSameGuestUpdates(): Promise<void> {
769792const jobs: Job[] = [];
770793if (this.options.platforms.has("macos")) {
771-ensureVmRunning(macosVm);
794+ensureVmRunning(this.macosVm);
772795jobs.push(this.spawnUpdate("macOS", "macos", (ctx) => this.runMacosUpdate(ctx)));
773796}
774797if (this.options.platforms.has("windows")) {
@@ -912,7 +935,7 @@ export class NpmUpdateSmoke {
912935ctx: UpdateJobContext,
913936): Promise<void> {
914937const scriptPath = this.writeGuestScript(
915-macosVm,
938+this.macosVm,
916939script,
917940"openclaw-parallels-npm-update-macos",
918941);
@@ -923,29 +946,29 @@ export class NpmUpdateSmoke {
923946 ? macosExecArgs[sudoUserArgIndex + 1]
924947 : "";
925948if (sudoUser) {
926-run("prlctl", ["exec", macosVm, "/usr/sbin/chown", sudoUser, scriptPath], {
949+run("prlctl", ["exec", this.macosVm, "/usr/sbin/chown", sudoUser, scriptPath], {
927950timeoutMs: 30_000,
928951});
929952}
930953try {
931954const status = await this.runStreamingToJobLog(
932955"prlctl",
933-["exec", macosVm, ...macosExecArgs, "/bin/bash", scriptPath],
956+["exec", this.macosVm, ...macosExecArgs, "/bin/bash", scriptPath],
934957timeoutMs,
935958ctx,
936959);
937960if (status !== 0) {
938961throw new Error(`macOS update command failed with exit code ${status}`);
939962}
940963} finally {
941-this.removeGuestScript(macosVm, scriptPath);
964+this.removeGuestScript(this.macosVm, scriptPath);
942965}
943966}
944967945968private resolveMacosUpdateExecArgs(ctx: UpdateJobContext): string[] {
946969const guestPath =
947970"/opt/homebrew/bin:/opt/homebrew/opt/node/bin:/usr/local/bin:/usr/local/sbin:/opt/homebrew/sbin:/usr/bin:/bin:/usr/sbin:/sbin";
948-const currentUser = run("prlctl", ["exec", macosVm, "--current-user", "whoami"], {
971+const currentUser = run("prlctl", ["exec", this.macosVm, "--current-user", "whoami"], {
949972check: false,
950973quiet: true,
951974timeoutMs: 45_000,
@@ -980,7 +1003,7 @@ export class NpmUpdateSmoke {
98010039811004private resolveMacosDesktopUser(): string {
9821005const consoleUser =
983-run("prlctl", ["exec", macosVm, "/usr/bin/stat", "-f", "%Su", "/dev/console"], {
1006+run("prlctl", ["exec", this.macosVm, "/usr/bin/stat", "-f", "%Su", "/dev/console"], {
9841007check: false,
9851008quiet: true,
9861009timeoutMs: 30_000,
@@ -998,7 +1021,7 @@ export class NpmUpdateSmoke {
9981021}
9991022const users = run(
10001023"prlctl",
1001-["exec", macosVm, "/usr/bin/dscl", ".", "-list", "/Users", "NFSHomeDirectory"],
1024+["exec", this.macosVm, "/usr/bin/dscl", ".", "-list", "/Users", "NFSHomeDirectory"],
10021025{ check: false, quiet: true, timeoutMs: 30_000 },
10031026).stdout.replaceAll("\r", "");
10041027for (const line of users.split("\n")) {
@@ -1019,7 +1042,7 @@ export class NpmUpdateSmoke {
10191042private resolveMacosDesktopHome(user: string): string {
10201043const output = run(
10211044"prlctl",
1022-["exec", macosVm, "/usr/bin/dscl", ".", "-read", `/Users/${user}`, "NFSHomeDirectory"],
1045+["exec", this.macosVm, "/usr/bin/dscl", ".", "-read", `/Users/${user}`, "NFSHomeDirectory"],
10231046{ check: false, quiet: true, timeoutMs: 30_000 },
10241047).stdout.replaceAll("\r", "");
10251048const match = /NFSHomeDirectory:\s*(\S+)/.exec(output);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。