openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
342 lines (341 loc) • 15.6 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs";
import { a as extractErrorCode } from "./error-coercion-W9BtigRm.mjs";
import { d as getPluginCacheRoot, f as getPluginCacheSource } from "./plugin-cache-CfBhQFSN.mjs";
import { r as resolveOpenClawPackageRootSync } from "./openclaw-root-BGdnWXIW.mjs";
import { c as isVitestRuntimeEnv } from "./env-Ca5Je5YP.mjs";
import { r as isPathInside } from "./path-guards-CH7noY0Z.mjs";
import { t as formatErrorMessage } from "./errors-BvOkmQM5.mjs";
import { t as createSubsystemLogger } from "./subsystem-4NzR43uz.mjs";
import { l as pluginCacheRealpathSync, s as pluginCacheExistsSync } from "./package-manifest-DKd3Hflg.mjs";
import { s as resolveBundledPluginsDir } from "./bundled-dir-yjbttD4_.mjs";
import { u as resolvePluginMetadataSnapshot } from "./plugin-metadata-snapshot-DZdnLZdU.mjs";
import { t as loadChannelPluginModule } from "./module-loader-C__O49mE.mjs";
import { i as resolveBundledPluginGeneratedPath } from "./bundled-plugin-scan-DAfwXJuI.mjs";
import { n as unwrapDefaultModuleExport } from "./module-export-BbYMQUy2.mjs";
import { fileURLToPath } from "node:url";
import path from "node:path";
//#region src/plugins/bundled-channel-runtime.ts
/** Loads bundled channel plugin runtime entries and setup metadata. */
function toBundledChannelPluginMetadata(record) {
if (record.origin !== "bundled" || !record.source) return null;
return {
dirName: path.basename(record.rootDir),
source: {
source: record.source,
built: record.source
},
...record.setupSource ? { setupSource: {
source: record.setupSource,
built: record.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 rootDir = params?.rootDir;
const overrideDir = params?.scanDir ? path.resolve(params.scanDir) : rootDir ? [
"extensions",
"dist-runtime/extensions",
"dist/extensions"
].map((relative) => path.join(rootDir, relative)).find((candidate) => pluginCacheExistsSync(candidate)) : void 0;
if (overrideDir ? !pluginCacheExistsSync(overrideDir) : rootDir) return [];
return resolvePluginMetadataSnapshot({ env: overrideDir ? {
...process.env,
OPENCLAW_BUNDLED_PLUGINS_DIR: overrideDir,
...isVitestRuntimeEnv() ? { OPENCLAW_TEST_TRUST_BUNDLED_PLUGINS_DIR: "1" } : {}
} : void 0 }).plugins.flatMap((record) => toBundledChannelPluginMetadata(record) ?? []);
}
//#endregion
//#region src/channels/plugins/bundled-root.ts
/**
* Bundled channel package-root resolver.
*
* Computes cache scopes for generated channel metadata across source and packaged layouts.
*/
const OPENCLAW_PACKAGE_ROOT = resolveOpenClawPackageRootSync({
argv1: process.argv[1],
cwd: process.cwd(),
moduleUrl: import.meta.url.startsWith("file:") ? import.meta.url : void 0
}) ?? (import.meta.url.startsWith("file:") ? path.resolve(fileURLToPath(new URL("../../..", import.meta.url))) : process.cwd());
function derivePackageRootFromExtensionsDir(extensionsDir) {
const parentDir = path.dirname(extensionsDir);
const parentBase = path.basename(parentDir);
if (parentBase === "dist" || parentBase === "dist-runtime") return path.dirname(parentDir);
return parentDir;
}
/**
* Resolves the package/cache scope used for bundled channel plugin metadata.
*/
function resolveBundledChannelRootScope(env = process.env) {
const bundledPluginsDir = resolveBundledPluginsDir(env);
if (!bundledPluginsDir) return { packageRoot: OPENCLAW_PACKAGE_ROOT };
const resolvedPluginsDir = path.resolve(bundledPluginsDir);
return {
packageRoot: path.basename(resolvedPluginsDir) === "extensions" ? derivePackageRootFromExtensionsDir(resolvedPluginsDir) : resolvedPluginsDir,
pluginsDir: resolvedPluginsDir
};
}
//#endregion
//#region src/channels/plugins/meta-normalization.ts
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 {
...existing,
...next,
id: params.id,
label,
selectionLabel,
docsPath,
blurb
};
}
//#endregion
//#region src/channels/plugins/bundled.ts
const log = createSubsystemLogger("channels");
function resolveCanonicalPathOrAbsolute(targetPath) {
return pluginCacheRealpathSync(targetPath, true) ?? path.resolve(targetPath);
}
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 = resolveBundledPluginGeneratedPath(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;
const rawEntry = params.entry.source;
const candidate = path.isAbsolute(rawEntry) ? path.normalize(rawEntry) : path.resolve(pluginRoot, rawEntry);
const realCandidate = pluginCacheRealpathSync(candidate, true);
return realCandidate && isPathInside(pluginRoot, realCandidate) ? realCandidate : 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
});
return loadChannelPluginModule({
modulePath,
rootDir: boundaryRoot
});
}
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 resolveBundledChannelMetadata(id, rootScope) {
return listBundledChannelMetadata(rootScope).findLast((metadata) => metadata.manifest.id === id || metadata.manifest.channels?.includes(id));
}
function rememberBundledChannelArtifact(rootScope, kind, id, artifact, 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,
metadata
});
rememberBundledChannelArtifact(rootScope, kind, id, artifact, metadata);
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, metadata);
return;
} finally {
artifactLoadsInProgress.delete(loadKey);
}
}
const bundledChannelArtifactLoaders = {
entry({ id, rootScope, metadata }) {
const entry = loadGeneratedBundledChannelEntry("entry", rootScope, metadata);
if (entry && entry.id !== id) rememberBundledChannelArtifact(rootScope, "entry", entry.id, entry);
return entry;
},
setupEntry({ id, rootScope, metadata }) {
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, metadata }) {
const entry = getBundledChannelArtifactForRoot("entry", id, rootScope);
if (!entry) return;
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, normalizeChannelMeta as c, getBundledChannelSetupPlugin as i, getBundledChannelPlugin as n, listBundledChannelPlugins as o, getBundledChannelSecrets as r, listBundledChannelSetupPlugins as s, getBundledChannelAccountInspector as t };