UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

212 lines (211 loc) • 10.1 kB
import { o as resolveUserPath } from "./home-dir-Dc6nN6HB.mjs"; import "./utils-DgZn2dLu.mjs"; import { r as isPathInside } from "./path-guards-CH7noY0Z.mjs"; import { o as parseRegistryNpmSpec } from "./npm-registry-spec-Dw2vyAJw.mjs"; import { a as safeRealpathSync } from "./path-safety-6KJ2Rbnw.mjs"; import { r as resolveInstalledPluginIndexInstallOwner, t as isInstalledPluginIndexInstallOwnerAmbiguous } from "./installed-plugin-index-install-owner-CQJv99I6.mjs"; import path from "node:path"; //#region src/plugins/installed-plugin-package-ownership.ts function collectDuplicateInstallRecordOwners(index, env, realpathCache) { const ownersByPath = /* @__PURE__ */ new Map(); const duplicateOwners = /* @__PURE__ */ new Set(); for (const [installOwner, record] of Object.entries(index.installRecords)) { const rawPath = record.installPath?.trim() || record.sourcePath?.trim(); if (!rawPath) continue; const resolved = path.resolve(resolveUserPath(rawPath, env)); const pathKey = safeRealpathSync(resolved, realpathCache) ?? resolved; const existingOwner = ownersByPath.get(pathKey); if (existingOwner && existingOwner !== installOwner) { duplicateOwners.add(existingOwner); duplicateOwners.add(installOwner); } ownersByPath.set(pathKey, installOwner); } return duplicateOwners; } function ownershipError(pluginId, detail) { return { ok: false, error: `Plugin "${pluginId}" ${detail}. Package maintenance requires an unambiguous install record and its discovered package owner. Refresh the plugin registry and run openclaw plugins doctor to inspect the install record before retrying.` }; } function createInstalledPluginOwnershipResolver(index, env = process.env) { const targets = /* @__PURE__ */ new Map(); const childrenByOwner = /* @__PURE__ */ new Map(); for (const entry of index.plugins) { if (!targets.has(entry.pluginId)) targets.set(entry.pluginId, entry); const installOwner = resolveInstalledPluginIndexInstallOwner(entry); if (installOwner) { const children = childrenByOwner.get(installOwner) ?? []; children.push(entry.pluginId); childrenByOwner.set(installOwner, children); } } for (const children of childrenByOwner.values()) children.sort(); function resolveShadowedInstallOwner(target) { if (Object.hasOwn(index.installRecords, target.pluginId)) return target.pluginId; const childSeparator = target.pluginId.lastIndexOf("/"); if (childSeparator <= 0) return; const parentId = target.pluginId.slice(0, childSeparator); const record = index.installRecords[parentId]; const spec = record?.resolvedSpec ?? record?.spec; const packageName = record?.resolvedName ?? (spec ? parseRegistryNpmSpec(spec)?.name : void 0) ?? record?.clawhubPackage; return target.packageName && packageName === target.packageName ? parentId : void 0; } const updateTargets = new Map(targets); for (const target of targets.values()) if (target.origin === "config" && !resolveInstalledPluginIndexInstallOwner(target)) { const owner = resolveShadowedInstallOwner(target); if (owner && !updateTargets.has(owner)) updateTargets.set(owner, target); } const realpathCache = /* @__PURE__ */ new Map(); let duplicateOwners; const duplicates = () => duplicateOwners ??= collectDuplicateInstallRecordOwners(index, env, realpathCache); const unsafeOwners = /* @__PURE__ */ new Map(); const matchesPluginRoot = createInstallRecordPathMatcher(env, realpathCache); function resolvePackage(pluginId) { const target = targets.get(pluginId); if (target && isInstalledPluginIndexInstallOwnerAmbiguous(target)) return ownershipError(pluginId, "has ambiguous package ownership"); const ownerFromTarget = target ? resolveInstalledPluginIndexInstallOwner(target) : void 0; if (target && !ownerFromTarget) return ownershipError(pluginId, "has no authoritative package-owner metadata"); const ownerFromRecord = Object.hasOwn(index.installRecords, pluginId) ? pluginId : void 0; const installOwner = ownerFromTarget ?? ownerFromRecord; if (!installOwner) return ownershipError(pluginId, "is not associated with a tracked package install"); if (ownerFromTarget && ownerFromRecord && ownerFromTarget !== ownerFromRecord) return ownershipError(pluginId, "matches conflicting package owners"); const installRecord = index.installRecords[installOwner]; if (!installRecord) return ownershipError(pluginId, `references missing package owner "${installOwner}"`); if (duplicates().has(installOwner)) return ownershipError(pluginId, `shares package path ownership with "${installOwner}"`); const [firstPluginId, ...remainingPluginIds] = childrenByOwner.get(installOwner) ?? []; if (!firstPluginId) return ownershipError(pluginId, `package owner "${installOwner}" has no authoritative runtime child list`); const pluginIds = [firstPluginId, ...remainingPluginIds]; const hasUnsafePackageEntry = unsafeOwners.get(installOwner) ?? index.plugins.some((entry) => matchesPluginRoot(installRecord, entry.rootDir) && resolveInstalledPluginIndexInstallOwner(entry) !== installOwner); unsafeOwners.set(installOwner, hasUnsafePackageEntry); if (hasUnsafePackageEntry) return ownershipError(pluginId, `package owner "${installOwner}" has conflicting child rows`); return { ok: true, value: { installOwner, installRecord, pluginIds } }; } function resolveLifecycle(pluginId) { const ownership = resolvePackage(pluginId); if (ownership.ok) return { ok: true, value: { kind: "package", ...ownership.value } }; const installRecord = index.installRecords[pluginId]; if (!Object.hasOwn(index.installRecords, pluginId) || !installRecord || duplicates().has(pluginId)) return ownership; if (index.plugins.some((entry) => entry.pluginId === pluginId || matchesPluginRoot(installRecord, entry.rootDir))) return ownership; return { ok: true, value: { kind: "orphan", installOwner: pluginId, installRecord, pluginIds: [] } }; } function resolveUpdate(pluginId) { const target = updateTargets.get(pluginId); const shadowedInstallOwner = target ? resolveShadowedInstallOwner(target) : void 0; if (target?.origin === "config" && !isInstalledPluginIndexInstallOwnerAmbiguous(target) && !resolveInstalledPluginIndexInstallOwner(target) && (!shadowedInstallOwner || !duplicates().has(shadowedInstallOwner))) { const record = shadowedInstallOwner ? index.installRecords[shadowedInstallOwner] : void 0; return { ok: true, value: { kind: "operator-managed", pluginIds: [target.pluginId], source: target.source, rootDir: target.rootDir, shadowedInstallOwner, ...record ? { shadowedInstallRecord: { source: record.source, spec: record.spec, installPath: record.installPath, sourcePath: record.sourcePath } } : {} } }; } return resolveLifecycle(pluginId); } function resolveReload(pluginId) { const target = targets.get(pluginId); if (target && !isInstalledPluginIndexInstallOwnerAmbiguous(target) && !resolveInstalledPluginIndexInstallOwner(target) && !Object.hasOwn(index.installRecords, pluginId) && !Object.values(index.installRecords).some((record) => matchesPluginRoot(record, target.rootDir))) return { ok: true, value: { kind: "discovered", pluginIds: [pluginId] } }; return resolveLifecycle(pluginId); } function isSourceInUse(sourcePath, loadPaths) { return isPluginSourcePathInUse(sourcePath, [ ...loadPaths, ...Object.values(index.installRecords).flatMap((record) => [record.installPath, record.sourcePath]), ...index.plugins.flatMap((entry) => [ entry.rootDir, entry.source, entry.manifestPath ]) ], env); } return { resolvePackage, resolveLifecycle, resolveUpdate, resolveReload, isSourceInUse }; } function isPluginSourcePathInUse(sourcePath, paths, env = process.env) { const realpathCache = /* @__PURE__ */ new Map(); const target = safeRealpathSync(sourcePath, realpathCache) ?? path.resolve(sourcePath); return paths.some((candidate) => { if (!candidate?.trim()) return false; const resolved = path.resolve(resolveUserPath(candidate, env)); const current = safeRealpathSync(resolved, realpathCache) ?? resolved; return isPathInside(target, current) || isPathInside(current, target); }); } function createInstallRecordPathMatcher(env, realpathCache) { const roots = /* @__PURE__ */ new Map(); const recordPaths = /* @__PURE__ */ new Map(); return (record, rootDir) => { let resolvedRoot = roots.get(rootDir); if (resolvedRoot === void 0) { const absoluteRoot = path.resolve(rootDir); resolvedRoot = safeRealpathSync(absoluteRoot, realpathCache) ?? absoluteRoot; roots.set(rootDir, resolvedRoot); } let candidates = recordPaths.get(record); if (candidates === void 0) { candidates = [record.installPath, record.sourcePath].filter((candidate) => Boolean(candidate?.trim())).map((candidate) => { const absolutePath = path.resolve(resolveUserPath(candidate, env)); return safeRealpathSync(absolutePath, realpathCache) ?? absolutePath; }); recordPaths.set(record, candidates); } for (const candidate of candidates) { if (process.platform !== "win32" && !resolvedRoot.startsWith(candidate)) continue; if (isPathInside(candidate, resolvedRoot)) return true; } return false; }; } function hasMissingInstalledPluginOwnerMetadata(index, env = process.env) { const realpathCache = /* @__PURE__ */ new Map(); if (collectDuplicateInstallRecordOwners(index, env, realpathCache).size > 0) return true; const installRecords = Object.entries(index.installRecords); const matchesPluginRoot = createInstallRecordPathMatcher(env, realpathCache); return index.plugins.some((plugin) => isInstalledPluginIndexInstallOwnerAmbiguous(plugin) || !resolveInstalledPluginIndexInstallOwner(plugin) && installRecords.some(([, record]) => matchesPluginRoot(record, plugin.rootDir))); } //#endregion export { hasMissingInstalledPluginOwnerMetadata as n, isPluginSourcePathInUse as r, createInstalledPluginOwnershipResolver as t };