UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

279 lines (278 loc) • 13.7 kB
import { o as normalizeLowercaseStringOrEmpty } from "./string-coerce-1VuiLaaR.mjs"; import { l as getPluginCacheRoot, u as getPluginCacheSource } from "./plugin-cache-BABafcXD.mjs"; import { i as pluginInstanceInvocation } from "./plugin-instance-invocation-CH4zOUb4.mjs"; import { o as openRootFileSync } from "./boundary-file-read-CCth2Hwg.mjs"; import { l as tryNativeRequireJavaScriptModule } from "./native-module-require-BX9Ubdbu.mjs"; import { c as toSafeImportPath, t as getCachedPluginModuleLoader } from "./plugin-module-loader-cache-CUtYxPiw.mjs"; import { s as resolveLoaderPackageRoot, t as buildPluginLoaderAliasMap } from "./sdk-alias-A9rXLURS.mjs"; import { n as formatPluginLoadProfileLine, r as shouldProfilePluginLoader, t as createProfiler } from "./plugin-load-profile-CMsyIVFI.mjs"; import { l as emptyChannelConfigSchema } from "./config-schema-Be-FohaC.mjs"; import { t as createCachedLazyValueGetter } from "./lazy-value-B2wh8onO.mjs"; import fs from "node:fs"; import { fileURLToPath } from "node:url"; import path from "node:path"; //#region src/plugin-sdk/channel-entry-contract.ts const disableBundledEntrySourceFallbackEnv = "OPENCLAW_DISABLE_BUNDLED_ENTRY_SOURCE_FALLBACK"; function isBundledEntrySourceFallbackDisabled(value) { return value !== void 0 && !/^(?:0|false)$/iu.test(value.trim()); } function resolveSpecifierCandidates(modulePath) { const ext = normalizeLowercaseStringOrEmpty(path.extname(modulePath)); if (ext === ".js") return [modulePath, modulePath.slice(0, -3) + ".ts"]; if (ext === ".mjs") return [modulePath, modulePath.slice(0, -4) + ".mts"]; if (ext === ".cjs") return [modulePath, modulePath.slice(0, -4) + ".cts"]; return [modulePath]; } function resolveEntryBoundaryRoot(importMetaUrl) { return path.dirname(fileURLToPath(importMetaUrl)); } function resolveBundledEntryBoundaryInfo(importMetaUrl) { const cacheKey = `${process.argv[1] ?? ""}\0${importMetaUrl}`; const entryBoundaryInfoCache = getPluginCacheRoot(resolveEntryBoundaryRoot(importMetaUrl)).entryBoundaries; const cached = entryBoundaryInfoCache.get(cacheKey); if (cached) return cached; const importerPath = fileURLToPath(importMetaUrl); const importerDir = path.dirname(importerPath); const info = { importerPath, importerDir, boundaryRoot: path.dirname(importerPath), packageRoot: resolveLoaderPackageRoot({ modulePath: importerPath, moduleUrl: importMetaUrl, cwd: importerDir, argv1: process.argv[1] }) ?? null }; entryBoundaryInfoCache.set(cacheKey, info); return info; } function addBundledEntryCandidates(candidates, basePath, boundaryRoot) { for (const candidate of resolveSpecifierCandidates(basePath)) { if (candidates.some((entry) => entry.path === candidate && entry.boundaryRoot === boundaryRoot)) continue; candidates.push({ path: candidate, boundaryRoot }); } } function resolveBundledEntryModuleCandidates(importMetaUrl, specifier) { const { importerPath, importerDir, boundaryRoot, packageRoot } = resolveBundledEntryBoundaryInfo(importMetaUrl); const primaryResolved = path.resolve(importerDir, specifier); const candidates = [{ path: primaryResolved, boundaryRoot }]; addBundledEntryCandidates(candidates, primaryResolved, boundaryRoot); const sourceRelativeSpecifier = specifier.replace(/^\.\/src\//u, "./"); if (sourceRelativeSpecifier !== specifier) addBundledEntryCandidates(candidates, path.resolve(importerDir, sourceRelativeSpecifier), boundaryRoot); if (!packageRoot) return candidates; const distExtensionsRoot = path.join(packageRoot, "dist", "extensions") + path.sep; if (!importerPath.startsWith(distExtensionsRoot)) return candidates; if (isBundledEntrySourceFallbackDisabled(process.env[disableBundledEntrySourceFallbackEnv])) return candidates; const pluginDirName = path.basename(importerDir); const sourcePluginRoot = path.join(packageRoot, "extensions", pluginDirName); if (sourcePluginRoot === boundaryRoot) return candidates; addBundledEntryCandidates(candidates, path.resolve(sourcePluginRoot, specifier), sourcePluginRoot); if (sourceRelativeSpecifier !== specifier) addBundledEntryCandidates(candidates, path.resolve(sourcePluginRoot, sourceRelativeSpecifier), sourcePluginRoot); return candidates; } function formatBundledEntryUnknownError(error) { if (typeof error === "string") return error; if (error === void 0) return "boundary validation failed"; try { return JSON.stringify(error); } catch { return "non-serializable error"; } } function formatBundledEntryModuleOpenFailure(params) { const importerPath = fileURLToPath(params.importMetaUrl); const errorDetail = params.failure.error instanceof Error ? params.failure.error.message : formatBundledEntryUnknownError(params.failure.error); return [ `bundled plugin entry "${params.specifier}" failed to open`, `from "${importerPath}"`, `(resolved "${params.resolvedPath}", plugin root "${params.boundaryRoot}",`, `reason "${params.failure.reason}"): ${errorDetail}` ].join(" "); } function createBundledEntryModulePathCacheKey(importMetaUrl, specifier) { return `${isBundledEntrySourceFallbackDisabled(process.env[disableBundledEntrySourceFallbackEnv]) ? "1" : "0"}\0${importMetaUrl}\0${specifier}`; } function resolveBundledEntryModulePath(importMetaUrl, specifier) { const cacheKey = createBundledEntryModulePathCacheKey(importMetaUrl, specifier); const resolvedModulePaths = getPluginCacheRoot(resolveEntryBoundaryRoot(importMetaUrl)).entryPaths; const cached = resolvedModulePaths.get(cacheKey); if (cached) { if ("error" in cached) throw cached.error; return cached.path; } const candidates = resolveBundledEntryModuleCandidates(importMetaUrl, specifier); let firstFailure = null; let candidateIndex = 0; let candidate = candidates[0]; do { const opened = openRootFileSync({ absolutePath: candidate.path, rootPath: candidate.boundaryRoot, boundaryLabel: "plugin root", rejectHardlinks: false, skipLexicalRootCheck: true }); if (opened.ok) { fs.closeSync(opened.fd); resolvedModulePaths.set(cacheKey, { path: opened.path }); return opened.path; } firstFailure ??= { candidate, failure: opened }; candidate = candidates[++candidateIndex]; } while (candidate); const failure = firstFailure; const error = new Error(formatBundledEntryModuleOpenFailure({ importMetaUrl, specifier, resolvedPath: failure.candidate.path, boundaryRoot: failure.candidate.boundaryRoot, failure: failure.failure })); resolvedModulePaths.set(cacheKey, { error }); throw error; } function canTryNodeRequireBuiltModule(modulePath) { return (modulePath.includes(`${path.sep}dist${path.sep}`) || modulePath.includes(`${path.sep}dist-runtime${path.sep}`)) && [ ".js", ".mjs", ".cjs" ].includes(normalizeLowercaseStringOrEmpty(path.extname(modulePath))); } function loadBundledEntryModuleSync(importMetaUrl, specifier, options = {}) { const modulePath = resolveBundledEntryModulePath(importMetaUrl, specifier); const instance = pluginInstanceInvocation.getStore()?.instance; const captured = instance?.hasModuleSource(modulePath); if (captured === false) throw new Error(`Bundled companion is outside the plugin's captured module graph: ${modulePath}`); if (instance && captured) return instance.loadModule(modulePath); const source = getPluginCacheSource(modulePath); const cached = source.variants.get("bundled-entry")?.exports; if (cached) return cached.value; let loaded; const profile = shouldProfilePluginLoader(); const loadStartMs = profile ? performance.now() : 0; let sourceLoaderReadyMs = 0; const native = canTryNodeRequireBuiltModule(modulePath) ? tryNativeRequireJavaScriptModule(modulePath, { aliasMap: buildPluginLoaderAliasMap(modulePath, process.argv[1], import.meta.url), fallbackOnMissingDependency: true }) : void 0; if (native?.ok) loaded = native.moduleExport; else { const moduleLoader = getCachedPluginModuleLoader({ modulePath, importerUrl: import.meta.url, loaderFilename: import.meta.url, ...options.createLoaderForTest ? { createLoader: options.createLoaderForTest } : {}, tryNative: false }); sourceLoaderReadyMs = profile ? performance.now() : 0; loaded = moduleLoader(toSafeImportPath(modulePath)); } if (profile) { const endMs = performance.now(); console.error(formatPluginLoadProfileLine({ phase: "bundled-entry-module-load", pluginId: "(bundled-entry)", source: modulePath, elapsedMs: endMs - loadStartMs, extras: [["sourceLoaderCreateMs", sourceLoaderReadyMs ? sourceLoaderReadyMs - loadStartMs : 0], ["sourceLoaderCallMs", sourceLoaderReadyMs ? endMs - sourceLoaderReadyMs : 0]] })); } source.variants.set("bundled-entry", { exports: { value: loaded } }); return loaded; } /** Loads one export from a bundled channel sidecar module through the guarded entry boundary. */ function loadBundledEntryExportSync(importMetaUrl, reference, options) { const loaded = loadBundledEntryModuleSync(importMetaUrl, reference.specifier, options); const resolved = loaded && typeof loaded === "object" && "default" in loaded ? loaded.default : loaded; if (!reference.exportName) return resolved; const record = resolved ?? loaded; if (!record || !(reference.exportName in record)) throw new Error(`missing export "${reference.exportName}" from bundled entry module ${reference.specifier}`); return record[reference.exportName]; } function createOptionalBundledEntryLoader(importMetaUrl, reference, loadExport) { return reference ? (options) => loadExport(importMetaUrl, reference, options) : void 0; } function createBundledEntryRuntimeSetter(importMetaUrl, reference) { return reference ? (runtime) => { loadBundledEntryExportSync(importMetaUrl, reference)(runtime); } : void 0; } /** Defines the full bundled channel entry contract used by core plugin registration. */ function defineBundledChannelEntry({ id, name, description, importMetaUrl, plugin, outbound, secrets, configSchema, runtime, accountInspect, features, registerCliMetadata, registerFull, registerCapabilities }) { const getConfigSchema = createCachedLazyValueGetter(configSchema ?? emptyChannelConfigSchema); const loadChannelPlugin = (options) => loadBundledEntryExportSync(importMetaUrl, plugin, options); const loadChannelOutbound = createOptionalBundledEntryLoader(importMetaUrl, outbound, loadBundledEntryExportSync); const loadChannelSecrets = createOptionalBundledEntryLoader(importMetaUrl, secrets, loadBundledEntryExportSync); const loadChannelAccountInspector = createOptionalBundledEntryLoader(importMetaUrl, accountInspect, loadBundledEntryExportSync); const setChannelRuntime = createBundledEntryRuntimeSetter(importMetaUrl, runtime); return { kind: "bundled-channel-entry", id, name, description, get configSchema() { return getConfigSchema(); }, ...features || accountInspect ? { features: { ...features, ...accountInspect ? { accountInspect: true } : {} } } : {}, register(api) { if (api.registrationMode === "cli-metadata") { registerCliMetadata?.(api); return; } const profile = createProfiler({ pluginId: id, source: importMetaUrl }); if (api.registrationMode === "tool-discovery") { profile("bundled-register:registerFull", () => registerFull?.(api)); profile("bundled-register:registerCapabilities", () => registerCapabilities?.(api)); return; } const channelPlugin = profile("bundled-register:loadChannelPlugin", loadChannelPlugin); profile("bundled-register:registerChannel", () => api.registerChannel({ plugin: channelPlugin })); profile("bundled-register:setChannelRuntime", () => setChannelRuntime?.(api.runtime)); const registrationMode = api.registrationMode; if (registrationMode !== "discovery" && registrationMode !== "full") return; profile("bundled-register:registerCliMetadata", () => registerCliMetadata?.(api)); if (registrationMode === "full") profile("bundled-register:registerFull", () => registerFull?.(api)); profile("bundled-register:registerCapabilities", () => registerCapabilities?.(api)); }, loadChannelPlugin, ...loadChannelOutbound ? { loadChannelOutbound } : {}, ...loadChannelSecrets ? { loadChannelSecrets } : {}, ...loadChannelAccountInspector ? { loadChannelAccountInspector } : {}, ...setChannelRuntime ? { setChannelRuntime } : {} }; } /** Defines the setup-only bundled channel entry contract for onboarding and migration surfaces. */ function defineBundledChannelSetupEntry({ importMetaUrl, plugin, secrets, runtime, legacyStateMigrations, legacySessionSurface, registerSetupRuntime, features }) { const setChannelRuntime = createBundledEntryRuntimeSetter(importMetaUrl, runtime); const loadSetupSecrets = createOptionalBundledEntryLoader(importMetaUrl, secrets, loadBundledEntryExportSync); const loadLegacyStateMigrationDetector = createOptionalBundledEntryLoader(importMetaUrl, legacyStateMigrations, loadBundledEntryExportSync); const loadLegacySessionSurface = createOptionalBundledEntryLoader(importMetaUrl, legacySessionSurface, loadBundledEntryExportSync); return { kind: "bundled-channel-setup-entry", loadSetupPlugin: (options) => loadBundledEntryExportSync(importMetaUrl, plugin, options), ...loadSetupSecrets ? { loadSetupSecrets } : {}, ...loadLegacyStateMigrationDetector ? { loadLegacyStateMigrationDetector } : {}, ...loadLegacySessionSurface ? { loadLegacySessionSurface } : {}, ...setChannelRuntime ? { setChannelRuntime } : {}, ...registerSetupRuntime ? { registerSetupRuntime } : {}, ...features ? { features } : {} }; } //#endregion export { defineBundledChannelSetupEntry as n, loadBundledEntryExportSync as r, defineBundledChannelEntry as t };