openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
363 lines (362 loc) • 16.8 kB
JavaScript
import { a as getPluginCache } from "./plugin-cache-DGWspMEc.js";
import { c as isRecord } from "./record-coerce-DItp3I4t.js";
import { g as readStringValue, l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
import { s as normalizeOptionalTrimmedStringList } from "./string-normalization-DsCfAx8q.js";
import { a as pluginCacheRealpathSync, c as readPluginCacheFile, n as parsePluginCacheJson, r as pluginCacheExistsSync } from "./plugin-cache-files-DLPF_Tw2.js";
import { i as resolveBundledPluginsDir } from "./bundled-dir-BEfbEeCF.js";
import { i as DEFAULT_PLUGIN_ENTRY_CANDIDATES, l as normalizeManifestChannelCommandDefaults, o as getPackageManifestMetadata } from "./manifest-ByRdkf9X.js";
import { f as extractPluginInstallRecordsFromInstalledPluginIndex } from "./installed-plugin-index-wrDsjyMD.js";
import { C as hashStableJson, d as recordPluginCandidateInstallOwner, g as listBundledSourceOverlayDirs, i as normalizePluginDependencySpecs, s as tracePluginLifecyclePhase, t as discoverConfiguredPluginLoadPaths } from "./discovery-D_VDsZuY.js";
import { r as resolveChannelSetupFieldCliAttributeName } from "./setup-contract-RbJSZiOH.js";
import { t as shouldRejectHardlinkedPluginFiles } from "./hardlink-policy-CslDqyMD.js";
import { r as resolveInstalledPluginIndexInstallOwner, t as isInstalledPluginIndexInstallOwnerAmbiguous } from "./installed-plugin-index-install-owner-Bd-Byre8.js";
import { n as loadPluginManifestRegistryCore } from "./manifest-registry-DCCgYk7q.js";
import path from "node:path";
//#region src/plugins/manifest-registry-installed.ts
/** Builds manifest registry records from installed plugin index snapshots. */
function isDeepFrozenJsonLike(value, seen = /* @__PURE__ */ new WeakSet()) {
if (!value || typeof value !== "object") return true;
const object = value;
if (seen.has(object)) return true;
if (!Object.isFrozen(object)) return false;
seen.add(object);
return Object.values(value).every((entry) => isDeepFrozenJsonLike(entry, seen));
}
function resolveInstalledManifestRegistryIndexFingerprint(index) {
const cached = getPluginCache().metadata.indexFingerprints.get(index);
if (cached) return cached;
const fingerprint = hashStableJson({
version: index.version,
hostContractVersion: index.hostContractVersion,
compatRegistryVersion: index.compatRegistryVersion,
migrationVersion: index.migrationVersion,
policyHash: index.policyHash,
installRecords: index.installRecords,
diagnostics: index.diagnostics,
plugins: index.plugins.map(({ doctorContractFile: _doctorContractFile, packageBuild, ...plugin }) => ({
...plugin,
...packageBuild?.bundledDist === void 0 ? {} : { packageBuild: { bundledDist: packageBuild.bundledDist } }
}))
});
if (isDeepFrozenJsonLike(index)) getPluginCache().metadata.indexFingerprints.set(index, fingerprint);
return fingerprint;
}
function resolveInstalledPluginRootDir(record) {
return record.rootDir || path.dirname(record.manifestPath || process.cwd());
}
function resolveFallbackPluginSource(record) {
const rootDir = resolveInstalledPluginRootDir(record);
for (const entry of DEFAULT_PLUGIN_ENTRY_CANDIDATES) {
const candidate = path.join(rootDir, entry);
if (pluginCacheExistsSync(candidate)) return candidate;
}
return path.join(rootDir, DEFAULT_PLUGIN_ENTRY_CANDIDATES[0]);
}
function normalizePackageChannelExposure(exposure) {
if (!isRecord(exposure)) return;
const normalized = {};
for (const key of [
"configured",
"setup",
"docs"
]) if (typeof exposure[key] === "boolean") normalized[key] = exposure[key];
return Object.keys(normalized).length > 0 ? normalized : void 0;
}
function normalizePackageChannelConfiguredState(configuredState) {
if (!isRecord(configuredState)) return;
const env = isRecord(configuredState.env) ? {
...normalizeOptionalTrimmedStringList(configuredState.env.allOf)?.length ? { allOf: normalizeOptionalTrimmedStringList(configuredState.env.allOf) } : {},
...normalizeOptionalTrimmedStringList(configuredState.env.anyOf)?.length ? { anyOf: normalizeOptionalTrimmedStringList(configuredState.env.anyOf) } : {}
} : void 0;
const specifier = normalizeOptionalString(configuredState.specifier);
const exportName = normalizeOptionalString(configuredState.exportName);
return specifier || exportName || env && Object.keys(env).length > 0 ? {
...specifier ? { specifier } : {},
...exportName ? { exportName } : {},
...env && Object.keys(env).length > 0 ? { env } : {}
} : void 0;
}
function normalizePackageChannelPersistedAuthState(persistedAuthState) {
if (!isRecord(persistedAuthState)) return;
const specifier = normalizeOptionalString(persistedAuthState.specifier);
const exportName = normalizeOptionalString(persistedAuthState.exportName);
return specifier || exportName ? {
...specifier ? { specifier } : {},
...exportName ? { exportName } : {}
} : void 0;
}
function normalizePackageChannelDoctorCapabilities(doctorCapabilities) {
if (!isRecord(doctorCapabilities)) return;
const normalized = {};
const { dmAllowFromMode, groupModel } = doctorCapabilities;
if (dmAllowFromMode === "topOnly" || dmAllowFromMode === "topOrNested" || dmAllowFromMode === "nestedOnly") normalized.dmAllowFromMode = dmAllowFromMode;
if (groupModel === "sender" || groupModel === "route" || groupModel === "hybrid") normalized.groupModel = groupModel;
for (const key of [
"openDmRequiresAllowFromWildcard",
"groupAllowFromFallbackToAllowFrom",
"warnOnEmptyGroupSenderAllowlist"
]) if (typeof doctorCapabilities[key] === "boolean") normalized[key] = doctorCapabilities[key];
return Object.keys(normalized).length > 0 ? normalized : void 0;
}
function normalizePackageChannelCliOptions(cliAddOptions) {
if (!Array.isArray(cliAddOptions)) return;
const normalized = cliAddOptions.flatMap((option) => {
if (!isRecord(option)) return [];
const flags = normalizeOptionalString(option.flags);
const description = normalizeOptionalString(option.description);
if (!flags || !description) return [];
const defaultValue = typeof option.defaultValue === "boolean" || typeof option.defaultValue === "string" ? option.defaultValue : void 0;
const valueType = option.valueType === "int" || option.valueType === "list" ? option.valueType : void 0;
return [{
flags,
description,
...defaultValue !== void 0 ? { defaultValue } : {},
...valueType ? { valueType } : {}
}];
});
return normalized.length > 0 ? normalized : void 0;
}
function normalizePackageChannelSetup(setup) {
if (!isRecord(setup) || !Array.isArray(setup.fields)) return;
const fields = [];
for (const value of setup.fields) {
if (!isRecord(value) || !isRecord(value.cli)) continue;
const key = normalizeOptionalString(value.key);
const kind = normalizeOptionalString(value.kind);
const flags = normalizeOptionalString(value.cli.flags);
const negatedFlags = normalizeOptionalString(value.cli.negatedFlags);
const description = normalizeOptionalString(value.cli.description);
if (!key || !flags || !description || !kind || kind !== "string" && kind !== "boolean" && kind !== "integer" && kind !== "string-list" && kind !== "choice") continue;
try {
if (resolveChannelSetupFieldCliAttributeName(flags) !== key || negatedFlags && resolveChannelSetupFieldCliAttributeName(negatedFlags) !== key) continue;
} catch {
continue;
}
const defaultValue = typeof value.cli.defaultValue === "boolean" || typeof value.cli.defaultValue === "string" ? value.cli.defaultValue : void 0;
const cli = {
flags,
...negatedFlags ? { negatedFlags } : {},
description,
...defaultValue !== void 0 ? { defaultValue } : {}
};
if (kind === "choice") {
const choices = normalizeOptionalTrimmedStringList(value.choices);
if (!choices?.length) continue;
fields.push({
key,
kind,
choices,
cli
});
continue;
}
if (kind === "string" || kind === "string-list") {
fields.push({
key,
kind,
...value.sensitive === true ? { sensitive: true } : {},
cli
});
continue;
}
if (kind === "boolean") {
const envVars = normalizeOptionalTrimmedStringList(value.envVars);
const envVarMode = value.envVarMode === "any" || value.envVarMode === "all" ? value.envVarMode : void 0;
fields.push({
key,
kind,
...envVars?.length ? { envVars } : {},
...envVars?.length && envVarMode ? { envVarMode } : {},
cli
});
continue;
}
fields.push({
key,
kind,
cli
});
}
return { fields };
}
function normalizePersistedPackageChannel(value) {
if (!isRecord(value)) return;
const id = normalizeOptionalString(value.id);
if (!id) return;
const channel = { id };
for (const key of [
"label",
"selectionLabel",
"detailLabel",
"docsPath",
"docsLabel",
"blurb",
"systemImage"
]) {
const normalized = normalizeOptionalString(value[key]);
if (normalized) channel[key] = normalized;
}
const selectionDocsPrefix = readStringValue(value.selectionDocsPrefix);
if (selectionDocsPrefix !== void 0) channel.selectionDocsPrefix = selectionDocsPrefix;
if (typeof value.order === "number" && Number.isFinite(value.order)) channel.order = value.order;
for (const key of [
"aliases",
"preferOver",
"selectionExtras"
]) {
const normalized = normalizeOptionalTrimmedStringList(value[key]);
if (normalized?.length) channel[key] = normalized;
}
if (Array.isArray(value.approvalFlags) && value.approvalFlags.includes("native")) channel.approvalFlags = ["native"];
for (const key of [
"selectionDocsOmitLabel",
"markdownCapable",
"quickstartAllowFrom",
"forceAccountBinding",
"preferSessionLookupForAnnounceTarget"
]) if (typeof value[key] === "boolean") channel[key] = value[key];
for (const [key, normalize] of [
["exposure", normalizePackageChannelExposure],
["commands", normalizeManifestChannelCommandDefaults],
["configuredState", normalizePackageChannelConfiguredState],
["persistedAuthState", normalizePackageChannelPersistedAuthState],
["doctorCapabilities", normalizePackageChannelDoctorCapabilities],
["setup", normalizePackageChannelSetup],
["cliAddOptions", normalizePackageChannelCliOptions]
]) {
const normalized = normalize(value[key]);
if (normalized) Object.assign(channel, { [key]: normalized });
}
return channel;
}
function normalizePreparedManifestRecord(record) {
if (!record.packageManifest?.channel && !record.packageChannel) return record;
const packageChannel = normalizePersistedPackageChannel(record.packageManifest?.channel ?? record.packageChannel);
const { channel: _ignoredChannel, ...packageManifest } = record.packageManifest ?? {};
return {
...record,
packageChannel,
...record.packageManifest ? { packageManifest: {
...packageManifest,
...packageChannel ? { channel: packageChannel } : {}
} } : {},
...!packageChannel && record.channelCatalogMeta ? { channelCatalogMeta: void 0 } : {}
};
}
function resolveInstalledPackageMetadata(record, env) {
const recordPackageChannel = normalizePersistedPackageChannel(record.packageChannel);
const fallbackPackageManifest = recordPackageChannel ? { channel: recordPackageChannel } : void 0;
const fallback = fallbackPackageManifest ? { packageManifest: fallbackPackageManifest } : {};
if (!record.packageJson?.path) return fallback;
const rootDir = resolveInstalledPluginRootDir(record);
const file = readPluginCacheFile({
rootDir,
relativePath: record.packageJson.path,
rejectHardlinks: shouldRejectHardlinkedPluginFiles({
origin: record.origin,
rootDir,
env
})
});
const parsed = file.ok ? parsePluginCacheJson(file) : void 0;
if (!parsed?.ok || !isRecord(parsed.value)) return fallback;
const packageJson = parsed.value;
const packageManifest = getPackageManifestMetadata(packageJson);
const dependencies = normalizePluginDependencySpecs({
dependencies: packageJson.dependencies,
optionalDependencies: packageJson.optionalDependencies
});
if (!packageManifest) return {
...fallback,
packageDependencies: dependencies.dependencies,
packageOptionalDependencies: dependencies.optionalDependencies
};
const packageChannel = normalizePersistedPackageChannel(packageManifest.channel);
const channel = recordPackageChannel || packageChannel ? {
...recordPackageChannel,
...packageChannel
} : void 0;
const { channel: _ignoredChannel, ...packageManifestWithoutChannel } = packageManifest;
return {
packageManifest: {
...packageManifestWithoutChannel,
...channel ? { channel } : {}
},
packageDependencies: dependencies.dependencies,
packageOptionalDependencies: dependencies.optionalDependencies
};
}
function toPluginCandidate(record, env) {
const rootDir = resolveInstalledPluginRootDir(record);
const packageMetadata = resolveInstalledPackageMetadata(record, env);
return recordPluginCandidateInstallOwner({
idHint: record.pluginId,
effectivePluginId: record.pluginId,
source: record.source ?? resolveFallbackPluginSource(record),
...record.setupSource ? { setupSource: record.setupSource } : {},
rootDir,
origin: record.origin,
...record.format ? { format: record.format } : {},
...record.bundleFormat ? { bundleFormat: record.bundleFormat } : {},
...record.packageName ? { packageName: record.packageName } : {},
...record.packageVersion ? { packageVersion: record.packageVersion } : {},
...packageMetadata.packageManifest ? { packageManifest: packageMetadata.packageManifest } : {},
...packageMetadata.packageDependencies ? { packageDependencies: packageMetadata.packageDependencies } : {},
...packageMetadata.packageOptionalDependencies ? { packageOptionalDependencies: packageMetadata.packageOptionalDependencies } : {},
packageDir: rootDir
}, resolveInstalledPluginIndexInstallOwner(record), isInstalledPluginIndexInstallOwnerAmbiguous(record));
}
/** Selects installed owners without projecting unrelated manifest fields. */
function selectInstalledPluginManifestRecords(index, registry, pluginIds, includeDisabled) {
const enabledPluginIds = new Set(index.plugins.filter((plugin) => includeDisabled || plugin.enabled).map((plugin) => plugin.pluginId));
return registry.plugins.filter((plugin) => enabledPluginIds.has(plugin.id) && (!pluginIds || pluginIds.has(plugin.id)));
}
function loadPluginManifestRegistryForInstalledIndex(params) {
return tracePluginLifecyclePhase("manifest registry", () => {
if (params.pluginIds && params.pluginIds.length === 0) return {
plugins: [],
diagnostics: []
};
const env = params.env ?? process.env;
const pluginIdSet = params.pluginIds?.length ? new Set(params.pluginIds) : null;
const diagnostics = pluginIdSet ? params.index.diagnostics.filter((diagnostic) => {
const pluginId = diagnostic.pluginId;
return !pluginId || pluginIdSet.has(pluginId);
}) : params.index.diagnostics;
if (params.manifestRegistry && !params.bundledChannelConfigCollector) return {
plugins: selectInstalledPluginManifestRecords(params.index, params.manifestRegistry, pluginIdSet, params.includeDisabled).map(normalizePreparedManifestRecord),
diagnostics: [...diagnostics]
};
const sourceRoots = new Set(listBundledSourceOverlayDirs({
bundledRoot: resolveBundledPluginsDir(env),
env
}).map((root) => pluginCacheRealpathSync(root) ?? root));
const loadPaths = params.config?.plugins?.load?.paths ?? [];
const configuredSources = new Set(loadPaths.length > 0 ? discoverConfiguredPluginLoadPaths({
loadPaths,
env,
workspaceDir: params.workspaceDir
}).candidates.map((candidate) => pluginCacheRealpathSync(candidate.source) ?? candidate.source) : []);
const candidates = params.index.plugins.filter((plugin) => params.includeDisabled || plugin.enabled).filter((plugin) => !pluginIdSet || pluginIdSet.has(plugin.pluginId)).map((plugin) => {
const candidate = toPluginCandidate(plugin, env);
if (candidate.origin === "bundled" && (sourceRoots.has(pluginCacheRealpathSync(candidate.rootDir) ?? candidate.rootDir) || configuredSources.has(pluginCacheRealpathSync(candidate.source) ?? candidate.source))) candidate.sourcePreferred = true;
return candidate;
});
return loadPluginManifestRegistryCore({
registryPath: params.registryPath,
config: params.config,
workspaceDir: params.workspaceDir,
env,
candidates,
diagnostics: [...diagnostics],
installRecords: extractPluginInstallRecordsFromInstalledPluginIndex(params.index),
...params.bundledChannelConfigCollector ? { bundledChannelConfigCollector: params.bundledChannelConfigCollector } : {}
});
}, {
includeDisabled: params.includeDisabled === true,
pluginIdCount: params.pluginIds?.length,
indexPluginCount: params.index.plugins.length
});
}
//#endregion
export { resolveInstalledManifestRegistryIndexFingerprint as n, selectInstalledPluginManifestRecords as r, loadPluginManifestRegistryForInstalledIndex as t };