UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

106 lines (105 loc) 5.27 kB
import { k as applyLegacyDoctorMigrations } from "./io.runtime-B9iJRs3w.js"; import { t as findLegacyConfigIssues } from "./legacy-D15RYgFr.js"; import { K as stampConfigWriteMetadata, _ as validateConfigObjectRaw, c as resolveManagedUnsetPathsForWrite, h as validateConfigObjectWithPlugins, s as applyUnsetPathsForWrite } from "./io.types-BUCjdS5v.js"; import { h as resolveConfigSnapshotHash, r as containsConfigIncludeDirective } from "./io.read-helpers-ZKp-UiGx.js"; import { i as transformConfigFile } from "./mutate-ZNN4iFCn.js"; import "./config-Cs0XXL3x.js"; import { t as prepareConfigWriteTopology } from "./io.write-topology-BvvklbCP.js"; import { r as restoreDoctorConfigEnvRefs } from "./config-flow-steps-CmbbCx-s.js"; import { n as findDoctorLegacyConfigIssues } from "./legacy-config-issues-Bz1S8JF8.js"; import { isDeepStrictEqual } from "node:util"; //#region src/commands/doctor/shared/automatic-startup-config-repair.ts function admitAutomaticConfigRepairSnapshot(snapshot) { return !snapshot.valid && snapshot.exists && snapshot.raw !== null && (snapshot.includedPaths?.length ?? 0) === 0 && !containsConfigIncludeDirective(snapshot.parsed); } function buildAutomaticConfigRepairPlan(snapshot, config, changes) { return { config, changes, snapshot: { ...snapshot, sourceConfig: config, resolved: config, runtimeConfig: config, config, valid: true, issues: [], legacyIssues: [] } }; } /** Admits only complete, deterministic single-file legacy migrations. */ function planAutomaticConfigRepair(snapshot) { if (!admitAutomaticConfigRepairSnapshot(snapshot)) return null; const { next: config, changes } = applyLegacyDoctorMigrations(snapshot.sourceConfig, { authoredRaw: snapshot.parsed, resolvedRaw: snapshot.sourceConfig }); if (!config || isDeepStrictEqual(config, snapshot.sourceConfig) || !validateConfigObjectWithPlugins(config).ok || findDoctorLegacyConfigIssues(config, config).length > 0) return null; return buildAutomaticConfigRepairPlan(snapshot, config, changes); } /** * State-free repairable preview for callers that run before the shared state database * may be touched (gateway pre-bootstrap selection, backup discovery). It skips plugin * doctor contracts and plugin validation, so it can admit a snapshot the full planner * later refuses — the preflight committer and canonical-write matcher stay authoritative, * and a refused commit keeps today's fail-closed startup refusal. */ function planStartupConfigRepairPreview(snapshot) { if (!admitAutomaticConfigRepairSnapshot(snapshot)) return null; const { next: config, changes } = applyLegacyDoctorMigrations(snapshot.sourceConfig, { authoredRaw: snapshot.parsed, resolvedRaw: snapshot.sourceConfig }, { pluginContracts: false }); if (!config || isDeepStrictEqual(config, snapshot.sourceConfig) || !validateConfigObjectRaw(config).ok || findLegacyConfigIssues(config, config).length > 0) return null; return buildAutomaticConfigRepairPlan(snapshot, config, changes); } /** * Repairable-snapshot trust check for callers that run before startup state admission * (gateway pre-bootstrap selection, backup discovery). The full planner covers * plugin-contract migrations but reads the installed-plugin registry from the shared * state database; when that store is unreachable, fall back to the state-free preview * so core-key repairs stay reachable and everything else keeps today's fail-closed * refusal. The preflight committer and canonical-write matcher stay authoritative. */ function resolveStartupConfigSnapshot(snapshot) { if (snapshot.valid) return snapshot; try { return planAutomaticConfigRepair(snapshot)?.snapshot; } catch { return planStartupConfigRepairPreview(snapshot)?.snapshot; } } /** Matches only the canonical writer result for a previously admitted startup repair. */ function isStartupConfigRepairResult(before, after) { const plan = planAutomaticConfigRepair(before); const unsetPaths = resolveManagedUnsetPathsForWrite(void 0); const expected = plan ? stampConfigWriteMetadata(applyUnsetPathsForWrite(prepareConfigWriteTopology({ snapshot: before, nextConfig: plan.config, options: { persistCanonicalAgentRoster: true }, unsetPaths, env: process.env }).nextConfig, unsetPaths), void 0, void 0, before.parsed) : null; return Boolean(expected && after.valid && before.path === after.path && isDeepStrictEqual(expected, after.sourceConfig)); } /** Commits a planned repair against the exact snapshot admitted by its caller. */ async function commitAutomaticConfigRepair(plan, snapshot) { await transformConfigFile({ baseHash: resolveConfigSnapshotHash(snapshot) ?? void 0, transform: (_current, { snapshot: currentSnapshot }, { envSnapshotForRestore }) => ({ nextConfig: restoreDoctorConfigEnvRefs(plan.config, currentSnapshot, envSnapshotForRestore) }), afterWrite: { mode: "none", reason: "automatic migration" }, writeOptions: { expectedConfigPath: snapshot.path, auditOrigin: "doctor", skipOutputLogs: true, skipRuntimeSnapshotRefresh: true, persistCanonicalAgentRoster: true } }); } //#endregion export { resolveStartupConfigSnapshot as i, isStartupConfigRepairResult as n, planAutomaticConfigRepair as r, commitAutomaticConfigRepair as t };