UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

67 lines (66 loc) • 3.93 kB
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; import { w as tryResolveConfiguredAgentWorkspaceDir } from "./agent-scope-config-BU4qc9bA.mjs"; import { t as resolveDefaultAgentWorkspaceDir } from "./workspace-default-path-BG9KN4ds.mjs"; import "./workspace-default-CQbD5G-j.mjs"; import { n as isUpdateRehearsalReadOnlyPath, r as resolveUpdateRehearsalRoot } from "./update-rehearsal-paths-C4PfIK1q.mjs"; import path from "node:path"; //#region src/plugins/doctor-migration-resources.ts /** Select one whole-plugin data scope for both rehearsal inventory and execution. */ async function preparePluginDoctorMigrationResources(entries, params) { const rehearsalRoot = resolveUpdateRehearsalRoot(params.env); const resources = /* @__PURE__ */ new Map(); const pluginResources = /* @__PURE__ */ new Map(); for (const { pluginId, migration } of entries) { if (migration.collectBackupResources === void 0) { if (!params.warnings.some((warning) => warning.pluginId === pluginId)) params.warnings.push({ kind: "undeclared-migration-resources", pluginId, message: `${pluginId} migration declares no data resources; its private state is not in the recovery set` }); continue; } const resolved = await migration.collectBackupResources({ config: params.config, env: params.env, stateDir: params.stateDir, serviceWorkspaceDir: tryResolveConfiguredAgentWorkspaceDir(params.config, params.env) ?? resolveDefaultAgentWorkspaceDir(params.env), ...params.requireLocalResources ? { requireLocalResources: true } : {} }); if (!Array.isArray(resolved)) throw new Error(`Invalid migration backup inventory from ${pluginId}/${migration.id}`); const candidates = resolved; for (const resource of candidates) { if (!isMigrationBackupResource(resource)) throw new Error(`Invalid migration backup resource from ${pluginId}/${migration.id}`); const resourcePath = resource.path; const previous = resources.get(resourcePath); if (previous && previous.kind !== resource.kind) throw new Error(`Conflicting migration backup resource kinds for ${resourcePath}`); resources.set(resourcePath, { path: resourcePath, kind: resource.kind }); const paths = pluginResources.get(pluginId) ?? /* @__PURE__ */ new Set(); paths.add(resourcePath); pluginResources.set(pluginId, paths); } } const deferredPluginIds = new Set(rehearsalRoot ? [...pluginResources].flatMap(([pluginId, paths]) => [...paths].some((file) => isUpdateRehearsalReadOnlyPath(file, params.env)) ? [pluginId] : []) : []); const selectedPaths = /* @__PURE__ */ new Set(); for (const [pluginId, paths] of pluginResources) if (!deferredPluginIds.has(pluginId)) for (const resourcePath of paths) selectedPaths.add(resourcePath); const selectedResources = [...resources.values()].filter((resource) => selectedPaths.has(resource.path)).toSorted((left, right) => left.path.localeCompare(right.path)); const assertCurrent = () => { if (!rehearsalRoot) return; if (resolveUpdateRehearsalRoot(params.env) !== rehearsalRoot) throw new Error("Plugin migration rehearsal scope changed during preparation"); for (const resource of selectedResources) if (isUpdateRehearsalReadOnlyPath(resource.path, params.env)) throw new Error(`Plugin migration data escaped the rehearsal root: ${resource.path}`); }; assertCurrent(); return { resources: selectedResources, deferredPluginIds, notices: [...deferredPluginIds].map((pluginId) => `rehearsal: ${pluginId} state migrations deferred; declared data outside the rehearsal root left untouched`), assertCurrent }; } function isMigrationBackupResource(value) { return isRecord(value) && typeof value.path === "string" && path.isAbsolute(value.path) && path.normalize(value.path) === value.path && (value.kind === "sqlite" || value.kind === "file" || value.kind === "directory"); } //#endregion export { preparePluginDoctorMigrationResources as t };