UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

529 lines (528 loc) 20.3 kB
import { a as getPluginCache, o as getPluginCacheRoot } from "./plugin-cache-DGWspMEc.js"; import { d as normalizeStringEntries, h as normalizeUniqueStringEntries } from "./string-normalization-DsCfAx8q.js"; import { r as normalizeProviderId } from "./provider-id-DMd-TDFp.js"; import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js"; import { n as registerPluginMetadataProcessMemoLifecycleClear } from "./plugin-metadata-lifecycle-C6m-q5Au.js"; import { r as createPluginCacheKey, t as PluginLruCache } from "./plugin-cache-primitives-8mVpZ8Xc.js"; import { t as resolvePluginRootArtifactPath } from "./root-artifact-path-BqN5KCyd.js"; import { t as getCachedPluginModuleLoader } from "./plugin-module-loader-cache-lf3kAaBw.js"; import { s as tracePluginLifecyclePhase } from "./discovery-D_VDsZuY.js"; import { a as loadPluginRegistrySnapshotWithMetadata } from "./plugin-registry-snapshot-Dy15Ew18.js"; import { r as selectInstalledPluginManifestRecords, t as loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed-DdhpzefH.js"; import { f as resolvePluginMetadataEnvFingerprint, m as resolvePluginControlPlaneFingerprint } from "./current-plugin-metadata-snapshot-CmSX4G3W.js"; import "./plugin-metadata-snapshot-w-4EjxI4.js"; import { n as hasPluginConfigMigrationSource } from "./config-contract-matches-CISXlkyE.js"; import "./plugin-registry-DD_0nL_t.js"; import { n as listSetupProviderIds, t as listSetupCliBackendIds } from "./setup-descriptors-C6ZUmfj0.js"; import { i as resolvePreferredBundledRootArtifact } from "./plugin-runtime-artifact-selection-OSt151GX.js"; import { n as createUnavailableRuntime, t as buildPluginApi } from "./api-builder-D8BkwR6_.js"; import { fileURLToPath } from "node:url"; import path from "node:path"; //#region src/plugins/setup-registry-loader-state.ts const pluginSetupRegistryLoaderState = { moduleLoaderFactory: void 0 }; //#endregion //#region src/plugins/setup-registry.ts const log = createSubsystemLogger("plugins/setup-registry"); const SETUP_API_EXTENSIONS = [ ".js", ".mjs", ".cjs", ".ts", ".mts", ".cts" ]; const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url); const RUNNING_FROM_BUILT_ARTIFACT = CURRENT_MODULE_PATH.includes(`${path.sep}dist${path.sep}`) || CURRENT_MODULE_PATH.includes(`${path.sep}dist-runtime${path.sep}`); const NOOP_LOGGER = { info() {}, warn() {}, error() {} }; const MAX_SETUP_REGISTRY_CACHE_ENTRIES = 16; let setupRegistryGenerationIdSeq = 0; let setupRegistryGenerations = /* @__PURE__ */ new WeakMap(); const pluginSetupRegistryCache = new PluginLruCache(MAX_SETUP_REGISTRY_CACHE_ENTRIES); function clearPluginSetupRegistryCache() { setupRegistryGenerations = /* @__PURE__ */ new WeakMap(); pluginSetupRegistryCache.clear(); } registerPluginMetadataProcessMemoLifecycleClear(clearPluginSetupRegistryCache); function getModuleLoader(modulePath, rootDir) { return getCachedPluginModuleLoader({ modulePath, rootDir, importerUrl: import.meta.url, ...pluginSetupRegistryLoaderState.moduleLoaderFactory ? { createLoader: pluginSetupRegistryLoaderState.moduleLoaderFactory } : {} }); } function resolveSetupApiPath(rootDir, options) { const artifacts = getPluginCacheRoot(rootDir).artifacts; const key = `setup-api:${options?.includeBundledSourceFallback !== false}:${RUNNING_FROM_BUILT_ARTIFACT}`; const cached = artifacts.get(key); if (cached !== void 0) return cached?.modulePath ?? null; const modulePath = resolveSetupApiPathUncached(rootDir, options); artifacts.set(key, modulePath ? { modulePath, boundaryRoot: path.dirname(modulePath) } : null); return modulePath; } function resolveSetupApiPathUncached(rootDir, options) { const orderedExtensions = RUNNING_FROM_BUILT_ARTIFACT ? SETUP_API_EXTENSIONS : [...SETUP_API_EXTENSIONS.slice(3), ...SETUP_API_EXTENSIONS.slice(0, 3)]; const artifactPaths = ["", "dist"].flatMap((directory) => orderedExtensions.map((extension) => path.join(directory, `setup-api${extension}`))); const direct = resolvePluginRootArtifactPath(rootDir, artifactPaths); if (direct || options?.includeBundledSourceFallback === false) return direct; const sourceExtensionRoot = path.resolve(path.dirname(CURRENT_MODULE_PATH), "..", "..", "extensions", path.basename(rootDir)); return sourceExtensionRoot === rootDir ? null : resolvePluginRootArtifactPath(sourceExtensionRoot, artifactPaths); } function collectConfiguredPluginEntryIds(config) { const entries = config.plugins?.entries; if (!entries || typeof entries !== "object") return []; return normalizeStringEntries(Object.keys(entries)).toSorted(); } function resolveRelevantSetupMigrationPluginIds(params) { const ids = new Set(collectConfiguredPluginEntryIds(params.config)); const plugins = loadSetupManifestRecords({ config: params.config, workspaceDir: params.workspaceDir, env: params.env }); for (const plugin of plugins) if (hasPluginConfigMigrationSource({ root: params.config, pathPatterns: plugin.configContracts?.compatibilityMigrationPaths })) ids.add(plugin.id); return [...ids].toSorted(); } function resolveRegister(mod) { if (typeof mod === "function") return { register: mod }; if (mod && typeof mod === "object" && typeof mod.register === "function") return { definition: mod, register: mod.register.bind(mod) }; return {}; } function resolveLoadableSetupRuntimeSource(record) { const source = record.setupSource ?? resolveSetupApiPath(record.rootDir); if (!source) return null; if (record.origin !== "bundled" || record.sourcePreferred) return { source, rootDir: record.rootDir }; return resolvePreferredBundledRootArtifact({ source, rootDir: record.rootDir, packageManifest: record.packageManifest }); } function resolveDeclaredSetupRuntimeSource(record) { return record.setupSource ?? resolveSetupApiPath(record.rootDir, { includeBundledSourceFallback: false }); } function resolveSetupRegistration(record, diagnostics) { if (record.setup?.requiresRuntime === false) return null; const setupArtifact = resolveLoadableSetupRuntimeSource(record); if (!setupArtifact) return null; const setupSource = setupArtifact.source; let mod; try { mod = getModuleLoader(setupSource, setupArtifact.rootDir)(setupSource); } catch (error) { diagnostics.push({ pluginId: record.id, code: "setup-entry-load-failed", message: `setup entry failed to load from ${setupSource}: ${String(error)}` }); return null; } const resolved = resolveRegister(mod.default ?? mod); if (!resolved.register) return null; if (resolved.definition?.id && resolved.definition.id !== record.id) return null; return { setupSource, register: resolved.register }; } function buildSetupPluginApi(params) { return buildPluginApi({ id: params.record.id, name: params.record.name ?? params.record.id, version: params.record.version, description: params.record.description, source: params.setupSource, rootDir: params.record.rootDir, registrationMode: "setup-only", config: {}, runtime: createUnavailableRuntime("setup-only", params.record.id), logger: NOOP_LOGGER, resolvePath: (input) => input, handlers: params.handlers }); } function ignoreAsyncSetupRegisterResult(result) { if (!result || typeof result.then !== "function") return; Promise.resolve(result).catch(() => void 0); } function runSetupRegistration(register, api, onError) { try { ignoreAsyncSetupRegisterResult(register(api)); return true; } catch (error) { onError(error); return false; } } function matchesProvider(provider, providerId) { const normalized = normalizeProviderId(providerId); if (normalizeProviderId(provider.id) === normalized) return true; return [...provider.aliases ?? [], ...provider.hookAliases ?? []].some((alias) => normalizeProviderId(alias) === normalized); } function resolveSetupRegistryCacheKey(params) { const env = params?.env ?? process.env; if (env !== process.env) return null; return createPluginCacheKey([ "setup-registry", resolvePluginControlPlaneFingerprint({ config: params?.config, env, workspaceDir: params?.workspaceDir }), resolvePluginMetadataEnvFingerprint(env), resolveSetupRuntimeGenerationId(), process.cwd(), params?.pluginIds ? [...params.pluginIds].toSorted() : null ]); } function resolveSetupRuntimeGenerationId() { const owner = getPluginCache(); const { snapshot } = owner.metadata.current; let generation = setupRegistryGenerations.get(owner); if (!generation || generation.snapshot !== snapshot) { generation = { snapshot, id: `s${++setupRegistryGenerationIdSeq}` }; setupRegistryGenerations.set(owner, generation); } return generation.id; } function cloneSetupRegistryValue(value, seen = /* @__PURE__ */ new WeakMap()) { if (!value || typeof value !== "object") return value; const cached = seen.get(value); if (cached !== void 0) return cached; if (value instanceof Date) { const clone = new Date(value); seen.set(value, clone); return clone; } if (value instanceof RegExp) { const clone = new RegExp(value.source, value.flags); clone.lastIndex = value.lastIndex; seen.set(value, clone); return clone; } if (Array.isArray(value)) { const clone = []; seen.set(value, clone); clone.push(...value.map((entry) => cloneSetupRegistryValue(entry, seen))); return clone; } if (value instanceof Map) { const clone = /* @__PURE__ */ new Map(); seen.set(value, clone); for (const [key, entry] of value.entries()) clone.set(cloneSetupRegistryValue(key, seen), cloneSetupRegistryValue(entry, seen)); return clone; } if (value instanceof Set) { const clone = /* @__PURE__ */ new Set(); seen.set(value, clone); for (const entry of value.values()) clone.add(cloneSetupRegistryValue(entry, seen)); return clone; } const prototype = Object.getPrototypeOf(value); if (prototype !== Object.prototype && prototype !== null) return value; const clone = Object.create(prototype); seen.set(value, clone); for (const key of Reflect.ownKeys(value)) { const descriptor = Object.getOwnPropertyDescriptor(value, key); if (!descriptor) continue; if ("value" in descriptor) descriptor.value = cloneSetupRegistryValue(descriptor.value, seen); Object.defineProperty(clone, key, descriptor); } return clone; } function cloneSetupRegistry(registry) { return cloneSetupRegistryValue(registry); } function loadSetupManifestRecords(params) { const { snapshot: index, manifestRegistry } = loadPluginRegistrySnapshotWithMetadata(params); if (!manifestRegistry) return loadPluginManifestRegistryForInstalledIndex({ ...params, index, includeDisabled: true }).plugins; return tracePluginLifecyclePhase("manifest registry", () => params.pluginIds?.length === 0 ? [] : selectInstalledPluginManifestRecords(index, manifestRegistry, params.pluginIds ? new Set(params.pluginIds) : null, true), { includeDisabled: true, pluginIdCount: params.pluginIds?.length, indexPluginCount: index.plugins.length }); } function findUniqueSetupManifestOwner(params) { const matches = params.plugins.filter((entry) => params.listIds(entry).some((id) => normalizeProviderId(id) === params.normalizedId)); if (matches.length === 0) return; return matches.length === 1 ? matches[0] : void 0; } function resolveSetupRegistryForManifestOwner(record) { return resolvePluginSetupRegistry({ manifestRegistry: { plugins: [record], diagnostics: [] } }); } function mapNormalizedIds(ids) { const mapped = /* @__PURE__ */ new Map(); for (const id of ids) { const normalized = normalizeProviderId(id); if (!normalized || mapped.has(normalized)) continue; mapped.set(normalized, id); } return mapped; } function pushDescriptorRuntimeDisabledDiagnostic(params) { if (!resolveDeclaredSetupRuntimeSource(params.record)) return; params.diagnostics.push({ pluginId: params.record.id, code: "setup-descriptor-runtime-disabled", message: "setup.requiresRuntime is false, so OpenClaw ignored the plugin setup runtime entry. Remove setup-api/openclaw.setupEntry or set requiresRuntime true if setup lookup still needs plugin code." }); } function pushSetupDescriptorDriftDiagnostics(params) { const declaredProviderIds = params.record.setup?.providers?.map((entry) => entry.id); if (declaredProviderIds) { for (const provider of params.providers) if (!declaredProviderIds.some((declaredId) => matchesProvider(provider, declaredId))) params.diagnostics.push({ pluginId: params.record.id, code: "setup-descriptor-provider-runtime-undeclared", runtimeId: provider.id, message: `setup runtime registered provider "${provider.id}" but setup.providers does not declare it.` }); } const declaredCliBackendIds = params.record.setup?.cliBackends; if (declaredCliBackendIds) { const declaredCliBackends = mapNormalizedIds(declaredCliBackendIds); const runtimeCliBackends = mapNormalizedIds(params.cliBackends.map((backend) => backend.id)); for (const [normalized, declaredId] of declaredCliBackends) if (!runtimeCliBackends.has(normalized)) params.diagnostics.push({ pluginId: params.record.id, code: "setup-descriptor-cli-backend-missing-runtime", declaredId, message: `setup.cliBackends declares "${declaredId}" but setup runtime did not register a matching CLI backend.` }); for (const [normalized, runtimeId] of runtimeCliBackends) if (!declaredCliBackends.has(normalized)) params.diagnostics.push({ pluginId: params.record.id, code: "setup-descriptor-cli-backend-runtime-undeclared", runtimeId, message: `setup runtime registered CLI backend "${runtimeId}" but setup.cliBackends does not declare it.` }); } } function resolvePluginSetupRegistry(params) { const env = params?.env ?? process.env; const scopedPluginIds = params?.pluginIds ? new Set(normalizeUniqueStringEntries(params.pluginIds)) : null; if (scopedPluginIds && scopedPluginIds.size === 0) return { providers: [], cliBackends: [], configMigrations: [], autoEnableProbes: [], diagnostics: [] }; const resultCacheKey = params?.manifestRegistry ? null : resolveSetupRegistryCacheKey(params); if (resultCacheKey !== null) { const cached = pluginSetupRegistryCache.get(resultCacheKey); if (cached) return cloneSetupRegistry(cached); } const providers = []; const cliBackends = []; const configMigrations = []; const autoEnableProbes = []; const diagnostics = []; let providerKeys = /* @__PURE__ */ new Set(); let cliBackendKeys = /* @__PURE__ */ new Set(); const plugins = params?.manifestRegistry == null ? loadSetupManifestRecords({ config: params?.config, workspaceDir: params?.workspaceDir, env, pluginIds: params?.pluginIds }) : params.manifestRegistry.plugins; for (const record of plugins) { if (scopedPluginIds && !scopedPluginIds.has(record.id)) continue; if (record.setup?.requiresRuntime === false) { pushDescriptorRuntimeDisabledDiagnostic({ record, diagnostics }); continue; } const setupRegistration = resolveSetupRegistration(record, diagnostics); if (!setupRegistration) continue; const recordProviders = []; const recordCliBackends = []; const recordConfigMigrations = []; const recordAutoEnableProbes = []; const recordProviderKeys = new Set(providerKeys); const recordCliBackendKeys = new Set(cliBackendKeys); let acceptingRegistrations = true; const api = buildSetupPluginApi({ record, setupSource: setupRegistration.setupSource, handlers: { registerProvider(provider) { const key = `${record.id}:${normalizeProviderId(provider.id)}`; if (!acceptingRegistrations || recordProviderKeys.has(key)) return; recordProviderKeys.add(key); recordProviders.push({ pluginId: record.id, provider }); }, registerCliBackend(backend) { const key = `${record.id}:${normalizeProviderId(backend.id)}`; if (!acceptingRegistrations || recordCliBackendKeys.has(key)) return; recordCliBackendKeys.add(key); recordCliBackends.push({ pluginId: record.id, backend }); }, registerConfigMigration(migrate) { if (!acceptingRegistrations) return; recordConfigMigrations.push({ pluginId: record.id, migrate }); }, registerAutoEnableProbe(probe) { if (!acceptingRegistrations) return; recordAutoEnableProbes.push({ pluginId: record.id, probe }); } } }); const registered = runSetupRegistration(setupRegistration.register, api, (error) => { diagnostics.push({ pluginId: record.id, code: "setup-registration-failed", message: `setup registration threw: ${String(error)}` }); }); acceptingRegistrations = false; if (!registered) continue; providers.push(...recordProviders); cliBackends.push(...recordCliBackends); configMigrations.push(...recordConfigMigrations); autoEnableProbes.push(...recordAutoEnableProbes); providerKeys = recordProviderKeys; cliBackendKeys = recordCliBackendKeys; pushSetupDescriptorDriftDiagnostics({ record, providers: recordProviders.map((entry) => entry.provider), cliBackends: recordCliBackends.map((entry) => entry.backend), diagnostics }); } const registry = { providers, cliBackends, configMigrations, autoEnableProbes, diagnostics }; for (const diagnostic of diagnostics) log.warn(`plugin setup [${diagnostic.pluginId}] ${diagnostic.code}: ${diagnostic.message}`); if (resultCacheKey === null) return registry; pluginSetupRegistryCache.set(resultCacheKey, cloneSetupRegistry(registry)); return registry; } function resolvePluginSetupProviderCore(params) { const env = params.env ?? process.env; const normalizedProvider = normalizeProviderId(params.provider); const record = findUniqueSetupManifestOwner({ plugins: loadSetupManifestRecords({ config: params.config, workspaceDir: params.workspaceDir, env, pluginIds: params.pluginIds }), normalizedId: normalizedProvider, listIds: listSetupProviderIds }); if (!record) return; return resolveSetupRegistryForManifestOwner(record).providers.findLast((entry) => matchesProvider(entry.provider, normalizedProvider))?.provider; } function resolvePluginSetupCliBackend(params) { const normalized = normalizeProviderId(params.backend); const env = params.env ?? process.env; const record = findUniqueSetupManifestOwner({ plugins: loadSetupManifestRecords({ config: params.config, workspaceDir: params.workspaceDir, env }), normalizedId: normalized, listIds: listSetupCliBackendIds }); if (!record) return; return resolveSetupRegistryForManifestOwner(record).cliBackends.find((entry) => normalizeProviderId(entry.backend.id) === normalized); } function runPluginSetupConfigMigrations(params) { let next = params.config; const changes = []; const pluginIds = resolveRelevantSetupMigrationPluginIds(params); if (pluginIds.length === 0) return { config: next, changes }; for (const entry of resolvePluginSetupRegistry({ config: params.config, workspaceDir: params.workspaceDir, env: params.env, pluginIds }).configMigrations) { const migration = entry.migrate(next); if (!migration || migration.changes.length === 0) continue; next = migration.config; changes.push(...migration.changes); } return { config: next, changes }; } function resolvePluginSetupAutoEnableReasons(params) { const env = params.env ?? process.env; const reasons = []; const seen = /* @__PURE__ */ new Set(); for (const entry of resolvePluginSetupRegistry({ config: params.config, workspaceDir: params.workspaceDir, env, pluginIds: params.pluginIds, manifestRegistry: params.manifestRegistry }).autoEnableProbes) { const raw = entry.probe({ config: params.config, env }); const values = Array.isArray(raw) ? raw : raw ? [raw] : []; for (const reason of values) { const normalized = reason.trim(); if (!normalized) continue; const key = `${entry.pluginId}:${normalized}`; if (seen.has(key)) continue; seen.add(key); reasons.push({ pluginId: entry.pluginId, reason: normalized }); } } return reasons; } //#endregion export { runPluginSetupConfigMigrations as a, resolvePluginSetupRegistry as i, resolvePluginSetupCliBackend as n, resolvePluginSetupProviderCore as r, resolvePluginSetupAutoEnableReasons as t };