refactor: reuse manifest registry for plugin id normalization

This commit is contained in:
Shakker
2026-04-27 07:10:56 +01:00
parent b8c9426911
commit 354eb37ff5
3 changed files with 62 additions and 8 deletions

View File

@@ -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) => {

View File

@@ -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<string, string>();
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(

View File

@@ -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();