openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
103 lines (102 loc) • 7.26 kB
JavaScript
import { o as resolveUserPath } from "./home-dir-Dc6nN6HB.mjs";
import { t as hasErrnoCode } from "./errno-FR4CRyya.mjs";
import { r as isPathInside } from "./path-guards-CH7noY0Z.mjs";
import { r as resolveStateDir } from "./state-dir-BHJORNly.mjs";
import "./paths-DGIwWbpu.mjs";
import { c as resolveOpenClawStateSqlitePath } from "./openclaw-state-db.paths-DfifnSGp.mjs";
import { a as resolveSqliteDatabaseFilePaths } from "./sqlite-files-BEC3zbaw.mjs";
import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs";
import { t as executeExistingOpenClawStateRead } from "./openclaw-state-db-readonly-CC57AD_q.mjs";
import "./session-key-C09ow4h0.mjs";
import { a as isPersistentOpenClawAgentDatabasePath, c as resolveOpenClawAgentSqlitePath, r as createOpenClawAgentDatabasePathMatcher } from "./openclaw-agent-db.paths-DVbbFaej.mjs";
import { w as resolveUnsuffixedSqliteTargetFromSessionStorePath } from "./openclaw-state-db-D1jWDzK3.mjs";
import { r as readAgentDatabaseDeletionSnapshot } from "./agent-deletion-journal.read-Bkjt0nDs.mjs";
import fs from "node:fs";
import path from "node:path";
//#region src/state/agent-deletion-discovery.ts
/** Read completed retained identities through the shared-state worker. */
async function listRetainedDeletedAgentIdsForCleanup(env) {
const reply = await executeExistingOpenClawStateRead({ env }, {
type: "agentDatabaseDeletion.snapshot",
purpose: "runtime"
});
if (reply && (!reply.ok || reply.type !== "agentDatabaseDeletion.snapshot")) throw new Error("Retained agent deletion read failed during plugin cleanup.");
const retained = reply?.snapshot.retainedDeletions;
return new Set(retained?.status === "present" ? retained.entries.map((entry) => entry.agentId) : []);
}
function hasSqliteFileFamily(pathname) {
return resolveSqliteDatabaseFilePaths(pathname).some((file) => fs.lstatSync(file, { throwIfNoEntry: false }) !== void 0);
}
function hasSqliteArtifacts(directory) {
try {
return fs.readdirSync(directory).some((name) => /\.(?:sqlite3?|db)(?:-(?:wal|shm|journal))?$/iu.test(name));
} catch (error) {
if (!hasErrnoCode(error, "ENOENT")) throw error;
return fs.lstatSync(directory, { throwIfNoEntry: false }) !== void 0;
}
}
/** Recorded surviving owners can share retained files; directory-name inference cannot. */
function createAgentDatabaseDeletionClassifier(params) {
const artifactDirectories = params.artifactDirectories;
const journal = params.retainedDeletions;
const known = journal.status === "present" ? journal : journal.status === "unavailable" ? journal.known : void 0;
const entries = known?.entries ?? [];
const unknown = journal.status === "unavailable" ? "unavailable" : void 0;
const samePath = createOpenClawAgentDatabasePathMatcher();
const recorded = artifactDirectories ?? [...params.configuredAgentDatabaseTargets, ...params.registeredAgentDatabases];
const heldPaths = !known ? [] : artifactDirectories ? known.held.flatMap((entry) => {
const defaultDirectory = path.dirname(resolveOpenClawAgentSqlitePath({
agentId: entry.agentId,
env: params.env
}));
const recordedDirectory = path.dirname(entry.path);
const canonicalAgentFile = path.basename(entry.path) === "openclaw-agent.sqlite";
const directories = [{
agentId: entry.agentId,
path: defaultDirectory
}, ...artifactDirectories.filter((directory) => normalizeAgentId(directory.agentId) === entry.agentId || canonicalAgentFile && samePath(directory.path, recordedDirectory))];
if (canonicalAgentFile && [params.env.OPENCLAW_AGENT_DIR, params.env.PI_CODING_AGENT_DIR].some((directory) => directory?.trim() && samePath(resolveUserPath(directory, params.env), recordedDirectory)) || canonicalAgentFile && path.basename(recordedDirectory) === "agent" && samePath(path.dirname(path.dirname(recordedDirectory)), path.dirname(path.dirname(defaultDirectory)))) directories.push({
agentId: entry.agentId,
path: recordedDirectory
});
return directories;
}) : known.held;
return (pathname, agentId) => {
let logicalTargets = [];
if (!artifactDirectories && agentId !== void 0) {
const ownerId = normalizeAgentId(agentId);
logicalTargets = params.configuredAgentDatabaseTargets.filter((target) => normalizeAgentId(target.agentId) === ownerId);
if (logicalTargets.length === 0) logicalTargets = [...params.registeredAgentDatabases.filter((target) => normalizeAgentId(target.agentId) === ownerId), {
agentId: ownerId,
path: resolveUnsuffixedSqliteTargetFromSessionStorePath(pathname).path
}];
}
if (heldPaths.some((entry) => artifactDirectories && entry.agentId === agentId || samePath(entry.path, pathname) || logicalTargets.some((target) => samePath(target.path, entry.path)))) return "held";
const deletion = entries.find((entry) => entry.agentId === agentId || (artifactDirectories ? [entry.agentDir] : entry.databasePaths).some((file) => samePath(file, pathname)));
if (!deletion) return unknown;
const surviving = recorded.some((target) => !entries.some((entry) => entry.agentId === normalizeAgentId(target.agentId)) && samePath(target.path, pathname) && (artifactDirectories !== void 0 || isPersistentOpenClawAgentDatabasePath(target.path, params.env) && (params.configuredAgentDatabaseTargets.includes(target) || isPathInside(fs.realpathSync.native(resolveStateDir(params.env)), fs.realpathSync.native(target.path)))));
return agentId === deletion.agentId || !surviving ? deletion : unknown;
};
}
function createRetainedAgentDatabaseMatcher(env, readConfiguredTargets, namespace = "database", purpose = "maintenance") {
return createRetainedAgentDatabaseMatcherFromSnapshot(env, readConfiguredTargets, readAgentDatabaseDeletionSnapshot(env, purpose), namespace, purpose);
}
function createRetainedAgentDatabaseMatcherFromSnapshot(env, readConfiguredTargets, snapshot, namespace = "database", purpose = "maintenance") {
const agentDirectories = namespace !== "database" && namespace.kind === "agent-directory";
if (!snapshot && namespace !== "database" && purpose === "maintenance") {
const unavailable = [resolveOpenClawStateSqlitePath(env), ...namespace.readDatabasePaths()].some(hasSqliteFileFamily) || agentDirectories && readConfiguredTargets().some((target) => hasSqliteArtifacts(target.path));
return (pathname, _agentId) => unavailable || agentDirectories && hasSqliteArtifacts(pathname) ? "unavailable" : void 0;
}
const retainedDeletions = snapshot?.retainedDeletions;
if (!retainedDeletions || retainedDeletions.status !== "present" && !(retainedDeletions.status === "unavailable" && retainedDeletions.known)) return (_pathname, _agentId) => purpose === "maintenance" && (!retainedDeletions || retainedDeletions.status === "unavailable") ? "unavailable" : void 0;
const configured = readConfiguredTargets();
return createAgentDatabaseDeletionClassifier({
env,
retainedDeletions,
configuredAgentDatabaseTargets: configured,
artifactDirectories: agentDirectories ? configured : void 0,
registeredAgentDatabases: snapshot?.registeredAgentDatabases ?? []
});
}
//#endregion
export { listRetainedDeletedAgentIdsForCleanup as a, hasSqliteFileFamily as i, createRetainedAgentDatabaseMatcher as n, createRetainedAgentDatabaseMatcherFromSnapshot as r, createAgentDatabaseDeletionClassifier as t };