























@@ -2,9 +2,11 @@ import { normalizeToolName } from "../agents/tool-policy.js";
22import type { AnyAgentTool } from "../agents/tools/common.js";
33import { createSubsystemLogger } from "../logging/subsystem.js";
44import { applyTestPluginDefaults, normalizePluginsConfig } from "./config-state.js";
5-import { listEnabledInstalledPluginRecords } from "./installed-plugin-index.js";
65import { resolveRuntimePluginRegistry, type PluginLoadOptions } from "./loader.js";
7-import { loadPluginRegistrySnapshot } from "./plugin-registry-snapshot.js";
6+import {
7+isManifestPluginAvailableForControlPlane,
8+loadManifestContractSnapshot,
9+} from "./manifest-contract-eligibility.js";
810import {
911getActivePluginChannelRegistry,
1012getActivePluginRegistry,
@@ -199,13 +201,54 @@ function describeMalformedPluginTool(tool: unknown): string | undefined {
199201return undefined;
200202}
201203202-function addLoadedPluginIdsFromRegistry(
204+function pluginToolNamesMatchAllowlist(params: {
205+names: readonly string[];
206+pluginId: string;
207+optional: boolean;
208+allowlist: Set<string>;
209+}): boolean {
210+if (params.allowlist.size === 0) {
211+return !params.optional;
212+}
213+return isOptionalToolEntryPotentiallyAllowed(params);
214+}
215+216+function manifestToolContractMatchesAllowlist(params: {
217+toolNames: readonly string[];
218+pluginId: string;
219+allowlist: Set<string>;
220+}): boolean {
221+if (params.toolNames.length === 0) {
222+return false;
223+}
224+if (params.allowlist.size === 0) {
225+return true;
226+}
227+if (params.allowlist.has("*") || params.allowlist.has("group:plugins")) {
228+return true;
229+}
230+const pluginKey = normalizeToolName(params.pluginId);
231+if (params.allowlist.has(pluginKey)) {
232+return true;
233+}
234+return params.toolNames.some((name) => params.allowlist.has(normalizeToolName(name)));
235+}
236+237+function addToolPluginIdsFromRegistry(
203238registry: ReturnType<typeof getActivePluginRegistry>,
204239pluginIds: Set<string>,
240+allowlist: Set<string>,
205241): void {
206-for (const plugin of registry?.plugins ?? []) {
207-if (plugin.status === undefined || plugin.status === "loaded") {
208-pluginIds.add(plugin.id);
242+for (const entry of registry?.tools ?? []) {
243+if (
244+pluginToolNamesMatchAllowlist({
245+names: entry.names,
246+pluginId: entry.pluginId,
247+optional: entry.optional,
248+ allowlist,
249+})
250+) {
251+pluginIds.add(entry.pluginId);
209252}
210253}
211254}
@@ -214,21 +257,38 @@ function resolvePluginToolRuntimePluginIds(params: {
214257config: PluginLoadOptions["config"];
215258workspaceDir?: string;
216259env: NodeJS.ProcessEnv;
217-}): string[] | undefined {
260+toolAllowlist?: string[];
261+}): string[] {
218262const pluginIds = new Set<string>();
219-addLoadedPluginIdsFromRegistry(getActivePluginChannelRegistry(), pluginIds);
220-addLoadedPluginIdsFromRegistry(getActivePluginRegistry(), pluginIds);
221-const index = loadPluginRegistrySnapshot({
263+const allowlist = normalizeAllowlist(params.toolAllowlist);
264+addToolPluginIdsFromRegistry(getActivePluginChannelRegistry(), pluginIds, allowlist);
265+addToolPluginIdsFromRegistry(getActivePluginRegistry(), pluginIds, allowlist);
266+const snapshot = loadManifestContractSnapshot({
222267config: params.config,
223268workspaceDir: params.workspaceDir,
224269env: params.env,
225270});
226-for (const plugin of listEnabledInstalledPluginRecords(index, params.config)) {
227-pluginIds.add(plugin.pluginId);
271+for (const plugin of snapshot.plugins) {
272+if (
273+!isManifestPluginAvailableForControlPlane({
274+ snapshot,
275+ plugin,
276+config: params.config,
277+})
278+) {
279+continue;
280+}
281+if (
282+manifestToolContractMatchesAllowlist({
283+toolNames: plugin.contracts?.tools ?? [],
284+pluginId: plugin.id,
285+ allowlist,
286+})
287+) {
288+pluginIds.add(plugin.id);
289+}
228290}
229-return pluginIds.size > 0
230- ? [...pluginIds].toSorted((left, right) => left.localeCompare(right))
231- : undefined;
291+return [...pluginIds].toSorted((left, right) => left.localeCompare(right));
232292}
233293234294function registryContainsPluginIds(
@@ -238,8 +298,11 @@ function registryContainsPluginIds(
238298if (!registry || pluginIds === undefined) {
239299return false;
240300}
241-const loadedPluginIds = new Set<string>();
242-addLoadedPluginIdsFromRegistry(registry, loadedPluginIds);
301+const loadedPluginIds = new Set(
302+(registry.plugins ?? [])
303+.filter((plugin) => plugin.status === undefined || plugin.status === "loaded")
304+.map((plugin) => plugin.id),
305+);
243306return pluginIds.every((pluginId) => loadedPluginIds.has(pluginId));
244307}
245308@@ -291,6 +354,7 @@ export function resolvePluginTools(params: {
291354config: context.config,
292355workspaceDir: context.workspaceDir,
293356 env,
357+toolAllowlist: params.toolAllowlist,
294358});
295359const loadOptions = buildPluginRuntimeLoadOptions(context, {
296360activate: false,
@@ -335,10 +399,10 @@ export function resolvePluginTools(params: {
335399}
336400const declaredNames = entry.names ?? [];
337401if (
338-entry.optional &&
339-!isOptionalToolEntryPotentiallyAllowed({
402+!pluginToolNamesMatchAllowlist({
340403names: declaredNames,
341404pluginId: entry.pluginId,
405+optional: entry.optional,
342406 allowlist,
343407})
344408) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。