UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

92 lines (91 loc) • 4.27 kB
import { n as resolvePathViaExistingAncestorSync } from "./boundary-path-CAv_plX7.mjs"; import { l as getOpenClawDatabaseMaintenanceScope } from "./openclaw-state-db-async-lifecycle-DLKxSPCk.mjs"; import { c as resolveOpenClawStateSqlitePath } from "./openclaw-state-db.paths-DfifnSGp.mjs"; import { a as resolveSqliteDatabaseFilePaths } from "./sqlite-files-BEC3zbaw.mjs"; import { i as resolveUpdateRehearsalRoot } from "./update-rehearsal-paths-DTVdt0cq.mjs"; import { t as createRehearsalPathInspector } from "./doctor-update-rehearsal-paths-Bu_Z53RK.mjs"; import { lstatSync, realpathSync } from "node:fs"; import path from "node:path"; //#region src/commands/doctor-rehearsal-databases.ts /** Only core images in Doctor's currently owned disposable namespace need no second backup. */ function createDoctorRehearsalDatabaseCoverage(env) { const root = resolveUpdateRehearsalRoot(env); const maintenance = getOpenClawDatabaseMaintenanceScope(); if (!root || !maintenance?.ownsSchemaMaintenance) return; maintenance.assertAdmission(); maintenance.assertDatabaseAccess(resolveOpenClawStateSqlitePath(env)); const inspect = (pathname) => { const inspector = createRehearsalPathInspector(root, []); const stat = inspector.inspectPath(pathname); const identities = /* @__PURE__ */ new Map(); for (const filename of inspector.identities.keys()) { const identity = lstatSync(filename, { bigint: true }); if (identity.dev === 0n || identity.ino === 0n) throw new Error(`Disposable database identity is unavailable: ${filename}`); identities.set(filename, identity); } if (!stat) identities.set(pathname, void 0); return { stat, identities }; }; let rootIdentity; try { if (path.resolve(root) !== root || realpathSync(root) !== root || !inspect(root).stat?.isDirectory()) return; rootIdentity = lstatSync(root, { bigint: true }); } catch { return; } const identities = /* @__PURE__ */ new Map([[root, rootIdentity]]); const databases = /* @__PURE__ */ new Set(); const family = /* @__PURE__ */ new Set(); const aliases = /* @__PURE__ */ new Map(); const assertCurrent = () => { maintenance.assertAdmission(); maintenance.assertDatabaseAccess(resolveOpenClawStateSqlitePath(env)); if (resolveUpdateRehearsalRoot(env) !== root || realpathSync(root) !== root) throw new Error("Disposable Doctor database namespace changed"); for (const [filename, before] of identities) { const { identities: current } = inspect(filename); const after = current.get(filename); if (before ? !after || after.dev !== before.dev || after.ino !== before.ino : after !== void 0) throw new Error(`Disposable Doctor database identity changed: ${filename}`); } for (const [filename, target] of aliases) if (resolvePathViaExistingAncestorSync(filename) !== target) throw new Error(`Disposable Doctor database alias changed: ${filename}`); }; return { assertCurrent, /** Call with the complete core discovery, never arbitrary plugin declarations. */ admit(paths) { assertCurrent(); for (const filename of paths) { if (databases.has(filename)) continue; const captured = /* @__PURE__ */ new Map(); try { if (!inspect(filename).stat?.isFile() || realpathSync(filename) !== filename) continue; for (const companion of resolveSqliteDatabaseFilePaths(filename)) { const inspected = inspect(companion); if (inspected.stat && !inspected.stat.isFile()) throw new Error(`Disposable database companion is not a regular file: ${companion}`); for (const [entry, identity] of inspected.identities) captured.set(entry, identity); } } catch { continue; } for (const [entry, identity] of captured) identities.set(entry, identity); databases.add(filename); for (const companion of resolveSqliteDatabaseFilePaths(filename)) family.add(companion); } assertCurrent(); return [...databases]; }, excludes(filename) { const target = resolvePathViaExistingAncestorSync(filename); if (!family.has(target)) return false; if (target !== filename && !aliases.has(filename)) aliases.set(filename, target); return true; }, get paths() { return [...family].toSorted(); } }; } //#endregion export { createDoctorRehearsalDatabaseCoverage as t };