274
*/
275
export function buildDiscoveredCustomizations(
277
>
mcpServers: readonly McpServerCustomization[],
278
>
hooks: readonly HookCustomization[],
279
>
nativePlugins: readonly IResolvedNativePlugin[],
280
>
workingDirectory: URI | undefined,
281
>
userHome: URI,
282
>
sdk: ISdkResolvedCustomizations | undefined,
283
>
): readonly Customization[] {
284
>
// Native plugins the live session actually loaded → surfaced as top-level
285
>
// containers (passed to the mapper at the end). The SDK `init.plugins`
286
>
// reports each loaded plugin's `source` (its `<plugin>@<marketplace>` id)
287
>
// and a `path`. Match on `source` against the resolved plugin id first — it
288
>
// is exact and stable — and fall back to a normalized `path` match (older
289
>
// SDKs without `source`). The `path` alone is unreliable: for a
290
>
// workspace-`local`-scoped plugin the SDK can report a non-cache path that
291
>
// never matches the resolved root. The plugin is the atomic filtering unit.
292
>
//
293
>
// A plugin's bundled components are ALSO reported by the live SDK as
294
>
// agents / commands / MCP servers. Collect each surfaced plugin's own
295
>
// parsed component names so those SDK entries are suppressed from the
296
>
// standalone fallbacks below — each component then appears once, under its
297
>
// plugin container, not also loose in the per-scope lists (Decision PB-10).
298
>
// The SDK names plugin components inconsistently (agents namespaced as
299
>
// `<plugin>:<name>`, skills usually bare), so both forms are registered.
300
>
// Only *surfaced* plugins contribute, so a loaded-but-unsurfaced plugin's
301
>
// components are never silently dropped. A single pass matches each native
302
>
// plugin to its SDK entry, building the visible set and the suppression
303
>
// name sets together (no second `find`).
304
>
const visiblePlugins: IResolvedNativePlugin[] = [];
305
>
const pluginAgentNames = new Set<string>();
306
>
const pluginSkillNames = new Set<string>();
307
>
const pluginMcpNames = new Set<string>();
308
>
if (sdk) {
309
for (const p of nativePlugins) {
310
const sdkPlugin = sdk.plugins.find(s => s.source === p.id || URI.file(s.path).fsPath === p.root.fsPath);