UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

162 lines (161 loc) 8.28 kB
import { S as createConfigIO } from "./io.runtime-B9iJRs3w.js"; import { n as resolvePathViaExistingAncestorSync } from "./boundary-path-DMNeww4q.js"; import { t as formatCliCommand } from "./command-format-C7YfyMTd.js"; import { a as isDefaultInstallIdentity, f as resolveConfigPath, w as resolveStateDir } from "./paths-D2sRr1a_.js"; import "./openclaw-state-db-contract-DYCYxE4w.js"; import { s as resolveOpenClawStateSqlitePath } from "./openclaw-state-db-schema-version-c1ZL6JGz.js"; import { n as acquireGatewayLifecycleCoordinator, r as acquireStateDatabaseCoordinator } from "./state-database-coordinator-opgcBiXJ.js"; import "./io-bdCzpGWJ.js"; import { a as readGatewayServiceState, o as resolveGatewayService } from "./service-Cc6NX6Jm.js"; import { n as waitForGatewayHealthyRestart, o as renderRestartDiagnostics } from "./restart-health-Btw0xxAB.js"; import "./openclaw-agent-db-contract-CGTyjij4.js"; import { c as resolveConfiguredAgentDatabaseTargets, s as resolveConfiguredAgentDatabaseCandidatePaths } from "./targets-Cknmo7YZ.js"; import { r as preflightOpenClawDatabaseSchemas, t as OpenClawDatabaseSchemaPreflightError } from "./openclaw-database-preflight-DmhpNBQv.js"; import { i as maybeStopManagedServiceBeforeMutableUpdate, o as revalidateManagedGatewayServiceAfterUpdate, r as maybeResumeWindowsTaskAutoStartAfterPackageUpdate } from "./update-command-service-maintenance-BOVvMegl.js"; import { c as resolveUpdatedGatewayRestartPort } from "./update-command-service-plan-Y641LZ_0.js"; import { i as isServiceRepairExternallyManaged, o as resolveUpdateParentGatewayActivation, s as shouldManageGatewayService } from "./doctor-service-repair-policy-S9bPaCiq.js"; import { n as resolveDoctorRepairMode, t as isDoctorUpdateRepairMode } from "./doctor-repair-mode-DYiiDZuy.js"; import path from "node:path"; //#region src/commands/doctor-maintenance.ts /** Coordinates explicit Doctor repair with the managed Gateway lifecycle. */ async function assertDoctorMaintenanceSchemasCompatible(env) { const snapshot = await createConfigIO({ env: { ...env }, observe: false, pluginValidation: "core-only" }).readConfigFileSnapshot(); const cfg = snapshot.sourceConfig ?? snapshot.config; const schemas = preflightOpenClawDatabaseSchemas({ env, supportedVersions: { state: 15, agent: 19 }, configuredAgentDatabaseTargets: (registeredAgentDatabases) => resolveConfiguredAgentDatabaseTargets(cfg, { env, registeredDatabases: registeredAgentDatabases }), configuredAgentDatabaseCandidatePaths: resolveConfiguredAgentDatabaseCandidatePaths(cfg, { env }), verifyCurrentSchemaShape: true }); if (schemas.incompatible.length > 0) throw new OpenClawDatabaseSchemaPreflightError(schemas.incompatible, { operation: "doctor" }); } function assertDoctorServiceSelection(env, serviceEnv) { const selection = (candidate) => { const stateDir = resolveStateDir(candidate); return [stateDir, resolveConfigPath(candidate, stateDir)].map((value) => resolvePathViaExistingAncestorSync(value)); }; const before = selection(env); if (selection(serviceEnv).some((value, index) => value !== before[index])) throw new Error("Doctor and the managed Gateway select different config or state directories. Run doctor with the Gateway's installation and profile; the service was left unchanged."); } function assertDoctorMaintenanceInspection(inspection, env) { const kind = inspection.serviceUpdateVerdict?.kind; if (!inspection.blockMessage && inspection.inspected && (kind === "owned" || kind === "absent" || inspection.offline === true)) return; throw new Error(kind === "owned" && inspection.blockMessage ? inspection.blockMessage : `Gateway service ownership or shutdown could not be verified. Run ${formatCliCommand("openclaw gateway status --deep", env)} and stop it through its service owner before retrying.`); } async function beginDoctorMaintenance(params) { if (!(params.options.repair === true || params.options.yes === true)) return; const env = { ...process.env }; const parentActivation = isDoctorUpdateRepairMode(resolveDoctorRepairMode(params.options)) ? resolveUpdateParentGatewayActivation(env) : void 0; await assertDoctorMaintenanceSchemasCompatible(env); let stopped; const coordinators = []; let repairStoresMayBeOpen = false; const release = async () => { try { if (repairStoresMayBeOpen) { repairStoresMayBeOpen = false; const [{ closeOpenClawAgentDatabasesAsync }, { closeOpenClawStateDatabaseByPath }] = await Promise.all([import("./openclaw-agent-db-Bfc4Wmxr.js"), import("./openclaw-state-db-B2_DN17n.js")]); await closeOpenClawAgentDatabasesAsync(); closeOpenClawStateDatabaseByPath(resolveOpenClawStateSqlitePath(env)); } } finally { for (const coordinator of coordinators.splice(0).toReversed()) coordinator.release(); const recovery = stopped?.windowsTaskAutoStartRecovery; try { await maybeResumeWindowsTaskAutoStartAfterPackageUpdate(stopped); } finally { recovery?.complete(); } } }; try { if (params.root && isDefaultInstallIdentity(env) && !isServiceRepairExternallyManaged() && await shouldManageGatewayService(env)) { const inspection = await maybeStopManagedServiceBeforeMutableUpdate({ updateInstallKind: "package", root: params.root, shouldRestart: true, jsonMode: true, phase: "inspect" }); assertDoctorMaintenanceInspection(inspection, env); if (parentActivation !== void 0 && inspection.serviceUpdateVerdict?.kind !== "absent" && inspection.offline !== true) throw new Error("The update parent owns Gateway activation. Stop the service through its owner before retrying the update; Doctor will not stop or restart it."); if (inspection.serviceUpdateVerdict?.kind === "owned") { if (inspection.serviceEnv) assertDoctorServiceSelection(env, inspection.serviceEnv); if (parentActivation === void 0) { inspection.serviceUpdateVerdict.refreshDefinition = false; stopped = await maybeStopManagedServiceBeforeMutableUpdate({ updateInstallKind: "package", root: params.root, shouldRestart: true, jsonMode: true, expectedService: inspection }); assertDoctorMaintenanceInspection(stopped, env); if (stopped.stopped) params.runtime.log("Stopped the managed Gateway for Doctor repair."); } } else if (inspection.serviceUpdateVerdict?.kind !== "absent") params.runtime.log("The stopped Gateway service was left unchanged; repairing Doctor's selected state only."); } const databasePath = path.resolve(resolveOpenClawStateSqlitePath(env)); coordinators.push(acquireGatewayLifecycleCoordinator({ databasePath, busyTimeoutMs: 250 })); coordinators.push(acquireStateDatabaseCoordinator({ databasePath, busyTimeoutMs: 250 })); repairStoresMayBeOpen = true; } catch (error) { await release(); throw new Error(`Doctor could not enter maintenance. Stop the Gateway through its service owner, then run ${formatCliCommand("openclaw doctor --fix", env)}. ${String(error)}`, { cause: error }); } return { release, async finish(cfg) { await release(); if (!stopped?.stopped || !stopped.serviceEnv || !params.root) return; const service = resolveGatewayService(); const state = await readGatewayServiceState(service, { env: stopped.serviceEnv, requireEffective: true }); assertDoctorServiceSelection(env, state.env); await revalidateManagedGatewayServiceAfterUpdate({ state, root: params.root, preManagedServiceStop: stopped }); await service.restart({ env: state.env, stdout: process.stdout, preserveDefinition: true }); const port = await resolveUpdatedGatewayRestartPort({ config: cfg, serviceEnv: state.env, serviceCommand: state.command }); const health = await waitForGatewayHealthyRestart({ service, port, env: state.env, requireRunningService: true }); if (!health.healthy) throw new Error(`Doctor repaired state, but the managed Gateway did not become ready: ${renderRestartDiagnostics(health).join(" ")}. Run ${formatCliCommand("openclaw gateway status --deep", env)}.`); params.runtime.log("Gateway restarted and verified after Doctor repair."); } }; } //#endregion export { beginDoctorMaintenance };