Files
openclaw/src/plugins/plugin-registry-id-normalizer.ts
2026-04-27 18:27:29 +01:00

75 lines
2.7 KiB
TypeScript

import type { InstalledPluginIndex } from "./installed-plugin-index.js";
import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
import type { PluginManifestRecord, PluginManifestRegistry } from "./manifest-registry.js";
export type PluginRegistryIdNormalizerOptions = {
manifestRegistry?: PluginManifestRegistry;
lookUpTable?: Pick<{ manifestRegistry: PluginManifestRegistry }, "manifestRegistry">;
};
function normalizePluginRegistryAlias(value: string): string {
return value.trim();
}
function normalizePluginRegistryAliasKey(value: string): string {
return normalizePluginRegistryAlias(value).toLowerCase();
}
function collectObjectKeys(value: Record<string, unknown> | undefined): readonly string[] {
return value ? Object.keys(value) : [];
}
function listPluginRegistryNormalizerAliases(plugin: PluginManifestRecord): readonly string[] {
return [
plugin.id,
...plugin.providers,
...plugin.channels,
...(plugin.setup?.providers?.map((provider) => provider.id) ?? []),
...plugin.cliBackends,
...(plugin.setup?.cliBackends ?? []),
...collectObjectKeys(plugin.modelCatalog?.providers),
...collectObjectKeys(plugin.modelCatalog?.aliases),
...(plugin.legacyPluginIds ?? []),
];
}
export function createPluginRegistryIdNormalizer(
index: InstalledPluginIndex,
options: PluginRegistryIdNormalizerOptions = {},
): (pluginId: string) => string {
const aliases = new Map<string, string>();
for (const plugin of index.plugins) {
const pluginId = normalizePluginRegistryAlias(plugin.pluginId);
if (pluginId) {
aliases.set(normalizePluginRegistryAliasKey(pluginId), plugin.pluginId);
}
}
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),
)) {
const pluginId = normalizePluginRegistryAlias(plugin.id);
if (!pluginId) {
continue;
}
aliases.set(normalizePluginRegistryAliasKey(pluginId), plugin.id);
for (const alias of listPluginRegistryNormalizerAliases(plugin)) {
const normalizedAlias = normalizePluginRegistryAlias(alias);
const normalizedAliasKey = normalizePluginRegistryAliasKey(alias);
if (normalizedAlias && !aliases.has(normalizedAliasKey)) {
aliases.set(normalizedAliasKey, pluginId);
}
}
}
return (pluginId: string) => {
const trimmed = normalizePluginRegistryAlias(pluginId);
return aliases.get(normalizePluginRegistryAliasKey(trimmed)) ?? trimmed;
};
}