From 354eb37ff579fe3f8fa26e397b3fd90a3526aebe Mon Sep 17 00:00:00 2001 From: Shakker Date: Mon, 27 Apr 2026 07:10:56 +0100 Subject: [PATCH] refactor: reuse manifest registry for plugin id normalization --- src/plugins/gateway-startup-plugin-ids.ts | 13 ++++++-- src/plugins/plugin-registry-contributions.ts | 23 ++++++++++--- src/plugins/plugin-registry.test.ts | 34 ++++++++++++++++++++ 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/plugins/gateway-startup-plugin-ids.ts b/src/plugins/gateway-startup-plugin-ids.ts index aa44e9320a8..26da5886e3f 100644 --- a/src/plugins/gateway-startup-plugin-ids.ts +++ b/src/plugins/gateway-startup-plugin-ids.ts @@ -212,7 +212,9 @@ export function resolveConfiguredDeferredChannelPluginIdsFromRegistry(params: { if (configuredChannelIds.size === 0) { return []; } - const pluginsConfig = normalizePluginsConfigWithRegistry(params.config.plugins, params.index); + const pluginsConfig = normalizePluginsConfigWithRegistry(params.config.plugins, params.index, { + manifestRegistry: params.manifestRegistry, + }); const activationSource = { plugins: pluginsConfig, rootConfig: params.config, @@ -270,7 +272,9 @@ export function resolveGatewayStartupPluginIdsFromRegistry(params: { manifestRegistry: PluginManifestRegistry; }): string[] { const configuredChannelIds = new Set(listPotentialEnabledChannelIds(params.config, params.env)); - const pluginsConfig = normalizePluginsConfigWithRegistry(params.config.plugins, params.index); + const pluginsConfig = normalizePluginsConfigWithRegistry(params.config.plugins, params.index, { + manifestRegistry: params.manifestRegistry, + }); // Startup must classify allowlist exceptions against the raw config snapshot, // not the auto-enabled effective snapshot, or configured-only channels can be // misclassified as explicit enablement. @@ -278,6 +282,7 @@ export function resolveGatewayStartupPluginIdsFromRegistry(params: { const activationSourcePlugins = normalizePluginsConfigWithRegistry( activationSourceConfig.plugins, params.index, + { manifestRegistry: params.manifestRegistry }, ); const activationSource = { plugins: activationSourcePlugins, @@ -290,7 +295,9 @@ export function resolveGatewayStartupPluginIdsFromRegistry(params: { const memorySlotStartupPluginId = resolveMemorySlotStartupPluginId({ activationSourceConfig, activationSourcePlugins, - normalizePluginId: createPluginRegistryIdNormalizer(params.index), + normalizePluginId: createPluginRegistryIdNormalizer(params.index, { + manifestRegistry: params.manifestRegistry, + }), }); return params.index.plugins .filter((plugin) => { diff --git a/src/plugins/plugin-registry-contributions.ts b/src/plugins/plugin-registry-contributions.ts index 37103638742..76dbaad8d00 100644 --- a/src/plugins/plugin-registry-contributions.ts +++ b/src/plugins/plugin-registry-contributions.ts @@ -85,6 +85,11 @@ export type ResolveManifestContractPluginIdsByCompatibilityRuntimePathParams = origin?: PluginOrigin; }; +export type PluginRegistryIdNormalizerOptions = { + manifestRegistry?: PluginManifestRegistry; + lookUpTable?: PluginLookUpTable; +}; + function normalizeContributionId(value: string): string { return value.trim(); } @@ -235,6 +240,7 @@ export function loadPluginManifestRegistryForPluginRegistry( export function createPluginRegistryIdNormalizer( index: PluginRegistrySnapshot, + options: PluginRegistryIdNormalizerOptions = {}, ): (pluginId: string) => string { const aliases = new Map(); for (const plugin of index.plugins) { @@ -243,10 +249,13 @@ export function createPluginRegistryIdNormalizer( aliases.set(normalizePluginRegistryAliasKey(pluginId), plugin.pluginId); } } - const registry = loadPluginManifestRegistryForInstalledIndex({ - index, - includeDisabled: true, - }); + const registry = + options.lookUpTable?.manifestRegistry ?? + options.manifestRegistry ?? + loadPluginManifestRegistryForInstalledIndex({ + index, + includeDisabled: true, + }); for (const plugin of [...registry.plugins].toSorted((left, right) => left.id.localeCompare(right.id), )) { @@ -280,8 +289,12 @@ export function createPluginRegistryIdNormalizer( export function normalizePluginsConfigWithRegistry( config: OpenClawConfig["plugins"] | undefined, index: PluginRegistrySnapshot, + options: PluginRegistryIdNormalizerOptions = {}, ): NormalizedPluginsConfig { - return normalizePluginsConfigWithResolver(config, createPluginRegistryIdNormalizer(index)); + return normalizePluginsConfigWithResolver( + config, + createPluginRegistryIdNormalizer(index, options), + ); } export function listPluginContributionIds( diff --git a/src/plugins/plugin-registry.test.ts b/src/plugins/plugin-registry.test.ts index e7baeb4e520..61cb5c9510c 100644 --- a/src/plugins/plugin-registry.test.ts +++ b/src/plugins/plugin-registry.test.ts @@ -300,6 +300,40 @@ describe("plugin registry facade", () => { }); }); + it("normalizes plugin config ids from a provided manifest registry without rereading manifests", () => { + const rootDir = makeTempDir(); + const candidate = createCandidate(rootDir); + const env = hermeticEnv(); + const index = loadPluginRegistrySnapshot({ + candidates: [candidate], + env, + preferPersisted: false, + }); + const lookUpTable = loadPluginLookUpTable({ + config: {}, + env, + index, + }); + fs.unlinkSync(path.join(rootDir, "openclaw.plugin.json")); + + const normalizePluginId = createPluginRegistryIdNormalizer(index, { + manifestRegistry: lookUpTable.manifestRegistry, + }); + + expect(normalizePluginId("demo-chat")).toBe("demo"); + expect( + normalizePluginsConfigWithRegistry( + { + allow: ["demo-chat"], + }, + index, + { manifestRegistry: lookUpTable.manifestRegistry }, + ), + ).toMatchObject({ + allow: ["demo"], + }); + }); + it("reads the persisted registry before deriving from discovered candidates", async () => { const stateDir = makeTempDir(); const rootDir = makeTempDir();