UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

94 lines (93 loc) • 5.25 kB
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; import { i as getNodeSqliteKysely, n as executeSqliteQuerySync } from "./kysely-sync-BMSZn9yz.mjs"; import { i as resolveOpenClawRegisteredAgentDatabasePath, r as resolveOpenClawAgentDatabaseStoredPath } from "./openclaw-state-db.paths-BvBEgHyD.mjs"; import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs"; import "./session-key-BC4m_Ly5.mjs"; import { r as createOpenClawAgentDatabasePathMatcher } from "./openclaw-agent-db.paths-DiWMV5LG.mjs"; import { t as assertAgentDeletionJournalAvailable, y as reconstructAgentDeletionJournalSchema } from "./openclaw-state-db-schema-additive-CKKd9dgw.mjs"; import { a as recordLegacyMigrationReceipt, r as readLegacyMigrationReceiptFromDatabase } from "./state-migrations.receipts-CG4TZyVG.mjs"; import { randomUUID } from "node:crypto"; //#region src/state/agent-deletion-journal-recovery.ts const SOURCE_KEY = "agent-deletion-journal-reconstruction"; const JOURNAL_TABLE = "agent_deletion_journal"; const DESCRIPTION = "Reconstructed the missing agent deletion journal; held databases require explicit agent restore or delete."; function readReport(database) { const receipt = readLegacyMigrationReceiptFromDatabase(database.db, SOURCE_KEY); if (!receipt) return; const report = JSON.parse(receipt.reportJson); if (!isRecord(report) || typeof report.description !== "string" || !Array.isArray(report.held)) throw new Error("Invalid agent deletion journal reconstruction receipt."); const held = report.held.map((entry) => { if (!isRecord(entry) || typeof entry.agentId !== "string" || entry.agentId !== normalizeAgentId(entry.agentId) || typeof entry.path !== "string" || !entry.path.trim()) throw new Error("Invalid agent database hold in deletion journal reconstruction receipt."); return { agentId: entry.agentId, path: entry.path }; }); return { description: report.description, held }; } function decodeHolds(database, held) { return held.map((entry) => ({ agentId: entry.agentId, path: resolveOpenClawRegisteredAgentDatabasePath(database.path, entry.path) })); } /** Read recovery facts from this exact shared-state generation without opening another database. */ function readAgentDeletionRecoveryHolds(database) { return decodeHolds(database, readReport(database)?.held ?? []); } /** Schema and Doctor producers cannot infer permission to repair an unverified store. */ function assertAgentDeletionRecoveryAllowsMutation(database, pathname) { assertAgentDeletionJournalAvailable(database.db); const samePath = createOpenClawAgentDatabasePathMatcher(); const held = readAgentDeletionRecoveryHolds(database).find((entry) => samePath(entry.path, pathname)); if (held) throw new Error(`Agent database ${held.path} is held after deletion journal reconstruction. Run openclaw doctor --fix for explicit restoration guidance before repairing agent ${held.agentId}.`); } /** The caller's transaction commits canonical reconstruction and its receipt together. */ function reconstructAgentDeletionJournal(database, held, now = Date.now()) { if (!database.db.isTransaction) throw new Error("Agent deletion journal reconstruction requires a shared-state transaction."); const previous = readReport(database); if (!reconstructAgentDeletionJournalSchema(database.db, database.path)) return decodeHolds(database, previous?.held ?? []); const entries = /* @__PURE__ */ new Map(); for (const entry of [...previous?.held ?? [], ...held.map((target) => ({ agentId: normalizeAgentId(target.agentId), path: resolveOpenClawAgentDatabaseStoredPath(database.path, target.path) }))]) entries.set(JSON.stringify([entry.agentId, entry.path]), entry); const report = { description: DESCRIPTION, held: [...entries.values()] }; recordLegacyMigrationReceipt(database.db, { sourceKey: SOURCE_KEY, migrationKind: SOURCE_KEY, sourcePath: database.path, targetTable: JOURNAL_TABLE, sourceSha256: null, sourceSizeBytes: null, sourceRecordCount: null, runId: `${SOURCE_KEY}:${randomUUID()}`, now, reportJson: JSON.stringify(report), upsert: true }); return decodeHolds(database, report.held); } /** Resolve only explicit targets; the immutable run report keeps the original reconstruction. */ function resolveAgentDeletionRecoveryHolds(database, agentId, targetPaths) { if (!database.db.isTransaction) throw new Error("Agent deletion recovery resolution requires a shared-state transaction."); const report = readReport(database); if (!report) return 0; const id = normalizeAgentId(agentId); const targets = new Set(targetPaths.map((pathname) => resolveOpenClawAgentDatabaseStoredPath(database.path, pathname))); const held = report.held.filter((entry) => entry.agentId !== id || !targets.has(entry.path)); const removed = report.held.length - held.length; if (removed > 0) executeSqliteQuerySync(database.db, getNodeSqliteKysely(database.db).updateTable("migration_sources").set({ report_json: JSON.stringify({ ...report, held }) }).where("source_key", "=", SOURCE_KEY)); return removed; } //#endregion export { resolveAgentDeletionRecoveryHolds as i, readAgentDeletionRecoveryHolds as n, reconstructAgentDeletionJournal as r, assertAgentDeletionRecoveryAllowsMutation as t };