@@ -419,78 +419,6 @@ export default async function AgentsPage({ searchParams }: AgentsPageProps) {
419419 < p className = "cell-sub mono muted" > { agentsPageCopy . metricSublines . schedulerHint ( lockedAgentCount ) } </ p >
420420 </ article >
421421 </ section >
422- < RoleConfigControlPlane roleCatalog = { roleCatalogAll } />
423- < section className = "app-section" aria-labelledby = "agents-role-catalog-title" >
424- < div className = "section-header" >
425- < div >
426- < h2 className = "sr-only" > Role catalog (read-only first screen)</ h2 >
427- < h2 id = "agents-role-catalog-title" className = "section-title" > { agentsPageCopy . roleCatalog . title } </ h2 >
428- < p className = "mono muted" > { agentsPageCopy . roleCatalog . subtitle } </ p >
429- </ div >
430- < div className = "toolbar" role = "group" aria-label = "Role catalog entry" >
431- < Button asChild variant = "secondary" aria-label = "Go to the full registered agent list" >
432- < Link href = "#agents-registered-title" > { agentsPageCopy . roleCatalog . fullList } </ Link >
433- </ Button >
434- </ div >
435- </ div >
436- < Card variant = "table" >
437- { payloadWarning ? (
438- < p className = "mono muted" > { agentsPageCopy . roleCatalog . registryUnavailable } </ p >
439- ) : roleCatalog . length === 0 ? (
440- < p className = "mono muted" > { agentsPageCopy . roleCatalog . noMatches } </ p >
441- ) : (
442- < table className = "run-table" >
443- < thead >
444- < tr >
445- < th scope = "col" > { agentsPageCopy . roleCatalog . headers . role } </ th >
446- < th scope = "col" > { agentsPageCopy . roleCatalog . headers . skillsBundle } </ th >
447- < th scope = "col" > { agentsPageCopy . roleCatalog . headers . mcpBundle } </ th >
448- < th scope = "col" > { agentsPageCopy . roleCatalog . headers . runtimeBinding } </ th >
449- < th scope = "col" > { agentsPageCopy . roleCatalog . headers . executionAuthority } </ th >
450- < th scope = "col" > { agentsPageCopy . roleCatalog . headers . registeredSeats } </ th >
451- </ tr >
452- </ thead >
453- < tbody >
454- { roleCatalog . map ( ( roleEntry ) => (
455- < tr key = { `role-catalog:${ roleEntry . role } ` } >
456- < th scope = "row" >
457- < div className = "stack-gap-2" >
458- < Badge > { roleEntry . role } </ Badge >
459- < span className = "muted" > { roleEntry . purpose || agentsPageCopy . roleCatalog . noRolePurpose } </ span >
460- </ div >
461- </ th >
462- < td >
463- < span className = "mono muted" >
464- { formatBindingReadModelLabel ( roleEntry . role_binding_read_model ?. skills_bundle_ref ) }
465- </ span >
466- </ td >
467- < td >
468- < span className = "mono muted" >
469- { formatBindingReadModelLabel ( roleEntry . role_binding_read_model ?. mcp_bundle_ref ) }
470- </ span >
471- </ td >
472- < td > < span className = "mono muted" > { formatRoleBindingRuntimeSummary ( roleEntry . role_binding_read_model ) } </ span > </ td >
473- < td >
474- < div className = "stack-gap-2" >
475- < Badge variant = "running" > { roleEntry . role_binding_read_model . execution_authority } </ Badge >
476- < span className = "muted" > { agentsPageCopy . roleCatalog . readOnlyMirror } </ span >
477- </ div >
478- </ td >
479- < td >
480- < div className = "stack-gap-2" >
481- < span className = "cell-primary" > { roleEntry . registered_agent_count } </ span >
482- < span className = "mono muted" >
483- { roleEntry . locked_agent_count } { agentsPageCopy . roleCatalog . lockedSuffix }
484- </ span >
485- </ div >
486- </ td >
487- </ tr >
488- ) ) }
489- </ tbody >
490- </ table >
491- ) }
492- </ Card >
493- </ section >
494422 < section className = "app-section" aria-labelledby = "agents-ops-title" >
495423 < div className = "section-header" >
496424 < div >
@@ -530,7 +458,6 @@ export default async function AgentsPage({ searchParams }: AgentsPageProps) {
530458 </ Button >
531459 </ form >
532460 </ section >
533-
534461 { /* ── Active State Machine ── */ }
535462 < section className = "app-section" aria-labelledby = "agents-state-machine-title" >
536463 < div className = "section-header" >
@@ -788,6 +715,84 @@ export default async function AgentsPage({ searchParams }: AgentsPageProps) {
788715 </ Card >
789716 </ section >
790717
718+ < RoleConfigControlPlane roleCatalog = { roleCatalogAll } />
719+ < section className = "app-section" aria-labelledby = "agents-role-catalog-title" >
720+ < Card asChild >
721+ < details >
722+ < summary className = "section-title" id = "agents-role-catalog-title" >
723+ { agentsPageCopy . roleCatalog . title }
724+ </ summary >
725+ < div className = "section-header mt-2" >
726+ < div >
727+ < p className = "mono muted" > { agentsPageCopy . roleCatalog . subtitle } </ p >
728+ </ div >
729+ < div className = "toolbar" role = "group" aria-label = "Role catalog entry" >
730+ < Button asChild variant = "secondary" aria-label = "Go to the full registered agent list" >
731+ < Link href = "#agents-registered-title" > { agentsPageCopy . roleCatalog . fullList } </ Link >
732+ </ Button >
733+ </ div >
734+ </ div >
735+ < div className = "table-card mt-2" >
736+ { payloadWarning ? (
737+ < p className = "mono muted" > { agentsPageCopy . roleCatalog . registryUnavailable } </ p >
738+ ) : roleCatalog . length === 0 ? (
739+ < p className = "mono muted" > { agentsPageCopy . roleCatalog . noMatches } </ p >
740+ ) : (
741+ < table className = "run-table" >
742+ < thead >
743+ < tr >
744+ < th scope = "col" > { agentsPageCopy . roleCatalog . headers . role } </ th >
745+ < th scope = "col" > { agentsPageCopy . roleCatalog . headers . skillsBundle } </ th >
746+ < th scope = "col" > { agentsPageCopy . roleCatalog . headers . mcpBundle } </ th >
747+ < th scope = "col" > { agentsPageCopy . roleCatalog . headers . runtimeBinding } </ th >
748+ < th scope = "col" > { agentsPageCopy . roleCatalog . headers . executionAuthority } </ th >
749+ < th scope = "col" > { agentsPageCopy . roleCatalog . headers . registeredSeats } </ th >
750+ </ tr >
751+ </ thead >
752+ < tbody >
753+ { roleCatalog . map ( ( roleEntry ) => (
754+ < tr key = { `role-catalog:${ roleEntry . role } ` } >
755+ < th scope = "row" >
756+ < div className = "stack-gap-2" >
757+ < Badge > { roleEntry . role } </ Badge >
758+ < span className = "muted" > { roleEntry . purpose || agentsPageCopy . roleCatalog . noRolePurpose } </ span >
759+ </ div >
760+ </ th >
761+ < td >
762+ < span className = "mono muted" >
763+ { formatBindingReadModelLabel ( roleEntry . role_binding_read_model ?. skills_bundle_ref ) }
764+ </ span >
765+ </ td >
766+ < td >
767+ < span className = "mono muted" >
768+ { formatBindingReadModelLabel ( roleEntry . role_binding_read_model ?. mcp_bundle_ref ) }
769+ </ span >
770+ </ td >
771+ < td > < span className = "mono muted" > { formatRoleBindingRuntimeSummary ( roleEntry . role_binding_read_model ) } </ span > </ td >
772+ < td >
773+ < div className = "stack-gap-2" >
774+ < Badge variant = "running" > { roleEntry . role_binding_read_model . execution_authority } </ Badge >
775+ < span className = "muted" > { agentsPageCopy . roleCatalog . readOnlyMirror } </ span >
776+ </ div >
777+ </ td >
778+ < td >
779+ < div className = "stack-gap-2" >
780+ < span className = "cell-primary" > { roleEntry . registered_agent_count } </ span >
781+ < span className = "mono muted" >
782+ { roleEntry . locked_agent_count } { agentsPageCopy . roleCatalog . lockedSuffix }
783+ </ span >
784+ </ div >
785+ </ td >
786+ </ tr >
787+ ) ) }
788+ </ tbody >
789+ </ table >
790+ ) }
791+ </ div >
792+ </ details >
793+ </ Card >
794+ </ section >
795+
791796 < section className = "app-section" aria-label = "Agent pagination navigation (footer)" >
792797 < nav className = "toolbar" aria-label = "Agent pagination navigation (footer)" >
793798 < span className = "mono muted" role = "status" aria-live = "polite" aria-atomic = "true" >
0 commit comments