


























@@ -33,6 +33,7 @@ import {
3333CROSS_OS_DASHBOARD_SMOKE_TIMEOUT_MS,
3434CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS,
3535isImmutableReleaseRef,
36+isRecoverableWindowsPackagedUpgradeSwapCleanupFailure,
3637looksLikeReleaseVersionRef,
3738normalizeRequestedRef,
3839normalizeWindowsCommandShimPath,
@@ -676,6 +677,59 @@ describe("scripts/openclaw-cross-os-release-checks", () => {
676677).toThrow(/Packaged upgrade failed/u);
677678});
678679680+it("recognizes the shipped Windows updater native-module backup cleanup failure", () => {
681+expect(
682+isRecoverableWindowsPackagedUpgradeSwapCleanupFailure(
683+{
684+exitCode: 1,
685+stdout: JSON.stringify({
686+status: "error",
687+reason: "global install swap",
688+after: { version: "2026.5.2" },
689+steps: [
690+{
691+name: "global install swap",
692+exitCode: 1,
693+stderrTail:
694+"EPERM: operation not permitted, unlink 'C:\\Users\\runner\\prefix\\node_modules\\.openclaw-5748-1777776287462\\node_modules\\@mariozechner\\clipboard-win32-x64-msvc\\clipboard.win32-x64-msvc.node'",
695+},
696+],
697+}),
698+stderr: "",
699+},
700+"win32",
701+),
702+).toBe(true);
703+});
704+705+it("does not recover unrelated packaged update failures", () => {
706+expect(
707+isRecoverableWindowsPackagedUpgradeSwapCleanupFailure(
708+{
709+exitCode: 1,
710+stdout: JSON.stringify({
711+status: "error",
712+reason: "global install swap",
713+steps: [{ name: "global install swap", exitCode: 1, stderrTail: "ENOENT: missing" }],
714+}),
715+stderr: "",
716+},
717+"win32",
718+),
719+).toBe(false);
720+expect(
721+isRecoverableWindowsPackagedUpgradeSwapCleanupFailure(
722+{
723+exitCode: 1,
724+stdout:
725+"EPERM: operation not permitted, unlink '/tmp/prefix/node_modules/.openclaw-1-2/native.node'",
726+stderr: "",
727+},
728+"linux",
729+),
730+).toBe(false);
731+});
732+679733it("only treats pinned baseline specs as exact installer version assertions", () => {
680734expect(resolveExplicitBaselineVersion("")).toBe("");
681735expect(resolveExplicitBaselineVersion("openclaw@latest")).toBe("");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。