openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
529 lines (528 loc) • 20.3 kB
JavaScript
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 };