UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

153 lines (152 loc) • 7.78 kB
import { f as toStringifiedError } from "./error-coercion-W9BtigRm.mjs"; import { t as formatErrorMessage } from "./errors-BvOkmQM5.mjs"; import "./kysely-sync-DUWzQvCU.mjs"; import { t as clearNodeSqliteKyselyCacheForDatabase } from "./kysely-sync-cache-state-DbAMR_DD.mjs"; import { o as resolveImmutableSqliteFileUri, r as openNodeSqliteDatabase } from "./node-sqlite-DyeJqxPf.mjs"; import { d as readSqliteWriterAppVersion, f as readExistingAgentSchemaMeta, u as readSqliteSchemaHeader } from "./sqlite-readonly-location-DEj0l7LR.mjs"; import { i as setSqliteBusyTimeout } from "./sqlite-busy-timeout-D3v1uB5d.mjs"; import { s as OPENCLAW_SQLITE_BUSY_TIMEOUT_MS } from "./openclaw-state-db-contract-BYv0nUQr.mjs"; import { a as readSqliteUserVersion } from "./sqlite-user-version-DLMl1A7W.mjs"; import { r as configureSqliteReadOnlyPragmas } from "./sqlite-wal-DfKCrDTQ.mjs"; import { t as isValidAgentId } from "./agent-id-D1-Q6vR4.mjs"; import "./session-key-DY3MOX4N.mjs"; import { n as assertSqliteIntegrity } from "./sqlite-integrity-D3yHPOet.mjs"; import { r as readMainTableList } from "./sqlite-strict-B8HPGv3j.mjs"; import "./openclaw-agent-db-contract-OYt2DCoK.mjs"; import { t as assertCanonicalAgentPersistenceVersion } from "./openclaw-agent-db-schema-read-y-s2h2dU.mjs"; import { t as canReuseOpenClawAgentIntegrityVerification } from "./openclaw-quarantine-store-CUJxC7wy.mjs"; import { n as assertOpenClawAgentCurrentRuntimeSchema, o as getOpenClawAgentMigrationSchema, r as assertOpenClawAgentSchemaContains, s as hasPendingCurrentVersionAgentDatabaseMigration } from "./openclaw-agent-db-schema-helpers-CXpPV9Zn.mjs"; import { t as assertOpenClawAgentDatabaseForMaintenance } from "./openclaw-agent-db-maintenance-BmCyifrn.mjs"; import { existsSync, realpathSync, statSync } from "node:fs"; import path from "node:path"; //#region src/state/openclaw-agent-schema-inspection.ts /** Only schema/default index metadata may survive a turn-less first run. */ function isEmptyAgentStore(database, input, version, metadata) { if (!input.agentId || metadata?.role !== "agent" || metadata.agentId !== input.agentId || metadata.schemaVersion == null || metadata.schemaVersion !== version || metadata.schemaVersion < 24 || metadata.schemaVersion > 25) return false; assertSqliteIntegrity(database, input.pathname); assertOpenClawAgentSchemaContains(database, input.pathname, getOpenClawAgentMigrationSchema(metadata.schemaVersion)); for (const table of readMainTableList(database, { includeInternal: true })) { if (table.type === "shadow" || table.name === "sqlite_schema") continue; const name = table.name; if (name.startsWith("sqlite_stat")) continue; const allowed = name === "schema_meta" ? "meta_key = 'primary'" : name === "session_key_contract" ? "id = 1 AND updated_at = 0" : name === "memory_index_meta" ? "key = 'memory_index_meta_v1' OR (key = 'memory_vector_rebuild_v1' AND value = 'clean')" : name === "memory_index_state" ? "id = 1 AND revision = 0" : name === "sqlite_sequence" ? "seq = 0" : "0"; if (database.prepare(`SELECT 1 FROM "${name.replaceAll("\"", "\"\"")}" WHERE (${allowed}) IS NOT TRUE LIMIT 1`).get()) return false; } return true; } /** All facts belong to the caller's single read transaction or private snapshot. */ function inspectAgentDatabaseSchema(database, input) { if (!input.verifyCurrentSchemaShape && !input.requireStartupMigrationReadiness) try { const { userVersion, ...header } = readSqliteSchemaHeader(database, input.inspectOwnership ? input.supportedVersion : void 0); return { version: userVersion, ...header, ...input.inspectEmptyStore ? { emptyStore: userVersion <= input.supportedVersion && isEmptyAgentStore(database, input, userVersion, header.agentSchemaMeta) } : {} }; } finally { clearNodeSqliteKyselyCacheForDatabase(database); } const version = readSqliteUserVersion(database); const inspection = { version }; let checkingShape = false; try { if (version > input.supportedVersion) { const writerAppVersion = readSqliteWriterAppVersion(database); return { version, ...writerAppVersion ? { writerAppVersion } : {} }; } if (input.inspectOwnership) inspection.agentSchemaMeta = readExistingAgentSchemaMeta(database); if (input.requireStartupMigrationReadiness) { const migrationPending = version !== input.supportedVersion || hasPendingCurrentVersionAgentDatabaseMigration(database); if (canReuseOpenClawAgentIntegrityVerification(input.pathname, input.startupIntegrityVerification, migrationPending)) inspection.integrityGateOutcome = "cached"; else if (input.deferRuntimeIntegrity && !migrationPending) inspection.preparationPending = true; else { assertSqliteIntegrity(database, input.pathname); inspection.integrityGateOutcome = "healthy"; } assertCanonicalAgentPersistenceVersion(database, input.pathname, version); } const agentId = input.agentId ?? (input.requireStartupMigrationReadiness ? readExistingAgentSchemaMeta(database)?.agentId : void 0); if (input.verifyCurrentSchemaShape && agentId != null && (!input.requireStartupMigrationReadiness || version > 0)) { checkingShape = true; if (assertOpenClawAgentDatabaseForMaintenance(database, { agentId, pathname: input.pathname, allowStartupIndexRepair: input.requireStartupMigrationReadiness })) inspection.preparationPending = true; } return inspection; } catch (error) { if (input.requireStartupMigrationReadiness) return { ...inspection, failure: toStringifiedError(error), ...checkingShape ? { reason: formatErrorMessage(error) } : {} }; return { ...inspection, reason: formatErrorMessage(error) }; } finally { clearNodeSqliteKyselyCacheForDatabase(database); } } /** Validate one consolidated agent copy using this release's exact maintenance reader. * This never discovers, registers, migrates, or opens an ordinary runtime store. */ async function preflightOpenClawAgentDatabasePath(databasePath, agentId) { const resolvedPath = path.resolve(databasePath); const base = { schema: "openclaw.agent-schema-preflight.v1", databasePath: resolvedPath, agentId, targetVersion: 25, requiresWrite: false, issues: [] }; let database; let foundVersion = null; let status = "indeterminate"; try { if (!isValidAgentId(agentId) || agentId !== agentId.trim().toLowerCase()) throw new Error("Agent preflight requires an explicit canonical agent ID."); const inspectionPath = realpathSync.native(resolvedPath); if (inspectionPath !== resolvedPath || !statSync(inspectionPath).isFile()) throw new Error("Agent preflight requires a canonical regular copied database path."); if ([ "-wal", "-shm", "-journal" ].some((suffix) => existsSync(inspectionPath + suffix))) throw new Error("Agent preflight requires a consolidated snapshot with no SQLite sidecars."); database = openNodeSqliteDatabase(resolveImmutableSqliteFileUri(inspectionPath), { readOnly: true }); setSqliteBusyTimeout(database, OPENCLAW_SQLITE_BUSY_TIMEOUT_MS); configureSqliteReadOnlyPragmas(database); assertSqliteIntegrity(database, resolvedPath); foundVersion = readSqliteUserVersion(database); status = "incompatible"; assertOpenClawAgentDatabaseForMaintenance(database, { agentId, pathname: resolvedPath }); assertOpenClawAgentCurrentRuntimeSchema(database, { agentId, pathname: resolvedPath }); return { ...base, foundVersion, status: "exact" }; } catch (error) { return { ...base, foundVersion, status, reason: formatErrorMessage(error) }; } finally { if (database) clearNodeSqliteKyselyCacheForDatabase(database); database?.close(); } } //#endregion export { preflightOpenClawAgentDatabasePath as n, inspectAgentDatabaseSchema as t };