mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 17:40:44 +00:00
fix(update): skip legacy parent doctor config writes
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import {
|
import {
|
||||||
resolveDoctorHealthContributions,
|
resolveDoctorHealthContributions,
|
||||||
shouldSkipLegacyUpdateDoctorMetadataWrite,
|
shouldSkipLegacyUpdateDoctorConfigWrite,
|
||||||
} from "./doctor-health-contributions.js";
|
} from "./doctor-health-contributions.js";
|
||||||
|
|
||||||
describe("doctor health contributions", () => {
|
describe("doctor health contributions", () => {
|
||||||
@@ -30,54 +30,39 @@ describe("doctor health contributions", () => {
|
|||||||
expect(ids.indexOf("doctor:command-owner")).toBeLessThan(ids.indexOf("doctor:write-config"));
|
expect(ids.indexOf("doctor:command-owner")).toBeLessThan(ids.indexOf("doctor:write-config"));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("skips metadata-only doctor writes under legacy update parents", () => {
|
it("skips doctor config writes under legacy update parents", () => {
|
||||||
expect(
|
expect(
|
||||||
shouldSkipLegacyUpdateDoctorMetadataWrite({
|
shouldSkipLegacyUpdateDoctorConfigWrite({
|
||||||
env: { OPENCLAW_UPDATE_IN_PROGRESS: "1" },
|
env: { OPENCLAW_UPDATE_IN_PROGRESS: "1" },
|
||||||
before: { gateway: { mode: "local" }, meta: { lastTouchedVersion: "2026.4.26" } },
|
|
||||||
after: {
|
|
||||||
gateway: { mode: "local" },
|
|
||||||
meta: { lastTouchedVersion: "2026.4.27" },
|
|
||||||
wizard: { lastRunCommand: "doctor" },
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps real doctor repairs writable during update", () => {
|
it("keeps doctor writes outside legacy update writable", () => {
|
||||||
expect(
|
expect(
|
||||||
shouldSkipLegacyUpdateDoctorMetadataWrite({
|
shouldSkipLegacyUpdateDoctorConfigWrite({
|
||||||
env: { OPENCLAW_UPDATE_IN_PROGRESS: "1" },
|
env: {},
|
||||||
before: { gateway: { mode: "local" } },
|
|
||||||
after: { gateway: { mode: "remote" } },
|
|
||||||
}),
|
|
||||||
).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps repair writes from doctor config preflight writable during legacy update", () => {
|
|
||||||
expect(
|
|
||||||
shouldSkipLegacyUpdateDoctorMetadataWrite({
|
|
||||||
env: { OPENCLAW_UPDATE_IN_PROGRESS: "1" },
|
|
||||||
hasPendingConfigWrite: true,
|
|
||||||
before: { gateway: { mode: "remote" } },
|
|
||||||
after: {
|
|
||||||
gateway: { mode: "remote" },
|
|
||||||
meta: { lastTouchedVersion: "2026.4.27" },
|
|
||||||
wizard: { lastRunCommand: "doctor" },
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps current update parents writable", () => {
|
it("keeps current update parents writable", () => {
|
||||||
expect(
|
expect(
|
||||||
shouldSkipLegacyUpdateDoctorMetadataWrite({
|
shouldSkipLegacyUpdateDoctorConfigWrite({
|
||||||
env: {
|
env: {
|
||||||
OPENCLAW_UPDATE_IN_PROGRESS: "1",
|
OPENCLAW_UPDATE_IN_PROGRESS: "1",
|
||||||
OPENCLAW_UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE: "1",
|
OPENCLAW_UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE: "1",
|
||||||
},
|
},
|
||||||
before: { meta: { lastTouchedVersion: "2026.4.26" } },
|
}),
|
||||||
after: { meta: { lastTouchedVersion: "2026.4.27" } },
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("treats falsey update env values as normal writes", () => {
|
||||||
|
expect(
|
||||||
|
shouldSkipLegacyUpdateDoctorConfigWrite({
|
||||||
|
env: {
|
||||||
|
OPENCLAW_UPDATE_IN_PROGRESS: "0",
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import { isDeepStrictEqual } from "node:util";
|
|
||||||
import type { probeGatewayMemoryStatus } from "../commands/doctor-gateway-health.js";
|
import type { probeGatewayMemoryStatus } from "../commands/doctor-gateway-health.js";
|
||||||
import type { DoctorOptions, DoctorPrompter } from "../commands/doctor-prompter.js";
|
import type { DoctorOptions, DoctorPrompter } from "../commands/doctor-prompter.js";
|
||||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||||
@@ -52,16 +51,8 @@ function isTruthyEnvValue(value: string | undefined): boolean {
|
|||||||
return normalized !== "" && normalized !== "0" && normalized !== "false" && normalized !== "no";
|
return normalized !== "" && normalized !== "0" && normalized !== "false" && normalized !== "no";
|
||||||
}
|
}
|
||||||
|
|
||||||
function omitDoctorWriteMetadata(cfg: OpenClawConfig): OpenClawConfig {
|
export function shouldSkipLegacyUpdateDoctorConfigWrite(params: {
|
||||||
const { meta: _meta, wizard: _wizard, ...rest } = cfg;
|
|
||||||
return rest;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function shouldSkipLegacyUpdateDoctorMetadataWrite(params: {
|
|
||||||
env: NodeJS.ProcessEnv;
|
env: NodeJS.ProcessEnv;
|
||||||
hasPendingConfigWrite?: boolean;
|
|
||||||
before: OpenClawConfig;
|
|
||||||
after: OpenClawConfig;
|
|
||||||
}): boolean {
|
}): boolean {
|
||||||
if (!isTruthyEnvValue(params.env.OPENCLAW_UPDATE_IN_PROGRESS)) {
|
if (!isTruthyEnvValue(params.env.OPENCLAW_UPDATE_IN_PROGRESS)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -69,13 +60,7 @@ export function shouldSkipLegacyUpdateDoctorMetadataWrite(params: {
|
|||||||
if (isTruthyEnvValue(params.env[UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE_ENV])) {
|
if (isTruthyEnvValue(params.env[UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE_ENV])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (params.hasPendingConfigWrite === true) {
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return isDeepStrictEqual(
|
|
||||||
omitDoctorWriteMetadata(params.before),
|
|
||||||
omitDoctorWriteMetadata(params.after),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDoctorHealthContribution(params: {
|
function createDoctorHealthContribution(params: {
|
||||||
@@ -534,15 +519,8 @@ async function runWriteConfigHealth(ctx: DoctorHealthFlowContext): Promise<void>
|
|||||||
command: "doctor",
|
command: "doctor",
|
||||||
mode: resolveDoctorMode(ctx.cfg),
|
mode: resolveDoctorMode(ctx.cfg),
|
||||||
});
|
});
|
||||||
if (
|
if (shouldSkipLegacyUpdateDoctorConfigWrite({ env: ctx.env })) {
|
||||||
shouldSkipLegacyUpdateDoctorMetadataWrite({
|
ctx.runtime.log("Skipping doctor config write during legacy update handoff.");
|
||||||
env: ctx.env ?? process.env,
|
|
||||||
hasPendingConfigWrite: ctx.configResult.shouldWriteConfig === true,
|
|
||||||
before: ctx.cfgForPersistence,
|
|
||||||
after: ctx.cfg,
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
ctx.runtime.log("Skipping doctor metadata-only config write during legacy update handoff.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await replaceConfigFile({
|
await replaceConfigFile({
|
||||||
|
|||||||
Reference in New Issue
Block a user