UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

194 lines (193 loc) • 8.61 kB
import { t as formatErrorMessage } from "./errors-O33D01XW.mjs"; import { t as formatCliCommand } from "./command-format-DwEdrDKL.mjs"; import { r as hasCommandProcessCleanupError } from "./exec-result-s7WOth0N.mjs"; import { o as findServiceOwnershipRefusal, r as ServiceInspectionError } from "./service-inspection-error-Bsltcpi4.mjs"; import { t as isManagedGatewayServiceOffline } from "./update-command-service-publication-BwkAYzt9.mjs"; import { n as assertDoctorServiceSelection } from "./doctor-service-repair-policy-dEj5KU5E.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-C5exmZL9.mjs"), import("./service-operation-lock-oHJtCFhr.mjs"), import("./update-command-service-maintenance-CSZZDAPb.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; const readInspection = async () => { current = void 0; inspectionFailure = void 0; 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(); return current; }; await readInspection(); assertMaintenanceCurrent(); let installation = before.serviceUpdateVerdict; const inspectActivation = async () => { const state = current; if (inspectionFailure || !state?.command) return { kind: "inconclusive", reason: inspectionFailure ? formatErrorMessage(inspectionFailure) : "The current service launcher could not be verified." }; if (installation?.kind !== "owned" || installation.requiresInstallRootRefresh) return { kind: "not-ours", reason: "The service does not target this installation." }; if (state.running || !await settle(() => isManagedGatewayServiceOffline(state))) return { kind: "inconclusive", reason: "The service is not verified offline." }; return { kind: "owned-offline" }; }; const mayRestore = async () => { if (before.stopped) return true; const inspection = await inspectActivation(); assertMaintenanceCurrent(); if (inspection.kind === "owned-offline") return true; const warning = `Warning: Gateway activation skipped (${inspection.kind}): ${inspection.reason} Run ${formatCliCommand("openclaw gateway status --deep", env)} before starting it.`; warnings.push(warning); params.runtime.log(warning); return false; }; const revalidate = async (state, allowIncompleteInspection = false) => { try { return await settle(() => revalidateManagedGatewayServiceAfterUpdate({ state, root, preManagedServiceStop: before, allowIncompleteInspection })); } catch (error) { if (before.stopped || hasCommandProcessCleanupError(error) || findServiceOwnershipRefusal(error)) throw error; inspectionFailure = error; return { kind: "unavailable", message: formatErrorMessage(error) }; } }; if (current) { assertDoctorServiceSelection(env, current.env); const verdict = await revalidate(current, before.stopped); if (verdict.kind === "unavailable") inspectionFailure ??= new Error(verdict.message); else installation = verdict; } if (!await mayRestore()) return; if (installation?.kind === "owned" && (installation.requiresInstallRootRefresh || writeConfig)) { const originalInstallation = installation; if (!inspectionFailure) { const assertInstallationCurrent = () => { assertMaintenanceCurrent(); params.assertInstallationAdmission?.(); }; assertInstallationCurrent(); const [{ maybeRepairGatewayServiceConfig }, { createDoctorPrompter }] = await Promise.all([import("./doctor-gateway-services-FpRV4nB0.mjs"), import("./doctor-prompter-BwkpDvhJ.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 = before.stopped ? await readCurrent() : await readInspection(); assertInstallationCurrent(); if (!repairedState) { await mayRestore(); return; } assertDoctorServiceSelection(env, repairedState.env); const repaired = await revalidate(repairedState); assertInstallationCurrent(); if (repaired.kind === "owned" && !repaired.requiresInstallRootRefresh) { if (originalInstallation.requiresInstallRootRefresh || repairedState.runtime?.status === "running") return repairedState; current = repairedState; } else if (before.stopped && !originalInstallation.requiresInstallRootRefresh) throw new Error("Gateway service ownership changed during Doctor repair; inspect the service before restarting it."); if (!before.stopped) { current = repairedState; installation = repaired; if (!await mayRestore()) return; } } if (originalInstallation.requiresInstallRootRefresh) { const message = `Gateway service still targets ${originalInstallation.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 };