UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

363 lines (362 loc) 16.8 kB
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 };