11import type { CSSProperties , ReactNode } from "react" ;
2+ import { baseAgentKind } from "@/shared/contracts" ;
23import type { StatusTone } from "./statusTone" ;
34import {
45 getUtilityTaskCandidates ,
@@ -74,6 +75,22 @@ function fallbackInitial(label: string | undefined): string {
7475 return ( raw . match ( / [ A - Z a - z 0 - 9 ] / ) ?. [ 0 ] ?? "?" ) . toUpperCase ( ) ;
7576}
7677
78+ function claudeProfileBadgeLabel ( kind : string , fallbackLabel : string | undefined ) : string {
79+ const profileId = kind . slice ( "claude:" . length ) ;
80+ const label = fallbackLabel ?. trim ( ) ;
81+ if ( ! label ) return profileId ;
82+ const profileLabel = label . replace ( / ^ c l a u d e \s + / i, "" ) . trim ( ) ;
83+ return profileLabel || profileId ;
84+ }
85+
86+ /** Registry lookup that falls back to the base kind for instance-scoped kinds. */
87+ function lookupByKind < T > ( registry : Map < string , T > , kind : string ) : T | undefined {
88+ const exact = registry . get ( kind ) ;
89+ if ( exact !== undefined ) return exact ;
90+ const baseKind = baseAgentKind ( kind ) ;
91+ return baseKind !== kind ? registry . get ( baseKind ) : undefined ;
92+ }
93+
7794function GenericProviderIcon ( props : { label ?: string ; tone : StatusTone ; className ?: string } ) {
7895 return (
7996 < span
@@ -103,7 +120,7 @@ export function ProviderIcon(props: {
103120 */
104121 pending ?: boolean | undefined ;
105122} ) {
106- const Icon = ICON_REGISTRY . get ( props . kind ) ;
123+ const Icon = lookupByKind ( ICON_REGISTRY , props . kind ) ;
107124 const tone = props . tone ?? "inactive" ;
108125 if ( ! Icon ) {
109126 if ( props . icon ) {
@@ -126,7 +143,20 @@ export function ProviderIcon(props: {
126143 />
127144 ) ;
128145 }
129- return < Icon tone = { tone } { ...( props . className ? { className : props . className } : { } ) } /> ;
146+ const rendered = (
147+ < Icon tone = { tone } { ...( props . className ? { className : props . className } : { } ) } />
148+ ) ;
149+ if ( props . kind . startsWith ( "claude:" ) ) {
150+ return (
151+ < span className = { `relative inline-flex ${ props . className ?? "" } ` } >
152+ { rendered }
153+ < span className = "absolute -bottom-0.5 -right-0.5 flex size-2.5 items-center justify-center rounded-full border border-background bg-surface text-[6px] font-semibold leading-none text-foreground" >
154+ { fallbackInitial ( claudeProfileBadgeLabel ( props . kind , props . fallbackLabel ) ) }
155+ </ span >
156+ </ span >
157+ ) ;
158+ }
159+ return rendered ;
130160}
131161
132162// --- Provider label registry ---
@@ -202,12 +232,7 @@ export function registerComposerControls(kind: string, registration: ComposerCon
202232}
203233
204234export function getComposerControls ( kind : string ) : ComposerControlsFactory | undefined {
205- const separatorIndex = kind . indexOf ( ":" ) ;
206- const registration =
207- COMPOSER_CONTROLS_REGISTRY . get ( kind ) ??
208- ( separatorIndex > 0
209- ? COMPOSER_CONTROLS_REGISTRY . get ( kind . slice ( 0 , separatorIndex ) )
210- : undefined ) ;
235+ const registration = lookupByKind ( COMPOSER_CONTROLS_REGISTRY , kind ) ;
211236 if ( ! registration ) return undefined ;
212237 if ( typeof registration === "function" ) return registration ;
213238 return ( input ) => {
@@ -252,7 +277,7 @@ export function registerGuiSlashCommands(kind: string, registration: GuiSlashCom
252277}
253278
254279export function getGuiSlashCommands ( kind : string ) : GuiSlashCommandRegistration | undefined {
255- return GUI_SLASH_COMMAND_REGISTRY . get ( kind ) ;
280+ return lookupByKind ( GUI_SLASH_COMMAND_REGISTRY , kind ) ;
256281}
257282
258283// --- Config normalizer registry ---
@@ -276,7 +301,7 @@ export function registerConfigNormalizer(kind: string, normalizer: ConfigNormali
276301}
277302
278303export function getConfigNormalizer ( kind : string ) : ConfigNormalizer | undefined {
279- return CONFIG_NORMALIZER_REGISTRY . get ( kind ) ;
304+ return lookupByKind ( CONFIG_NORMALIZER_REGISTRY , kind ) ;
280305}
281306
282307// --- Trigger word registry ---
@@ -303,10 +328,7 @@ export function getTriggerWords(
303328 model : string | undefined ,
304329) : readonly TriggerWordDef [ ] {
305330 if ( ! kind ) return [ ] ;
306- const separatorIndex = kind . indexOf ( ":" ) ;
307- const matcher =
308- TRIGGER_WORD_REGISTRY . get ( kind ) ??
309- ( separatorIndex > 0 ? TRIGGER_WORD_REGISTRY . get ( kind . slice ( 0 , separatorIndex ) ) : undefined ) ;
331+ const matcher = lookupByKind ( TRIGGER_WORD_REGISTRY , kind ) ;
310332 return matcher ? matcher ( model ) : [ ] ;
311333}
312334
@@ -321,7 +343,7 @@ export function registerCommitGenDefaults(kind: string, defaults: CommitGenDefau
321343}
322344
323345export function getCommitGenDefaults ( kind : string ) : CommitGenDefaults | undefined {
324- return COMMIT_GEN_REGISTRY . get ( kind ) ;
346+ return lookupByKind ( COMMIT_GEN_REGISTRY , kind ) ;
325347}
326348
327349export function getCommitGenDefaultsHint ( ) : string | undefined {
@@ -339,7 +361,7 @@ export function registerTitleGenDefaults(kind: string, defaults: TitleGenDefault
339361}
340362
341363export function getTitleGenDefaults ( kind : string ) : TitleGenDefaults | undefined {
342- return TITLE_GEN_REGISTRY . get ( kind ) ;
364+ return lookupByKind ( TITLE_GEN_REGISTRY , kind ) ;
343365}
344366
345367export function getTitleGenDefaultsHint ( ) : string | undefined {
@@ -357,7 +379,7 @@ export function registerConflictResolverDefaults(kind: string, defaults: Conflic
357379}
358380
359381export function getConflictResolverDefaults ( kind : string ) : ConflictResolverDefaults | undefined {
360- return CONFLICT_RESOLVER_REGISTRY . get ( kind ) ;
382+ return lookupByKind ( CONFLICT_RESOLVER_REGISTRY , kind ) ;
361383}
362384
363385export function getConflictResolverDefaultsHint ( ) : string | undefined {
0 commit comments