UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

228 lines (227 loc) • 13.5 kB
import { D as withPluginCache, a as createPluginCache, o as getPluginCache } from "./plugin-cache-Bn9I3v9Q.mjs"; import { r as createLazyRuntimeModule } from "./lazy-runtime-CJrzFzqU.mjs"; import { a as measureGatewayBootstrapStep } from "./startup-trace-DymW1VdV.mjs"; import { n as sanitizeTerminalText } from "./safe-text-C6FhHCw7.mjs"; import { m as withOpenClawStateDatabaseReadSnapshot, o as withArtifactPreservingStateReads } from "./openclaw-state-db-readonly-BLZyK3So.mjs"; import "./agent-scope-config-BU4qc9bA.mjs"; import { i as listAgentIds } from "./agent-roster-B45JERT5.mjs"; import { t as createConfigIO } from "./io.factory-SFi7FTm2.mjs"; import { a as isConfigReadFailure, i as formatInvalidConfigDetails, n as createConfigReadError } from "./io.invalid-config-DkKUeCUl.mjs"; import { c as readConfigFileSnapshot, d as readConfigFileSnapshotWithPluginMetadata } from "./io.runtime-FunTy0y1.mjs"; import "./io-DQAKeHvj.mjs"; import { h as readAgentDatabaseAdmissionRefusal, p as listAgentDatabaseAdmissionRefusals } from "./agent-database-admission-BBZaKb2P.mjs"; import { f as withDeferredPluginDoctorMigrations } from "./doctor-contract-registry-BxFlpr_g.mjs"; import { t as describeConfigSnapshotInputChange } from "./snapshot-inputs-DRbOtoHS.mjs"; import { a as throwStartupMigrationIdentityChanged, i as throwStartupMigrationGuardRejected, n as refuseStartupMigrationsForLiveGatewayOwner, r as rethrowStartupConfigFailure } from "./doctor-startup-migration-refusal-DiDIJiE_.mjs"; import { t as addDoctorLegacyIssues } from "./legacy-config-issues-DB6Epvf4.mjs"; import { s as recordStartupMigrationWarnings } from "./state-migrations.messages-BNF0lAqi.mjs"; import { t as completeDoctorPluginMetadataSnapshot } from "./plugin-metadata-snapshot-scope-C0AWSGa_.mjs"; //#region src/commands/doctor-config-preflight-measure.ts async function measureDoctorConfigPreflightStep(name, run, measure, metrics) { const tracedRun = () => measureGatewayBootstrapStep(`cli.bootstrap.${name}`, run, metrics); return measure ? await measure(`doctor.config-preflight.${name}`, tracedRun) : await tracedRun(); } //#endregion //#region src/commands/config-preflight-snapshot.ts const loadInstalledPluginIndexStoreWrite = createLazyRuntimeModule(() => import("./installed-plugin-index-store-write-fCBZqXy3.mjs")); function throwPluginRegistryPersistenceFailed(reason, repair = "Run \"openclaw doctor --fix\" and retry.") { throw new Error(`OpenClaw refreshed the plugin registry but could not verify the persisted replacement (${reason}); refusing to accept the plugin registry. ${repair}`); } function formatPluginRegistryDifferences(snapshot) { const differences = new Map(snapshot?.registryDiagnostics.flatMap((diagnostic) => diagnostic.differences ?? []).map((difference) => [JSON.stringify(difference), difference])); if (differences.size === 0) return; return [...differences.values()].toSorted((left, right) => [ left.pluginId, left.persistedSource, left.derivedSource ].join("\0").localeCompare([ right.pluginId, right.persistedSource, right.derivedSource ].join("\0"))).map((difference) => `${sanitizeTerminalText(difference.pluginId)} (${difference.changed.join("+")} changed; persisted source: ${JSON.stringify(difference.persistedSource)}; derived source: ${JSON.stringify(difference.derivedSource)})`).join(", "); } async function readConfigPreflightSnapshot(params) { const cache = params.allowCurrentPluginMetadata ? getPluginCache() : createPluginCache(); return withPluginCache(cache, async () => { const sharedOptions = { ...params.isolateEnv ? { isolateEnv: true } : {}, ...params.observe === false ? { observe: false } : {}, ...params.measure ? { measure: params.measure } : {}, ...params.allowCurrentPluginMetadata ? {} : { allowCurrentPluginMetadata: false } }; let deferred = params.deferredPluginMigrations; if (params.preparePluginMigrations) { const core = await readConfigFileSnapshot({ ...sharedOptions, pluginValidation: "core-only", deferredPluginMigrations: deferred }); await params.prepareSnapshot?.(core); deferred = await params.preparePluginMigrations(core); } const readOptions = { ...sharedOptions, deferredPluginMigrations: deferred }; return withDeferredPluginDoctorMigrations(deferred?.map((entry) => entry.pluginId) ?? [], async () => { if (params.includePluginMetadata && !params.skipPluginValidation) { const result = await readConfigFileSnapshotWithPluginMetadata(readOptions); const pluginMetadataSnapshot = params.preparePluginMetadataSnapshot ? completeDoctorPluginMetadataSnapshot({ snapshot: result.pluginMetadataSnapshot, config: result.snapshot.sourceConfig ?? result.snapshot.config ?? {} }) : result.pluginMetadataSnapshot; return { snapshot: addDoctorLegacyIssues(result.snapshot, pluginMetadataSnapshot), ...pluginMetadataSnapshot ? { pluginMetadataSnapshot } : {} }; } const snapshot = await readConfigFileSnapshot({ ...readOptions, skipPluginValidation: params.skipPluginValidation }); if (!params.preparePluginMigrations) await params.prepareSnapshot?.(snapshot); return { snapshot: addDoctorLegacyIssues(snapshot) }; }); }); } function needsRefreshedPluginIndexPersistence(snapshotRead) { return snapshotRead.pluginMetadataSnapshot?.registrySource === "derived"; } async function persistRefreshedPluginIndex(params) { const lease = params.lease; if (!lease) throwPluginRegistryPersistenceFailed("startup migration lease was not acquired"); const { withPluginLifecycleLease } = await import("./plugin-lifecycle-lease-CV7hIcdl.mjs"); return await withPluginLifecycleLease({ env: params.env, assertCurrent: params.assertCurrent, processBound: true }, async (pluginLease) => { const fresh = await params.readPersistedSnapshot(); assertPreflightConfigUnchanged(params.snapshotRead.snapshot, fresh.snapshot); pluginLease.assertOwned(); if (!needsRefreshedPluginIndexPersistence(fresh)) { if (fresh.pluginMetadataSnapshot?.registrySource !== "persisted") throwPluginRegistryPersistenceFailed("fresh metadata was not persisted or derived"); return { snapshotRead: fresh }; } const derivedPluginMetadataSnapshot = fresh.pluginMetadataSnapshot; if (!derivedPluginMetadataSnapshot?.configFingerprint?.trim()) throwPluginRegistryPersistenceFailed("derived metadata was incomplete"); const { writePersistedInstalledPluginIndexWithLeaseSync } = await params.measure("plugin-index-store-import", loadInstalledPluginIndexStoreWrite); await params.measure("plugin-index-persistence", () => writePersistedInstalledPluginIndexWithLeaseSync(derivedPluginMetadataSnapshot.registryIndex, { env: params.env, lease: { assertOwnedInTransaction(database) { lease.assertOwnedInTransaction(database); pluginLease.assertOwnedInTransaction(database); } } })); const persistedSnapshotRead = await params.readPersistedSnapshot(); const persistedPluginMetadataSnapshot = persistedSnapshotRead.pluginMetadataSnapshot; if (persistedPluginMetadataSnapshot?.registrySource !== "persisted") { const diagnosticCodes = persistedPluginMetadataSnapshot?.registryDiagnostics.map((diagnostic) => diagnostic.code); const differences = formatPluginRegistryDifferences(persistedPluginMetadataSnapshot); throwPluginRegistryPersistenceFailed(`reread source was ${persistedPluginMetadataSnapshot?.registrySource ?? "missing"}${differences ? `; differences: ${differences}` : ""}${diagnosticCodes?.length ? `; diagnostics: ${diagnosticCodes.join(", ")}` : ""}`, "Stop plugin package changes, run \"openclaw plugins registry --refresh\", then retry."); } assertPreflightConfigUnchanged(params.snapshotRead.snapshot, persistedSnapshotRead.snapshot); return { snapshotRead: persistedSnapshotRead }; }); } /** Admit the same config and state before the lease and again before persistent writes. */ async function readAdmittedConfigSnapshot(params) { return await withArtifactPreservingStateReads(async () => { await measureDoctorConfigPreflightStep("admission.live-owner", () => refuseStartupMigrationsForLiveGatewayOwner(params.env)); try { const selected = await measureDoctorConfigPreflightStep("admission.core-config", () => readConfigFileSnapshot({ observe: false, isolateEnv: true, pluginValidation: "core-only" })); if (isConfigReadFailure(selected) || selected.issues.some((issue) => issue.errorCode === "CONFIG_SOURCE_INVALID")) return { snapshot: selected }; const recoveryOptions = { configPath: selected.path, observe: false, env: params.env }; const coreRecovery = await measureDoctorConfigPreflightStep("admission.core-recovery", () => createConfigIO({ ...recoveryOptions, pluginValidation: "core-only" }).prepareConfigRecovery(selected)); const candidate = coreRecovery?.snapshot ?? selected; await assertStartupStateReady({ cfg: candidate.sourceConfig ?? candidate.config, env: params.env }); if (candidate.valid) { await params.validateConfig?.(candidate); const { loadDeviceIdentityIfPresent } = await import("./device-identity-DWNlA3as.mjs"); loadDeviceIdentityIfPresent({ env: params.env }); } let read = await withOpenClawStateDatabaseReadSnapshot(() => params.readSnapshot(coreRecovery ? { isolateEnv: true } : void 0), { env: params.env }); assertPreflightConfigUnchanged(selected, read.snapshot); const recovery = await measureDoctorConfigPreflightStep("admission.config-recovery", () => createConfigIO(recoveryOptions).prepareConfigRecovery(read.snapshot)); if (Boolean(coreRecovery) !== Boolean(recovery)) throwStartupMigrationIdentityChanged(); if (recovery) { assertPreflightConfigUnchanged(candidate, recovery.snapshot); read = { snapshot: recovery.snapshot, pluginMetadataSnapshot: recovery.pluginMetadataSnapshot }; } if (read.snapshot.valid) await params.validateConfig?.(read.snapshot); if (params.beforeStatePreparation && !await measureDoctorConfigPreflightStep("admission.config-guard", () => params.beforeStatePreparation?.(read.snapshot))) throwStartupMigrationGuardRejected(); if (read.snapshot.valid) { const { loadDeviceIdentityIfPresent } = await import("./device-identity-DWNlA3as.mjs"); loadDeviceIdentityIfPresent({ env: params.env }); } return { ...read, ...recovery ? { recovery } : {} }; } catch (error) { return rethrowStartupConfigFailure(error); } }); } function assertPreflightConfigUnchanged(before, after) { const unreadable = [before, after].find(isConfigReadFailure); if (unreadable) throw createConfigReadError(unreadable.path, formatInvalidConfigDetails(unreadable.issues)); const change = describeConfigSnapshotInputChange(before, after); if (change) throwStartupMigrationIdentityChanged(change); } /** Admission runs before lease acquisition: even acquiring a lease commits SQLite writes. */ async function assertStartupStateReady(params) { const { assertOpenClawDatabasesReady } = await measureDoctorConfigPreflightStep("admission.database-runtime-import", () => import("./openclaw-database-preflight-DI4G8oRa.mjs")); const agentCount = listAgentIds(params.cfg).length; const admissionMetrics = { agentCount }; await measureDoctorConfigPreflightStep("admission.database-readiness", () => assertOpenClawDatabasesReady({ env: params.env, config: params.cfg, operation: "gateway-startup", onAgentInspection: (stats) => { Object.assign(admissionMetrics, stats); } }), void 0, () => admissionMetrics); const [{ assertSessionStoreMigrationComplete }, { resolveAllAgentSessionStoreCandidateTargetsSync }, { inspectOpenClawRegisteredAgentDatabases }] = await measureDoctorConfigPreflightStep("admission.session-runtime-import", () => Promise.all([ import("./startup-migration-Q9d_dmEC.mjs"), import("./targets-CiqcUql-.mjs"), import("./openclaw-agent-db-registry-d7XXr2GL.mjs") ])); const registeredDatabases = await measureDoctorConfigPreflightStep("admission.agent-inventory", () => inspectOpenClawRegisteredAgentDatabases({ env: params.env, includeIncompatibleSchemaVersions: true })); const targets = await measureDoctorConfigPreflightStep("admission.session-targets", () => resolveAllAgentSessionStoreCandidateTargetsSync(params.cfg, { env: params.env, registeredDatabases }).filter((target) => !readAgentDatabaseAdmissionRefusal(target.agentId, { env: params.env })), void 0, () => ({ agentCount, registeredDatabaseCount: registeredDatabases.length })); await measureDoctorConfigPreflightStep("admission.session-readiness", () => assertSessionStoreMigrationComplete({ ...params, targets }), void 0, () => ({ targetCount: targets.length })); recordStartupMigrationWarnings(listAgentDatabaseAdmissionRefusals({ env: params.env }).map((refusal) => `${refusal.reason}\n${refusal.repairHint}`)); const { assertConfiguredWorkspaceStateReady } = await measureDoctorConfigPreflightStep("admission.workspace-runtime-import", () => import("./workspace-state-dirs-DtIW2mA7.mjs")); await measureDoctorConfigPreflightStep("admission.workspace-readiness", () => assertConfiguredWorkspaceStateReady(params), void 0, () => ({ agentCount })); } //#endregion export { readConfigPreflightSnapshot as a, readAdmittedConfigSnapshot as i, needsRefreshedPluginIndexPersistence as n, measureDoctorConfigPreflightStep as o, persistRefreshedPluginIndex as r, assertPreflightConfigUnchanged as t };