UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

380 lines (379 loc) 17.1 kB
import { o as getPluginCacheRoot, s as getPluginCacheSource } from "./plugin-cache-DGWspMEc.js"; import { i as extractErrorCode } from "./error-coercion-D_-xJ90S.js"; import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js"; import { n as isVitestRuntimeEnv } from "./test-runtime-env-DQDRzsLt.js"; import "./env-M3R40TOb.js"; import { r as isPathInside } from "./path-guards-Cp-mGr3-.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js"; import { a as pluginCacheRealpathSync, r as pluginCacheExistsSync } from "./plugin-cache-files-DLPF_Tw2.js"; import { r as resolveBundledPluginGeneratedPath } from "./bundled-plugin-metadata-DpCt5e_p.js"; import { t as getCachedPluginModuleLoader } from "./plugin-module-loader-cache-lf3kAaBw.js"; import { c as resolvePluginMetadataSnapshot } from "./plugin-metadata-snapshot-w-4EjxI4.js"; import { t as unwrapDefaultModuleExport } from "./module-export-DsZgGIbX.js"; import { t as resolveBundledChannelRootScope } from "./bundled-root-D2RWPqH5.js"; import { t as loadChannelPluginModule } from "./module-loader-VIb38139.js"; import path from "node:path"; //#region src/plugins/bundled-channel-runtime.ts /** Loads bundled channel plugin runtime entries and setup metadata. */ function resolveBundledMetadataScope(params) { const overrideDir = params?.scanDir ? path.resolve(params.scanDir) : params?.rootDir ? resolveBundledPluginsDirForRoot(params.rootDir) : void 0; if (!overrideDir) return params?.rootDir ? { kind: "empty" } : { kind: "default" }; if (!pluginCacheExistsSync(overrideDir)) return { kind: "empty" }; return { kind: "env", env: { ...process.env, OPENCLAW_BUNDLED_PLUGINS_DIR: overrideDir, ...isVitestRuntimeEnv() ? { OPENCLAW_TEST_TRUST_BUNDLED_PLUGINS_DIR: "1" } : {} } }; } function resolveBundledPluginsDirForRoot(rootDir) { return [ path.join(rootDir, "extensions"), path.join(rootDir, "dist-runtime", "extensions"), path.join(rootDir, "dist", "extensions") ].find((candidate) => pluginCacheExistsSync(candidate)); } function toBundledChannelEntryPair(source) { if (!source) return null; return { source, built: source }; } function toBundledChannelPluginMetadata(record) { if (record.origin !== "bundled") return null; const source = toBundledChannelEntryPair(record.source); if (!source) return null; const setupSource = toBundledChannelEntryPair(record.setupSource); return { dirName: path.basename(record.rootDir), source, ...setupSource ? { setupSource } : {}, manifest: { id: record.id, channels: record.channels }, ...record.packageManifest ? { packageManifest: record.packageManifest } : {}, rootDir: record.rootDir }; } /** Lists bundled channel plugin metadata from default or caller-provided scan roots. */ function listBundledChannelPluginMetadata(params) { const scope = resolveBundledMetadataScope(params); if (scope.kind === "empty") return []; return resolvePluginMetadataSnapshot({ env: scope.kind === "env" ? scope.env : void 0 }).plugins.flatMap((record) => toBundledChannelPluginMetadata(record) ?? []); } /** Resolves a generated runtime path for a bundled channel entry. */ function resolveBundledChannelGeneratedPath(rootDir, entry, pluginDirName, scanDir) { return resolveBundledPluginGeneratedPath(rootDir, entry, pluginDirName, scanDir); } //#endregion //#region src/channels/plugins/meta-normalization.ts /** * Channel metadata normalizer. * * Recomputes required metadata fields while preserving optional manifest/registry fields. */ function stripRequiredChannelMeta(meta) { const { id: _ignoredId, label: _ignoredLabel, selectionLabel: _ignoredSelectionLabel, docsPath: _ignoredDocsPath, blurb: _ignoredBlurb, ...rest } = meta ?? {}; return rest; } function normalizeChannelMeta(params) { const next = params.meta ?? void 0; const existing = params.existing ?? void 0; const label = normalizeOptionalString(next?.label) ?? normalizeOptionalString(existing?.label) ?? normalizeOptionalString(next?.selectionLabel) ?? normalizeOptionalString(existing?.selectionLabel) ?? params.id; const selectionLabel = normalizeOptionalString(next?.selectionLabel) ?? normalizeOptionalString(existing?.selectionLabel) ?? label; const docsPath = normalizeOptionalString(next?.docsPath) ?? normalizeOptionalString(existing?.docsPath) ?? `/channels/${params.id}`; const blurb = normalizeOptionalString(next?.blurb) ?? normalizeOptionalString(existing?.blurb) ?? ""; return { ...stripRequiredChannelMeta(existing), ...stripRequiredChannelMeta(next), id: params.id, label, selectionLabel, docsPath, blurb }; } //#endregion //#region src/channels/plugins/bundled.ts /** * Bundled channel plugin loader. * * Loads generated bundled channel entries, setup metadata, secrets, and legacy migration hooks. */ const log = createSubsystemLogger("channels"); function isSourceModulePath(modulePath) { return /\.(?:c|m)?tsx?$/iu.test(modulePath); } function resolveCanonicalPathOrAbsolute(targetPath) { return pluginCacheRealpathSync(targetPath, true) ?? path.resolve(targetPath); } function isPathInsideCanonicalRoot(rootPath, targetPath) { return isPathInside(resolveCanonicalPathOrAbsolute(rootPath), resolveCanonicalPathOrAbsolute(targetPath)); } function isPackageLocalBundledDistModulePath(params) { return [...params.rootScope.pluginsDir ? [path.join(params.rootScope.pluginsDir, params.metadata.dirName, "dist")] : [], path.join(params.rootScope.packageRoot, "extensions", params.metadata.dirName, "dist")].some((root) => isPathInsideCanonicalRoot(root, params.modulePath)); } function resolveBundledChannelModuleEntry(moduleExport, kind) { const resolved = unwrapDefaultModuleExport(moduleExport); if (!resolved || typeof resolved !== "object") return null; const record = resolved; const setup = kind === "setupEntry"; if (record.kind !== (setup ? "bundled-channel-setup-entry" : "bundled-channel-entry")) return null; const stringFields = setup ? [] : [ "id", "name", "description" ]; const functionFields = setup ? ["loadSetupPlugin"] : ["register", "loadChannelPlugin"]; if (stringFields.some((field) => typeof record[field] !== "string") || functionFields.some((field) => typeof record[field] !== "function")) return null; return record; } function resolveBundledChannelBoundaryRoot(params) { const cacheKey = [ params.packageRoot, params.pluginsDir ?? "", params.metadata.dirName, params.modulePath ].join("\0"); const artifacts = getPluginCacheRoot(params.packageRoot).artifacts; const cached = artifacts.get(`bundled-channel-boundary:${cacheKey}`); if (cached) return cached.boundaryRoot; const canonicalModulePath = resolveCanonicalPathOrAbsolute(params.modulePath); const sourceRoot = path.resolve(params.packageRoot, "extensions", params.metadata.dirName); const boundaryRoot = [ ...params.pluginsDir ? [path.resolve(params.pluginsDir, params.metadata.dirName)] : [], ...["dist", "dist-runtime"].map((layout) => path.resolve(params.packageRoot, layout, "extensions", params.metadata.dirName)), sourceRoot ].map(resolveCanonicalPathOrAbsolute).find((root) => isPathInside(root, canonicalModulePath)) ?? resolveCanonicalPathOrAbsolute(sourceRoot); artifacts.set(`bundled-channel-boundary:${cacheKey}`, { modulePath: params.modulePath, boundaryRoot }); return boundaryRoot; } function resolveGeneratedBundledChannelModulePath(params) { if (!params.entry) return null; const generatedPath = resolveBundledChannelGeneratedPath(params.rootScope.packageRoot, params.entry, params.metadata.dirName, params.rootScope.pluginsDir); if (generatedPath) return generatedPath; const packageRoot = pluginCacheRealpathSync(params.rootScope.packageRoot, true); const pluginRoot = pluginCacheRealpathSync(params.metadata.rootDir, true); if (!packageRoot || !pluginRoot || !isPathInside(packageRoot, pluginRoot)) return null; for (const rawEntry of [params.entry.built, params.entry.source]) { if (!rawEntry) continue; const candidate = path.isAbsolute(rawEntry) ? path.normalize(rawEntry) : path.resolve(pluginRoot, rawEntry); const realCandidate = pluginCacheRealpathSync(candidate, true); if (realCandidate && isPathInside(pluginRoot, realCandidate)) return realCandidate; } return null; } function loadGeneratedBundledChannelModule(params) { const modulePath = resolveGeneratedBundledChannelModulePath(params); if (!modulePath) throw new Error(`missing generated module for bundled channel ${params.metadata.manifest.id}`); const scanDir = params.rootScope.pluginsDir; const boundaryRoot = resolveBundledChannelBoundaryRoot({ packageRoot: params.rootScope.packageRoot, ...scanDir ? { pluginsDir: scanDir } : {}, metadata: params.metadata, modulePath }); try { return loadChannelPluginModule({ modulePath, rootDir: boundaryRoot }); } catch (error) { if (!(isSourceModulePath(modulePath) || isPackageLocalBundledDistModulePath({ rootScope: params.rootScope, metadata: params.metadata, modulePath }) && findMissingModuleCodeInChain(error) !== void 0)) throw error; return getCachedPluginModuleLoader({ modulePath, rootDir: boundaryRoot, importerUrl: import.meta.url, preferBuiltDist: true, cacheScopeKey: "bundled-channel-entry" })(modulePath); } } function findMissingModuleCodeInChain(error) { const seen = /* @__PURE__ */ new Set(); let current = error; while (current && !seen.has(current)) { seen.add(current); const code = extractErrorCode(current); if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") return code; if (typeof current !== "object") return; current = current.cause; } } function describeBundledChannelLoadError(error, channelId) { const detail = formatErrorMessage(error); if (findMissingModuleCodeInChain(error) !== void 0) return `${detail} (run \`openclaw doctor --fix\` to install missing bundled runtime dependencies for channel ${channelId})`; return detail; } function loadGeneratedBundledChannelEntry(kind, rootScope, metadata) { const setup = kind === "setupEntry"; const source = setup ? metadata.setupSource : metadata.source; if (setup && !source) return; try { const entry = resolveBundledChannelModuleEntry(loadGeneratedBundledChannelModule({ rootScope, metadata, entry: source }), kind); if (!entry) { const description = setup ? "setup entry" : "entry"; const contract = setup ? "bundled-channel-setup-entry" : "bundled-channel-entry"; log.warn(`[channels] bundled channel ${description} ${metadata.manifest.id} missing ${contract} contract; skipping`); } return entry ?? void 0; } catch (error) { const detail = describeBundledChannelLoadError(error, metadata.manifest.id); const description = setup ? " setup entry" : ""; log.warn(`[channels] failed to load bundled channel${description} ${metadata.manifest.id}: ${detail}`); return; } } function listBundledChannelMetadata(rootScope = resolveBundledChannelRootScope()) { const scanDir = rootScope.pluginsDir; return listBundledChannelPluginMetadata({ rootDir: rootScope.packageRoot, ...scanDir ? { scanDir } : {}, includeChannelConfigs: false, includeSyntheticChannelConfigs: false }).filter((metadata) => (metadata.manifest.channels?.length ?? 0) > 0); } function listBundledChannelPluginIdsForRoot(rootScope) { return listBundledChannelMetadata(rootScope).map((metadata) => metadata.manifest.id).toSorted((left, right) => left.localeCompare(right)); } function hasBundledChannelPackageSetupFeature(id, feature) { return resolveBundledChannelMetadata(id, resolveBundledChannelRootScope())?.packageManifest?.setupFeatures?.[feature] === true; } function resolveBundledChannelMetadata(id, rootScope) { return listBundledChannelMetadata(rootScope).findLast((metadata) => metadata.manifest.id === id || metadata.manifest.channels?.includes(id)); } function rememberBundledChannelArtifact(rootScope, kind, id, artifact) { const metadata = resolveBundledChannelMetadata(id, rootScope); if (metadata) getPluginCacheSource(path.resolve(metadata.rootDir, metadata.source.source)).variants.set(`bundled-channel:${kind}:${id}`, { exports: { value: artifact } }); } function getBundledChannelArtifactForRoot(kind, id, rootScope) { const metadata = resolveBundledChannelMetadata(id, rootScope); if (!metadata) return; const cached = getPluginCacheSource(path.resolve(metadata.rootDir, metadata.source.source)).variants.get(`bundled-channel:${kind}:${id}`)?.exports; if (cached) return cached.value; const loadKey = `${kind}\0${id}`; const { artifactLoadsInProgress } = getPluginCacheRoot(metadata.rootDir); if (artifactLoadsInProgress.has(loadKey)) return; artifactLoadsInProgress.add(loadKey); try { const artifact = bundledChannelArtifactLoaders[kind]({ id, rootScope }); rememberBundledChannelArtifact(rootScope, kind, id, artifact); return artifact; } catch (error) { if (kind === "entry" || kind === "setupEntry") throw error; const descriptions = { entry: "", setupEntry: " setup entry", plugin: "", setupPlugin: " setup", secrets: " secrets", setupSecrets: " setup secrets", accountInspector: " account inspector" }; const detail = describeBundledChannelLoadError(error, id); log.warn(`[channels] failed to load bundled channel${descriptions[kind]} ${id}: ${detail}`); rememberBundledChannelArtifact(rootScope, kind, id, void 0); return; } finally { artifactLoadsInProgress.delete(loadKey); } } const bundledChannelArtifactLoaders = { entry({ id, rootScope }) { const metadata = resolveBundledChannelMetadata(id, rootScope); if (!metadata) return; const entry = loadGeneratedBundledChannelEntry("entry", rootScope, metadata); if (entry && entry.id !== id) rememberBundledChannelArtifact(rootScope, "entry", entry.id, entry); return entry; }, setupEntry({ id, rootScope }) { const metadata = resolveBundledChannelMetadata(id, rootScope); if (!metadata) return; const entry = loadGeneratedBundledChannelEntry("setupEntry", rootScope, metadata); const aliases = /* @__PURE__ */ new Set([ metadata.manifest.id, ...metadata.manifest.channels ?? [], id ]); for (const alias of aliases) rememberBundledChannelArtifact(rootScope, "setupEntry", alias, entry); return entry; }, plugin({ id, rootScope }) { const entry = getBundledChannelArtifactForRoot("entry", id, rootScope); if (!entry) return; const metadata = resolveBundledChannelMetadata(id, rootScope); const plugin = entry.loadChannelPlugin(); return plugin ? { ...plugin, meta: normalizeChannelMeta({ id: plugin.id, meta: plugin.meta, existing: metadata?.packageManifest?.channel }) } : void 0; }, setupPlugin({ id, rootScope }) { return getBundledChannelArtifactForRoot("setupEntry", id, rootScope)?.loadSetupPlugin(); }, secrets({ id, rootScope }) { const entry = getBundledChannelArtifactForRoot("entry", id, rootScope); return entry ? entry.loadChannelSecrets?.() ?? getBundledChannelArtifactForRoot("plugin", id, rootScope)?.secrets : void 0; }, setupSecrets({ id, rootScope }) { const entry = getBundledChannelArtifactForRoot("setupEntry", id, rootScope); return entry ? entry.loadSetupSecrets?.() ?? getBundledChannelArtifactForRoot("setupPlugin", id, rootScope)?.secrets : void 0; }, accountInspector({ id, rootScope }) { return getBundledChannelArtifactForRoot("entry", id, rootScope)?.loadChannelAccountInspector?.(); } }; function listBundledChannelPlugins() { const rootScope = resolveBundledChannelRootScope(); return listBundledChannelPluginIdsForRoot(rootScope).flatMap((id) => { const plugin = getBundledChannelArtifactForRoot("plugin", id, rootScope); return plugin ? [plugin] : []; }); } function listBundledChannelSetupPlugins() { const rootScope = resolveBundledChannelRootScope(); return listBundledChannelPluginIdsForRoot(rootScope).flatMap((id) => { const plugin = getBundledChannelArtifactForRoot("setupPlugin", id, rootScope); return plugin ? [plugin] : []; }); } function getBundledChannelAccountInspector(id) { return getBundledChannelArtifactForRoot("accountInspector", id, resolveBundledChannelRootScope()); } function getBundledChannelPlugin(id) { return getBundledChannelArtifactForRoot("plugin", id, resolveBundledChannelRootScope()); } function getBundledChannelSecrets(id) { return getBundledChannelArtifactForRoot("secrets", id, resolveBundledChannelRootScope()); } function getBundledChannelSetupPlugin(id, env = process.env) { return getBundledChannelArtifactForRoot("setupPlugin", id, resolveBundledChannelRootScope(env)); } function getBundledChannelSetupSecrets(id, env = process.env) { return getBundledChannelArtifactForRoot("setupSecrets", id, resolveBundledChannelRootScope(env)); } //#endregion export { getBundledChannelSetupSecrets as a, listBundledChannelSetupPlugins as c, getBundledChannelSetupPlugin as i, normalizeChannelMeta as l, getBundledChannelPlugin as n, hasBundledChannelPackageSetupFeature as o, getBundledChannelSecrets as r, listBundledChannelPlugins as s, getBundledChannelAccountInspector as t };