UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

151 lines (150 loc) 7.25 kB
import { r as createLazyRuntimeModule } from "./lazy-runtime-CgCh8H_K.js"; import { t as formatCliCommand } from "./command-format-C7YfyMTd.js"; import { w as resolveStateDir } from "./paths-D2sRr1a_.js"; import { r as stylePromptTitle } from "./prompt-style-BQVvtDcR.js"; import fs from "node:fs"; import { intro, outro } from "@clack/prompts"; //#region src/flows/doctor-health.ts const intro$1 = (message) => intro(stylePromptTitle(message) ?? message); const outro$1 = (message) => outro(stylePromptTitle(message) ?? message); const loadConfigModule = createLazyRuntimeModule(() => import("./config/config.js")); async function assertDoctorDatabaseSchemasCompatible() { const [databasePreflight, agentDatabase, stateDatabase] = await Promise.all([ import("./openclaw-database-preflight-of3VjD09.js"), import("./openclaw-agent-db-contract-D9PUUtGr.js"), import("./openclaw-state-db-contract-Ciz9ElQz.js") ]); const databaseSchemas = databasePreflight.preflightOpenClawDatabaseSchemas({ env: process.env, supportedVersions: { state: stateDatabase.OPENCLAW_STATE_SCHEMA_VERSION, agent: agentDatabase.OPENCLAW_AGENT_SCHEMA_VERSION } }); if (databaseSchemas.incompatible.length > 0) throw new databasePreflight.OpenClawDatabaseSchemaPreflightError(databaseSchemas.incompatible, { operation: "doctor" }); const unreadableStateDatabase = databaseSchemas.indeterminate.find((database) => database.kind === "state"); if (unreadableStateDatabase) throw new Error(`Doctor cannot continue because the shared state database is unreadable: ${unreadableStateDatabase.path}: ${unreadableStateDatabase.reason}. The database was left unchanged; doctor will not recreate it because that could discard persistent operator data. Stop the Gateway and other OpenClaw processes, then restore this file from a verified backup or repair it manually. After recovery, run ${formatCliCommand("openclaw doctor --fix")} again. See ${stateDatabase.OPENCLAW_DATABASE_SCHEMA_DOCS_URL}.`); } function stateDirectoryExistsAtDoctorStart() { try { return fs.statSync(resolveStateDir()).isDirectory(); } catch { return false; } } /** Runs the full interactive doctor flow against the provided or default runtime. */ async function runDoctorHealthFlow(runtime, options = {}) { const effectiveRuntime = runtime ?? (await import("./runtime-DixL8FcQ.js")).defaultRuntime; const stateDirExistedAtStart = stateDirectoryExistsAtDoctorStart(); intro$1("OpenClaw doctor"); const { createDoctorPrompter } = await import("./doctor-prompter-DzatNY0G.js"); const prompter = createDoctorPrompter({ runtime: effectiveRuntime, options }); const { resolveOpenClawPackageRoot } = await import("./openclaw-root-BE8vlD1q.js"); const root = await resolveOpenClawPackageRoot({ moduleUrl: import.meta.url, argv1: process.argv[1], cwd: process.cwd() }); const { maybeOfferUpdateBeforeDoctor } = await import("./doctor-update-CRs55eRG.js"); if ((await maybeOfferUpdateBeforeDoctor({ runtime: effectiveRuntime, options, root, confirm: (p) => prompter.confirm(p), outro: outro$1 })).handled) return; await assertDoctorDatabaseSchemasCompatible(); if (options.repair === true || options.yes === true || options.generateGatewayToken === true) { const { assertConfigWriteAllowedInCurrentMode } = await loadConfigModule(); assertConfigWriteAllowedInCurrentMode(); } const { beginDoctorMaintenance } = await import("./doctor-maintenance-BRbfb7tx.js"); const maintenance = await beginDoctorMaintenance({ options, root, runtime: effectiveRuntime }); let exitCode; try { const { maybeRepairUiProtocolFreshness } = await import("./doctor-ui-DEM9GZ0y.js"); const { noteSourceInstallIssues } = await import("./doctor-install-CzcMiwfj.js"); const { noteStalePluginRuntimeSymlinks } = await import("./plugin-runtime-symlinks-DAlgAibd.js"); const { noteStartupOptimizationHints } = await import("./doctor-platform-notes-u2dKqvJ4.js"); await maybeRepairUiProtocolFreshness(effectiveRuntime, prompter); noteSourceInstallIssues(root); await noteStalePluginRuntimeSymlinks(root); noteStartupOptimizationHints(); const { loadAndMaybeMigrateDoctorConfig } = await import("./doctor-config-flow-j00DTj1G.js"); const configResult = await loadAndMaybeMigrateDoctorConfig({ options, confirm: (p) => prompter.confirm(p), runtime: effectiveRuntime, prompter }); const { CONFIG_PATH } = await loadConfigModule(); const ctx = { runtime: effectiveRuntime, options, prompter, configResult, cfg: configResult.cfg, cfgForPersistence: structuredClone(configResult.cfg), sourceConfigValid: configResult.sourceConfigValid ?? true, configPath: configResult.path ?? CONFIG_PATH, stateDirExistedAtStart, gatewayMaintenanceActive: maintenance !== void 0, runWithPluginMetadataSnapshot: configResult.runWithPluginMetadataSnapshot, invalidatePluginMetadataSnapshot: configResult.invalidatePluginMetadataSnapshot }; const { runDoctorHealthContributions } = await import("./doctor-health-contributions-Bzhef3DP.js"); await runDoctorHealthContributions(ctx); if (ctx.configWriteRefusal) { outro$1(ctx.configResultWriteCommitted === true ? "Doctor finished, but some config fixes were not applied." : "Doctor finished, but config fixes were not applied."); exitCode = 1; return; } if (options.repair === true || options.yes === true) { const { assertSessionStoreMigrationComplete } = await import("./startup-migration-BV-eQ791.js"); assertSessionStoreMigrationComplete({ cfg: ctx.cfg, env: process.env }); const { assertOpenClawDatabasesReady } = await import("./openclaw-database-preflight-of3VjD09.js"); const { resolveConfiguredAgentDatabaseTargets } = await import("./targets-nZHFRtE8.js"); assertOpenClawDatabasesReady({ env: process.env, operation: "doctor", configuredAgentDatabaseTargets: resolveConfiguredAgentDatabaseTargets(ctx.cfg, { env: process.env }) }); const { assertConfiguredWorkspaceStateReady } = await import("./workspace-state-dirs-B8xySjIm.js"); assertConfiguredWorkspaceStateReady({ cfg: ctx.cfg }); const { assertNoPendingLegacyExecApprovals } = await import("./exec-approvals-migration-gate-DqHllFZW.js"); assertNoPendingLegacyExecApprovals(); } await maintenance?.finish(ctx.cfg); if (ctx.postInstallDoctorResult) { const { UPDATE_POST_INSTALL_DOCTOR_ADVISORY_EXIT_CODE, UPDATE_POST_INSTALL_DOCTOR_RESULT_PATH_ENV, writeUpdatePostInstallDoctorResult } = await import("./update-doctor-result-DpZ1G9Ee.js"); const resultPath = process.env[UPDATE_POST_INSTALL_DOCTOR_RESULT_PATH_ENV]?.trim(); if (resultPath) { await writeUpdatePostInstallDoctorResult({ resultPath, result: ctx.postInstallDoctorResult }); exitCode = UPDATE_POST_INSTALL_DOCTOR_ADVISORY_EXIT_CODE; return; } } } catch (error) { if (maintenance) effectiveRuntime.error("Doctor could not complete maintenance. Check the reported service state, resolve the failure, and rerun doctor --fix."); throw error; } finally { await maintenance?.release(); if (exitCode !== void 0) effectiveRuntime.exit(exitCode); } outro$1("Doctor complete."); } //#endregion export { runDoctorHealthFlow };