@@ -268,6 +268,91 @@ export class ObjectQL implements IDataEngine {
268268 this . logger . debug ( 'Registered Kind' , { kind : kind . name || kind . type , from : id } ) ;
269269 }
270270 }
271+
272+ // 7. Recursively register nested plugins
273+ if ( Array . isArray ( manifest . plugins ) && manifest . plugins . length > 0 ) {
274+ console . log ( `[ObjectQL] Processing ${ manifest . plugins . length } nested plugins from ${ id } ` ) ;
275+ this . logger . debug ( 'Processing nested plugins' , { id, count : manifest . plugins . length } ) ;
276+ for ( const plugin of manifest . plugins ) {
277+ if ( plugin && typeof plugin === 'object' ) {
278+ const pluginName = plugin . name || plugin . id || 'unnamed-plugin' ;
279+ console . log ( `[ObjectQL] Registering nested plugin: ${ pluginName } , has objects: ${ ! ! plugin . objects } , objects type: ${ typeof plugin . objects } ` ) ;
280+ this . logger . debug ( 'Registering nested plugin' , { pluginName, parentId : id } ) ;
281+ this . registerPlugin ( plugin , id , namespace ) ;
282+ }
283+ }
284+ }
285+ }
286+
287+ /**
288+ * Register a nested plugin's metadata (objects, actions, views, etc.)
289+ *
290+ * Unlike registerApp(), this does NOT call SchemaRegistry.installPackage()
291+ * because plugins are not formal manifests — they are lightweight config
292+ * bundles with objects, actions, triggers, and navigation.
293+ *
294+ * @param plugin - The plugin config object
295+ * @param parentId - The parent package ID (for ownership tracking)
296+ * @param parentNamespace - The parent package's namespace (for FQN resolution)
297+ */
298+ private registerPlugin ( plugin : any , parentId : string , parentNamespace ?: string ) {
299+ const pluginId = plugin . id || plugin . name || parentId ;
300+ const pluginNamespace = plugin . namespace || parentNamespace ;
301+
302+ // Register objects (supports both Array and Map formats)
303+ if ( plugin . objects ) {
304+ try {
305+ if ( Array . isArray ( plugin . objects ) ) {
306+ console . log ( `[ObjectQL] Registering ${ plugin . objects . length } objects (Array) for plugin ${ pluginId } ` ) ;
307+ for ( const objDef of plugin . objects ) {
308+ const fqn = SchemaRegistry . registerObject ( objDef , pluginId , pluginNamespace , 'own' ) ;
309+ console . log ( `[ObjectQL] Registered Object: ${ fqn } ` ) ;
310+ }
311+ } else {
312+ const entries = Object . entries ( plugin . objects ) ;
313+ console . log ( `[ObjectQL] Registering ${ entries . length } objects (Map) for plugin ${ pluginId } , namespace: ${ pluginNamespace } ` ) ;
314+ for ( const [ name , objDef ] of entries ) {
315+ ( objDef as any ) . name = name ;
316+ const fqn = SchemaRegistry . registerObject ( objDef as any , pluginId , pluginNamespace , 'own' ) ;
317+ console . log ( `[ObjectQL] Registered Object: ${ fqn } ` ) ;
318+ }
319+ }
320+ } catch ( err : any ) {
321+ console . error ( `[ObjectQL] Failed to register plugin objects for ${ pluginId } :` , err . message ) ;
322+ }
323+ } else {
324+ console . log ( `[ObjectQL] Plugin ${ pluginId } has no objects` ) ;
325+ }
326+
327+ // Register plugin as app if it has navigation (for sidebar display)
328+ if ( plugin . name && plugin . navigation ) {
329+ try {
330+ SchemaRegistry . registerApp ( plugin , pluginId ) ;
331+ this . logger . debug ( 'Registered plugin-as-app' , { app : plugin . name , from : pluginId } ) ;
332+ } catch ( err : any ) {
333+ this . logger . warn ( 'Failed to register plugin as app' , { pluginId, error : err . message } ) ;
334+ }
335+ }
336+
337+ // Register metadata arrays (actions, views, triggers, etc.)
338+ const metadataArrayKeys = [
339+ 'actions' , 'views' , 'pages' , 'dashboards' , 'reports' , 'themes' ,
340+ 'flows' , 'workflows' , 'approvals' , 'webhooks' ,
341+ 'roles' , 'permissions' , 'profiles' , 'sharingRules' , 'policies' ,
342+ 'agents' , 'ragPipelines' , 'apis' ,
343+ 'hooks' , 'mappings' , 'analyticsCubes' , 'connectors' ,
344+ ] ;
345+ for ( const key of metadataArrayKeys ) {
346+ const items = ( plugin as any ) [ key ] ;
347+ if ( Array . isArray ( items ) && items . length > 0 ) {
348+ for ( const item of items ) {
349+ const itemName = item . name || item . id ;
350+ if ( itemName ) {
351+ SchemaRegistry . registerItem ( key , item , 'name' as any , pluginId ) ;
352+ }
353+ }
354+ }
355+ }
271356 }
272357
273358 /**
0 commit comments