






















@@ -0,0 +1,385 @@
1+import { normalizeProviderId } from "../agents/provider-id.js";
2+import type { OpenClawConfig } from "../config/types.openclaw.js";
3+import {
4+normalizePluginsConfigWithResolver,
5+type NormalizedPluginsConfig,
6+} from "./config-normalization-shared.js";
7+import { isInstalledPluginEnabled } from "./installed-plugin-index.js";
8+import { loadPluginManifestRegistryForInstalledIndex } from "./manifest-registry-installed.js";
9+import type {
10+PluginManifestContractListKey,
11+PluginManifestRecord,
12+PluginManifestRegistry,
13+} from "./manifest-registry.js";
14+import type { PluginOrigin } from "./plugin-origin.types.js";
15+import {
16+loadPluginRegistrySnapshot,
17+type LoadPluginRegistryParams,
18+type PluginRegistrySnapshot,
19+} from "./plugin-registry-snapshot.js";
20+21+export type PluginRegistryContributionOptions = LoadPluginRegistryParams & {
22+includeDisabled?: boolean;
23+};
24+25+export type LoadPluginRegistryManifestParams = LoadPluginRegistryParams & {
26+includeDisabled?: boolean;
27+pluginIds?: readonly string[];
28+};
29+30+export type PluginRegistryContributionKey =
31+| "providers"
32+| "channels"
33+| "channelConfigs"
34+| "setupProviders"
35+| "cliBackends"
36+| "modelCatalogProviders"
37+| "commandAliases"
38+| "contracts";
39+40+export type ResolvePluginContributionOwnersParams = PluginRegistryContributionOptions & {
41+contribution: PluginRegistryContributionKey;
42+matches: string | ((contributionId: string) => boolean);
43+};
44+45+export type ListPluginContributionIdsParams = PluginRegistryContributionOptions & {
46+contribution: PluginRegistryContributionKey;
47+};
48+49+export type ResolveProviderOwnersParams = PluginRegistryContributionOptions & {
50+providerId: string;
51+};
52+53+export type ResolveChannelOwnersParams = PluginRegistryContributionOptions & {
54+channelId: string;
55+};
56+57+export type ResolveCliBackendOwnersParams = PluginRegistryContributionOptions & {
58+cliBackendId: string;
59+};
60+61+export type ResolveSetupProviderOwnersParams = PluginRegistryContributionOptions & {
62+setupProviderId: string;
63+};
64+65+export type ResolveManifestContractPluginIdsParams = LoadPluginRegistryParams & {
66+contract: PluginManifestContractListKey;
67+origin?: PluginOrigin;
68+onlyPluginIds?: readonly string[];
69+};
70+71+export type ResolveManifestContractOwnerPluginIdParams = LoadPluginRegistryParams & {
72+contract: PluginManifestContractListKey;
73+value: string | undefined;
74+origin?: PluginOrigin;
75+};
76+77+export type ResolveManifestContractPluginIdsByCompatibilityRuntimePathParams =
78+LoadPluginRegistryParams & {
79+contract: PluginManifestContractListKey;
80+path: string | undefined;
81+origin?: PluginOrigin;
82+};
83+84+function normalizeContributionId(value: string): string {
85+return value.trim();
86+}
87+88+function normalizePluginRegistryAlias(value: string): string {
89+return value.trim();
90+}
91+92+function normalizePluginRegistryAliasKey(value: string): string {
93+return normalizePluginRegistryAlias(value).toLowerCase();
94+}
95+96+function sortUnique(values: Iterable<string>): string[] {
97+return [...new Set([...values].map((value) => value.trim()).filter(Boolean))].toSorted(
98+(left, right) => left.localeCompare(right),
99+);
100+}
101+102+function collectObjectKeys(value: Record<string, unknown> | undefined): readonly string[] {
103+return value ? Object.keys(value) : [];
104+}
105+106+function collectContractKeys(plugin: PluginManifestRecord): readonly string[] {
107+const contracts = plugin.contracts;
108+if (!contracts) {
109+return [];
110+}
111+return Object.entries(contracts).flatMap(([key, value]) =>
112+Array.isArray(value) && value.length > 0 ? [key] : [],
113+);
114+}
115+116+function listManifestContractValues(
117+plugin: PluginManifestRecord,
118+contract: PluginManifestContractListKey,
119+): readonly string[] {
120+return plugin.contracts?.[contract] ?? [];
121+}
122+123+function loadManifestContractRegistry(
124+params: LoadPluginRegistryParams & {
125+onlyPluginIds?: readonly string[];
126+},
127+): PluginManifestRegistry {
128+return loadPluginManifestRegistryForPluginRegistry({
129+ ...params,
130+pluginIds: params.onlyPluginIds,
131+includeDisabled: true,
132+});
133+}
134+135+function listManifestContributionIds(
136+plugin: PluginManifestRecord,
137+contribution: PluginRegistryContributionKey,
138+): readonly string[] {
139+switch (contribution) {
140+case "providers":
141+return plugin.providers;
142+case "channels":
143+return plugin.channels;
144+case "channelConfigs":
145+return collectObjectKeys(plugin.channelConfigs);
146+case "setupProviders":
147+return plugin.setup?.providers?.map((provider) => provider.id) ?? [];
148+case "cliBackends":
149+return [...plugin.cliBackends, ...(plugin.setup?.cliBackends ?? [])];
150+case "modelCatalogProviders":
151+return collectObjectKeys(plugin.modelCatalog?.providers);
152+case "commandAliases":
153+return plugin.commandAliases?.map((alias) => alias.name) ?? [];
154+case "contracts":
155+return collectContractKeys(plugin);
156+}
157+return [];
158+}
159+160+function resolveContributionPluginIds(params: {
161+index: PluginRegistrySnapshot;
162+includeDisabled?: boolean;
163+config?: OpenClawConfig;
164+}): readonly string[] {
165+if (params.includeDisabled) {
166+return params.index.plugins.map((plugin) => plugin.pluginId);
167+}
168+return params.index.plugins
169+.filter((plugin) => isInstalledPluginEnabled(params.index, plugin.pluginId, params.config))
170+.map((plugin) => plugin.pluginId);
171+}
172+173+function loadContributionManifestRegistry(
174+params: LoadPluginRegistryParams & {
175+index: PluginRegistrySnapshot;
176+includeDisabled?: boolean;
177+},
178+): PluginManifestRegistry {
179+return loadPluginManifestRegistryForInstalledIndex({
180+index: params.index,
181+config: params.config,
182+workspaceDir: params.workspaceDir,
183+env: params.env,
184+pluginIds: resolveContributionPluginIds({
185+index: params.index,
186+includeDisabled: params.includeDisabled,
187+config: params.config,
188+}),
189+includeDisabled: true,
190+});
191+}
192+193+export function loadPluginManifestRegistryForPluginRegistry(
194+params: LoadPluginRegistryManifestParams = {},
195+): PluginManifestRegistry {
196+const index = loadPluginRegistrySnapshot(params);
197+return loadPluginManifestRegistryForInstalledIndex({
198+ index,
199+config: params.config,
200+workspaceDir: params.workspaceDir,
201+env: params.env,
202+pluginIds: params.pluginIds,
203+includeDisabled: params.includeDisabled,
204+});
205+}
206+207+export function createPluginRegistryIdNormalizer(
208+index: PluginRegistrySnapshot,
209+): (pluginId: string) => string {
210+const aliases = new Map<string, string>();
211+for (const plugin of index.plugins) {
212+const pluginId = normalizePluginRegistryAlias(plugin.pluginId);
213+if (pluginId) {
214+aliases.set(normalizePluginRegistryAliasKey(pluginId), plugin.pluginId);
215+}
216+}
217+const registry = loadPluginManifestRegistryForInstalledIndex({
218+ index,
219+includeDisabled: true,
220+});
221+for (const plugin of [...registry.plugins].toSorted((left, right) =>
222+left.id.localeCompare(right.id),
223+)) {
224+const pluginId = normalizePluginRegistryAlias(plugin.id);
225+if (!pluginId) {
226+continue;
227+}
228+aliases.set(normalizePluginRegistryAliasKey(pluginId), plugin.id);
229+for (const alias of [
230+plugin.id,
231+ ...listManifestContributionIds(plugin, "providers"),
232+ ...listManifestContributionIds(plugin, "channels"),
233+ ...listManifestContributionIds(plugin, "setupProviders"),
234+ ...listManifestContributionIds(plugin, "cliBackends"),
235+ ...listManifestContributionIds(plugin, "modelCatalogProviders"),
236+ ...(plugin.legacyPluginIds ?? []),
237+]) {
238+const normalizedAlias = normalizePluginRegistryAlias(alias);
239+const normalizedAliasKey = normalizePluginRegistryAliasKey(alias);
240+if (normalizedAlias && !aliases.has(normalizedAliasKey)) {
241+aliases.set(normalizedAliasKey, pluginId);
242+}
243+}
244+}
245+return (pluginId: string) => {
246+const trimmed = normalizePluginRegistryAlias(pluginId);
247+return aliases.get(normalizePluginRegistryAliasKey(trimmed)) ?? trimmed;
248+};
249+}
250+251+export function normalizePluginsConfigWithRegistry(
252+config: OpenClawConfig["plugins"] | undefined,
253+index: PluginRegistrySnapshot,
254+): NormalizedPluginsConfig {
255+return normalizePluginsConfigWithResolver(config, createPluginRegistryIdNormalizer(index));
256+}
257+258+export function listPluginContributionIds(
259+params: ListPluginContributionIdsParams,
260+): readonly string[] {
261+const index = loadPluginRegistrySnapshot(params);
262+const registry = loadContributionManifestRegistry({
263+ ...params,
264+ index,
265+});
266+return sortUnique(
267+registry.plugins.flatMap((plugin) => listManifestContributionIds(plugin, params.contribution)),
268+);
269+}
270+271+export function resolvePluginContributionOwners(
272+params: ResolvePluginContributionOwnersParams,
273+): readonly string[] {
274+const matcher =
275+typeof params.matches === "string"
276+ ? (contributionId: string) => contributionId === params.matches
277+ : params.matches;
278+const index = loadPluginRegistrySnapshot(params);
279+const registry = loadContributionManifestRegistry({
280+ ...params,
281+ index,
282+});
283+return sortUnique(
284+registry.plugins.flatMap((plugin) =>
285+listManifestContributionIds(plugin, params.contribution).some(matcher) ? [plugin.id] : [],
286+),
287+);
288+}
289+290+export function resolveProviderOwners(params: ResolveProviderOwnersParams): readonly string[] {
291+const providerId = normalizeProviderId(params.providerId);
292+if (!providerId) {
293+return [];
294+}
295+return resolvePluginContributionOwners({
296+ ...params,
297+contribution: "providers",
298+matches: (contributionId) => normalizeProviderId(contributionId) === providerId,
299+});
300+}
301+302+export function resolveChannelOwners(params: ResolveChannelOwnersParams): readonly string[] {
303+const channelId = normalizeContributionId(params.channelId);
304+if (!channelId) {
305+return [];
306+}
307+return resolvePluginContributionOwners({
308+ ...params,
309+contribution: "channels",
310+matches: channelId,
311+});
312+}
313+314+export function resolveCliBackendOwners(params: ResolveCliBackendOwnersParams): readonly string[] {
315+const cliBackendId = normalizeContributionId(params.cliBackendId);
316+if (!cliBackendId) {
317+return [];
318+}
319+return resolvePluginContributionOwners({
320+ ...params,
321+contribution: "cliBackends",
322+matches: cliBackendId,
323+});
324+}
325+326+export function resolveSetupProviderOwners(
327+params: ResolveSetupProviderOwnersParams,
328+): readonly string[] {
329+const setupProviderId = normalizeContributionId(params.setupProviderId);
330+if (!setupProviderId) {
331+return [];
332+}
333+return resolvePluginContributionOwners({
334+ ...params,
335+contribution: "setupProviders",
336+matches: setupProviderId,
337+});
338+}
339+340+export function resolveManifestContractPluginIds(
341+params: ResolveManifestContractPluginIdsParams,
342+): string[] {
343+return loadManifestContractRegistry(params)
344+.plugins.filter(
345+(plugin) =>
346+(!params.origin || plugin.origin === params.origin) &&
347+listManifestContractValues(plugin, params.contract).length > 0,
348+)
349+.map((plugin) => plugin.id)
350+.toSorted((left, right) => left.localeCompare(right));
351+}
352+353+export function resolveManifestContractPluginIdsByCompatibilityRuntimePath(
354+params: ResolveManifestContractPluginIdsByCompatibilityRuntimePathParams,
355+): string[] {
356+const normalizedPath = params.path?.trim();
357+if (!normalizedPath) {
358+return [];
359+}
360+return loadManifestContractRegistry(params)
361+.plugins.filter(
362+(plugin) =>
363+(!params.origin || plugin.origin === params.origin) &&
364+listManifestContractValues(plugin, params.contract).length > 0 &&
365+(plugin.configContracts?.compatibilityRuntimePaths ?? []).includes(normalizedPath),
366+)
367+.map((plugin) => plugin.id)
368+.toSorted((left, right) => left.localeCompare(right));
369+}
370+371+export function resolveManifestContractOwnerPluginId(
372+params: ResolveManifestContractOwnerPluginIdParams,
373+): string | undefined {
374+const normalizedValue = normalizeContributionId(params.value ?? "").toLowerCase();
375+if (!normalizedValue) {
376+return undefined;
377+}
378+return loadManifestContractRegistry(params).plugins.find(
379+(plugin) =>
380+(!params.origin || plugin.origin === params.origin) &&
381+listManifestContractValues(plugin, params.contract).some(
382+(candidate) => normalizeContributionId(candidate).toLowerCase() === normalizedValue,
383+),
384+)?.id;
385+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。