Files
openclaw/src/config/channel-config-metadata.ts
2026-04-06 22:46:33 +01:00

93 lines
3.0 KiB
TypeScript

import type { PluginManifestRegistry } from "../plugins/manifest-registry.js";
import type { PluginOrigin } from "../plugins/types.js";
import type { ChannelUiMetadata, PluginUiMetadata } from "./schema.js";
type ChannelMetadataRecord = ChannelUiMetadata & {
originRank: number;
};
const PLUGIN_ORIGIN_RANK: Readonly<Record<PluginOrigin, number>> = {
config: 0,
workspace: 1,
global: 2,
bundled: 3,
};
export function collectPluginSchemaMetadata(registry: PluginManifestRegistry): PluginUiMetadata[] {
const deduped = new Map<
string,
PluginUiMetadata & {
originRank: number;
}
>();
for (const record of registry.plugins) {
const current = deduped.get(record.id);
const nextRank = PLUGIN_ORIGIN_RANK[record.origin] ?? Number.MAX_SAFE_INTEGER;
if (current && current.originRank <= nextRank) {
continue;
}
deduped.set(record.id, {
id: record.id,
name: record.name,
description: record.description,
configUiHints: record.configUiHints,
configSchema: record.configSchema,
originRank: nextRank,
});
}
return [...deduped.values()]
.toSorted((left, right) => left.id.localeCompare(right.id))
.map(({ originRank: _originRank, ...record }) => record);
}
export function collectChannelSchemaMetadata(
registry: PluginManifestRegistry,
): ChannelUiMetadata[] {
const byChannelId = new Map<string, ChannelMetadataRecord>();
for (const record of registry.plugins) {
const originRank = PLUGIN_ORIGIN_RANK[record.origin] ?? Number.MAX_SAFE_INTEGER;
const rootLabel = record.channelCatalogMeta?.label;
const rootDescription = record.channelCatalogMeta?.blurb;
for (const channelId of record.channels) {
const current = byChannelId.get(channelId);
if (!current || originRank <= current.originRank) {
byChannelId.set(channelId, {
id: channelId,
label: rootLabel ?? current?.label,
description: rootDescription ?? current?.description,
configSchema: current?.configSchema,
configUiHints: current?.configUiHints,
originRank,
});
}
}
for (const [channelId, channelConfig] of Object.entries(record.channelConfigs ?? {})) {
const current = byChannelId.get(channelId);
if (
current &&
current.originRank < originRank &&
(current.configSchema !== undefined || current.configUiHints !== undefined)
) {
continue;
}
byChannelId.set(channelId, {
id: channelId,
label: channelConfig.label ?? rootLabel ?? current?.label,
description: channelConfig.description ?? rootDescription ?? current?.description,
configSchema: channelConfig.schema,
configUiHints: channelConfig.uiHints as ChannelUiMetadata["configUiHints"],
originRank,
});
}
}
return [...byChannelId.values()]
.toSorted((left, right) => left.id.localeCompare(right.id))
.map(({ originRank: _originRank, ...entry }) => entry);
}