fix(update): continue after package doctor warnings (#91586)

* fix(update): continue after package doctor warnings

* fix(update): type advisory step rendering

* fix(update): preserve advisory doctor step state

* fix(update): share advisory doctor state

* fix(update): keep timed-out doctor failures blocking

* fix(update): require explicit doctor advisory result

* fix(update): reject malformed doctor advisory results

* fix(update): bound doctor advisory diagnostics

* fix(update): keep doctor advisory restart-neutral

* fix(update): protect doctor advisory IPC

* fix(update): scope doctor advisories to converging updater

* fix(update): scope doctor advisories to deferred repairs

* fix(update): secure doctor advisory IPC

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Jason (Json)
2026-06-13 22:03:57 -06:00
committed by GitHub
parent 889bc52ba5
commit 7259cb5c77
16 changed files with 779 additions and 33 deletions
+40 -10
View File
@@ -52,7 +52,10 @@ import {
import { createLowDiskSpaceWarning } from "../../infra/disk-space.js";
import { pathExists } from "../../infra/fs-safe.js";
import { readJsonIfExists, writeJson } from "../../infra/json-files.js";
import { runGlobalPackageUpdateSteps } from "../../infra/package-update-steps.js";
import {
markPackagePostInstallDoctorAdvisory,
runGlobalPackageUpdateSteps,
} from "../../infra/package-update-steps.js";
import { parseStrictPositiveInteger } from "../../infra/parse-finite-number.js";
import { getSelfAndAncestorPidsSync } from "../../infra/restart-stale-pids.js";
import { nodeVersionSatisfiesEngine } from "../../infra/runtime-guard.js";
@@ -75,6 +78,11 @@ import {
writeControlPlaneUpdateRestartSentinel,
type ControlPlaneUpdateSentinelMetaFile,
} from "../../infra/update-control-plane-sentinel.js";
import {
consumeUpdatePostInstallDoctorResult,
createUpdatePostInstallDoctorResultPath,
UPDATE_POST_INSTALL_DOCTOR_RESULT_PATH_ENV,
} from "../../infra/update-doctor-result.js";
import {
canResolveRegistryVersionForPackageTarget,
createGlobalInstallEnv,
@@ -1558,15 +1566,24 @@ async function runPackageInstallUpdate(params: {
if (entryPath) {
await createUpdateConfigSnapshot();
const candidateHostVersion = await readPackageVersion(verifiedPackageRoot);
return await runUpdateStep({
const doctorResultPath = createUpdatePostInstallDoctorResultPath();
const doctorArgv = [
params.nodeRunner ?? resolveNodeRunner(),
entryPath,
"doctor",
"--non-interactive",
"--fix",
];
const doctorProgressInfo = {
name: `${CLI_NAME} doctor`,
argv: [
params.nodeRunner ?? resolveNodeRunner(),
entryPath,
"doctor",
"--non-interactive",
"--fix",
],
command: doctorArgv.join(" "),
index: 0,
total: 0,
};
params.progress?.onStepStart?.(doctorProgressInfo);
const doctorStep = await runUpdateStep({
name: `${CLI_NAME} doctor`,
argv: doctorArgv,
cwd: verifiedPackageRoot,
env: {
...resolvePostInstallDoctorEnv({
@@ -1576,13 +1593,26 @@ async function runPackageInstallUpdate(params: {
OPENCLAW_UPDATE_IN_PROGRESS: "1",
[UPDATE_DEFER_CONFIGURED_PLUGIN_INSTALL_REPAIR_ENV]: "1",
[UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE_ENV]: "1",
[UPDATE_POST_INSTALL_DOCTOR_RESULT_PATH_ENV]: doctorResultPath,
...(candidateHostVersion === null
? {}
: { OPENCLAW_COMPATIBILITY_HOST_VERSION: candidateHostVersion }),
},
timeoutMs: params.timeoutMs,
progress: params.progress,
});
const doctorResult = await consumeUpdatePostInstallDoctorResult(doctorResultPath);
const completedDoctorStep = markPackagePostInstallDoctorAdvisory(doctorStep, doctorResult);
params.progress?.onStepComplete?.({
...doctorProgressInfo,
durationMs: completedDoctorStep.durationMs,
exitCode: completedDoctorStep.exitCode,
stderrTail: completedDoctorStep.stderrTail,
signal: completedDoctorStep.signal,
killed: completedDoctorStep.killed,
termination: completedDoctorStep.termination,
advisory: completedDoctorStep.advisory,
});
return completedDoctorStep;
}
return null;
},