openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
960 lines (959 loc) • 45.9 kB
JavaScript
import { t as createDeferredCore } from "./deferred-D0La5CRk.mjs";
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import { o as racePromiseWithAbortSignal } from "./src-D1BHGNTj.mjs";
import "./abort-signal-QqAmLWTl.mjs";
import { r as resolveStateDir } from "./state-dir-CYkBUd_G.mjs";
import "./paths-BP0DYpE8.mjs";
import "./kysely-sync-DUWzQvCU.mjs";
import { c as registerNodeSqliteDisposeCallback, r as enableNodeSqliteKyselyStatementCache } from "./kysely-sync-cache-state-DbAMR_DD.mjs";
import { t as admitSqliteSchema } from "./sqlite-schema-facts-BVf0E_0z.mjs";
import { d as readDatabasePathIdentitySync, r as assertExistingDatabaseIdentity } from "./sqlite-worker-identity-BRNRpRyc.mjs";
import { a as resolveExistingSqliteFileUri, l as supportsNodeSqliteExtensionLoading, r as openNodeSqliteDatabase } from "./node-sqlite-DyeJqxPf.mjs";
import { n as isArtifactPreservingStateRead } from "./artifact-preserving-state-reads-BQnQLAJR.mjs";
import { f as readExistingAgentSchemaMeta } from "./sqlite-readonly-location-DEj0l7LR.mjs";
import { s as OPENCLAW_SQLITE_BUSY_TIMEOUT_MS } from "./openclaw-state-db-contract-BYv0nUQr.mjs";
import { c as withSqlitePostCommitPublications } from "./sqlite-post-commit-DENvzR6w.mjs";
import { a as runSqliteImmediateTransactionSync } from "./sqlite-transaction-DBRLvCDM.mjs";
import { i as isSqliteSchemaVersionError } from "./sqlite-user-version-DLMl1A7W.mjs";
import { a as registerSqliteCacheExitClose, c as registerDeferredSqliteWalWriteAdmission, f as prepareSqliteDatabaseDirectory, l as registerSqliteWalWorkerMaintenance, n as configureSqlitePreSchemaPragmas, t as configureSqliteConnectionPragmas, u as createSqliteWalReclamationResult } from "./sqlite-wal-DfKCrDTQ.mjs";
import { m as observeOpenClawDatabaseMaintenanceResource, u as getOpenClawDatabaseMaintenanceScope } from "./openclaw-state-db-async-lifecycle-DwFy2ZTk.mjs";
import { c as matchesAgentDatabaseReadCandidatePath } from "./agent-database-readers-m64TtGjG.mjs";
import { i as quarantineOrphanedSqliteSidecars } from "./sqlite-files-D1rDNZzV.mjs";
import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs";
import "./session-key-DY3MOX4N.mjs";
import { l as runSqliteIntegrityCheckSync, s as isTerminalSqliteIntegrityError, u as runSqliteIntegrityOperationSync } from "./sqlite-integrity-D3yHPOet.mjs";
import { r as assertCanonicalSessionValidationSchema } from "./openclaw-agent-canonical-validation-schema-4dL3LLg2.mjs";
import "./openclaw-agent-db-contract-OYt2DCoK.mjs";
import { a as readOpenClawAgentDatabaseIdentity, o as registerOpenClawAgentDatabaseIdentity, t as assertOpenClawAgentDatabaseIdentity } from "./openclaw-agent-db-identity-BlmER9-X.mjs";
import { i as assertSupportedAgentSchemaVersion, n as assertCurrentAgentSchemaMetadata, r as assertExistingAgentSchemaOwner, t as assertCanonicalAgentPersistenceVersion } from "./openclaw-agent-db-schema-read-y-s2h2dU.mjs";
import { t as assertSqliteIntegrityInWorker } from "./sqlite-integrity-worker-B-14oZqk.mjs";
import { c as revalidateAgentDatabaseTerminalOpen, l as revalidateAgentDatabaseTerminalOpenAsync } from "./openclaw-agent-db-readonly-open-CLVyHzjq.mjs";
import { _ as reserveAgentCreationClaimAdmission, d as assertAgentCreationClaimAccess, f as assertAgentCreationClaimAliases, h as registerAgentCreationClaimHandle, m as captureAgentCreationClaim, o as registerOpenClawAgentDatabaseAsyncResource, p as assertAgentCreationClaimCurrent, t as assertAgentDatabaseResourceAdmission } from "./openclaw-agent-db-resources-Cm-sH7kg.mjs";
import { c as getOpenClawAgentDatabaseValidation, d as hasOpenClawAgentDatabaseValidationSpelling, h as invalidateOpenClawAgentDatabaseValidation, i as captureOpenClawAgentDatabaseAliasPublication, l as getOpenClawAgentDatabaseValidationForTransfer, n as adoptOpenClawAgentDatabaseValidation, t as adoptOpenClawAgentDatabaseSchema, v as publishOpenClawAgentDatabaseSchema } from "./openclaw-agent-db-validation-cache-CHrtutWN.mjs";
import { i as isIncognitoOpenClawAgentSqlitePath, l as resolveOpenClawAgentSqlitePath, n as assertIncognitoAgentDatabasePathAvailable, o as isSameOpenClawAgentDatabasePath } from "./openclaw-agent-db.paths-BbmZlEP5.mjs";
import { l as resolveAgentDatabaseIntegrityGateReason, o as readOpenClawDatabaseQuarantineFailure, r as clearOpenClawDatabaseQuarantine } from "./openclaw-quarantine-store-CUJxC7wy.mjs";
import { n as closeIdleOpenClawAgentDatabaseReadOnly } from "./openclaw-agent-db-readonly-scope-8pVQvbhg.mjs";
import { o as isGatewayExternallySupervised } from "./gateway-supervision-D9M_dluZ.mjs";
import { r as createSqliteWorkerOperationAdmission, s as requestSqliteWorkerOperationAdmission, t as SqliteWorkerOpenRefusedError } from "./sqlite-worker-operation-admission-C5lBzzTk.mjs";
import { n as assertAgentDatabaseAdmitted } from "./agent-database-admission-CRwW7FsI.mjs";
import { r as cloneEnvWithPlatformSemantics } from "./config-env-vars-BzUE_dOh.mjs";
import { S as registerAgentDeletionDatabaseCleanup, _ as assertAgentDeletionCleanupAliases, l as readAgentDeletionJournal, v as assertAgentDeletionDatabaseCleanupAccess, x as getAgentDeletionDatabaseCleanup } from "./agent-deletion-journal-DkfGlzu8.mjs";
import "./openclaw-state-db-DJZ7EKoI.mjs";
import { c as claimOpenClawAgentDatabaseLease, g as releaseOpenClawAgentDatabaseLease, l as hasAgentDatabaseMaintenanceAuthority, m as recordOpenClawAgentDatabaseAdmission, s as assertOpenClawAgentDatabaseLease, y as agentDatabaseAdmissionProvenanceRefusal } from "./openclaw-agent-db-lease-zP0JO4hP.mjs";
import "./openclaw-agent-db-schema-helpers-CXpPV9Zn.mjs";
import { C as retainFailedAgentDatabaseClose, D as startAgentDatabaseOpenTiming, S as retainAgentDatabase, T as revokePendingAgentDatabaseOpen, a as closeOpenClawAgentDatabaseByPathAsync, b as refreshAgentDatabaseIdleTimer, l as createAgentDatabaseScopeOwnedClose, n as closeCachedOpenClawAgentDatabase, o as closeOpenClawAgentDatabases, r as closeMaintenanceAgentDatabase, t as cache, w as retainIncognitoSharedState, x as registerAgentDatabaseHandle, y as recordOpenClawAgentDatabaseOpenFailure } from "./openclaw-agent-db-lifecycle-C9dal1XJ.mjs";
import { n as ensureAgentSchema, s as ensureOpenClawAgentDatabasePermissions, t as agentDatabaseIntegrityBeforeMutationSteps } from "./openclaw-agent-db-schema-CppMSzFp.mjs";
import { t as runOpenClawAgentWorkerWrite } from "./openclaw-agent-write-admission-CXJiE5VB.mjs";
import { t as registerOpenClawAgentDatabase } from "./openclaw-agent-db-registry-iOyfY9cK.mjs";
import { n as requestOpenClawAgentDatabaseIntegrityCheck } from "./openclaw-database-verify-CGIYTxWq.mjs";
import path from "node:path";
import { isMainThread } from "node:worker_threads";
//#region src/state/openclaw-agent-db-integrity-driver.ts
/** Keep synchronous generator resumption bound to the caller's original authority. */
function runPreparedAgentDatabaseIntegrity(steps, preparedLease, repairAdmission, assertAuthority) {
const assertCurrent = () => {
repairAdmission?.assertCurrent?.();
if (preparedLease && !isMainThread) requestSqliteWorkerOperationAdmission({
stage: "prepare",
facts: {
kind: "agent-open-resume",
lease: preparedLease.receipt
}
});
};
const repair = preparedLease?.startupRepair;
return runSqliteIntegrityOperationSync(steps, preparedLease && !isMainThread || repairAdmission?.assertCurrent ? () => assertAuthority(steps, assertCurrent) : void 0, repair && !isMainThread ? (check, error) => repair(check, error, assertCurrent) : void 0);
}
//#endregion
//#region src/state/openclaw-agent-db-admission.ts
/** Refusal must unwind ownership without entering corruption repair or changing its caller error. */
function assertAgentDatabaseOpenAuthority(operation, assertCurrent) {
try {
assertCurrent?.();
} catch (error) {
const refusal = new Error("Agent database open authority was refused", { cause: error });
try {
operation.throw(refusal);
} catch (cleanupError) {
if (cleanupError !== refusal) throw new AggregateError([error, cleanupError], `Agent database authority and cleanup failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`, { cause: cleanupError });
}
throw error;
}
}
function assertAgentDatabaseOperationCurrent(database, options, pending, assertCurrent) {
pending.controller.signal.throwIfAborted();
assertAgentDatabaseAdmitted(database.agentId, { env: options.env });
if (cache.databases.get(pending.path) !== database || !database.db.isOpen) throw new Error(`Agent database closed before its admitted operation: ${pending.path}`);
assertAgentDeletionDatabaseCleanupAccess(database, options);
assertAgentCreationClaimAccess(database, options);
assertCurrent?.();
}
function assertAgentDatabaseWriteAllowed(pathname) {
if (isArtifactPreservingStateRead("agent", pathname)) throw new Error("Programming error: writable agent database open during read-only inspection.");
}
/** Bind admission drivers to the canonical private database-open generator. */
function createOpenClawAgentDatabaseAdmissionOwner(openSteps) {
/** Open or return a cached per-agent database after schema and owner validation. */
function openOpenClawAgentDatabase(options, preparedLease, registrationObserver) {
return openAgentDatabase(options, preparedLease, registrationObserver);
}
function openAgentDatabase(options, preparedLease, registrationObserver, repairAdmission) {
assertAgentDatabaseWriteAllowed(resolveOpenClawAgentSqlitePath(options));
const run = () => {
return runPreparedAgentDatabaseIntegrity(openSteps(options, void 0, preparedLease, registrationObserver, repairAdmission), preparedLease, repairAdmission, assertAgentDatabaseOpenAuthority);
};
const scope = getOpenClawDatabaseMaintenanceScope();
return scope ? scope.run(run) : run();
}
function runOpenClawAgentWriteTransaction(operation, options, transactionOptions = {}) {
const { repairAdmission, ...writeOptions } = transactionOptions;
const database = openAgentDatabase(options, void 0, void 0, repairAdmission);
const deletionCommit = getAgentDeletionDatabaseCleanup(options)?.withCommit;
const withCommit = repairAdmission ? (commit) => {
repairAdmission.assertCurrent?.();
if (repairAdmission.expectedIdentity) assertOpenClawAgentDatabaseIdentity(database, repairAdmission.expectedIdentity);
if (deletionCommit) deletionCommit(commit);
else commit();
} : deletionCommit;
const enteredNestedTransaction = database.db.isTransaction;
return withSqlitePostCommitPublications(database.db, () => runSqliteImmediateTransactionSync(database.db, () => {
assertAgentDeletionDatabaseCleanupAccess(database, options);
assertAgentCreationClaimAccess(database, options);
const operationResult = operation(database);
if (!enteredNestedTransaction && !cache.incognito.has(database)) ensureOpenClawAgentDatabasePermissions(database.path, options);
return operationResult;
}, {
busyTimeoutMs: writeOptions.busyTimeoutMs ?? 5e3,
databaseLabel: database.path,
...writeOptions,
operationLabel: writeOptions.operationLabel ?? "agent.write",
withCommit
}));
}
/** Released SDK guards may read SQLite; preserve their native open and integrity-resume checkpoints. */
function withOpenClawAgentDatabaseAsync(inputOptions, operation, assertCurrent, signal) {
const run = () => runAgentDatabaseAsync(inputOptions, operation, assertCurrent, signal, "native");
const scope = getOpenClawDatabaseMaintenanceScope();
return scope ? scope.run(run) : run();
}
/** Runtime authority runs in worker grants: same-owner row predicates belong in the worker. */
function withOpenClawAgentDatabaseRuntime(inputOptions, operation, assertCurrent, signal) {
const run = () => runAgentDatabaseAsync(inputOptions, operation, assertCurrent, signal);
const scope = getOpenClawDatabaseMaintenanceScope();
return scope ? scope.run(run) : run();
}
/** Core callers retain their original creating reference through native handle admission. */
function withOpenClawAgentDatabaseRuntimeFromExecution(inputOptions, execution, operation, assertCurrent, signal) {
const agentId = normalizeAgentId(inputOptions.agentId);
const pathname = resolveOpenClawAgentSqlitePath({
...inputOptions,
agentId
});
const assertExecutionCurrent = () => {
execution.assertCurrent();
if (execution.agentId !== agentId || execution.path !== pathname) throw new Error("Agent runtime admission differs from its captured execution");
assertCurrent?.();
};
const run = () => runAgentDatabaseAsync(inputOptions, operation, assertExecutionCurrent, signal, void 0, execution);
const scope = getOpenClawDatabaseMaintenanceScope();
return scope ? scope.run(run) : run();
}
async function runAgentDatabaseAsync(inputOptions, operation, assertCurrent, signal, prepared, execution) {
signal?.throwIfAborted();
assertCurrent?.();
const options = {
...inputOptions,
env: cloneEnvWithPlatformSemantics(inputOptions.env ?? process.env)
};
const agentId = normalizeAgentId(options.agentId);
const pathname = resolveOpenClawAgentSqlitePath({
...options,
agentId
});
assertAgentDatabaseWriteAllowed(pathname);
options.env.OPENCLAW_STATE_DIR = resolveStateDir(options.env);
options.path = pathname;
if (cache.terminal.peek(pathname)) await revalidateAgentDatabaseTerminalOpenAsync(pathname, assertCurrent, signal);
const cached = cache.databases.get(pathname);
const schema = getOpenClawAgentDatabaseValidationForTransfer({
agentId,
path: pathname
})?.schema;
if (!prepared && isMainThread && (!cached?.db.isOpen || !cache.incognito.has(cached) && (!schema || Atomics.load(new Int32Array(schema.valid), 0) !== 1)) && !cache.pending.has(pathname)) return withWorkerAdmission(options, assertCurrent, signal, (preparation) => runAgentDatabaseAsync(options, operation, assertCurrent, signal, preparation, execution), execution);
const existing = cache.pending.get(pathname);
if (existing?.agentId !== void 0 && existing.agentId !== agentId) throw new Error(`Agent database ${pathname} is opening for ${existing.agentId}`);
if (existing?.controller.signal.aborted) return existing.promise.then(() => runAgentDatabaseAsync(options, operation, assertCurrent, signal, prepared, execution), () => runAgentDatabaseAsync(options, operation, assertCurrent, signal, prepared, execution));
const pending = existing ?? startOpenClawAgentDatabaseAdmission(options, agentId, pathname, assertCurrent, prepared === "worker");
pending.operations += 1;
return racePromiseWithAbortSignal(pending.promise, signal).then((database) => {
signal?.throwIfAborted();
assertAgentDatabaseOperationCurrent(database, options, pending, assertCurrent);
observeOpenClawDatabaseMaintenanceResource(database.db);
return operation(database);
}).finally(() => {
pending.operations -= 1;
if (!pending.operations) {
if (!pending.releaseBorrow) pending.controller.abort(/* @__PURE__ */ new Error("Agent database admission has no waiting callers"));
pending.releaseBorrow?.();
}
});
}
/** Run on a Worker to keep its same-connection integrity check outside the parent writer. */
function withOpenClawAgentDatabaseAdmission(inputOptions, withAdmission, operation) {
const run = () => runAgentDatabaseAdmission(inputOptions, withAdmission, operation);
const scope = getOpenClawDatabaseMaintenanceScope();
return scope ? scope.run(() => scope.track(run())) : run();
}
async function runAgentDatabaseAdmission(inputOptions, withAdmission, operation) {
const options = {
...inputOptions,
env: cloneEnvWithPlatformSemantics(inputOptions.env ?? process.env)
};
const agentId = normalizeAgentId(options.agentId);
const pathname = resolveOpenClawAgentSqlitePath({
...options,
agentId
});
assertAgentDatabaseWriteAllowed(pathname);
if (cache.terminal.peek(pathname)) await revalidateAgentDatabaseTerminalOpenAsync(pathname);
const existing = cache.pending.get(pathname);
if (existing) {
if (existing.agentId !== agentId) throw new Error(`Agent database ${pathname} is opening for ${existing.agentId}`);
try {
await existing.promise;
} catch (error) {
if (!existing.controller.signal.aborted) throw error;
}
return withOpenClawAgentDatabaseAdmission(options, withAdmission, operation);
}
const admission = createOpenClawAgentDatabaseAdmission(agentId, pathname);
const { pending } = admission;
pending.promise.catch(() => {});
pending.operations += 1;
const steps = openSteps(options, pending);
let check;
let failure;
let suspended = false;
try {
while (true) {
const outcome = await withAdmission(async (assertCurrent, validation) => {
suspended = false;
assertAgentDatabaseOpenAuthority(steps, () => {
assertCurrent();
assertOpenClawAgentDatabaseAdmissionCurrent(options, pending, check?.database);
});
pending.validation = validation;
const step = failure ? steps.throw(failure.error) : steps.next();
if (!step.done) {
suspended = true;
return {
done: false,
check: step.value
};
}
pending.releaseBorrow = retainAgentDatabase(step.value.db);
admission.complete(step.value);
const assertOperationCurrent = () => assertAgentDatabaseOperationCurrent(step.value, options, pending, assertCurrent);
assertOperationCurrent();
const flushMaintenance = isMainThread ? void 0 : registerDeferredSqliteWalWriteAdmission(step.value.db);
flushMaintenance?.(assertOperationCurrent);
const result = await operation(step.value);
flushMaintenance?.(assertOperationCurrent);
return {
done: true,
result
};
});
if (outcome.done) return outcome.result;
check = outcome.check;
failure = void 0;
try {
pending.controller.signal.throwIfAborted();
runSqliteIntegrityCheckSync(check);
} catch (error) {
failure = { error };
}
}
} catch (error) {
const failures = [error];
if (suspended) {
const cancellation = new Error(`Agent database admission failed: ${pathname}`, { cause: error });
try {
steps.throw(cancellation);
} catch (cleanupError) {
if (cleanupError !== cancellation) failures.push(cleanupError);
}
}
const terminalFailure = failures.length === 1 ? error : new AggregateError(failures, "Agent database admission and cleanup failed", { cause: error });
admission.fail(terminalFailure);
throw terminalFailure;
} finally {
pending.operations -= 1;
if (!pending.operations) pending.releaseBorrow?.();
}
}
function createOpenClawAgentDatabaseAdmission(agentId, pathname) {
assertAgentDatabaseResourceAdmission({
agentId,
path: pathname
});
const completion = createDeferredCore();
const pending = {
agentId,
path: pathname,
controller: new AbortController(),
promise: completion.promise,
operations: 0
};
cache.pending.set(pathname, pending);
cache.activePending.add(pending);
const retire = () => {
if (cache.pending.get(pathname) === pending) cache.pending.delete(pathname);
cache.activePending.delete(pending);
};
return {
pending,
complete: (database) => {
retire();
if (pending.controller.signal.aborted || cache.databases.get(pathname) !== database || !database.db.isOpen) {
const error = pending.controller.signal.reason ?? /* @__PURE__ */ new Error(`Agent database closed before admission completed: ${pathname}`);
completion.reject(error);
throw error;
}
completion.resolve(database);
},
fail: (error) => {
retire();
completion.reject(error);
}
};
}
function assertOpenClawAgentDatabaseAdmissionCurrent(options, pending, database) {
const pathname = pending.path;
pending.controller.signal.throwIfAborted();
assertAgentDatabaseAdmitted(pending.agentId, { env: options.env });
if (cache.pending.get(pathname) !== pending) throw new Error(`Agent database open was replaced: ${pathname}`);
assertAgentCreationClaimCurrent(options);
getAgentDeletionDatabaseCleanup(options)?.assertCurrent();
pending.assertHeld?.();
if (database) {
assertSupportedAgentSchemaVersion(database, pathname);
assertExistingAgentSchemaOwner(readExistingAgentSchemaMeta(database), pending.agentId, pathname);
}
}
function startOpenClawAgentDatabaseAdmission(options, agentId, pathname, assertCurrent, workerPrepared = false) {
const admission = createOpenClawAgentDatabaseAdmission(agentId, pathname);
const { pending } = admission;
pending.workerPrepared = workerPrepared;
const operation = openSteps(options, pending);
(async () => {
assertAgentDatabaseOpenAuthority(operation, assertCurrent);
let step = operation.next();
while (!step.done) {
const database = step.value.database;
let failure;
let failed = false;
try {
await assertSqliteIntegrityInWorker(pathname, OPENCLAW_SQLITE_BUSY_TIMEOUT_MS, pending.controller.signal, void 0, step.value.timing);
} catch (error) {
failure = error;
failed = true;
}
assertAgentDatabaseOpenAuthority(operation, () => {
assertOpenClawAgentDatabaseAdmissionCurrent(options, pending, database);
assertCurrent?.();
});
step = failed ? operation.throw(failure) : operation.next();
}
pending.releaseBorrow = retainAgentDatabase(step.value.db);
return step.value;
})().then(admission.complete, admission.fail).catch(admission.fail);
return pending;
}
return {
openOpenClawAgentDatabase,
runOpenClawAgentWriteTransaction,
withOpenClawAgentDatabaseAsync,
withOpenClawAgentDatabaseRuntime,
withOpenClawAgentDatabaseRuntimeFromExecution,
withOpenClawAgentDatabaseAdmission
};
}
/** The existing executor owns cold admission; the native callback retains the SDK handle contract. */
async function withWorkerAdmission(options, assertCurrent, signal, run, borrowedExecution) {
const pathname = resolveOpenClawAgentSqlitePath(options);
assertAgentCreationClaimCurrent(options);
assertAgentCreationClaimAliases(options);
const creationClaim = captureAgentCreationClaim(options);
const identity = readDatabasePathIdentitySync(pathname);
const agentId = normalizeAgentId(options.agentId);
if (borrowedExecution) {
borrowedExecution.assertCurrent();
if (borrowedExecution.agentId !== agentId || borrowedExecution.path !== pathname) throw new Error("Agent worker admission differs from its captured execution");
}
let publishAlias = identity.canonicalPath !== pathname ? captureOpenClawAgentDatabaseAliasPublication({
agentId,
path: pathname
}) : void 0;
const completion = createDeferredCore();
let revoked = false;
let releaseExecution;
const assertAdmission = () => {
if (revoked) throw new Error("Agent database admission closed during worker preparation");
assertCurrent?.();
borrowedExecution?.assertCurrent();
creationClaim?.assertCurrent();
signal?.throwIfAborted();
const current = readDatabasePathIdentitySync(pathname);
if (current.canonicalPath !== identity.canonicalPath || identity.key.startsWith("file:") && (current.key !== identity.key || current.birthtime !== identity.birthtime)) throw new Error("Agent database changed during worker preparation");
};
const unregister = registerOpenClawAgentDatabaseAsyncResource({
agentId,
path: pathname,
revoke: () => {
revoked = true;
},
close: () => completion.promise
}, options);
try {
const owner = await import("./openclaw-agent-execution-YL4WBaP9.mjs");
assertAdmission();
if (!owner.supportsOpenClawAgentDatabaseExecution(options)) return await run("native");
let execution;
if (borrowedExecution) execution = borrowedExecution;
else {
const captured = owner.captureOpenClawAgentDatabaseExecution(options, identity.key.startsWith("file:") ? { expectedIdentity: {
kind: "file",
physicalIdentity: identity.key.slice(5),
nativeLocation: identity.canonicalPath,
birthtime: identity.birthtime
} } : {});
execution = captured;
releaseExecution = () => captured.release();
}
const source = {
assertCurrent: assertAdmission,
createAdmission: (binding) => () => ({
nativeLocations: binding.nativeLocations,
admission: createSqliteWorkerOperationAdmission((request, grant) => {
binding.authorize(request);
assertAdmission();
if (publishAlias && request.stage === "prepare" && isRecord(request.facts) && request.facts.kind === "agent-validation-start") publishAlias = captureOpenClawAgentDatabaseAliasPublication({
agentId,
path: pathname
});
if (!grant()) throw new Error("Agent database preparation lost its admission");
}, binding.attachment)
})
};
await runOpenClawAgentWorkerWrite(options, () => execution.prepare(source, signal, { readmitSchema: true }));
assertAdmission();
publishAlias?.(execution.captureGenerationClaim().identity, getOpenClawAgentDatabaseValidationForTransfer({
agentId,
path: identity.canonicalPath
}));
return await run("worker");
} finally {
try {
await releaseExecution?.();
} finally {
unregister();
completion.resolve();
}
}
}
//#endregion
//#region src/state/openclaw-agent-db-opening-refusal.ts
const mainThread = isMainThread;
function classifyAgentDatabaseOpeningRefusal(error, preparedLease) {
const refused = error instanceof SqliteWorkerOpenRefusedError;
return {
deferLeaseRelease: preparedLease !== void 0 && !isMainThread && refused,
closeOutcome: refused ? "read-only" : void 0
};
}
//#endregion
//#region src/state/openclaw-agent-db.wal.ts
/** Keep the published timer's exact native owner pinned through worker settlement. */
function registerOpenClawAgentWalMaintenance(database, env) {
const options = {
agentId: database.agentId,
path: database.path,
env
};
const identity = readOpenClawAgentDatabaseIdentity(database);
if (typeof identity.identity !== "string") return;
const expectedIdentity = {
kind: "file",
physicalIdentity: identity.identity,
birthtime: identity.birthtime,
nativeLocation: identity.filename
};
const controller = new AbortController();
let pending;
let unregister;
const cancel = () => {
controller.abort();
};
const assertCurrent = () => {
controller.signal.throwIfAborted();
if (cache.databases.get(database.path) !== database || !database.db.isOpen) throw new Error("Agent WAL maintenance owner changed");
};
registerSqliteWalWorkerMaintenance(database.db, async (request) => {
if (controller.signal.aborted) return;
const release = retainAgentDatabase(database.db);
const active = runOpenClawAgentWorkerWrite(options, async () => {
assertCurrent();
unregister = registerOpenClawAgentDatabaseAsyncResource({
...options,
revoke: cancel,
async close() {
cancel();
await pending?.catch(() => {});
}
});
const { captureOpenClawAgentDatabaseExecution } = await import("./openclaw-agent-execution-YL4WBaP9.mjs");
assertCurrent();
const execution = captureOpenClawAgentDatabaseExecution(options, { expectedIdentity });
try {
const result = await execution.runExisting({
assertCurrent,
createAdmission: (binding) => () => ({
nativeLocations: binding.nativeLocations,
admission: createSqliteWorkerOperationAdmission((authority, grant) => {
binding.authorize(authority);
assertCurrent();
if (!grant()) throw new Error("Agent WAL maintenance authority expired");
}, binding.attachment)
})
}, (worker) => worker.execute({
type: "database.walMaintenance",
input: request
}));
assertCurrent();
execution.assertCurrent();
return result;
} finally {
await execution.release();
}
}, void 0, controller.signal);
pending = active;
try {
return await active;
} finally {
release();
pending = void 0;
unregister?.();
unregister = void 0;
}
}, cancel);
}
//#endregion
//#region src/state/openclaw-agent-db.ts
/** Drain the live owner before reconfirming an advisory failure in a native child. */
async function confirmOpenClawAgentDatabaseIntegrity(pathname, lifetime) {
const resolvedPath = path.resolve(pathname);
await closeOpenClawAgentDatabaseByPathAsync(resolvedPath);
invalidateOpenClawAgentDatabaseValidation(resolvedPath);
const { confirmDatabaseVerifyWorker } = await import("./openclaw-database-verify.impl-CWLbdhUw.mjs");
return confirmDatabaseVerifyWorker({
path: resolvedPath,
kind: "agent",
label: resolvedPath
}, lifetime);
}
/**
* Clear a terminal open failure after doctor rewrites the database file.
* Returns false when the persisted quarantine row survived; callers must
* surface that, or the next open re-quarantines the repaired file.
*/
function clearOpenClawAgentDatabaseOpenFailure(pathname, options = {}) {
const resolvedPath = path.resolve(pathname);
const cleared = clearOpenClawDatabaseQuarantine(resolvedPath, { env: options.env });
cache.terminal.clear(resolvedPath);
return cleared;
}
const { openOpenClawAgentDatabase, runOpenClawAgentWriteTransaction, withOpenClawAgentDatabaseAsync, withOpenClawAgentDatabaseRuntime, withOpenClawAgentDatabaseRuntimeFromExecution, withOpenClawAgentDatabaseAdmission } = createOpenClawAgentDatabaseAdmissionOwner(openOpenClawAgentDatabaseSteps);
function* openOpenClawAgentDatabaseSteps(options, pending, preparedLease, registrationObserver, repairAdmission) {
const agentId = normalizeAgentId(options.agentId);
assertAgentDatabaseAdmitted(agentId, { env: options.env });
const databaseOptions = {
...options,
agentId
};
const pathname = resolveOpenClawAgentSqlitePath(databaseOptions);
const assertCurrent = (database) => {
repairAdmission?.assertCurrent?.();
if (repairAdmission?.expectedIdentity) {
if (database) assertOpenClawAgentDatabaseIdentity(database, repairAdmission.expectedIdentity);
else assertExistingDatabaseIdentity(pathname, repairAdmission.expectedIdentity.key, repairAdmission.expectedIdentity.birthtime);
}
};
assertCurrent();
assertAgentCreationClaimCurrent(databaseOptions);
getAgentDeletionDatabaseCleanup(databaseOptions)?.assertCurrent();
const incognito = isIncognitoOpenClawAgentSqlitePath(pathname, databaseOptions);
const opened = getOpenClawAgentDatabaseIfOpen(databaseOptions);
if (opened) {
assertCurrent(opened);
if (preparedLease) throw new Error("A prepared Worker lease cannot adopt an existing agent database handle");
if (pending?.workerPrepared) adoptOpenClawAgentDatabaseSchema(opened, true, true);
return opened;
}
assertAgentDatabaseResourceAdmission({
agentId,
path: pathname
});
if (!pending) revokePendingAgentDatabaseOpen(pathname);
const cached = cache.databases.get(pathname);
const allowExtension = !process.permission && supportsNodeSqliteExtensionLoading();
if (incognito) {
assertIncognitoAgentDatabasePathAvailable(pathname);
if (cached) {
closeCachedOpenClawAgentDatabase(cached);
cache.databases.delete(pathname);
cache.failures.delete(pathname);
}
const db = openNodeSqliteDatabase(":memory:", { allowExtension });
db.enableLoadExtension(false);
if (!mainThread) {
db.exec("PRAGMA temp_store=MEMORY");
if (db.prepare("PRAGMA temp_store").get()?.temp_store !== 2) throw new Error("Incognito actor requires memory-only SQLite temporary storage");
}
configureSqlitePreSchemaPragmas(db, { busyTimeoutMs: OPENCLAW_SQLITE_BUSY_TIMEOUT_MS });
const walMaintenance = configureSqliteConnectionPragmas(db, {
busyTimeoutMs: OPENCLAW_SQLITE_BUSY_TIMEOUT_MS,
databaseLabel: `openclaw-agent-incognito:${agentId}`,
foreignKeys: true,
synchronous: "NORMAL"
});
ensureAgentSchema(db, agentId, pathname);
admitSqliteSchema(db);
assertCanonicalSessionValidationSchema(db);
registerOpenClawAgentDatabaseIdentity(db);
const database = {
agentId,
db,
path: pathname,
walMaintenance
};
cache.incognito.add(database);
cache.unregisterExitClose ??= registerSqliteCacheExitClose(closeOpenClawAgentDatabases);
cache.databases.set(pathname, database);
cache.generation += 1;
registerNodeSqliteDisposeCallback(db, retainIncognitoSharedState(options.env));
getOpenClawDatabaseMaintenanceScope()?.own(database.db, "agent-handles", () => closeMaintenanceAgentDatabase(database));
return database;
}
if (!repairAdmission?.expectedIdentity) quarantineOrphanedSqliteSidecars(pathname);
revalidateAgentDatabaseTerminalOpen(pathname);
const persistedFailure = readOpenClawDatabaseQuarantineFailure("agent", pathname, { env: databaseOptions.env });
if (persistedFailure) {
recordOpenClawAgentDatabaseOpenFailure(pathname, persistedFailure);
throw persistedFailure;
}
if (cached) {
closeCachedOpenClawAgentDatabase(cached);
cache.databases.delete(pathname);
cache.failures.delete(pathname);
}
const leaseEnvironment = {
...options.env ?? process.env,
OPENCLAW_STATE_DIR: resolveStateDir(options.env ?? process.env),
...isGatewayExternallySupervised(options.env ?? process.env) ? { OPENCLAW_SUPERVISOR_MODE: "external" } : {}
};
if (preparedLease && (preparedLease.receipt.agentId !== agentId || preparedLease.receipt.path !== pathname)) throw new Error("Prepared agent database lease belongs to another store");
let verification;
let reuseIntegrity = false;
let integrityRevoked = false;
const diagnostics = {};
const validation = pending?.validation ?? preparedLease?.validation;
const captureVerification = (record, runtimeIntegrityAllowed, invalidated, because) => {
verification = record;
reuseIntegrity = runtimeIntegrityAllowed;
integrityRevoked = invalidated;
diagnostics.because = invalidated ? because : void 0;
if (invalidated && validation) Atomics.store(new Int32Array(validation.valid), 0, 0);
};
const releaseOptions = {
env: leaseEnvironment,
initializationAgentPaths: [pathname]
};
assertCurrent();
const leaseId = preparedLease ? preparedLease.claim(captureVerification) : claimOpenClawAgentDatabaseLease({
agentId,
path: pathname,
env: leaseEnvironment
}, void 0, captureVerification);
if (pending) pending.assertHeld = () => assertOpenClawAgentDatabaseLease(leaseId, {
agentId,
path: pathname,
env: leaseEnvironment
});
const finishPhase = startAgentDatabaseOpenTiming(agentId, pathname, pending ? "async" : "sync", diagnostics);
let openedDb;
let openedDatabase;
let openedWalMaintenance;
let releaseCreationAdmission;
try {
assertCurrent();
if (!repairAdmission?.expectedIdentity) {
ensureOpenClawAgentDatabasePermissions(pathname, databaseOptions);
prepareSqliteDatabaseDirectory(pathname);
}
closeIdleOpenClawAgentDatabaseReadOnly(pathname);
const db = openNodeSqliteDatabase(repairAdmission?.expectedIdentity ? resolveExistingSqliteFileUri(pathname) : pathname, { allowExtension });
openedDb = db;
registerOpenClawAgentDatabaseIdentity(db);
assertCurrent({
db,
path: pathname
});
if (repairAdmission?.expectedIdentity) ensureOpenClawAgentDatabasePermissions(pathname, databaseOptions);
db.enableLoadExtension(false);
enableNodeSqliteKyselyStatementCache(db);
if (preparedLease) db.exec("PRAGMA temp_store = FILE");
finishPhase("open");
const validationDatabase = {
db,
path: pathname,
agentId
};
if (validation) adoptOpenClawAgentDatabaseValidation(validationDatabase, validation);
let isValidatedReopen = Boolean(getOpenClawAgentDatabaseValidation(validationDatabase));
const reuseAdmittedIntegrity = reuseIntegrity || pending?.workerPrepared === true && !integrityRevoked;
let reusedSchema = false;
let walMaintenance;
try {
db.exec(`PRAGMA busy_timeout = ${OPENCLAW_SQLITE_BUSY_TIMEOUT_MS};`);
reusedSchema = adoptOpenClawAgentDatabaseSchema(validationDatabase, reuseAdmittedIntegrity, pending?.workerPrepared);
assertSupportedAgentSchemaVersion(db, pathname);
const existingSchema = readExistingAgentSchemaMeta(db);
assertExistingAgentSchemaOwner(existingSchema, agentId, pathname);
if (reusedSchema) assertCurrentAgentSchemaMetadata(existingSchema, agentId, pathname);
if (pending) releaseCreationAdmission = reserveAgentCreationClaimAdmission(pending, databaseOptions, async () => {
await closeOpenClawAgentDatabaseByPathAsync(pathname, agentId);
});
diagnostics.integrityGateReason = resolveAgentDatabaseIntegrityGateReason(validationDatabase, {
verification,
validation,
integrityRevoked,
reuseIntegrity
});
diagnostics.because ??= integrityRevoked ? agentDatabaseAdmissionProvenanceRefusal(preparedLease?.provenance, pathname) : void 0;
if (preparedLease && !mainThread) requestSqliteWorkerOperationAdmission({
stage: "prepare",
facts: {
kind: "agent-validation-start",
lease: preparedLease.receipt
}
});
const requiresCurrentVersionConvergence = yield* agentDatabaseIntegrityBeforeMutationSteps(db, agentId, pathname, diagnostics, verification, isValidatedReopen && reuseAdmittedIntegrity, integrityRevoked && !diagnostics.because, reusedSchema, preparedLease?.deferUnverifiedIntegrity);
assertCurrent(validationDatabase);
if (!diagnostics.integrityGateOutcome || diagnostics.integrityGateOutcome === "cached") delete diagnostics.integrityGateReason;
if (isValidatedReopen && (!existingSchema || requiresCurrentVersionConvergence)) {
invalidateOpenClawAgentDatabaseValidation(pathname);
isValidatedReopen = false;
}
assertCanonicalAgentPersistenceVersion(db, pathname);
finishPhase("validation");
configureSqlitePreSchemaPragmas(db, { busyTimeoutMs: OPENCLAW_SQLITE_BUSY_TIMEOUT_MS });
walMaintenance = configureSqliteConnectionPragmas(db, {
busyTimeoutMs: OPENCLAW_SQLITE_BUSY_TIMEOUT_MS,
databaseLabel: `openclaw-agent:${agentId}`,
databasePath: pathname,
foreignKeys: true,
synchronous: "NORMAL"
});
openedWalMaintenance = walMaintenance;
finishPhase("configuration");
assertCurrent(validationDatabase);
if (!isValidatedReopen) ensureAgentSchema(db, agentId, pathname);
finishPhase("schema");
} catch (err) {
if (diagnostics.integrityGateOutcome === "failed") finishPhase("validation");
openedWalMaintenance?.close();
if (db.isOpen) db.close();
const current = cache.databases.get(pathname);
if (!current || current.db === db) invalidateOpenClawAgentDatabaseValidation(pathname);
if (err instanceof Error && (isSqliteSchemaVersionError(err) || isTerminalSqliteIntegrityError(err))) recordOpenClawAgentDatabaseOpenFailure(pathname, err);
throw err;
}
assertCurrent({
db,
path: pathname
});
ensureOpenClawAgentDatabasePermissions(pathname, databaseOptions);
if (!reusedSchema) {
admitSqliteSchema(db);
assertCanonicalSessionValidationSchema(db);
}
const database = {
agentId,
db,
path: pathname,
walMaintenance
};
openedDatabase = database;
if (hasAgentDatabaseMaintenanceAuthority()) throw new Error("Agent database maintenance is in progress; retry after openclaw doctor --fix completes.");
registerAgentDeletionDatabaseCleanup(database, databaseOptions)?.registerClose(createAgentDatabaseScopeOwnedClose(database, "Agent deletion cleanup"));
registerAgentCreationClaimHandle(database, databaseOptions)?.registerClose(createAgentDatabaseScopeOwnedClose(database, "Agent creation claim"));
if (!isValidatedReopen || !hasOpenClawAgentDatabaseValidationSpelling(pathname)) {
assertCurrent(database);
registerOpenClawAgentDatabase({
agentId,
path: pathname,
env: options.env,
admittedDb: db
}, registrationObserver);
} else if (!reusedSchema) publishOpenClawAgentDatabaseSchema(database);
cache.terminal.clear(pathname);
cache.unregisterExitClose ??= registerSqliteCacheExitClose(closeOpenClawAgentDatabases);
finishPhase("registration");
const deferred = diagnostics.integrityGateMode === "deferred";
registerAgentDatabaseHandle(database, leaseId, leaseEnvironment, deferred);
const identity = readOpenClawAgentDatabaseIdentity(database).identity;
assertCurrent(database);
if (deferred || diagnostics.integrityGateOutcome === "cached" && !(isValidatedReopen && reuseIntegrity)) {
const check = deferred ? "full" : "quick";
if (preparedLease) requestSqliteWorkerOperationAdmission({
stage: "prepare",
facts: {
kind: "agent-integrity-check",
lease: preparedLease.receipt,
check
}
});
else requestOpenClawAgentDatabaseIntegrityCheck({
path: pathname,
env: leaseEnvironment,
check
});
}
if (typeof identity === "string") recordOpenClawAgentDatabaseAdmission(leaseId, {
agentId,
path: pathname,
env: leaseEnvironment
}, identity, !deferred && diagnostics.integrityGateOutcome !== "cached");
refreshAgentDatabaseIdleTimer(database);
if (mainThread) registerOpenClawAgentWalMaintenance(database, leaseEnvironment);
getOpenClawDatabaseMaintenanceScope()?.own(database.db, "agent-handles", () => closeMaintenanceAgentDatabase(database));
releaseCreationAdmission?.();
return database;
} catch (error) {
const refusal = classifyAgentDatabaseOpeningRefusal(error, preparedLease);
let closeError;
if (openedDatabase) try {
closeCachedOpenClawAgentDatabase(openedDatabase);
} catch (caught) {
closeError = caught;
}
if (openedDb?.isOpen) {
if (pending && cache.databases.has(pathname) && cache.databases.get(pathname)?.db !== openedDb) {
const retainedDb = openedDb;
retainFailedAgentDatabaseClose(agentId, pathname, () => {
openedWalMaintenance?.close();
if (retainedDb.isOpen) retainedDb.close();
releaseOpenClawAgentDatabaseLease(leaseId, releaseOptions);
});
throw error;
}
invalidateOpenClawAgentDatabaseValidation(pathname);
const retainedDatabase = openedDatabase ?? {
agentId,
db: openedDb,
path: pathname,
walMaintenance: openedWalMaintenance ?? {
checkpoint: () => false,
stop: async () => {},
reclaimFreePages: createSqliteWalReclamationResult,
close: () => false
}
};
cache.databases.set(pathname, retainedDatabase);
refreshAgentDatabaseIdleTimer(retainedDatabase);
cache.leases.set(pathname, {
leaseId,
env: leaseEnvironment
});
cache.failures.set(pathname, closeError ?? error);
getOpenClawDatabaseMaintenanceScope()?.own(retainedDatabase.db, "agent-handles", () => closeMaintenanceAgentDatabase(retainedDatabase));
cache.unregisterExitClose ??= registerSqliteCacheExitClose(closeOpenClawAgentDatabases);
} else if (!refusal.deferLeaseRelease) try {
releaseOpenClawAgentDatabaseLease(leaseId, releaseOptions, refusal.closeOutcome);
} catch (releaseError) {
retainFailedAgentDatabaseClose(agentId, pathname, () => releaseOpenClawAgentDatabaseLease(leaseId, releaseOptions, refusal.closeOutcome));
throw releaseError;
}
throw closeError ?? error;
}
}
/** Retain the exact verified connection across awaits; explicit disposal still revokes it. */
function borrowOpenClawAgentDatabase(options) {
const { db } = openOpenClawAgentDatabase(options);
return {
db,
release: retainAgentDatabase(db)
};
}
function isOpenClawAgentDatabaseOpen(pathname) {
return cache.databases.get(path.resolve(pathname))?.db.isOpen === true;
}
/** Return the matching live cache entry without materializing a database. */
function getOpenClawAgentDatabaseIfOpen(options) {
const agentId = normalizeAgentId(options.agentId);
assertAgentDatabaseAdmitted(agentId, { env: options.env });
const pathname = resolveOpenClawAgentSqlitePath({
...options,
agentId
});
if (isIncognitoOpenClawAgentSqlitePath(pathname, options) && readAgentDeletionJournal(agentId, { env: options.env }, "runtime")) throw new Error(`OpenClaw agent database is unavailable while agent ${agentId} is deleted.`);
const database = cache.databases.get(pathname);
if (!database?.db.isOpen) {
assertAgentDeletionCleanupAliases(options, isSameOpenClawAgentDatabasePath);
assertAgentCreationClaimAliases(options);
return;
}
if (cache.failures.has(pathname)) throw cache.failures.get(pathname);
if (database.agentId !== agentId) throw new Error(`OpenClaw agent database ${pathname} is already open for agent ${database.agentId}; requested agent ${agentId}.`);
assertAgentDeletionDatabaseCleanupAccess(database, options);
assertAgentCreationClaimAccess(database, options);
observeOpenClawDatabaseMaintenanceResource(database.db);
refreshAgentDatabaseIdleTimer(database);
return database;
}
/** Pin only admitted native readers already present in captured discovery families. */
function retainOpenClawAgentDatabaseReadCandidates(candidates, env) {
const retained = [];
const release = () => {
for (const reader of retained.toReversed()) reader.release();
};
try {
for (const database of cache.databases.values()) {
if (!database.db.isOpen || database.db.isTransaction || cache.incognito.has(database) || !candidates.some((candidate) => matchesAgentDatabaseReadCandidatePath(candidate, database.path))) continue;
let admitted;
try {
admitted = getOpenClawAgentDatabaseIfOpen({
agentId: database.agentId,
path: database.path,
env
});
} catch {
continue;
}
if (admitted === database) retained.push({
database,
release: retainAgentDatabase(database.db)
});
}
return {
databases: retained.map(({ database }) => database),
release
};
} catch (error) {
release();
throw error;
}
}
//#endregion
export { isOpenClawAgentDatabaseOpen as a, runOpenClawAgentWriteTransaction as c, withOpenClawAgentDatabaseRuntime as d, withOpenClawAgentDatabaseRuntimeFromExecution as f, getOpenClawAgentDatabaseIfOpen as i, withOpenClawAgentDatabaseAdmission as l, clearOpenClawAgentDatabaseOpenFailure as n, openOpenClawAgentDatabase as o, confirmOpenClawAgentDatabaseIntegrity as r, retainOpenClawAgentDatabaseReadCandidates as s, borrowOpenClawAgentDatabase as t, withOpenClawAgentDatabaseAsync as u };