UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

193 lines (192 loc) • 10.6 kB
import { a as executeSqliteQueryTakeFirstSync, i as executeSqliteQuerySync, o as getNodeSqliteKysely } from "./kysely-sync-DUWzQvCU.mjs"; import { i as tableExists } from "./openclaw-state-db-schema-helpers-DKz5xGgh.mjs"; import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs"; import "./session-key-DY3MOX4N.mjs"; import { i as deferSqliteWorkerCommitReceipt, s as requestSqliteWorkerOperationAdmission } from "./sqlite-worker-operation-admission-C5lBzzTk.mjs"; import { a as deleteAgentDeletionJournalInDatabase, d as readAgentDeletionJournalInDatabase, f as updateAgentDeletionJournalPathsInDatabase, i as completeAgentDeletionJournalInDatabase, o as handoffAgentDeletionJournalInDatabase, r as beginAgentDeletionJournalInDatabase } from "./agent-deletion-journal-DkfGlzu8.mjs"; import { a as assertNoOpenClawAgentDatabaseLeases } from "./openclaw-agent-db-lease-zP0JO4hP.mjs"; import { r as unregisterOpenClawAgentDatabases } from "./openclaw-agent-db-registry-iOyfY9cK.mjs"; import { t as createOpenClawStateSchemaEnsurer } from "./openclaw-state-feature-schema-BHGUhcMT.mjs"; import { n as readClawInstallRecordFromDatabase } from "./provenance-read.kernel-BQe6L4vF.mjs"; import { n as assertOpenClawStateLeaseWorkerOwnedInTransaction } from "./openclaw-state-lease-worker-Ddwq3QcA.mjs"; import { isDeepStrictEqual } from "node:util"; //#region src/state/agent-deletion-journal-authority.worker.ts /** Deletion authority requires its admitted journal; unavailable rows must never grant cleanup. */ function readAgentDeletionJournalAuthorityInDatabase(database, agentId) { const row = executeSqliteQueryTakeFirstSync(database, getNodeSqliteKysely(database).selectFrom("agent_deletion_journal").select([ "agent_id", "operation_id", "cleanup_completed" ]).where("agent_id", "=", normalizeAgentId(agentId))); if (!row) return; if (typeof row.operation_id !== "string" || !row.operation_id || row.cleanup_completed !== 0 && row.cleanup_completed !== 1) throw new Error("Agent deletion journal authority is unreadable."); return { agentId: row.agent_id, operationId: row.operation_id, cleanupCompleted: row.cleanup_completed === 1 }; } //#endregion //#region src/state/agent-provenance.schema.ts const ensureAgentProvenanceSchema = createOpenClawStateSchemaEnsurer({ table: "agent_provenance", operationLabel: "agent-provenance.schema.ensure" }); //#endregion //#region src/state/agent-deletion.worker.ts /** The caller holds the real lease grant and this transaction's shared-state snapshot. */ function assertAgentDeletionWorkerPredicate(database, predicate, currentJournal) { const journal = currentJournal === void 0 ? readAgentDeletionJournalAuthorityInDatabase(database.db, predicate.agentId) : currentJournal; if (!journal || journal.agentId !== predicate.agentId || journal.operationId !== predicate.operationId || journal.cleanupCompleted) throw new Error(`Agent ${predicate.agentId} deletion no longer owns database cleanup.`); assertClawInstall(database, predicate); } function assertClawInstall(database, predicate) { if (predicate.expectedClawInstall !== void 0 && !isDeepStrictEqual(readClawInstallRecordFromDatabase(database.db, predicate.agentId) ?? null, predicate.expectedClawInstall)) throw Object.assign(/* @__PURE__ */ new Error(`Claw removal no longer owns agent ${predicate.agentId}.`), { code: "CLAW_INSTALL_CHANGED" }); } function assertLease(database, lease, agentId, stage = "transaction") { if (lease.scope !== "core:agent-deletion" || lease.key !== agentId) throw new Error("Agent deletion requires its original target lease"); assertOpenClawStateLeaseWorkerOwnedInTransaction(database.db, lease, "write", stage); } function guarded(guard, context, mutate, publication) { return context.write((database) => { assertLease(database, guard.lease, guard.predicate.agentId); assertAgentDeletionWorkerPredicate(database, guard.predicate); const result = mutate(database); assertLease(database, guard.lease, guard.predicate.agentId, "commit"); if (publication) deferSqliteWorkerCommitReceipt(database.db, { ...publication.journalChanged ? { kind: "agent-deletion-mutated", agentId: guard.predicate.agentId, operationId: guard.predicate.operationId, unregisterDatabases: publication.unregisterDatabases === true } : {}, ...publication.nonce ? { receiptAuthority: { nonce: publication.nonce, sequence: 1 } } : {} }); return result; }, { operationLabel: "agent.deletion" }); } const agentDeletionOperations = { "agentDeletion.claimCompleted": (input, context) => context.write((database) => { requestSqliteWorkerOperationAdmission({ stage: "transaction", facts: void 0 }); const claimed = deleteAgentDeletionJournalInDatabase(database, input.agentId, input.operationId, true); requestSqliteWorkerOperationAdmission({ stage: "commit", facts: void 0 }); deferSqliteWorkerCommitReceipt(database.db, { kind: "agent-deletion-claimed", agentId: input.agentId, operationId: input.operationId, claimed, receiptAuthority: { nonce: input.nonce, sequence: 1 } }); return claimed; }, { operationLabel: "agent.deletion.claim" }), "agentDeletion.read": (input, { open }) => readAgentDeletionJournalInDatabase(open(), input.agentId), "agentDeletion.begin": (input, context) => context.write((database) => { assertLease(database, input.lease, input.entry.agentId); assertClawInstall(database, { agentId: input.entry.agentId, expectedClawInstall: input.expectedClawInstall }); ensureAgentProvenanceSchema({ database, ...context.stateOptions() }); const result = beginAgentDeletionJournalInDatabase(database, input.entry, input.preserveDeleteFiles); assertLease(database, input.lease, input.entry.agentId, "commit"); deferSqliteWorkerCommitReceipt(database.db, { kind: "agent-deletion-began", agentId: input.entry.agentId, operationId: input.entry.operationId, receiptAuthority: { nonce: input.nonce, sequence: 1 } }); return result; }, { operationLabel: "agent.deletion.begin" }), "agentDeletion.assertCurrent": (input, context) => guarded(input.guard, context, () => void 0), "agentDeletion.assertNoDatabaseLeasesUnowned": (input, context) => assertNoOpenClawAgentDatabaseLeases(input.agentId, { database: context.open(), ...context.stateOptions() }), "agentDeletion.assertNoDatabaseLeases": (input, context) => guarded(input.guard, context, (database) => assertNoOpenClawAgentDatabaseLeases(input.guard.predicate.agentId, { database, ...context.stateOptions() })), "agentDeletion.fencePaths": (input, context) => guarded(input.guard, context, (database) => { const { agentId, operationId } = input.guard.predicate; if (!updateAgentDeletionJournalPathsInDatabase(database, agentId, operationId, input.paths.kind === "database" ? "database_paths_json" : "cleanup_paths_json", input.paths.paths)) throw new Error(`Failed to fence cleanup paths for agent ${agentId}.`); }, { journalChanged: true }), "agentDeletion.finish": (input, context) => guarded(input.guard, context, (database) => { const { agentId, operationId } = input.guard.predicate; if (input.unregisterDatabases) unregisterOpenClawAgentDatabases({ agentId, database, env: context.stateOptions().env }); if (!completeAgentDeletionJournalInDatabase(database, agentId, operationId)) throw new Error(`Failed to complete deletion journal for agent ${agentId}.`); }, { journalChanged: true, unregisterDatabases: input.unregisterDatabases }), "agentDeletion.rollback": (input, context) => guarded(input.guard, context, (database) => { const { agentId, operationId } = input.guard.predicate; if (!deleteAgentDeletionJournalInDatabase(database, agentId, operationId, false)) throw new Error(`Failed to roll back deletion journal for agent ${agentId}.`); }, { nonce: input.nonce, journalChanged: true }), "agentDeletion.releaseClawRows": (input, context) => guarded(input.guard, context, (database) => { const { agentId, operationId } = input.guard.predicate; if (input.complete) unregisterOpenClawAgentDatabases({ agentId, database, env: context.stateOptions().env }); const query = getNodeSqliteKysely(database.db); const paths = [...new Set(input.files.filter((file) => file.action !== "error").map((file) => file.path))]; if (paths.length && tableExists(database.db, "claw_workspace_files")) executeSqliteQuerySync(database.db, query.deleteFrom("claw_workspace_files").where("agent_id", "=", agentId).where("target_path", "in", paths)); if (!input.complete) return false; if (tableExists(database.db, "claw_package_refs")) executeSqliteQuerySync(database.db, query.deleteFrom("claw_package_refs").where("agent_id", "=", agentId)); if (tableExists(database.db, "claw_installs")) executeSqliteQuerySync(database.db, query.deleteFrom("claw_installs").where("agent_id", "=", agentId)); if (!completeAgentDeletionJournalInDatabase(database, agentId, operationId)) throw new Error(`Failed to complete deletion journal for agent ${agentId}.`); return true; }, { journalChanged: true, unregisterDatabases: input.complete }), "agentDeletion.handoffClawRetry": (input, context) => context.write((database) => { const { agentId, operationId } = input.guard.predicate; assertLease(database, input.guard.lease, agentId); const journal = readAgentDeletionJournalInDatabase(database, agentId); if (!journal || journal.operationId !== operationId || journal.cleanupCompleted || input.guard.predicate.expectedClawInstall !== void 0 && !isDeepStrictEqual(readClawInstallRecordFromDatabase(database.db, agentId) ?? null, input.guard.predicate.expectedClawInstall)) { assertLease(database, input.guard.lease, agentId, "commit"); return false; } if (executeSqliteQuerySync(database.db, getNodeSqliteKysely(database.db).updateTable("claw_installs").set({ status: "partial", updated_at_ms: input.nowMs }).where("agent_id", "=", agentId)).numAffectedRows !== 1n || !handoffAgentDeletionJournalInDatabase(database, agentId, operationId, input.retryOperationId)) throw new Error(`Failed to hand off deletion journal for agent ${agentId}.`); assertLease(database, input.guard.lease, agentId, "commit"); deferSqliteWorkerCommitReceipt(database.db, { kind: "agent-deletion-mutated", agentId, operationId, unregisterDatabases: false }); return true; }, { operationLabel: "agent.deletion.handoff" }) }; //#endregion export { assertAgentDeletionWorkerPredicate as n, ensureAgentProvenanceSchema as r, agentDeletionOperations as t };