openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
93 lines (92 loc) • 5.05 kB
JavaScript
import { r as resolveRealpathOrAbsolute } from "./boundary-path-CAv_plX7.mjs";
import { u as getOpenClawDatabaseMaintenanceScope } from "./openclaw-state-db-async-lifecycle-DwFy2ZTk.mjs";
import { n as ok, t as err } from "./result-BQGgYouL.mjs";
import { a as resolveSessionArtifactDirectory } from "./paths-Bonddxfk.mjs";
import { r as isMigrationArchiveArtifactName } from "./artifacts-C6u8F4sP.mjs";
import { r as listDurableSqliteTargetPathsForSessionStorePath } from "./session-sqlite-target-Dd3VSz82.mjs";
import { t as runTasksWithConcurrency } from "./run-with-concurrency-Dtu208ef.mjs";
import fs from "node:fs";
import path from "node:path";
//#region src/config/sessions/disk-budget-files.ts
const SESSIONS_DIR_STAT_CONCURRENCY = 8;
async function removeFileIfExists(filePath) {
const stat = await fs.promises.stat(filePath).catch(() => null);
if (!stat?.isFile()) return err("not-removed");
getOpenClawDatabaseMaintenanceScope()?.assertAdmission();
return fs.promises.rm(filePath).then(() => ok(stat.size), () => err("not-removed"));
}
async function readSessionFileStat(filePath) {
const stat = await fs.promises.stat(filePath).catch(() => null);
return stat?.isFile() ? {
path: filePath,
canonicalPath: resolveRealpathOrAbsolute(filePath),
name: path.basename(filePath),
size: stat.size,
mtimeMs: stat.mtimeMs
} : null;
}
async function readSessionsDirFiles(sessionsDir) {
const tasks = (await fs.promises.readdir(sessionsDir, { withFileTypes: true }).catch(() => [])).filter((dirent) => dirent.isFile() && !isMigrationArchiveArtifactName(dirent.name)).map((dirent) => () => readSessionFileStat(path.join(sessionsDir, dirent.name)));
const { results } = await runTasksWithConcurrency({
tasks,
limit: SESSIONS_DIR_STAT_CONCURRENCY
});
return results.filter((file) => Boolean(file));
}
async function readSqliteDatabaseFiles(databasePaths) {
const files = [];
for (const databasePath of databasePaths) for (const filePath of [databasePath, `${databasePath}-wal`]) {
const file = await readSessionFileStat(filePath);
if (file) files.push(file);
}
return files;
}
/** Measures current physical session artifacts plus the agent SQLite main file and WAL. */
async function readSessionPhysicalDiskUsage(storePath) {
const sessionsDir = resolveSessionArtifactDirectory(storePath);
const sessionsDirFiles = await readSessionsDirFiles(sessionsDir);
const coldArchiveFiles = await readSessionsDirFiles(path.join(sessionsDir, "cold"));
const promptBlobFiles = await readSessionPromptBlobFiles(sessionsDir);
const databasePaths = listDurableSqliteTargetPathsForSessionStorePath(storePath);
const databaseFiles = await readSqliteDatabaseFiles(databasePaths);
const databaseSharedMemoryPaths = new Set(databasePaths.map((databasePath) => resolveRealpathOrAbsolute(`${databasePath}-shm`)));
const databaseMainPaths = new Set(databaseFiles.filter((file) => !file.path.endsWith("-wal")).map((file) => file.canonicalPath));
const databaseWalPaths = new Set(databaseFiles.filter((file) => file.path.endsWith("-wal")).map((file) => file.canonicalPath));
const uniqueFiles = /* @__PURE__ */ new Map();
for (const file of [
...sessionsDirFiles,
...coldArchiveFiles,
...promptBlobFiles,
...databaseFiles
]) if (!databaseSharedMemoryPaths.has(file.canonicalPath)) uniqueFiles.set(file.canonicalPath, file);
const databaseMainBytes = [...databaseMainPaths].reduce((sum, databasePath) => sum + (uniqueFiles.get(databasePath)?.size ?? 0), 0);
const databaseWalBytes = [...databaseWalPaths].reduce((sum, databasePath) => sum + (uniqueFiles.get(databasePath)?.size ?? 0), 0);
const totalBytes = [...uniqueFiles.values()].reduce((sum, file) => sum + file.size, 0);
return {
databaseMainBytes,
databaseWalBytes,
sessionFilesBytes: totalBytes - databaseMainBytes - databaseWalBytes,
totalBytes
};
}
async function readSessionPromptBlobFiles(sessionsDir) {
const root = path.join(sessionsDir, "skills-prompts", "sha256");
const prefixEntries = await fs.promises.readdir(root, { withFileTypes: true }).catch(() => []);
const files = [];
for (const prefixEntry of prefixEntries) {
if (!prefixEntry.isDirectory() || !/^[a-f0-9]{2}$/u.test(prefixEntry.name)) continue;
const prefixDir = path.join(root, prefixEntry.name);
const blobEntries = await fs.promises.readdir(prefixDir, { withFileTypes: true }).catch(() => []);
for (const blobEntry of blobEntries) {
if (!blobEntry.isFile() || !/^[a-f0-9]{64}\.txt$/u.test(blobEntry.name) && !isSessionPromptBlobTempArtifactName(blobEntry.name)) continue;
const file = await readSessionFileStat(path.join(prefixDir, blobEntry.name));
if (file) files.push(file);
}
}
return files;
}
function isSessionPromptBlobTempArtifactName(name) {
return /^[a-f0-9]{64}\.txt\.(?:\d+\.)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.tmp$/u.test(name);
}
//#endregion
export { removeFileIfExists as a, readSessionsDirFiles as i, readSessionPhysicalDiskUsage as n, readSessionPromptBlobFiles as r, isSessionPromptBlobTempArtifactName as t };