openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
392 lines (391 loc) • 20.8 kB
JavaScript
import { o as getPluginCache } from "./plugin-cache-Bn9I3v9Q.mjs";
import { o as resolveUserPath } from "./home-dir-CjKH62jd.mjs";
import { l as normalizeSortedUniqueStringEntries } from "./string-normalization-YMwDjufr.mjs";
import { n as getPluginRuntimeLoadContextState } from "./load-context-state-Dj3BDflJ.mjs";
import { r as getPluginRegistryForContext } from "./gateway-request-scope-Btza1qbw.mjs";
import { X as resolveConfigEnvVars } from "./redact-BEIE6NCT.mjs";
import "./utils-DUAwk2p5.mjs";
import { o as createConfigRuntimeEnv } from "./config-env-vars-oFV7TqIg.mjs";
import { p as extractPluginInstallRecordsFromInstalledPluginIndex } from "./installed-plugin-index-DyE_yB6z.mjs";
import { f as resolvePluginRuntimeArtifactPreference } from "./bundled-dir-CGDkeqDD.mjs";
import { l as normalizePluginsConfig, n as createPluginActivationSource, t as applyTestPluginDefaults } from "./config-state-1t-kMQI9.mjs";
import { i as loadInstalledPluginIndexInstallRecordsSync } from "./installed-plugin-index-record-reader--X-E60FV.mjs";
import { n as resolvePluginDiscoveryContext } from "./plugin-control-plane-context-BhsvNWYe.mjs";
import { i as getCurrentPluginMetadataSnapshot, p as normalizePluginIdScope } from "./current-plugin-metadata-snapshot-BvP9Ow4r.mjs";
import { I as getRuntimeConfigCapture } from "./runtime-snapshot-CifcQ780.mjs";
import { c as getPluginLoaderCacheState } from "./registry-lifecycle-ywOMiXNf.mjs";
import { f as getActivePluginRegistryWorkspaceDir, l as getActivePluginRegistry, u as getActivePluginRegistryKey } from "./runtime-zG-NbNbr.mjs";
import { t as resolvePluginActivationSourceConfig } from "./activation-source-config-B9oPNkDf.mjs";
import { t as captureRuntimeConfig } from "./runtime-source-projection-CAFQ9dqa.mjs";
import "./env-vars-B0Mhe0wI.mjs";
import "./installed-plugin-index-records-CH0xW_k-.mjs";
import { s as resolvePluginRegistrationConfigKey, t as activationConfigFingerprint } from "./load-context-CMDQ-dOD.mjs";
import { n as getPluginRegistryRuntime } from "./registry-runtime-binding-i7RQa2C4.mjs";
import { a as matchesPluginRuntimeArtifactSelection } from "./plugin-runtime-artifact-binding-Cv-2_-lT.mjs";
import { createHash } from "node:crypto";
//#region src/plugins/loader-load-context.ts
const runtimeBindingCacheIds = /* @__PURE__ */ new WeakMap();
let nextRuntimeBindingCacheId = 1;
function resolveRuntimeBindingCacheId(value) {
if (!value) return;
const existing = runtimeBindingCacheIds.get(value);
if (existing !== void 0) return existing;
const id = nextRuntimeBindingCacheId++;
runtimeBindingCacheIds.set(value, id);
return id;
}
function buildActivationMetadataHash(params) {
const sourceChannelEnablement = Object.entries(params.activationSource.rootConfig?.channels ?? {}).flatMap(([channelId, value]) => {
if (!value || typeof value !== "object" || Array.isArray(value)) return [];
const enabled = value.enabled;
return typeof enabled === "boolean" ? [[channelId, enabled]] : [];
}).toSorted(([left], [right]) => left.localeCompare(right));
const pluginEntryInputs = Object.entries(params.activationSource.plugins.entries).map(([pluginId, { enabled }]) => [pluginId, enabled]).toSorted(([left], [right]) => left.localeCompare(right));
const autoEnableReasonEntries = Object.entries(params.autoEnabledReasons).map(([pluginId, reasons]) => [pluginId, [...reasons]]).toSorted(([left], [right]) => left.localeCompare(right));
return createHash("sha256").update(JSON.stringify({
enabled: params.activationSource.plugins.enabled,
allow: params.activationSource.plugins.allow,
deny: params.activationSource.plugins.deny,
memorySlot: params.activationSource.plugins.slots.memory,
entries: pluginEntryInputs,
channelEnablement: sourceChannelEnablement,
autoEnabledReasons: autoEnableReasonEntries
})).digest("hex");
}
function buildCacheKeys(params) {
const { roots, loadPaths, devSourceRoot } = params.discoveryContext;
const installs = Object.fromEntries(Object.entries(params.installs ?? {}).map(([pluginId, install]) => [pluginId, {
...install,
installPath: typeof install.installPath === "string" ? resolveUserPath(install.installPath, params.env) : install.installPath,
sourcePath: typeof install.sourcePath === "string" ? resolveUserPath(install.sourcePath, params.env) : install.sourcePath
}]));
const cacheIdentity = {
roots,
devSourceRoot,
plugins: {
...params.plugins,
loadPaths,
entries: Object.entries(params.plugins.entries).map(([id, entry]) => [id, entry.enabled])
},
registrationConfigKey: params.registrationConfigKey,
installs,
discoverySources: params.discovery?.candidates.map((candidate) => [
candidate.effectivePluginId ?? candidate.idHint,
candidate.origin,
candidate.rootDir,
candidate.source,
candidate.setupSource,
candidate.sourcePreferred,
candidate.configSelected,
candidate.packageManifest?.build?.bundledDist
]),
activationMetadataKey: params.activationMetadataKey ?? "",
capabilityCatalogIdentity: params.capabilityCatalogIdentity,
allowProcessHomeSessionCatalogs: params.allowProcessHomeSessionCatalogs !== false,
onlyPluginIds: params.onlyPluginIds,
includeSetupOnlyChannelPlugins: params.includeSetupOnlyChannelPlugins === true,
forceSetupOnlyChannelPlugins: params.forceSetupOnlyChannelPlugins === true,
channelPluginLoadIntent: params.channelPluginLoadIntent,
artifactPreference: params.artifactPreference,
resolveRawConfigEnvVars: params.resolveRawConfigEnvVars === true,
loadModules: params.loadModules !== false,
toolDiscovery: params.toolDiscovery === true,
runtimeSubagentMode: params.runtimeSubagentMode ?? "default",
runtimeBindingIdentity: params.runtimeBindingIdentity ?? "{}",
pluginSdkResolution: params.pluginSdkResolution ?? "auto",
coreGatewayMethodNames: params.coreGatewayMethodNames ?? [],
activate: params.activate !== false,
runtimeSideEffects: params.runtimeSideEffects,
mode: params.mode,
expectedSourceDigests: params.expectedSourceDigests ? Object.entries(params.expectedSourceDigests).toSorted(([a], [b]) => a.localeCompare(b)) : void 0
};
const requestIdentity = JSON.stringify(cacheIdentity);
const preparedIdentity = params.registrationSnapshots ? JSON.stringify({
...cacheIdentity,
roots: {
...roots,
workspace: void 0
},
registrationConfigOrigin: params.registrationConfigOrigin,
registrationSnapshots: params.registrationSnapshots
}) : requestIdentity;
const resolveManifestCacheKey = (manifestRegistry) => createHash("sha256").update(manifestRegistry ? preparedIdentity : requestIdentity).update(JSON.stringify(manifestRegistry?.plugins.map((plugin) => [
plugin.id,
plugin.origin,
plugin.rootDir,
plugin.source,
plugin.setupSource,
plugin.providerDiscoverySource,
plugin.capabilityCatalogSource,
plugin.sourcePreferred,
plugin.packageManifest?.build?.bundledDist
])) ?? "").digest("hex");
return {
cacheKey: resolveManifestCacheKey(params.manifestRegistry),
resolveManifestCacheKey
};
}
function resolveRuntimeSubagentMode(runtimeOptions) {
if (runtimeOptions?.allowGatewaySubagentBinding === true) return "gateway-bindable";
return runtimeOptions?.subagent ? "explicit" : "default";
}
function resolveCoreGatewayMethodNames(options) {
const names = new Set(options.coreGatewayMethodNames ?? []);
for (const name of Object.keys(options.coreGatewayHandlers ?? {})) names.add(name);
const methodNames = Array.from(names);
methodNames.sort();
return methodNames;
}
function mergePluginTrustList(runtimeList, sourceList) {
if (runtimeList === sourceList || sourceList.length === 0) return runtimeList;
const merged = [...runtimeList];
const seen = new Set(merged);
for (const entry of sourceList) if (!seen.has(entry)) {
merged.push(entry);
seen.add(entry);
}
return merged.length === runtimeList.length ? runtimeList : merged;
}
function mergeTrustPluginConfigFromActivationSource(params) {
const source = params.activationSource.plugins;
const allow = mergePluginTrustList(params.normalized.allow, source.allow);
const deny = mergePluginTrustList(params.normalized.deny, source.deny);
const loadPaths = mergePluginTrustList(params.normalized.loadPaths, source.loadPaths);
if (allow === params.normalized.allow && deny === params.normalized.deny && loadPaths === params.normalized.loadPaths) return params.normalized;
return {
...params.normalized,
allow,
deny,
loadPaths
};
}
function resolvePluginLoadCacheContext(options = {}) {
const cacheState = getPluginLoaderCacheState();
const shouldResolveRawConfigEnvVars = options.resolveRawConfigEnvVars === true;
const baseEnv = options.env ?? process.env;
const rawConfig = options.config ?? {};
const rawActivationSourceConfig = resolvePluginActivationSourceConfig({
config: options.config,
activationSourceConfig: options.activationSourceConfig
});
const env = shouldResolveRawConfigEnvVars ? createConfigRuntimeEnv(rawConfig, baseEnv) : baseEnv;
const runtimeConfig = applyTestPluginDefaults(shouldResolveRawConfigEnvVars ? resolveConfigEnvVars(rawConfig, env, { onMissing: () => void 0 }) : rawConfig, env);
const activationConfig = shouldResolveRawConfigEnvVars ? resolveConfigEnvVars(rawActivationSourceConfig, env, { onMissing: () => void 0 }) : rawActivationSourceConfig;
const normalized = normalizePluginsConfig(runtimeConfig.plugins);
const activationSource = createPluginActivationSource({
config: activationConfig,
plugins: runtimeConfig.plugins === activationConfig.plugins ? normalized : void 0
});
const trustNormalized = mergeTrustPluginConfigFromActivationSource({
normalized,
activationSource
});
const onlyPluginIds = normalizePluginIdScope(options.onlyPluginIds);
const includeSetupOnlyChannelPlugins = options.includeSetupOnlyChannelPlugins === true;
const forceSetupOnlyChannelPlugins = options.forceSetupOnlyChannelPlugins === true;
const channelPluginLoadIntent = options.channelPluginLoadIntent ?? "full";
const artifactPreference = resolvePluginRuntimeArtifactPreference(options.preferBuiltPluginArtifacts);
const runtimeSubagentMode = resolveRuntimeSubagentMode(options.runtimeOptions);
const activeRegistry = runtimeSubagentMode === "gateway-bindable" && options.mode !== "cli-metadata" && (!options.runtimeOptions?.nodes || !options.runtimeOptions?.subagent) ? getActivePluginRegistry() : void 0;
const borrowedGatewayRuntime = activeRegistry ? getPluginRegistryRuntime(activeRegistry) : void 0;
const coreGatewayMethodNames = resolveCoreGatewayMethodNames(options);
const currentMetadataSnapshot = options.installRecords === void 0 && trustNormalized.loadPaths === normalized.loadPaths && !shouldResolveRawConfigEnvVars && (options.env === void 0 || options.env === process.env) ? getCurrentPluginMetadataSnapshot({
config: rawConfig,
env,
workspaceDir: options.workspaceDir
}) ?? (onlyPluginIds !== void 0 ? getCurrentPluginMetadataSnapshot({
config: rawConfig,
env,
workspaceDir: options.workspaceDir,
pluginIds: onlyPluginIds
}) : void 0) : void 0;
const preparedInstallRecords = currentMetadataSnapshot && (options.manifestRegistry === void 0 || options.manifestRegistry === currentMetadataSnapshot.manifestRegistry) ? extractPluginInstallRecordsFromInstalledPluginIndex(currentMetadataSnapshot.index) : void 0;
const installRecords = {
...options.installRecords ?? preparedInstallRecords ?? loadInstalledPluginIndexInstallRecordsSync({ env }),
...runtimeConfig.plugins?.installs
};
const discoveryContext = resolvePluginDiscoveryContext({
workspaceDir: options.workspaceDir,
loadPaths: trustNormalized.loadPaths,
env
});
const registrationConfigKey = resolvePluginRegistrationConfigKey({
runtimeEntries: normalized.entries,
sourceEntries: activationSource.plugins.entries
});
const shouldActivate = options.mode !== "cli-metadata" && options.activate !== false;
const runtimeSideEffects = options.runtimeSideEffects ?? shouldActivate;
const registrationConfigOrigin = options.registrationConfigOrigin;
const registrationGeneration = !shouldActivate && registrationConfigOrigin && getRuntimeConfigCapture(registrationConfigOrigin) ? resolveRuntimeBindingCacheId(registrationConfigOrigin) : void 0;
const manifestRegistry = options.manifestRegistry ?? (options.discovery === void 0 ? currentMetadataSnapshot?.manifestRegistry : void 0);
const { cacheKey, resolveManifestCacheKey } = buildCacheKeys({
discoveryContext,
plugins: trustNormalized,
registrationConfigKey,
activationMetadataKey: buildActivationMetadataHash({
activationSource,
autoEnabledReasons: options.autoEnabledReasons ?? {}
}),
installs: installRecords,
manifestRegistry,
discovery: options.manifestRegistry ? void 0 : options.discovery,
env,
onlyPluginIds,
includeSetupOnlyChannelPlugins,
forceSetupOnlyChannelPlugins,
channelPluginLoadIntent,
artifactPreference,
resolveRawConfigEnvVars: options.resolveRawConfigEnvVars,
toolDiscovery: options.toolDiscovery,
capabilityCatalogIdentity: options.capabilityCatalog ? JSON.stringify([
options.capabilityCatalog.family,
resolveRuntimeBindingCacheId(options.capabilityCatalog.context),
resolveRuntimeBindingCacheId(getPluginCache()),
resolveRuntimeBindingCacheId(getPluginRegistryForContext() ?? void 0)
]) : void 0,
loadModules: options.loadModules,
runtimeSubagentMode,
runtimeBindingIdentity: JSON.stringify({
capabilityCatalogContext: resolveRuntimeBindingCacheId(options.capabilityCatalogContext),
modelAuth: resolveRuntimeBindingCacheId(options.runtimeOptions?.modelAuth),
modelConfig: resolveRuntimeBindingCacheId(options.runtimeOptions?.modelConfig),
nodes: resolveRuntimeBindingCacheId(options.runtimeOptions?.nodes),
subagent: resolveRuntimeBindingCacheId(options.runtimeOptions?.subagent),
borrowedGatewayRuntime: shouldActivate ? void 0 : resolveRuntimeBindingCacheId(borrowedGatewayRuntime)
}),
pluginSdkResolution: options.pluginSdkResolution,
coreGatewayMethodNames,
allowProcessHomeSessionCatalogs: options.allowProcessHomeSessionCatalogs,
activate: shouldActivate,
runtimeSideEffects,
registrationConfigOrigin: registrationGeneration,
registrationSnapshots: registrationGeneration ? [activationConfigFingerprint(runtimeConfig), activationConfigFingerprint(activationConfig)] : void 0,
expectedSourceDigests: options.expectedSourceDigests,
mode: options.mode ?? "full"
});
let captured;
const capture = () => {
if (!captured) {
const cfg = captureRuntimeConfig(runtimeConfig);
if (registrationGeneration !== void 0 && cfg !== runtimeConfig) runtimeBindingCacheIds.set(cfg, registrationGeneration);
const activationSourceConfig = activationConfig === runtimeConfig ? cfg : captureRuntimeConfig(activationConfig);
const capturedNormalized = normalizePluginsConfig(cfg.plugins);
const capturedActivationSource = createPluginActivationSource({
config: activationSourceConfig,
plugins: cfg.plugins === activationSourceConfig.plugins ? capturedNormalized : void 0
});
captured = {
cfg,
activationSourceConfig,
activationSource: capturedActivationSource,
normalized: mergeTrustPluginConfigFromActivationSource({
normalized: capturedNormalized,
activationSource: capturedActivationSource
})
};
}
return captured;
};
return {
cacheState,
env,
get cfg() {
return capture().cfg;
},
registrationConfigKey,
metadataSnapshot: currentMetadataSnapshot,
get normalized() {
return capture().normalized;
},
get activationSourceConfig() {
return capture().activationSourceConfig;
},
get activationSource() {
return capture().activationSource;
},
autoEnabledReasons: options.autoEnabledReasons ?? {},
onlyPluginIds,
includeSetupOnlyChannelPlugins,
forceSetupOnlyChannelPlugins,
channelPluginLoadIntent,
artifactPreference,
shouldActivate,
runtimeSideEffects,
shouldLoadModules: options.loadModules !== false,
runtimeSubagentMode,
borrowedGatewayRuntime,
installRecords,
devSourceRoot: discoveryContext.devSourceRoot,
cacheKey,
resolveManifestCacheKey
};
}
//#endregion
//#region src/plugins/active-runtime-registry.ts
/** Return the exact active registry without triggering a fresh load on cache miss. */
function resolveCompatibleRuntimePluginRegistry(options) {
const activeRegistry = getActivePluginRegistry() ?? void 0;
if (!activeRegistry || options === void 0) return activeRegistry;
const activeCacheKey = getActivePluginRegistryKey();
if (!activeCacheKey) return;
const requestedKey = resolvePluginLoadCacheContext(options).cacheKey;
if (requestedKey === activeCacheKey) return activeRegistry;
const identity = getPluginRuntimeLoadContextState(activeRegistry)?.loaderCacheIdentity;
return identity && (identity.requestKey === activeCacheKey && identity.resolvedKey === requestedKey || identity.resolvedKey === activeCacheKey && identity.requestKey === requestedKey) ? activeRegistry : void 0;
}
function isRuntimePluginRecordLoaded(plugin) {
return plugin.status === "loaded" && (plugin.format === "bundle" || plugin.imported !== false);
}
/** Lists runtime-loaded plugin ids from an immutable/request-scoped registry handle. */
function listRuntimePluginIdsFromRegistry(registry) {
return normalizeSortedUniqueStringEntries(registry.plugins.filter(isRuntimePluginRecordLoaded).map((plugin) => plugin.id));
}
function listLoadedRuntimePluginIds() {
const registry = getActivePluginRegistry();
return registry ? listRuntimePluginIdsFromRegistry(registry) : [];
}
function registryContainsRuntimePluginIds(registry, pluginIds) {
if (pluginIds === void 0) return true;
if (pluginIds.length === 0 && registry.plugins.length > 0) return false;
const missing = new Set(pluginIds);
for (const plugin of registry.plugins) if (plugin.status === void 0 || isRuntimePluginRecordLoaded(plugin)) missing.delete(plugin.id);
if (pluginIds.length > 0 && missing.size === 0) return true;
if (registry.plugins.some((plugin) => missing.has(plugin.id))) return false;
for (const [key, value] of Object.entries(registry)) {
if (key === "diagnostics" || key === "channelSetups" || !Array.isArray(value)) continue;
for (const entry of value) if (entry && typeof entry === "object" && "pluginId" in entry) {
const pluginId = entry.pluginId;
if (typeof pluginId === "string" && pluginId.length > 0) {
if (pluginIds.length === 0) return false;
missing.delete(pluginId);
if (missing.size === 0) return true;
}
}
}
return pluginIds.length === 0;
}
/** Indexes selected owners; omitted artifact preference retains the loaded owner's policy. */
function createRuntimePluginManifestLookup(registry, manifestPlugins, preferBuiltPluginArtifacts) {
const records = new Map(registry.plugins.filter(isRuntimePluginRecordLoaded).map((plugin) => [plugin.id, plugin]));
const manifests = new Map(manifestPlugins.toReversed().map((plugin) => [plugin.id, plugin]));
return (pluginId) => {
const record = records.get(pluginId);
const manifest = manifests.get(pluginId);
return record && manifest && record.origin === manifest.origin && matchesPluginRuntimeArtifactSelection(record, manifest, preferBuiltPluginArtifacts) ? record : void 0;
};
}
function getLoadedRuntimePluginRegistry(params = {}) {
const requiredIds = params.requiredPluginIds ?? params.loadOptions?.onlyPluginIds;
const requiredPluginIds = requiredIds === void 0 ? void 0 : normalizeSortedUniqueStringEntries(requiredIds);
if (params.loadOptions && requiredPluginIds === void 0) return resolveCompatibleRuntimePluginRegistry(params.loadOptions);
const activeWorkspaceDir = getActivePluginRegistryWorkspaceDir();
const requestedWorkspaceDir = params.workspaceDir ?? params.loadOptions?.workspaceDir;
if ((Object.hasOwn(params, "workspaceDir") || params.loadOptions || requestedWorkspaceDir !== void 0) && activeWorkspaceDir !== requestedWorkspaceDir) return;
const registry = getActivePluginRegistry();
if (!registry) return;
if (!registryContainsRuntimePluginIds(registry, requiredPluginIds) || params.loadOptions?.manifestRegistry && requiredPluginIds !== void 0 && !requiredPluginIds.every(createRuntimePluginManifestLookup(registry, params.loadOptions.manifestRegistry.plugins, params.loadOptions.preferBuiltPluginArtifacts))) return;
if (params.loadOptions?.discovery && !params.loadOptions.manifestRegistry) return resolveCompatibleRuntimePluginRegistry(params.loadOptions);
return registry;
}
//#endregion
export { registryContainsRuntimePluginIds as a, resolveRuntimeSubagentMode as c, listRuntimePluginIdsFromRegistry as i, getLoadedRuntimePluginRegistry as n, resolveCompatibleRuntimePluginRegistry as o, listLoadedRuntimePluginIds as r, resolvePluginLoadCacheContext as s, createRuntimePluginManifestLookup as t };