UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

604 lines (603 loc) • 26.8 kB
import { D as withPluginCache, M as getPluginSdkHostFacts, l as getPluginCacheRoot, o as getPluginCache, r as bindPluginCacheRoot, u as getPluginCacheSource } from "./plugin-cache-Bn9I3v9Q.mjs"; import { c as isRecord } from "./record-coerce-TIsquoVR.mjs"; import { a as getPluginRuntimeGatewayRequestScope } from "./gateway-request-scope-Btza1qbw.mjs"; import { i as isPathStrictlyInside, r as isPathInside } from "./path-guards-CH7noY0Z.mjs"; import { t as escapeRegExp } from "./regexp-BZyMFTlj.mjs"; import { n as isPathInside$1, r as openPluginRootFileSync } from "./path-safety-DRBJanJw.mjs"; import { l as pluginCacheRealpathSync, s as pluginCacheExistsSync } from "./package-manifest-zwWxdzub.mjs"; import { c as supportsNativeModuleAliasHooks, i as isPluginSourceModulePath, l as tryNativeRequireJavaScriptModule, n as clearPluginModuleRequireCache, o as resolvePluginLoaderTryNative, u as tryNativeRequireModule } from "./native-module-require-CnCGzFSR.mjs"; import { t as createJiti } from "./jiti-factory-B7ZlEz2u.mjs"; import { t as getPluginInstance } from "./plugin-instance-scope-C4zdRFkI.mjs"; import { a as listWorkspacePackageExportAliasEntries, i as isPluginSdkAliasSpecifier, n as buildPluginLoaderJitiOptions, o as preparePluginLoaderAliases, r as createPluginLoaderModuleCacheKey } from "./sdk-alias-BQkrpnVJ.mjs"; import { t as resolvePluginRuntimeRecord } from "./runtime-context-sdqZyTzk.mjs"; import Module from "node:module"; import fs from "node:fs"; import { fileURLToPath, pathToFileURL } from "node:url"; import path from "node:path"; import { sameFileIdentity } from "@openclaw/fs-safe/advanced"; //#region src/shared/import-specifier.ts /** * On Windows, Node's ESM loader requires absolute paths to be expressed as * file:// URLs. Raw drive-letter paths like C:\... are parsed as URL schemes. */ function toSafeImportPath(specifier) { if (process.platform !== "win32") return specifier; if (specifier.startsWith("file://")) return specifier; if (path.win32.isAbsolute(specifier)) return pathToFileURL(specifier, { windows: true }).href; return specifier; } //#endregion //#region src/plugins/plugin-sdk-native-resolver.ts /** Installs native Node resolution aliases so plugins can import the OpenClaw SDK in dev and tests. */ const moduleWithResolver = Module; const nodeResolveFilenameProperty = "_resolveFilename"; const INTERNAL_CORE_PACKAGE_ALIASES = [ { packageName: "@openclaw/markdown-core", packageDir: "markdown-core", subpaths: [ ["", "index.ts"], ["code-spans", "code-spans.ts"], ["fences", "fences.ts"], ["frontmatter", "frontmatter.ts"], ["ir", "ir.ts"], ["render", "render.ts"], ["render-aware-chunking", "render-aware-chunking.ts"], ["tables", "tables.ts"], ["types", "types.ts"] ] }, { packageName: "@openclaw/ai", packageDir: "ai", subpaths: [ ["", "index.ts"], ["providers", "providers.ts"], ["transports", "transports.ts"], ["diagnostics", path.join("utils", "diagnostics.ts")], ["event-stream", path.join("utils", "event-stream.ts")], ["types", "types.ts"], ["validation", "validation.ts"], ["internal/anthropic", path.join("internal", "anthropic.ts")], ["internal/google-model-family", path.join("internal", "google-model-family.ts")], ["internal/openai", path.join("internal", "openai.ts")], ["internal/openai-responses-payload-policy", path.join("internal", "openai-responses-payload-policy.ts")], ["internal/retry-after", path.join("internal", "retry-after.ts")], ["internal/runtime", path.join("internal", "runtime.ts")], ["internal/shared", path.join("internal", "shared.ts")], ["internal/tool-schema", path.join("internal", "tool-schema.ts")] ] }, { packageName: "@openclaw/llm-core", packageDir: "llm-core", subpaths: [ ["", "index.ts"], ["model-contracts/anthropic", path.join("model-contracts", "anthropic.ts")], ["diagnostics", path.join("utils", "diagnostics.ts")], ["event-stream", path.join("utils", "event-stream.ts")], ["types", "types.ts"], ["validation", "validation.ts"] ] } ]; const INTERNAL_CORE_EXPORTED_PACKAGE_DIRS = [ "media-core", "normalization-core", "acp-core" ]; const BUN_NATIVE_ALIAS_FILTER = new RegExp(`^(?:${[ "openclaw/plugin-sdk", "@openclaw/plugin-sdk", ...INTERNAL_CORE_PACKAGE_ALIASES.map((entry) => entry.packageName), ...INTERNAL_CORE_EXPORTED_PACKAGE_DIRS.map((packageDir) => `@openclaw/${packageDir}`) ].map(escapeRegExp).join("|")})(?:/|$)`, "u"); let installed = false; function resolveLoaderModulePath(options) { return options.modulePath ?? fileURLToPath(options.moduleUrl ?? import.meta.url); } function isNativeLoadableSdkTarget(targetPath) { switch (path.extname(targetPath)) { case ".cjs": case ".js": case ".mjs": return true; default: return isPluginSourceModulePath(targetPath); } } const normalizePathForBoundary = (targetPath) => pluginCacheRealpathSync(targetPath) ?? path.resolve(targetPath); function findNearestPackageRoot(modulePath) { const normalizedModulePath = path.resolve(modulePath); const roots = getPluginCache().sdk.native.nearestPackageRoots; const cached = roots.get(normalizedModulePath); if (cached) return cached; let cursor = path.dirname(normalizedModulePath); for (let i = 0; i < 12; i += 1) { if (pluginCacheExistsSync(path.join(cursor, "package.json"))) { roots.set(normalizedModulePath, cursor); return cursor; } const parent = path.dirname(cursor); if (parent === cursor) break; cursor = parent; } const fallback = path.dirname(normalizedModulePath); roots.set(normalizedModulePath, fallback); return fallback; } function findBundledPluginRoot(modulePath) { const resolvedModulePath = normalizePathForBoundary(modulePath); const packageRoot = normalizePathForBoundary(resolveLoaderPackageRootFromModulePath(modulePath)); for (const relativeRoot of [ "extensions", "dist/extensions", "dist-runtime/extensions" ]) { const bundledRoot = path.join(packageRoot, relativeRoot); if (!isPathStrictlyInside(bundledRoot, resolvedModulePath)) continue; const [pluginId] = path.relative(bundledRoot, resolvedModulePath).split(path.sep); if (pluginId) return path.join(bundledRoot, pluginId); } } function resolveLoaderPackageRootFromModulePath(modulePath) { const normalizedModulePath = path.resolve(modulePath); const roots = getPluginCache().sdk.native.loaderPackageRoots; const cached = roots.get(normalizedModulePath); if (cached) return cached; let cursor = path.dirname(normalizedModulePath); for (let i = 0; i < 12; i += 1) { const packageJsonPath = path.join(cursor, "package.json"); if (pluginCacheExistsSync(packageJsonPath)) { const facts = getPluginSdkHostFacts(getPluginCache().sdk, cursor); if (facts.nativePackage === void 0) try { const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); facts.nativePackage = isRecord(parsed) ? { ...typeof parsed.name === "string" ? { name: parsed.name } : {}, hasOpenClawBin: isRecord(parsed.bin) && typeof parsed.bin.openclaw === "string" } : null; } catch { facts.nativePackage = null; } if (facts.nativePackage?.name === "openclaw" || facts.nativePackage?.hasOpenClawBin) { roots.set(normalizedModulePath, cursor); return cursor; } } const parent = path.dirname(cursor); if (parent === cursor) break; cursor = parent; } const fallback = findNearestPackageRoot(modulePath); roots.set(normalizedModulePath, fallback); return fallback; } function resolveInternalCorePackageHostRoot(modulePath) { const normalizedModulePath = path.resolve(modulePath); const internalCorePackageHostRoots = getPluginCache().sdk.native.hostRoots; const cached = internalCorePackageHostRoots.get(normalizedModulePath); if (cached) return cached; const packageRoot = normalizePathForBoundary(resolveLoaderPackageRootFromModulePath(normalizedModulePath)); internalCorePackageHostRoots.set(normalizedModulePath, packageRoot); return packageRoot; } function resolveAllowedParentRoot(modulePath) { const roots = getPluginCache().sdk.native.allowedParentRoots; const key = path.resolve(modulePath); const cached = roots.get(key); if (cached) return cached; const root = findBundledPluginRoot(modulePath) ?? findNearestPackageRoot(modulePath); roots.set(key, root); return root; } function resolveAllowedParentRoots(options) { const roots = /* @__PURE__ */ new Set(); if (options.pluginModulePath) roots.add(normalizePathForBoundary(resolveAllowedParentRoot(options.pluginModulePath))); for (const root of options.allowedParentRoots ?? []) roots.add(normalizePathForBoundary(root)); return [...roots]; } function isWithinRoot(candidate, root) { return isPathInside(root, normalizePathForBoundary(candidate)); } function resolveAliasTargetForParentUrl(request, parentUrl) { if (!parentUrl?.startsWith("file:") || !isPluginSdkAliasSpecifier(request) && !getPluginCache().sdk.native.aliases.has(request)) return; try { return resolveAliasTargetForParentPath(request, fileURLToPath(parentUrl)); } catch { return; } } function resolveAliasTargetForParentPath(request, parentFilename) { const native = getPluginCache().sdk.native; if (parentFilename && isPluginSdkAliasSpecifier(request)) { let first; for (const [root, provider] of native.sdkProviders) { if (!isWithinRoot(parentFilename, root)) continue; provider.order ??= native.nextSdkProviderOrder++; const target = provider.resolveAlias(request.endsWith(".js") ? request.slice(0, -3) : request); if (target && isNativeLoadableSdkTarget(target) && (!first || provider.order < first.order)) first = { target, order: provider.order }; } return first?.target; } const entries = native.aliases.get(request); if (!entries || !parentFilename) return; return entries.find((entry) => isWithinRoot(parentFilename, entry.parentRoot))?.target; } function listInternalCorePackageNativeAliases(packageRoot) { const parentRoots = [ "src", "scripts", "packages", "test" ].map((segment) => path.join(packageRoot, segment)).filter((candidate) => pluginCacheExistsSync(candidate)).map(normalizePathForBoundary); if (parentRoots.length === 0) return []; const aliases = []; const internalCorePackageAliases = [...INTERNAL_CORE_PACKAGE_ALIASES, ...INTERNAL_CORE_EXPORTED_PACKAGE_DIRS.map((packageDir) => ({ packageName: `@openclaw/${packageDir}`, packageDir, subpaths: listWorkspacePackageExportAliasEntries({ packageRoot, packageName: `@openclaw/${packageDir}`, packageDir }).map((entry) => [entry.subpath, entry.srcFile]) }))]; for (const entry of internalCorePackageAliases) for (const [subpath, srcFile] of entry.subpaths) { const request = subpath ? `${entry.packageName}/${subpath}` : entry.packageName; const target = path.join(packageRoot, "packages", entry.packageDir, "src", srcFile); if (pluginCacheExistsSync(target)) aliases.push({ request, target, parentRoots }); } return aliases; } function installResolver() { const native = getPluginCache().sdk.native; if (installed || !(native.aliases.size || native.sdkProviders.size)) return; const bun = globalThis.Bun; if (bun) bun.plugin({ name: "openclaw-plugin-sdk-alias", setup(builder) { builder.onResolve({ filter: BUN_NATIVE_ALIAS_FILTER, namespace: "file" }, ({ path: request, importer }) => { const target = resolveAliasTargetForParentPath(request, importer); return target ? { path: target, namespace: "file" } : void 0; }); } }); const previousResolveFilename = moduleWithResolver[nodeResolveFilenameProperty]; if (!previousResolveFilename || !supportsNativeModuleAliasHooks()) { installed = Boolean(bun); return; } moduleWithResolver[nodeResolveFilenameProperty] = ((request, parent, isMain, options) => resolveAliasTargetForParentPath(request, parent?.filename) ?? previousResolveFilename(request, parent, isMain, options)); moduleWithResolver.registerHooks?.({ resolve(specifier, context, nextResolve) { const aliasTarget = resolveAliasTargetForParentUrl(specifier, context.parentURL); const resolved = aliasTarget ? { shortCircuit: true, url: pathToFileURL(aliasTarget).href } : nextResolve(specifier, context); if (context.conditions.includes("import") && resolved.url.startsWith("file:")) { const filename = fileURLToPath(resolved.url); const sdkTarget = isPluginSdkAliasSpecifier(specifier) ? aliasTarget : Array.from(getPluginCache().sdk.contexts.values()).some(({ sdkRoots }) => sdkRoots.includes(path.dirname(filename))) ? resolveAliasTargetForParentUrl(`openclaw/plugin-sdk/${path.basename(filename, path.extname(filename))}`, context.parentURL) : void 0; if (sdkTarget && pathToFileURL(sdkTarget).href === resolved.url) Module.createRequire(import.meta.url)(sdkTarget); } return resolved; } }); installed = true; } function registerNativeAlias(params) { const pluginSdkNativeAliases = getPluginCache().sdk.native.aliases; const entries = pluginSdkNativeAliases.get(params.request) ?? []; for (const parentRoot of params.parentRoots) { const existingIndex = entries.findIndex((entry) => entry.parentRoot === parentRoot); if (existingIndex !== -1) { entries[existingIndex] = { parentRoot, target: params.target }; continue; } entries.push({ parentRoot, target: params.target }); } if (entries.length > 0) pluginSdkNativeAliases.set(params.request, entries); } function clearNativeAliasesForParentRoots(parentRoots) { if (parentRoots.length === 0) return; const parentRootSet = new Set(parentRoots); for (const root of parentRoots) getPluginCache().sdk.native.sdkProviders.delete(root); const pluginSdkNativeAliases = getPluginCache().sdk.native.aliases; for (const [request, entries] of pluginSdkNativeAliases) { const nextEntries = entries.filter((entry) => !parentRootSet.has(entry.parentRoot)); if (nextEntries.length === 0) pluginSdkNativeAliases.delete(request); else pluginSdkNativeAliases.set(request, nextEntries); } } function registerInternalCorePackageNativeAliases(options) { const packageRoot = resolveInternalCorePackageHostRoot(resolveLoaderModulePath(options)); const registeredInternalCorePackageHosts = getPluginCache().sdk.native.registeredHosts; if (registeredInternalCorePackageHosts.has(packageRoot)) return; for (const alias of listInternalCorePackageNativeAliases(packageRoot)) registerNativeAlias(alias); registeredInternalCorePackageHosts.add(packageRoot); } function installOpenClawPluginSdkNativeResolver(options = {}) { const parentRoots = resolveAllowedParentRoots(options); clearNativeAliasesForParentRoots(parentRoots); const aliases = preparePluginLoaderAliases({ modulePath: options.pluginModulePath ?? resolveLoaderModulePath(options), argv1: options.argv1 ?? process.argv[1], moduleUrl: options.moduleUrl ?? pathToFileURL(resolveLoaderModulePath(options)).href, pluginSdkResolution: options.pluginSdkResolution, devSourceRoot: options.devSourceRoot }); const native = getPluginCache().sdk.native; for (const parentRoot of parentRoots) native.sdkProviders.set(parentRoot, { resolveAlias: aliases.resolveAlias }); registerInternalCorePackageNativeAliases(options); installResolver(); } function installOpenClawInternalCorePackageNativeResolver(options = {}) { registerInternalCorePackageNativeAliases(options); installResolver(); return [...getPluginCache().sdk.native.aliases.keys()].toSorted(); } //#endregion //#region src/plugins/plugin-module-loader-cache.ts /** Caches plugin module loaders and native-load stats for runtime/source module imports. */ const MAX_TRACKED_SOURCE_TRANSFORM_TARGETS = 24; const pluginModuleLoaderStats = { calls: 0, nativeHits: 0, nativeMisses: 0, sourceTransformForced: 0, sourceTransformFallbacks: 0, sourceTransformTargets: /* @__PURE__ */ new Map() }; function recordSourceTransformTarget(target) { const current = pluginModuleLoaderStats.sourceTransformTargets.get(target) ?? 0; pluginModuleLoaderStats.sourceTransformTargets.set(target, current + 1); if (pluginModuleLoaderStats.sourceTransformTargets.size <= MAX_TRACKED_SOURCE_TRANSFORM_TARGETS) return; const [leastUsedTarget] = [...pluginModuleLoaderStats.sourceTransformTargets].reduce((least, entry) => entry[1] < least[1] ? entry : least); pluginModuleLoaderStats.sourceTransformTargets.delete(leastUsedTarget); } /** Returns process-local plugin module loader stats for diagnostics and tests. */ function getPluginModuleLoaderStats() { const { sourceTransformTargets, ...stats } = pluginModuleLoaderStats; return { ...stats, topSourceTransformTargets: [...sourceTransformTargets].toSorted((left, right) => right[1] - left[1] || left[0].localeCompare(right[0])).slice(0, 8).map(([target, count]) => ({ target, count })) }; } function toSourceTransformImportPath(specifier) { if (process.platform === "win32" && path.isAbsolute(specifier)) return pathToFileURL(specifier).href; return toSafeImportPath(specifier); } function resolveAutomaticJitiTsconfig(loaderFilename) { const enabled = process.env.JITI_TSCONFIG_PATHS; if (enabled !== "1" && enabled !== "true") return; let directory = path.dirname(loaderFilename); while (true) { const config = path.join(directory, "tsconfig.json"); if (fs.existsSync(config)) return config; const parent = path.dirname(directory); if (parent === directory) return; directory = parent; } } function createBunJitiImportCachePlugin(babel) { return { visitor: { Program: { exit(program) { const calls = []; program.traverse({ CallExpression(call) { if (call.node.callee.type === "Identifier" && call.node.callee.name === "jitiImport" && !call.scope.getBinding("jitiImport")) calls.push(call); } }); if (calls.length === 0) return; const cache = program.scope.generateUidIdentifier("openclawJitiImports"); const load = program.scope.generateUidIdentifier("openclawJitiImport"); for (const call of calls) call.replaceWith(babel.types.callExpression(babel.types.identifier(load.name), call.node.arguments)); program.unshiftContainer("body", babel.template.statements.ast(` var ${cache.name}; function ${load.name}(specifier, ...args) { let entry = ${cache.name}; while (entry) { if (entry.specifier === specifier) { return entry.pending; } entry = entry.next; } const pending = (async () => { await 0; return jitiImport(specifier, ...args); })(); ${cache.name} = { specifier, pending, next: ${cache.name} }; return pending; } `)); } } } }; } function preserveBunJitiDynamicImportResults(loader) { if (!process.versions.bun || typeof loader.options?.transform !== "function") return; const transform = loader.options.transform; loader.options.transform = (options) => transform({ ...options, babel: { ...options.babel, plugins: [...Array.isArray(options.babel?.plugins) ? options.babel.plugins : [], createBunJitiImportCachePlugin] } }); } function resolvePluginModuleLoaderCacheEntry(params) { const loaderFilename = toSafeImportPath(params.loaderFilename ?? params.modulePath); const tryNative = params.tryNative ?? resolvePluginLoaderTryNative(params.modulePath, params); const explicit = params.aliasMap ? { ...params.aliasMap } : void 0; const aliases = explicit ? { cacheKey: createPluginLoaderModuleCacheKey({ tryNative, aliasMap: explicit }), getAliasMap: () => explicit, getSourceTransformAliasMap: () => explicit, resolveAlias: (specifier) => explicit[specifier] } : preparePluginLoaderAliases({ modulePath: params.modulePath, argv1: params.argvEntry ?? process.argv[1], moduleUrl: params.importerUrl, devSourceRoot: params.devSourceRoot, pluginSdkResolution: params.pluginSdkResolution }); const moduleConfigCacheKey = `${tryNative ? "native" : "transform"}\0${aliases.cacheKey}`; const lazyNativeAliasFallback = tryNative && typeof Module.registerHooks !== "function"; const scopedCacheKey = `${loaderFilename}::${params.cacheScopeKey ? `${params.cacheScopeKey}::` : ""}${moduleConfigCacheKey}`; return { loaderFilename, getAliasMap: aliases.getAliasMap, resolveAlias: aliases.resolveAlias, tryNative, sourceTransformAliasMap: lazyNativeAliasFallback ? aliases.getSourceTransformAliasMap : void 0, scopedCacheKey }; } function createPluginModuleLoader(params) { let loadWithSourceTransform; const getLoadWithSourceTransform = () => { if (loadWithSourceTransform) return loadWithSourceTransform; const aliasMap = params.sourceTransformAliasMap?.() ?? params.getAliasMap(); const jitiOptions = buildPluginLoaderJitiOptions(aliasMap, { modulePath: params.loaderFilename }); const automaticTsconfig = resolveAutomaticJitiTsconfig(params.loaderFilename); const jitiLoader = (params.createLoader ?? createJiti)(params.loaderFilename, { ...jitiOptions, ...automaticTsconfig ? { tsconfigPaths: automaticTsconfig } : {}, virtualModules: new Proxy({}, { has(_target, key) { return typeof key === "string" && isPluginSdkAliasSpecifier(key) && Boolean(params.resolveAlias(key)); }, get(_target, key) { const target = typeof key === "string" ? params.resolveAlias(key) : void 0; if (!target) return; const native = tryNativeRequireModule(target, { aliasMap: params.resolveAlias }); if (!native.ok) throw new Error(`Unable to load host Plugin SDK natively: ${target}. Use a supported native TypeScript loader for a source host, or rebuild the host SDK.`); return native.moduleExport; } }), tryNative: false }); preserveBunJitiDynamicImportResults(jitiLoader); loadWithSourceTransform = (target) => jitiLoader(toSourceTransformImportPath(target)); return loadWithSourceTransform; }; return (target) => { const source = getPluginCacheSource(target, params.cache); const cached = source.variants.get(params.scopedCacheKey)?.exports; if (cached) return cached.value; const loaded = withPluginCache(params.cache, () => { pluginModuleLoaderStats.calls += 1; if (params.tryNative) { const native = tryNativeRequireJavaScriptModule(target, { aliasMap: params.resolveAlias, fallbackOnMissingDependency: true }); if (native.ok) { pluginModuleLoaderStats.nativeHits += 1; return native.moduleExport; } pluginModuleLoaderStats.nativeMisses += 1; pluginModuleLoaderStats.sourceTransformFallbacks += 1; } else pluginModuleLoaderStats.sourceTransformForced += 1; recordSourceTransformTarget(target); return getLoadWithSourceTransform()(target); }); source.variants.set(params.scopedCacheKey, { exports: { value: loaded } }); return loaded; }; } function getCachedPluginModuleLoader(params) { const cacheEntry = resolvePluginModuleLoaderCacheEntry(params); const cache = getPluginCache(); const cached = cache.moduleLoaders.get(cacheEntry.scopedCacheKey); if (cached) return cached; installOpenClawInternalCorePackageNativeResolver({ moduleUrl: params.importerUrl }); const loader = createPluginModuleLoader({ ...cacheEntry, cache, ...params.createLoader ? { createLoader: params.createLoader } : {} }); cache.moduleLoaders.set(cacheEntry.scopedCacheKey, loader); return loader; } function resolvePublicSurfaceInstance(params) { if (!isPathInside$1(params.boundaryRoot, params.modulePath) && !isPathInside$1(getPluginCacheRoot(params.boundaryRoot).rootDir, params.modulePath)) throw new Error(`Unable to open ${params.surfaceLabel}: outside ${params.boundaryLabel}`); const owner = resolvePluginRuntimeRecord(params); const instance = owner ? getPluginInstance(owner) : void 0; if ((owner?.origin ?? params.origin) === "bundled" && (owner?.status !== "loaded" || instance?.hasModuleSource(params.modulePath) === void 0)) return; if (!owner || owner.status !== "loaded") { if (getPluginRuntimeGatewayRequestScope()?.pluginRegistry) throw new Error(`Plugin public surface ${params.modulePath} has no active runtime owner.`); return; } if (!instance) throw new Error(`Plugin ${owner.id} has no runtime module owner`); return instance; } /** Validates an entry once per generation without changing its module export shape. */ function preparePluginModule(params) { const cache = getPluginCache(); let source = getPluginCacheSource(params.modulePath, cache); const boundaryKey = `${getPluginCacheRoot(params.boundaryRoot).rootDir}\0${params.rejectHardlinks}`; if (source.validatedBoundaries.has(boundaryKey)) return { source, modulePath: source.modulePath ?? params.modulePath }; const opened = openPluginRootFileSync({ filePath: params.modulePath, rootPath: params.boundaryRoot, boundaryLabel: params.boundaryLabel, rejectHardlinks: params.rejectHardlinks }); if (!opened.ok) throw new Error(`Unable to open ${params.surfaceLabel}`, { cause: opened.error }); fs.closeSync(opened.fd); if (!sameFileIdentity(opened.stat, fs.statSync(opened.path))) throw new Error(`${params.surfaceLabel} changed after validation`); const root = bindPluginCacheRoot(params.boundaryRoot, opened.rootRealPath); root.publicSurfaceBoundary ??= { boundaryLabel: params.boundaryLabel, rejectHardlinks: params.rejectHardlinks }; cache.sourceAliases.set(path.resolve(params.modulePath), opened.path); source = getPluginCacheSource(opened.path, cache); source.modulePath = opened.path; source.validatedBoundaries.add(`${opened.rootRealPath}\0${params.rejectHardlinks}`); return { source, modulePath: opened.path }; } /** Public artifacts and SDK facades share one validated module, including circular imports. */ function loadPluginPublicSurfaceModuleSync(params) { const instance = resolvePublicSurfaceInstance(params); if (instance) return instance.loadModule(params.modulePath); const { source, modulePath } = preparePluginModule(params); const cached = source.publicSurface?.exports; if (cached) return cached; const sentinel = {}; const boundaryRoot = getPluginCacheRoot(params.boundaryRoot).rootDir; source.disposeModule ??= () => clearPluginModuleRequireCache(modulePath, boundaryRoot); source.publicSurface = { exports: sentinel }; try { Object.assign(sentinel, params.loadModule(modulePath)); return sentinel; } catch (error) { delete source.publicSurface; source.validatedBoundaries.clear(); throw error; } } //#endregion export { installOpenClawInternalCorePackageNativeResolver as a, preparePluginModule as i, getPluginModuleLoaderStats as n, installOpenClawPluginSdkNativeResolver as o, loadPluginPublicSurfaceModuleSync as r, toSafeImportPath as s, getCachedPluginModuleLoader as t };