
























@@ -29,8 +29,11 @@ import {
2929type BundledRuntimeDepsPackageManager,
3030type BundledRuntimeDepsPackageManagerRunner,
3131} from "./bundled-runtime-deps-package-manager.js";
32-import { normalizePluginsConfig } from "./config-state.js";
33-import { passesManifestOwnerBasePolicy } from "./manifest-owner-policy.js";
32+import {
33+normalizePluginsConfigWithResolver,
34+type NormalizedPluginsConfig,
35+type NormalizePluginId,
36+} from "./config-normalization-shared.js";
3437import { satisfies, validSemver } from "./semver.runtime.js";
35383639export {
@@ -832,6 +835,9 @@ function replaceNodeModulesDir(targetDir: string, sourceDir: string): void {
832835type BundledPluginRuntimeDepsManifest = {
833836channels: string[];
834837enabledByDefault: boolean;
838+id?: string;
839+legacyPluginIds: string[];
840+providers: string[];
835841};
836842837843type BundledPluginRuntimeDepsManifestCache = Map<string, BundledPluginRuntimeDepsManifest>;
@@ -846,36 +852,135 @@ function readBundledPluginRuntimeDepsManifest(
846852}
847853const manifest = readJsonObject(path.join(pluginDir, "openclaw.plugin.json"));
848854const channels = manifest?.channels;
855+const legacyPluginIds = manifest?.legacyPluginIds;
856+const providers = manifest?.providers;
849857const runtimeDepsManifest = {
850858channels: Array.isArray(channels)
851859 ? channels.filter((entry): entry is string => typeof entry === "string" && entry !== "")
852860 : [],
853861enabledByDefault: manifest?.enabledByDefault === true,
862+ ...(typeof manifest?.id === "string" && manifest.id.trim() ? { id: manifest.id } : {}),
863+legacyPluginIds: Array.isArray(legacyPluginIds)
864+ ? legacyPluginIds.filter(
865+(entry): entry is string => typeof entry === "string" && entry !== "",
866+)
867+ : [],
868+providers: Array.isArray(providers)
869+ ? providers.filter((entry): entry is string => typeof entry === "string" && entry !== "")
870+ : [],
854871};
855872cache?.set(pluginDir, runtimeDepsManifest);
856873return runtimeDepsManifest;
857874}
858875876+const BUILT_IN_RUNTIME_DEPS_PLUGIN_ALIAS_FALLBACKS: ReadonlyArray<
877+readonly [alias: string, pluginId: string]
878+> = [
879+["openai-codex", "openai"],
880+["google-gemini-cli", "google"],
881+["minimax-portal", "minimax"],
882+["minimax-portal-auth", "minimax"],
883+] as const;
884+885+function addBundledRuntimeDepsPluginAlias(
886+lookup: Map<string, string>,
887+alias: string | undefined,
888+pluginId: string,
889+): void {
890+const normalizedAlias = normalizeOptionalLowercaseString(alias);
891+if (normalizedAlias) {
892+lookup.set(normalizedAlias, pluginId);
893+}
894+}
895+896+function createBundledRuntimeDepsPluginIdNormalizer(params: {
897+extensionsDir: string;
898+manifestCache: BundledPluginRuntimeDepsManifestCache;
899+}): NormalizePluginId {
900+const lookup = new Map<string, string>();
901+for (const [alias, pluginId] of BUILT_IN_RUNTIME_DEPS_PLUGIN_ALIAS_FALLBACKS) {
902+lookup.set(alias, pluginId);
903+lookup.set(pluginId, pluginId);
904+}
905+if (!fs.existsSync(params.extensionsDir)) {
906+return (id) => {
907+const trimmed = id.trim();
908+const normalized = normalizeOptionalLowercaseString(trimmed);
909+return (normalized && lookup.get(normalized)) || trimmed;
910+};
911+}
912+for (const entry of fs.readdirSync(params.extensionsDir, { withFileTypes: true })) {
913+if (!entry.isDirectory()) {
914+continue;
915+}
916+const fallbackPluginId = entry.name;
917+const pluginDir = path.join(params.extensionsDir, fallbackPluginId);
918+const manifest = readBundledPluginRuntimeDepsManifest(pluginDir, params.manifestCache);
919+const pluginId = manifest.id ?? fallbackPluginId;
920+addBundledRuntimeDepsPluginAlias(lookup, pluginId, pluginId);
921+addBundledRuntimeDepsPluginAlias(lookup, fallbackPluginId, pluginId);
922+for (const providerId of manifest.providers) {
923+addBundledRuntimeDepsPluginAlias(lookup, providerId, pluginId);
924+}
925+for (const legacyPluginId of manifest.legacyPluginIds) {
926+addBundledRuntimeDepsPluginAlias(lookup, legacyPluginId, pluginId);
927+}
928+}
929+return (id) => {
930+const trimmed = id.trim();
931+const normalized = normalizeOptionalLowercaseString(trimmed);
932+return (normalized && lookup.get(normalized)) || trimmed;
933+};
934+}
935+936+function passesRuntimeDepsPluginPolicy(params: {
937+pluginId: string;
938+plugins: NormalizedPluginsConfig;
939+allowExplicitlyDisabled?: boolean;
940+allowRestrictiveAllowlistBypass?: boolean;
941+}): boolean {
942+if (!params.plugins.enabled) {
943+return false;
944+}
945+if (params.plugins.deny.includes(params.pluginId)) {
946+return false;
947+}
948+if (
949+params.plugins.entries[params.pluginId]?.enabled === false &&
950+params.allowExplicitlyDisabled !== true
951+) {
952+return false;
953+}
954+return (
955+params.allowRestrictiveAllowlistBypass === true ||
956+params.plugins.allow.length === 0 ||
957+params.plugins.allow.includes(params.pluginId)
958+);
959+}
960+859961function isBundledPluginConfiguredForRuntimeDeps(params: {
860962config: OpenClawConfig;
963+plugins: NormalizedPluginsConfig;
861964pluginId: string;
862965pluginDir: string;
863966includeConfiguredChannels?: boolean;
864967manifestCache?: BundledPluginRuntimeDepsManifestCache;
865968}): boolean {
866-const plugins = normalizePluginsConfig(params.config.plugins);
867969if (
868-!passesManifestOwnerBasePolicy({
869-plugin: { id: params.pluginId },
870-normalizedConfig: plugins,
970+!passesRuntimeDepsPluginPolicy({
971+pluginId: params.pluginId,
972+plugins: params.plugins,
871973allowRestrictiveAllowlistBypass: true,
872974})
873975) {
874976return false;
875977}
876-const entry = plugins.entries[params.pluginId];
978+const entry = params.plugins.entries[params.pluginId];
877979const manifest = readBundledPluginRuntimeDepsManifest(params.pluginDir, params.manifestCache);
878-if (plugins.slots.memory === params.pluginId || plugins.slots.contextEngine === params.pluginId) {
980+if (
981+params.plugins.slots.memory === params.pluginId ||
982+params.plugins.slots.contextEngine === params.pluginId
983+) {
879984return true;
880985}
881986let hasExplicitChannelDisable = false;
@@ -917,7 +1022,7 @@ function isBundledPluginConfiguredForRuntimeDeps(params: {
9171022if (hasExplicitChannelDisable) {
9181023return false;
9191024}
920-if (plugins.allow.length > 0 && !plugins.allow.includes(params.pluginId)) {
1025+if (params.plugins.allow.length > 0 && !params.plugins.allow.includes(params.pluginId)) {
9211026return false;
9221027}
9231028if (entry?.enabled === true) {
@@ -931,12 +1036,12 @@ function isBundledPluginConfiguredForRuntimeDeps(params: {
93110369321037function isBundledPluginExplicitlyDisabledForRuntimeDeps(params: {
9331038config: OpenClawConfig;
1039+plugins: NormalizedPluginsConfig;
9341040pluginId: string;
9351041pluginDir: string;
9361042manifestCache?: BundledPluginRuntimeDepsManifestCache;
9371043}): boolean {
938-const plugins = normalizePluginsConfig(params.config.plugins);
939-if (plugins.entries[params.pluginId]?.enabled === false) {
1044+if (params.plugins.entries[params.pluginId]?.enabled === false) {
9401045return true;
9411046}
9421047const manifest = readBundledPluginRuntimeDepsManifest(params.pluginDir, params.manifestCache);
@@ -959,6 +1064,7 @@ function isBundledPluginExplicitlyDisabledForRuntimeDeps(params: {
95910649601065function shouldIncludeBundledPluginRuntimeDeps(params: {
9611066config?: OpenClawConfig;
1067+plugins?: NormalizedPluginsConfig;
9621068pluginIds?: ReadonlySet<string>;
9631069selectedPluginIds?: ReadonlySet<string>;
9641070pluginId: string;
@@ -971,8 +1077,10 @@ function shouldIncludeBundledPluginRuntimeDeps(params: {
9711077params.selectedPluginIds.has(params.pluginId) &&
9721078!(
9731079params.config &&
1080+params.plugins &&
9741081isBundledPluginExplicitlyDisabledForRuntimeDeps({
9751082config: params.config,
1083+plugins: params.plugins,
9761084pluginId: params.pluginId,
9771085pluginDir: params.pluginDir,
9781086manifestCache: params.manifestCache,
@@ -993,15 +1101,21 @@ function shouldIncludeBundledPluginRuntimeDeps(params: {
9931101return true;
9941102}
9951103if (scopedToPluginIds) {
996-const plugins = normalizePluginsConfig(params.config.plugins);
997-return passesManifestOwnerBasePolicy({
998-plugin: { id: params.pluginId },
999-normalizedConfig: plugins,
1104+if (!params.plugins) {
1105+return true;
1106+}
1107+return passesRuntimeDepsPluginPolicy({
1108+pluginId: params.pluginId,
1109+plugins: params.plugins,
10001110allowRestrictiveAllowlistBypass: true,
10011111});
10021112}
1113+if (!params.plugins) {
1114+return false;
1115+}
10031116return isBundledPluginConfiguredForRuntimeDeps({
10041117config: params.config,
1118+plugins: params.plugins,
10051119pluginId: params.pluginId,
10061120pluginDir: params.pluginDir,
10071121includeConfiguredChannels: params.includeConfiguredChannels,
@@ -1015,13 +1129,27 @@ function collectBundledPluginRuntimeDeps(params: {
10151129pluginIds?: ReadonlySet<string>;
10161130selectedPluginIds?: ReadonlySet<string>;
10171131includeConfiguredChannels?: boolean;
1132+manifestCache?: BundledPluginRuntimeDepsManifestCache;
1133+normalizePluginId?: NormalizePluginId;
10181134}): {
10191135deps: RuntimeDepEntry[];
10201136conflicts: RuntimeDepConflict[];
10211137pluginIds: string[];
10221138} {
10231139const versionMap = new Map<string, Map<string, Set<string>>>();
1024-const manifestCache: BundledPluginRuntimeDepsManifestCache = new Map();
1140+const manifestCache: BundledPluginRuntimeDepsManifestCache = params.manifestCache ?? new Map();
1141+const needsPluginIdNormalizer = Boolean(params.config);
1142+const normalizePluginId =
1143+params.normalizePluginId ??
1144+(needsPluginIdNormalizer
1145+ ? createBundledRuntimeDepsPluginIdNormalizer({
1146+extensionsDir: params.extensionsDir,
1147+ manifestCache,
1148+})
1149+ : undefined);
1150+const plugins = params.config
1151+ ? normalizePluginsConfigWithResolver(params.config.plugins, normalizePluginId)
1152+ : undefined;
10251153const includedPluginIds = new Set<string>();
1026115410271155for (const entry of fs.readdirSync(params.extensionsDir, { withFileTypes: true })) {
@@ -1033,6 +1161,7 @@ function collectBundledPluginRuntimeDeps(params: {
10331161if (
10341162!shouldIncludeBundledPluginRuntimeDeps({
10351163config: params.config,
1164+ plugins,
10361165pluginIds: params.pluginIds,
10371166selectedPluginIds: params.selectedPluginIds,
10381167 pluginId,
@@ -1099,12 +1228,13 @@ function collectBundledPluginRuntimeDeps(params: {
1099122811001229function normalizePluginIdSet(
11011230pluginIds: readonly string[] | undefined,
1231+normalizePluginId: NormalizePluginId = (id) => normalizeOptionalLowercaseString(id) ?? "",
11021232): ReadonlySet<string> | undefined {
11031233if (!pluginIds) {
11041234return undefined;
11051235}
11061236const normalized = pluginIds
1107-.map((entry) => normalizeOptionalLowercaseString(entry))
1237+.map((entry) => normalizePluginId(entry))
11081238.filter((entry): entry is string => Boolean(entry));
11091239return new Set(normalized);
11101240}
@@ -1128,12 +1258,22 @@ export function scanBundledPluginRuntimeDeps(params: {
11281258if (!fs.existsSync(extensionsDir)) {
11291259return { deps: [], missing: [], conflicts: [] };
11301260}
1261+const manifestCache: BundledPluginRuntimeDepsManifestCache = new Map();
1262+const normalizePluginId =
1263+params.config || params.pluginIds || params.selectedPluginIds
1264+ ? createBundledRuntimeDepsPluginIdNormalizer({
1265+ extensionsDir,
1266+ manifestCache,
1267+})
1268+ : undefined;
11311269const { deps, conflicts, pluginIds } = collectBundledPluginRuntimeDeps({
11321270 extensionsDir,
11331271config: params.config,
1134-pluginIds: normalizePluginIdSet(params.pluginIds),
1135-selectedPluginIds: normalizePluginIdSet(params.selectedPluginIds),
1272+pluginIds: normalizePluginIdSet(params.pluginIds, normalizePluginId),
1273+selectedPluginIds: normalizePluginIdSet(params.selectedPluginIds, normalizePluginId),
11361274includeConfiguredChannels: params.includeConfiguredChannels,
1275+ manifestCache,
1276+ ...(normalizePluginId ? { normalizePluginId } : {}),
11371277});
11381278const packageRuntimeDeps =
11391279pluginIds.length > 0 ? collectMirroredPackageRuntimeDeps(params.packageRoot) : [];
@@ -1705,12 +1845,26 @@ export function ensureBundledPluginRuntimeDeps(params: {
17051845config?: OpenClawConfig;
17061846installDeps?: (params: BundledRuntimeDepsInstallParams) => void;
17071847}): BundledRuntimeDepsEnsureResult {
1848+const extensionsDir = path.dirname(params.pluginRoot);
1849+const manifestCache: BundledPluginRuntimeDepsManifestCache = new Map();
1850+const normalizePluginId = params.config
1851+ ? createBundledRuntimeDepsPluginIdNormalizer({
1852+ extensionsDir,
1853+ manifestCache,
1854+})
1855+ : undefined;
1856+const plugins = params.config
1857+ ? normalizePluginsConfigWithResolver(params.config.plugins, normalizePluginId)
1858+ : undefined;
17081859if (
17091860params.config &&
1861+plugins &&
17101862!isBundledPluginConfiguredForRuntimeDeps({
17111863config: params.config,
1864+ plugins,
17121865pluginId: params.pluginId,
17131866pluginDir: params.pluginRoot,
1867+ manifestCache,
17141868})
17151869) {
17161870return createBundledRuntimeDepsEnsureResult([]);
@@ -1738,8 +1892,10 @@ export function ensureBundledPluginRuntimeDeps(params: {
17381892let deps = pluginDepEntries;
17391893if (usePackageLevelPlan && packageRoot) {
17401894const packagePlan = collectBundledPluginRuntimeDeps({
1741-extensionsDir: path.dirname(params.pluginRoot),
1895+ extensionsDir,
17421896 ...(params.config ? { config: params.config } : {}),
1897+ manifestCache,
1898+ ...(normalizePluginId ? { normalizePluginId } : {}),
17431899});
17441900if (packagePlan.conflicts.length === 0 && packagePlan.deps.length > 0) {
17451901deps = mergeRuntimeDepEntries([
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。