@@ -101,6 +101,81 @@ const commands = {
101101 }
102102 } ,
103103
104+
105+ todo : {
106+ desc : 'Scan for TODO/FIXME/HACK comments' ,
107+ run : ( dir = '.' ) => {
108+ const results = [ ] ;
109+ const scan = ( d ) => {
110+ fs . readdirSync ( d ) . forEach ( f => {
111+ const p = path . join ( d , f ) ;
112+ if ( f . startsWith ( '.' ) || f === 'node_modules' ) return ;
113+ if ( fs . statSync ( p ) . isDirectory ( ) ) scan ( p ) ;
114+ else if ( / \. ( j s | t s | p y | g o | r s | c | h | j a v a | r b | m d ) $ / . test ( f ) ) {
115+ const lines = fs . readFileSync ( p , 'utf8' ) . split ( '\n' ) ;
116+ lines . forEach ( ( line , i ) => {
117+ if ( / T O D O | F I X M E | H A C K | X X X / . test ( line ) ) {
118+ results . push ( ` ${ p } :${ i + 1 } ${ line . trim ( ) } ` ) ;
119+ }
120+ } ) ;
121+ }
122+ } ) ;
123+ } ;
124+ scan ( dir ) ;
125+ if ( results . length === 0 ) {
126+ console . log ( '✅ No TODOs found. Grug impressed.' ) ;
127+ } else {
128+ console . log ( `📋 Found ${ results . length } TODO(s):\n` ) ;
129+ results . forEach ( r => console . log ( r ) ) ;
130+ }
131+ }
132+ } ,
133+
134+ size : {
135+ desc : 'Find largest files in project' ,
136+ run : ( dir = '.' , limit = 10 ) => {
137+ const files = [ ] ;
138+ const scan = ( d ) => {
139+ fs . readdirSync ( d ) . forEach ( f => {
140+ const p = path . join ( d , f ) ;
141+ if ( f . startsWith ( '.' ) || f === 'node_modules' ) return ;
142+ const stat = fs . statSync ( p ) ;
143+ if ( stat . isDirectory ( ) ) scan ( p ) ;
144+ else files . push ( { path : p , size : stat . size } ) ;
145+ } ) ;
146+ } ;
147+ scan ( dir ) ;
148+ files . sort ( ( a , b ) => b . size - a . size ) ;
149+ const fmt = ( b ) => b > 1024 * 1024 ? `${ ( b / 1024 / 1024 ) . toFixed ( 1 ) } MB` : b > 1024 ? `${ ( b / 1024 ) . toFixed ( 1 ) } KB` : `${ b } B` ;
150+ console . log ( `📦 Largest ${ Math . min ( limit , files . length ) } files:\n` ) ;
151+ files . slice ( 0 , parseInt ( limit ) ) . forEach ( f => {
152+ const flag = f . size > 500 * 1024 ? ' ⚠️' : '' ;
153+ console . log ( ` ${ fmt ( f . size ) . padEnd ( 8 ) } ${ f . path } ${ flag } ` ) ;
154+ } ) ;
155+ }
156+ } ,
157+
158+ env : {
159+ desc : 'List .env keys (no values shown)' ,
160+ run : ( file = '.env' ) => {
161+ if ( ! fs . existsSync ( file ) ) {
162+ console . log ( `❌ ${ file } not found` ) ;
163+ return ;
164+ }
165+ const lines = fs . readFileSync ( file , 'utf8' ) . split ( '\n' ) ;
166+ const keys = lines
167+ . filter ( l => l . trim ( ) && ! l . startsWith ( '#' ) && l . includes ( '=' ) )
168+ . map ( l => l . split ( '=' ) [ 0 ] . trim ( ) ) ;
169+ if ( keys . length === 0 ) {
170+ console . log ( '📭 No keys found' ) ;
171+ return ;
172+ }
173+ console . log ( `🔑 ${ file } keys (${ keys . length } ):\n` ) ;
174+ keys . forEach ( k => console . log ( ` ${ k } ` ) ) ;
175+ console . log ( '\n🔒 Values hidden. Grug protect secrets.' ) ;
176+ }
177+ } ,
178+
104179 help : {
105180 desc : 'Show this help' ,
106181 run : ( ) => {
0 commit comments