@@ -24,6 +24,95 @@ function getMetaDir(): string {
2424// Commands
2525// ---------------------------------------------------------------------------
2626
27+ function padColumn ( text : string , width : number ) : string {
28+ return text . length >= width ? text + ' ' : text . padEnd ( width )
29+ }
30+
31+ function printTable ( headers : string [ ] , rows : string [ ] [ ] ) : void {
32+ const widths = headers . map (
33+ ( h , i ) => Math . max ( h . length , ...rows . map ( ( r ) => ( r [ i ] ?? '' ) . length ) ) + 2 ,
34+ )
35+
36+ const headerLine = headers . map ( ( h , i ) => padColumn ( h , widths [ i ] ! ) ) . join ( '' )
37+ const separator = widths . map ( ( w ) => '─' . repeat ( w ) ) . join ( '' )
38+
39+ console . log ( headerLine )
40+ console . log ( separator )
41+ for ( const row of rows ) {
42+ console . log ( row . map ( ( cell , i ) => padColumn ( cell , widths [ i ] ! ) ) . join ( '' ) )
43+ }
44+ }
45+
46+ interface SkillDisplay {
47+ name : string
48+ description : string
49+ type ?: string
50+ }
51+
52+ function printSkillTree (
53+ skills : SkillDisplay [ ] ,
54+ opts : { nameWidth : number ; showTypes : boolean } ,
55+ ) : void {
56+ const roots : string [ ] = [ ]
57+ const children = new Map < string , SkillDisplay [ ] > ( )
58+
59+ for ( const skill of skills ) {
60+ const slashIdx = skill . name . indexOf ( '/' )
61+ if ( slashIdx === - 1 ) {
62+ roots . push ( skill . name )
63+ } else {
64+ const parent = skill . name . slice ( 0 , slashIdx )
65+ if ( ! children . has ( parent ) ) children . set ( parent , [ ] )
66+ children . get ( parent ) ! . push ( skill )
67+ }
68+ }
69+
70+ if ( roots . length === 0 ) {
71+ for ( const skill of skills ) {
72+ if ( ! roots . includes ( skill . name ) ) roots . push ( skill . name )
73+ }
74+ }
75+
76+ for ( const rootName of roots ) {
77+ const rootSkill = skills . find ( ( s ) => s . name === rootName )
78+ if ( ! rootSkill ) continue
79+
80+ printSkillLine ( rootName , rootSkill , 4 , opts )
81+
82+ for ( const sub of children . get ( rootName ) ?? [ ] ) {
83+ const childName = sub . name . slice ( sub . name . indexOf ( '/' ) + 1 )
84+ printSkillLine ( childName , sub , 6 , opts )
85+ }
86+ }
87+ }
88+
89+ function printSkillLine (
90+ displayName : string ,
91+ skill : SkillDisplay ,
92+ indent : number ,
93+ opts : { nameWidth : number ; showTypes : boolean } ,
94+ ) : void {
95+ const nameStr = ' '. repeat ( indent ) + displayName
96+ const padding = ' ' . repeat ( Math . max ( 2 , opts . nameWidth - nameStr . length ) )
97+ const typeCol = opts . showTypes
98+ ? ( skill . type ? `[${ skill . type } ]` : '' ) . padEnd ( 14 )
99+ : ''
100+ console . log ( `${ nameStr } ${ padding } ${ typeCol } ${ skill . description } ` )
101+ }
102+
103+ function computeSkillNameWidth ( allPackageSkills : SkillDisplay [ ] [ ] ) : number {
104+ let max = 0
105+ for ( const skills of allPackageSkills ) {
106+ for ( const s of skills ) {
107+ const slashIdx = s . name . indexOf ( '/' )
108+ const displayName = slashIdx === - 1 ? s . name : s . name . slice ( slashIdx + 1 )
109+ const indent = slashIdx === - 1 ? 4 : 6
110+ max = Math . max ( max , indent + displayName . length )
111+ }
112+ }
113+ return max + 2
114+ }
115+
27116async function cmdList ( args : string [ ] ) : Promise < void > {
28117 const jsonOutput = args . includes ( '--json' )
29118
@@ -49,18 +138,32 @@ async function cmdList(args: string[]): Promise<void> {
49138 return
50139 }
51140
52- console . log ( `Intent-enabled packages (${ result . packages . length } found):\n` )
53-
141+ const totalSkills = result . packages . reduce (
142+ ( sum , p ) => sum + p . skills . length ,
143+ 0 ,
144+ )
145+ console . log (
146+ `\n${ result . packages . length } intent-enabled packages, ${ totalSkills } skills (${ result . packageManager } )\n` ,
147+ )
148+
149+ // Summary table
150+ const rows = result . packages . map ( ( pkg ) => [
151+ pkg . name ,
152+ pkg . version ,
153+ String ( pkg . skills . length ) ,
154+ pkg . intent . requires ?. join ( ', ' ) || '–' ,
155+ ] )
156+ printTable ( [ 'PACKAGE' , 'VERSION' , 'SKILLS' , 'REQUIRES' ] , rows )
157+
158+ // Skills detail
159+ const allSkills = result . packages . map ( ( p ) => p . skills )
160+ const nameWidth = computeSkillNameWidth ( allSkills )
161+ const showTypes = result . packages . some ( ( p ) => p . skills . some ( ( s ) => s . type ) )
162+
163+ console . log ( `\nSkills:\n` )
54164 for ( const pkg of result . packages ) {
55- const reqStr = pkg . intent . requires ?. length
56- ? ` (requires: ${ pkg . intent . requires . join ( ', ' ) } )`
57- : ''
58- console . log ( `${ pkg . name } v${ pkg . version } ${ reqStr } ` )
59-
60- for ( const skill of pkg . skills ) {
61- const desc = skill . description ? ` ${ skill . description } ` : ''
62- console . log ( ` ${ skill . name . padEnd ( 32 ) } ${ desc } ` )
63- }
165+ console . log ( ` ${ pkg . name } ` )
166+ printSkillTree ( pkg . skills , { nameWidth, showTypes } )
64167 console . log ( )
65168 }
66169
0 commit comments