openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
142 lines (141 loc) • 6.49 kB
JavaScript
import { t as formatErrorMessage } from "./errors-BSdPMFao.mjs";
import { t as formatCliCommand } from "./command-format-Cte1SWM4.mjs";
import { r as hasCommandProcessCleanupError } from "./exec-result-LNNPagt0.mjs";
import { o as findServiceOwnershipRefusal, r as ServiceInspectionError } from "./service-inspection-error-DN1EVxrD.mjs";
import { n as assertDoctorServiceSelection } from "./doctor-service-repair-policy-BJrQJIOB.mjs";
//#region src/commands/doctor-maintenance-restoration.ts
async function restoreDoctorGatewayService(params) {
const { before, serviceEnv, root, env, writeConfig, warnings, settle, assertCustody, assertRestoreAdmission } = params;
let cfg = params.cfg;
const [{ readGatewayServiceState, resolveGatewayService }, { withGatewayServiceOperationLock }, { revalidateManagedGatewayServiceAfterUpdate }] = await Promise.all([
import("./service-BYSUnilS.mjs"),
import("./service-operation-lock-D_K5BO0M.mjs"),
import("./update-command-service-maintenance-yw-hzrZK.mjs")
]);
const service = resolveGatewayService();
return {
service,
state: await withGatewayServiceOperationLock(serviceEnv, async (assertCurrent) => {
const assertInspectionCurrent = () => {
assertCustody?.();
assertCurrent();
};
const assertMaintenanceCurrent = () => {
assertInspectionCurrent();
assertRestoreAdmission?.();
};
assertMaintenanceCurrent();
const readCurrent = () => settle(() => readGatewayServiceState(service, {
env: serviceEnv,
requireEffective: true,
requireLoadedCommand: true,
...process.platform === "linux" && before.serviceManagerUid !== void 0 ? { loadForInspection: {
managerUid: before.serviceManagerUid,
assertCurrent: assertInspectionCurrent
} } : {}
}));
let current;
let inspectionFailure;
try {
current = await readCurrent();
if (current.inspectionReason) {
inspectionFailure = new ServiceInspectionError(current.inspectionReason);
const refusal = findServiceOwnershipRefusal(inspectionFailure);
if (refusal) throw refusal;
} else if (current.loadState.status === "unknown" || current.runtime?.status !== "running" && current.runtime?.status !== "stopped") inspectionFailure = new Error(current.loadState.status === "unknown" ? current.loadState.detail : current.runtime?.inspectionFailure?.detail ?? "Gateway runtime inspection was inconclusive.");
} catch (error) {
if (hasCommandProcessCleanupError(error)) throw error;
const refusal = findServiceOwnershipRefusal(error);
if (refusal) throw refusal;
inspectionFailure = error;
}
assertMaintenanceCurrent();
let installation = before.serviceUpdateVerdict;
if (current) {
assertDoctorServiceSelection(env, current.env);
const inspected = current;
const verdict = await settle(() => revalidateManagedGatewayServiceAfterUpdate({
state: inspected,
root,
preManagedServiceStop: before,
allowIncompleteInspection: true
}));
if (verdict.kind === "unavailable") inspectionFailure ??= new Error(verdict.message);
else installation = verdict;
}
if (installation?.kind === "owned" && (installation.requiresInstallRootRefresh || writeConfig)) {
if (!inspectionFailure) {
const assertInstallationCurrent = () => {
assertMaintenanceCurrent();
params.assertInstallationAdmission?.();
};
assertInstallationCurrent();
const [{ maybeRepairGatewayServiceConfig }, { createDoctorPrompter }] = await Promise.all([import("./doctor-gateway-services-ChFRGQfd.mjs"), import("./doctor-prompter-DsEMIp1J.mjs")]);
assertInstallationCurrent();
cfg = await settle(() => maybeRepairGatewayServiceConfig(cfg, "local", params.runtime, createDoctorPrompter({
runtime: params.runtime,
options: params.options,
signal: params.signal
}), {
async writeConfig(nextConfig) {
assertInstallationCurrent();
if (!writeConfig) throw new Error("Doctor config writer is unavailable during service restoration.");
const committed = await writeConfig(nextConfig);
assertInstallationCurrent();
return committed;
},
serviceMaintenance: {
managerUid: before.serviceManagerUid,
assertCurrent: assertInstallationCurrent,
assertReadCurrent: assertInspectionCurrent
}
}));
assertInstallationCurrent();
const repairedState = await readCurrent();
assertInstallationCurrent();
assertDoctorServiceSelection(env, repairedState.env);
const repaired = await settle(() => revalidateManagedGatewayServiceAfterUpdate({
state: repairedState,
root,
preManagedServiceStop: before
}));
assertInstallationCurrent();
if (repaired.kind === "owned" && !repaired.requiresInstallRootRefresh) {
if (installation.requiresInstallRootRefresh || repairedState.runtime?.status === "running") return repairedState;
current = repairedState;
} else if (!installation.requiresInstallRootRefresh) throw new Error("Gateway service ownership changed during Doctor repair; inspect the service before restarting it.");
}
if (installation.requiresInstallRootRefresh) {
const message = `Gateway service still targets ${installation.root}; Doctor could not reconcile it with ${root}. The previous installation remains stopped because state compatibility is unverified. Run ${formatCliCommand("openclaw gateway install --force", env)} from the intended install.`;
warnings.push(message);
params.runtime.log(message);
return;
}
}
if (inspectionFailure) {
const warning = `Warning: Gateway restoration inspection was inconclusive: ${formatErrorMessage(inspectionFailure)} Starting the managed Gateway stopped by Doctor and verifying readiness.`;
warnings.push(warning);
params.runtime.log(warning);
}
assertMaintenanceCurrent();
const restore = current && !inspectionFailure ? service.restart : service.start;
await settle(async () => {
await restore({
env: current?.env ?? serviceEnv,
stdout: params.options.json ? process.stderr : process.stdout,
preserveDefinition: true,
assertCurrent: assertMaintenanceCurrent,
...before.serviceSystemdIdentity ? { systemdIdentity: before.serviceSystemdIdentity } : {}
});
});
assertMaintenanceCurrent();
return current ?? {
env: serviceEnv,
command: null
};
}),
cfg
};
}
//#endregion
export { restoreDoctorGatewayService };