openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
97 lines (96 loc) • 4.76 kB
JavaScript
import { n as normalizeAgentId } from "./agent-id-CeT3w4ap.js";
import { c as resolveAgentConfig } from "./agent-scope-config-DcbEhP0R.js";
import "./session-key-BnWWjqNc.js";
import { s as resolveOpenClawStateSqlitePath } from "./openclaw-state-db-schema-version-c1ZL6JGz.js";
import { C as createAgentDeletionDatabaseCleanup, _ as readAgentDeletionJournal, a as assertNoOpenClawAgentDatabaseLeases, b as updateAgentDeletionJournalDatabasePaths, f as beginAgentDeletionJournal, m as completeAgentDeletionJournal, p as claimCompletedAgentDeletionJournal, v as removeAgentDeletionJournal, y as updateAgentDeletionJournalCleanupPaths } from "./openclaw-agent-db-lease-Djvd6LWN.js";
import { i as readAgentProvenance } from "./agent-provenance-Cp8HmAX0.js";
import { isDeepStrictEqual } from "node:util";
import path from "node:path";
import crypto from "node:crypto";
//#region src/agents/agent-lifecycle-registry.ts
var AgentDeletionAuthorityRollbackError = class extends AggregateError {};
var AgentDeletionCommitUncertainError = class extends Error {
constructor(cause) {
super(cause instanceof Error ? cause.message : String(cause), { cause });
}
};
/** Fence authority producers while an agent deletion is pending or committed. */
function beginAgentDeletion(entry, options = {}) {
const id = normalizeAgentId(entry.agentId);
const statePath = path.resolve(options.path ?? resolveOpenClawStateSqlitePath(options.env ?? process.env));
const stateOptions = {
...options,
path: statePath,
env: options.env && { ...options.env }
};
const operationId = crypto.randomUUID();
const journal = beginAgentDeletionJournal({
...entry,
agentId: id,
operationId,
deleteFiles: entry.deleteFiles !== false
}, stateOptions);
let active = true;
const assertJournal = (currentStatePath, entries) => {
if (!active || path.resolve(currentStatePath) !== statePath || !entries.some((current) => current.agentId === id && current.operationId === operationId && !current.cleanupCompleted)) throw new Error(`Agent ${id} deletion no longer owns database cleanup.`);
return id;
};
return {
entry: journal,
runDatabaseCleanup: createAgentDeletionDatabaseCleanup({
statePath,
assertAdmission: () => assertNoOpenClawAgentDatabaseLeases(id, stateOptions),
assertJournal,
assertCurrent: () => {
const current = readAgentDeletionJournal(id, stateOptions);
assertJournal(statePath, current ? [current] : []);
}
}),
fenceDatabasePaths: (paths) => {
if (!updateAgentDeletionJournalDatabasePaths(id, operationId, paths, stateOptions)) throw new Error(`Failed to fence database cleanup paths for agent ${id}.`);
journal.databasePaths = [...new Set(paths.map((entryPath) => path.resolve(entryPath)))];
},
fenceCleanupPaths: (paths) => {
if (!updateAgentDeletionJournalCleanupPaths(id, operationId, paths, stateOptions)) throw new Error(`Failed to fence cleanup paths for agent ${id}.`);
journal.cleanupPaths = [...paths];
},
finish: () => {
try {
completeAgentDeletionJournal(id, operationId, stateOptions);
} finally {
active = false;
}
},
rollback: () => {
try {
removeAgentDeletionJournal(id, operationId, stateOptions);
} finally {
active = false;
}
}
};
}
/** Atomically claim a completed deletion tombstone for a newly created identity. */
function claimCompletedAgentDeletion(agentId, operationId, options = {}) {
return claimCompletedAgentDeletionJournal(normalizeAgentId(agentId), operationId, options);
}
/** Return whether this process must refuse new authority for an agent id. */
function isAgentDeletionBlocked(agentId, options = {}) {
return Boolean(readAgentDeletionJournal(normalizeAgentId(agentId), options));
}
/** Captures the exact durable incarnation of an existing, deletion-safe agent. */
function captureAgentLifecycleBinding(config, agentId, options = {}) {
const id = normalizeAgentId(agentId);
if (!resolveAgentConfig(config, id) || isAgentDeletionBlocked(id, options)) return;
return Object.freeze({
agentId: id,
provenance: readAgentProvenance(id, options) ?? null
});
}
/** Revalidates an agent binding against both the roster and lifecycle owner. */
function matchesAgentLifecycleBinding(config, binding, options = {}) {
const id = normalizeAgentId(binding.agentId);
return id === binding.agentId && Boolean(resolveAgentConfig(config, id)) && !isAgentDeletionBlocked(id, options) && isDeepStrictEqual(readAgentProvenance(id, options) ?? null, binding.provenance);
}
//#endregion
export { claimCompletedAgentDeletion as a, captureAgentLifecycleBinding as i, AgentDeletionCommitUncertainError as n, isAgentDeletionBlocked as o, beginAgentDeletion as r, matchesAgentLifecycleBinding as s, AgentDeletionAuthorityRollbackError as t };