@@ -107,17 +107,19 @@ function buildPluginGroups(params: {
107107 suppressNameConflicts : true ,
108108 allowGatewaySubagentBinding : true ,
109109 } ) ;
110+ const activeRegistry = getActivePluginRegistry ( ) ;
110111 const groups = new Map < string , ToolCatalogGroup > ( ) ;
111112 // Key metadata by plugin ownership and tool name so we only project metadata that
112113 // was registered BY the tool's owning plugin. Without this scoping, plugin-X
113114 // could override the catalog label/description/risk/tags for another plugin's
114115 // tool by registering metadata with the same toolName.
115116 const pluginToolMetadata = new Map (
116- ( getActivePluginRegistry ( ) ?. toolMetadata ?? [ ] ) . map ( ( entry ) => [
117+ ( activeRegistry ?. toolMetadata ?? [ ] ) . map ( ( entry ) => [
117118 buildPluginToolMetadataKey ( entry . pluginId , entry . metadata . toolName ) ,
118119 entry . metadata ,
119120 ] ) ,
120121 ) ;
122+ const seenToolIds = new Set < string > ( ) ;
121123 for ( const tool of pluginTools ) {
122124 const meta = getPluginToolMeta ( tool ) ;
123125 const pluginId = meta ?. pluginId ?? "plugin" ;
@@ -153,8 +155,46 @@ function buildPluginGroups(params: {
153155 tags : ownedMetadata ?. tags ,
154156 defaultProfiles : [ ] ,
155157 } ) ;
158+ seenToolIds . add ( tool . name ) ;
156159 groups . set ( groupId , existing ) ;
157160 }
161+ for ( const entry of activeRegistry ?. tools ?? [ ] ) {
162+ const names = entry . names . length > 0 ? entry . names : ( entry . declaredNames ?? [ ] ) ;
163+ for ( const name of names ) {
164+ if ( seenToolIds . has ( name ) || params . existingToolNames . has ( name ) ) {
165+ continue ;
166+ }
167+ const groupId = `plugin:${ entry . pluginId } ` ;
168+ const existing =
169+ groups . get ( groupId ) ??
170+ ( {
171+ id : groupId ,
172+ label : entry . pluginName ?? entry . pluginId ,
173+ source : "plugin" ,
174+ pluginId : entry . pluginId ,
175+ tools : [ ] ,
176+ } as ToolCatalogGroup ) ;
177+ const ownedMetadata = pluginToolMetadata . get (
178+ buildPluginToolMetadataKey ( entry . pluginId , name ) ,
179+ ) ;
180+ existing . tools . push ( {
181+ id : name ,
182+ label : normalizeOptionalString ( ownedMetadata ?. displayName ) ?? name ,
183+ description :
184+ summarizeToolDescriptionText ( {
185+ rawDescription : ownedMetadata ?. description ,
186+ } ) || `Plugin tool from ${ entry . pluginName ?? entry . pluginId } ` ,
187+ source : "plugin" ,
188+ pluginId : entry . pluginId ,
189+ optional : entry . optional ,
190+ risk : ownedMetadata ?. risk ,
191+ tags : ownedMetadata ?. tags ,
192+ defaultProfiles : [ ] ,
193+ } ) ;
194+ seenToolIds . add ( name ) ;
195+ groups . set ( groupId , existing ) ;
196+ }
197+ }
158198 return [ ...groups . values ( ) ]
159199 . map ( ( group ) =>
160200 Object . assign ( { } , group , { tools : group . tools . toSorted ( ( a , b ) => a . id . localeCompare ( b . id ) ) } ) ,
0 commit comments