UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

180 lines (179 loc) • 8.84 kB
import { r as resolveStateDir } from "./state-dir-CYkBUd_G.mjs"; import { t as formatErrorMessage } from "./errors-BvOkmQM5.mjs"; import { a as executeSqliteQueryTakeFirstSync, i as executeSqliteQuerySync, o as getNodeSqliteKysely } from "./kysely-sync-DUWzQvCU.mjs"; import { i as isSqliteCorruptionError } from "./sqlite-error-diagnostics-CWRyv4lz.mjs"; import { i as tableExists } from "./openclaw-state-db-schema-helpers-DKz5xGgh.mjs"; import { r as runSqliteDeferredTransactionSync } from "./sqlite-transaction-DBRLvCDM.mjs"; import { c as resolveOpenClawStateSqlitePath, r as resolveDatabasePath } from "./openclaw-state-db.paths-CmKkMYdo.mjs"; import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs"; import "./session-key-DY3MOX4N.mjs"; import { i as sessionChanges, n as isSessionStoreTopologyChange } from "./session-row-changes-Dj2yVWo-.mjs"; import { r as cloneEnvWithPlatformSemantics } from "./config-env-vars-BzUE_dOh.mjs"; import { m as hasPreJournalStateSchema } from "./openclaw-state-db-DJZ7EKoI.mjs"; import { t as executeExistingOpenClawStateRead, u as withExistingOpenClawStateDatabaseReadOnly } from "./openclaw-state-db-readonly-ywwvuxdQ.mjs"; import { i as prepareOpenClawStateReadSource } from "./openclaw-state-worker-context-BvvgY6-t.mjs"; import { s as readAgentDeletionRecoveryHolds } from "./agent-deletion-journal-recovery.kernel-CRZY70U8.mjs"; import { g as readRegisteredAgentDatabaseRows, l as prepareOpenClawAgentDatabaseRegistrySnapshotRead, s as isOpenClawAgentDatabaseRegistryChange } from "./openclaw-agent-db-registry-listing-DIA5wIwi.mjs"; import path from "node:path"; //#region src/state/agent-deletion-journal.read.ts async function readAgentDeletionRecoveryHoldsInWorker(options = {}) { const statePath = resolveDatabasePath(options); const reply = await executeExistingOpenClawStateRead({ ...options, path: statePath }, { type: "agentRecovery.holds", input: { statePath } }, { current: true }); if (reply && (!reply.ok || reply.type !== "agentRecovery.holds")) throw new Error("Unexpected agent recovery holds result"); return reply?.held ?? []; } async function readAgentDeletionJournalForCreation(agentId, options = {}) { const reply = await executeExistingOpenClawStateRead(options, { type: "agentRecovery.creationJournal", input: { agentId: normalizeAgentId(agentId) } }, { current: true }); if (reply && (!reply.ok || reply.type !== "agentRecovery.creationJournal")) throw new Error("Unexpected agent creation journal result"); return reply?.journal; } /** Completed cleanup still retains a deletion tombstone. */ function readAgentDeletionJournalStatusInDatabase(database, agentId) { if (!tableExists(database, "agent_deletion_journal")) return "absent"; const row = executeSqliteQueryTakeFirstSync(database, getNodeSqliteKysely(database).selectFrom("agent_deletion_journal").select("cleanup_completed").where("agent_id", "=", normalizeAgentId(agentId))); return row ? row.cleanup_completed === 1 ? "complete" : "pending" : "absent"; } async function readAgentDeletionJournalStatusInWorker(agentId, options = {}, signal) { const reply = await executeExistingOpenClawStateRead(options, { type: "agentDeletionJournal.status", agentId: normalizeAgentId(agentId) }, { current: true, signal }); if (reply && (!reply.ok || reply.type !== "agentDeletionJournal.status")) throw new Error("Unexpected agent deletion journal read result"); return reply?.status ?? "absent"; } function parseAgentDeletionDatabasePaths(value) { const parsed = JSON.parse(value); if (Array.isArray(parsed) && parsed.every((entry) => typeof entry === "string")) return parsed; throw new Error("Invalid agent deletion database path journal."); } /** Read existing deletion history without initializing or repairing the journal. */ function readRetainedAgentDeletionsFromDatabase(database, statePath, purpose = "maintenance") { let entries = []; let missing = false; let unreadableReason; try { missing = !tableExists(database, "agent_deletion_journal"); if (!missing) entries = executeSqliteQuerySync(database, getNodeSqliteKysely(database).selectFrom("agent_deletion_journal").select([ "agent_id", "agent_dir", "database_paths_json" ]).where("cleanup_completed", "=", 1).where("delete_files", "=", 0).orderBy("agent_id", "asc")).rows.map((row) => { let databasePaths = []; try { databasePaths = parseAgentDeletionDatabasePaths(row.database_paths_json); } catch (error) { if (purpose === "maintenance") unreadableReason ??= formatErrorMessage(error); } return { agentId: row.agent_id, agentDir: row.agent_dir, databasePaths: [path.join(row.agent_dir, "openclaw-agent.sqlite"), ...databasePaths] }; }); } catch (error) { if (isSqliteCorruptionError(error)) throw error; unreadableReason = formatErrorMessage(error); } const held = purpose === "maintenance" && tableExists(database, "migration_sources") ? readAgentDeletionRecoveryHolds({ db: database, path: statePath }) : []; if (missing && held.length === 0 && hasPreJournalStateSchema(database)) return { status: "empty" }; if (missing || unreadableReason !== void 0) return { status: "unavailable", cause: missing ? "missing" : "unreadable", reason: missing ? "deletion journal missing" : `deletion journal unreadable: ${unreadableReason}`, ...entries.length || held.length ? { known: { entries, held } } : {} }; return entries.length || held.length ? { status: "present", entries, held } : { status: "empty" }; } /** Read journal and registered-owner facts from one shared-state generation. */ function readAgentDatabaseDeletionSnapshot(env, purpose = "maintenance") { return withExistingOpenClawStateDatabaseReadOnly(({ db, path: statePath }) => runSqliteDeferredTransactionSync(db, () => ({ retainedDeletions: readRetainedAgentDeletionsFromDatabase(db, statePath, purpose), registeredAgentDatabases: readRegisteredAgentDatabaseRows(db, statePath, false) }), { operationLabel: "agentDeletionJournal.snapshot" }), { env }); } /** Repeated discovery reads keep their original source custody and observe current committed facts. */ function prepareAgentDatabaseDeletionSnapshotRead(inputOptions = {}, purpose = "maintenance") { const env = cloneEnvWithPlatformSemantics(inputOptions.env ?? process.env); env.OPENCLAW_STATE_DIR = resolveStateDir(env); const options = { env, path: path.resolve(inputOptions.path ?? resolveOpenClawStateSqlitePath(env)) }; const source = prepareOpenClawStateReadSource(options); const context = source.workerContext(); const readSnapshot = async (readContext) => { const assertReadCurrent = () => { readContext.maintenanceScope?.assertAdmission(); readContext.admission.assertCurrent(); }; assertReadCurrent(); const reply = await executeExistingOpenClawStateRead(options, { type: "agentDatabaseDeletion.snapshot", purpose }, { context: readContext, current: true }); assertReadCurrent(); if (reply && (!reply.ok || reply.type !== "agentDatabaseDeletion.snapshot")) throw new Error("Unexpected agent database deletion snapshot result"); return { snapshot: reply?.snapshot, assertCurrent: assertReadCurrent }; }; const read = () => readSnapshot(context); return { read, async readWithCurrentAdmission() { return source.withCurrent(readSnapshot); }, async withCurrentSnapshot(consume) { let changed; let assertRegistryCurrent; const stop = sessionChanges.subscribeFacts((change) => { if (isSessionStoreTopologyChange(change) && (!assertRegistryCurrent || !isOpenClawAgentDatabaseRegistryChange(change))) changed = true; }); try { for (;;) { changed = false; const { snapshot, assertCurrent } = await read(); assertCurrent(); if (changed) continue; assertRegistryCurrent = prepareOpenClawAgentDatabaseRegistrySnapshotRead(options, (mutation) => mutation.kind === "upsert" && mutation.sources.every((registration) => snapshot?.registeredAgentDatabases.some((entry) => entry.agentId === registration.agentId && entry.path === registration.path && entry.schemaVersion === registration.schemaVersion))).assertCurrent; return await consume(snapshot, () => { assertCurrent(); if (changed) throw new Error("Agent database deletion snapshot changed during consumption."); assertRegistryCurrent?.(); }); } } finally { changed = true; stop(); } } }; } //#endregion export { readAgentDeletionJournalStatusInDatabase as a, readRetainedAgentDeletionsFromDatabase as c, readAgentDeletionJournalForCreation as i, prepareAgentDatabaseDeletionSnapshotRead as n, readAgentDeletionJournalStatusInWorker as o, readAgentDatabaseDeletionSnapshot as r, readAgentDeletionRecoveryHoldsInWorker as s, parseAgentDeletionDatabasePaths as t };