codymaster 4.5.1 → 4.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,552 @@
1
+ #!/usr/bin/env bash
2
+ # =============================================================================
3
+ # CodyMaster Skeleton Indexer — Zero-Dependency Lightning-Fast Code Scanner
4
+ # =============================================================================
5
+ # TRIZ Principles Applied:
6
+ # #1 Segmentation — Index only signatures, not full content
7
+ # #2 Taking Out — Extract skeleton, discard body
8
+ # #3 Local Quality — Different patterns per language
9
+ # #10 Prior Action — Run once, reuse across sessions
10
+ # #13 Inversion — Code summarizes itself to the agent
11
+ # #25 Self-Service — Auto-detects languages, zero config
12
+ # #35 Parameter Changes — Unit: file content → function signature
13
+ #
14
+ # Usage:
15
+ # ./index-codebase.sh [project_root] [output_file]
16
+ #
17
+ # Output: Compact skeleton.md (~3000 tokens for 200-file project)
18
+ # Speed: <2 seconds on most projects
19
+ # Deps: ZERO (uses grep, find, awk, wc — standard POSIX tools)
20
+ # =============================================================================
21
+
22
+ set -uo pipefail
23
+
24
+ # --- Configuration ---
25
+ PROJECT_ROOT="${1:-.}"
26
+ OUTPUT_FILE="${2:-$PROJECT_ROOT/.cm/skeleton.md}"
27
+ MAX_DEPTH=10
28
+ MAX_SIGS_PER_FILE=15
29
+ MAX_FILES_PER_DIR=15
30
+ MAX_TOTAL_LINES=600
31
+
32
+ # Colors for terminal output
33
+ RED='\033[0;31m'
34
+ GREEN='\033[0;32m'
35
+ CYAN='\033[0;36m'
36
+ NC='\033[0m' # No Color
37
+
38
+ # --- Ensure .cm directory exists ---
39
+ mkdir -p "$(dirname "$OUTPUT_FILE")"
40
+
41
+ # --- Detect project name ---
42
+ PROJECT_NAME=$(basename "$(cd "$PROJECT_ROOT" && pwd)")
43
+
44
+ # --- Count files by extension ---
45
+ count_files() {
46
+ local ext="$1"
47
+ find "$PROJECT_ROOT" -name "*.${ext}" \
48
+ -not -path "*/node_modules/*" \
49
+ -not -path "*/.git/*" \
50
+ -not -path "*/dist/*" \
51
+ -not -path "*/build/*" \
52
+ -not -path "*/.next/*" \
53
+ -not -path "*/vendor/*" \
54
+ -not -path "*/__pycache__/*" \
55
+ -not -path "*/target/*" \
56
+ -not -path "*/.cm/*" \
57
+ -not -path "*/.codegraph/*" \
58
+ -not -name "*.min.*" \
59
+ -not -name "*.d.ts" \
60
+ -not -name "*.map" \
61
+ -type f 2>/dev/null | wc -l | tr -d ' '
62
+ }
63
+
64
+ # --- Detect languages ---
65
+ detect_languages() {
66
+ local langs=""
67
+ local ts_count=$(count_files "ts")
68
+ local tsx_count=$(count_files "tsx")
69
+ local js_count=$(count_files "js")
70
+ local jsx_count=$(count_files "jsx")
71
+ local py_count=$(count_files "py")
72
+ local go_count=$(count_files "go")
73
+ local rs_count=$(count_files "rs")
74
+ local java_count=$(count_files "java")
75
+ local php_count=$(count_files "php")
76
+ local rb_count=$(count_files "rb")
77
+ local c_count=$(count_files "c")
78
+ local cpp_count=$(count_files "cpp")
79
+ local swift_count=$(count_files "swift")
80
+ local kt_count=$(count_files "kt")
81
+ local vue_count=$(count_files "vue")
82
+ local svelte_count=$(count_files "svelte")
83
+
84
+ [ "$ts_count" -gt 0 ] || [ "$tsx_count" -gt 0 ] && langs="${langs}typescript($((ts_count+tsx_count))) "
85
+ [ "$js_count" -gt 0 ] || [ "$jsx_count" -gt 0 ] && langs="${langs}javascript($((js_count+jsx_count))) "
86
+ [ "$py_count" -gt 0 ] && langs="${langs}python($py_count) "
87
+ [ "$go_count" -gt 0 ] && langs="${langs}go($go_count) "
88
+ [ "$rs_count" -gt 0 ] && langs="${langs}rust($rs_count) "
89
+ [ "$java_count" -gt 0 ] && langs="${langs}java($java_count) "
90
+ [ "$php_count" -gt 0 ] && langs="${langs}php($php_count) "
91
+ [ "$rb_count" -gt 0 ] && langs="${langs}ruby($rb_count) "
92
+ [ "$c_count" -gt 0 ] && langs="${langs}c($c_count) "
93
+ [ "$cpp_count" -gt 0 ] && langs="${langs}cpp($cpp_count) "
94
+ [ "$swift_count" -gt 0 ] && langs="${langs}swift($swift_count) "
95
+ [ "$kt_count" -gt 0 ] && langs="${langs}kotlin($kt_count) "
96
+ [ "$vue_count" -gt 0 ] && langs="${langs}vue($vue_count) "
97
+ [ "$svelte_count" -gt 0 ] && langs="${langs}svelte($svelte_count) "
98
+
99
+ echo "$langs"
100
+ }
101
+
102
+ # --- Total source file count ---
103
+ total_source_files() {
104
+ find "$PROJECT_ROOT" \
105
+ \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \
106
+ -o -name "*.py" -o -name "*.go" -o -name "*.rs" -o -name "*.java" \
107
+ -o -name "*.php" -o -name "*.rb" -o -name "*.c" -o -name "*.cpp" \
108
+ -o -name "*.h" -o -name "*.swift" -o -name "*.kt" \
109
+ -o -name "*.vue" -o -name "*.svelte" \) \
110
+ -not -path "*/node_modules/*" \
111
+ -not -path "*/.git/*" \
112
+ -not -path "*/dist/*" \
113
+ -not -path "*/build/*" \
114
+ -not -path "*/.next/*" \
115
+ -not -path "*/vendor/*" \
116
+ -not -path "*/__pycache__/*" \
117
+ -not -path "*/target/*" \
118
+ -not -path "*/.cm/*" \
119
+ -not -name "*.min.*" \
120
+ -not -name "*.d.ts" \
121
+ -not -name "*.map" \
122
+ -type f 2>/dev/null | wc -l | tr -d ' '
123
+ }
124
+
125
+ # --- Standard exclude args for find ---
126
+ FIND_EXCLUDES=(
127
+ -not -path "*/node_modules/*"
128
+ -not -path "*/.git/*"
129
+ -not -path "*/dist/*"
130
+ -not -path "*/build/*"
131
+ -not -path "*/.next/*"
132
+ -not -path "*/vendor/*"
133
+ -not -path "*/__pycache__/*"
134
+ -not -path "*/target/*"
135
+ -not -path "*/.cm/*"
136
+ -not -path "*/.codegraph/*"
137
+ -not -path "*/.venv/*"
138
+ -not -path "*/.wrangler/*"
139
+ -not -path "*/.pytest_cache/*"
140
+ -not -path "*/output/*"
141
+ -not -path "*/docs/js/lang/*"
142
+ -not -name "*.min.*"
143
+ -not -name "*.d.ts"
144
+ -not -name "*.map"
145
+ -not -name "*.pyc"
146
+ )
147
+
148
+ # =============================================================================
149
+ # EXTRACTION ENGINES — One per language family
150
+ # =============================================================================
151
+
152
+ # --- TypeScript/JavaScript: exports, functions, classes, interfaces, types ---
153
+ extract_ts_js() {
154
+ local file="$1"
155
+ local relpath="${file#$PROJECT_ROOT/}"
156
+ grep -n \
157
+ -e '^export ' \
158
+ -e '^export default ' \
159
+ -e '^ export ' \
160
+ -e '^function ' \
161
+ -e '^async function ' \
162
+ -e '^class ' \
163
+ -e '^interface ' \
164
+ -e '^type ' \
165
+ -e '^enum ' \
166
+ -e '^const .* = (' \
167
+ -e '^const .* = async (' \
168
+ -e '^const .* = () =>' \
169
+ -e '^const .* = async () =>' \
170
+ -e 'router\.\(get\|post\|put\|delete\|patch\)(' \
171
+ -e 'app\.\(get\|post\|put\|delete\|patch\)(' \
172
+ "$file" 2>/dev/null | \
173
+ sed 's/{.*//;s/ =>.*//' | \
174
+ head -40 || true
175
+ }
176
+
177
+ # --- Python: def, class, decorators, imports ---
178
+ extract_python() {
179
+ local file="$1"
180
+ grep -n \
181
+ -e '^def ' \
182
+ -e '^async def ' \
183
+ -e '^class ' \
184
+ -e '^ def ' \
185
+ -e '^ async def ' \
186
+ -e '^@app\.\(route\|get\|post\|put\|delete\)' \
187
+ -e '^@router\.\(get\|post\|put\|delete\)' \
188
+ -e '^from .* import ' \
189
+ "$file" 2>/dev/null | \
190
+ sed 's/:$/:/;s/{.*//;s/""".*//;s/#.*//' | \
191
+ head -40 || true
192
+ }
193
+
194
+ # --- Go: func, type, interface ---
195
+ extract_go() {
196
+ local file="$1"
197
+ grep -n \
198
+ -e '^func ' \
199
+ -e '^type .* struct' \
200
+ -e '^type .* interface' \
201
+ -e '^package ' \
202
+ "$file" 2>/dev/null | \
203
+ sed 's/{.*//' | \
204
+ head -40 || true
205
+ }
206
+
207
+ # --- Rust: fn, struct, enum, impl, trait ---
208
+ extract_rust() {
209
+ local file="$1"
210
+ grep -n \
211
+ -e '^pub fn ' \
212
+ -e '^fn ' \
213
+ -e '^pub struct ' \
214
+ -e '^struct ' \
215
+ -e '^pub enum ' \
216
+ -e '^enum ' \
217
+ -e '^impl ' \
218
+ -e '^pub trait ' \
219
+ -e '^trait ' \
220
+ -e '^mod ' \
221
+ -e '^pub mod ' \
222
+ "$file" 2>/dev/null | \
223
+ sed 's/{.*//' | \
224
+ head -40 || true
225
+ }
226
+
227
+ # --- Java/Kotlin: class, interface, method ---
228
+ extract_java_kt() {
229
+ local file="$1"
230
+ grep -n \
231
+ -e '^\(public\|private\|protected\) .* class ' \
232
+ -e '^\(public\|private\|protected\) .* interface ' \
233
+ -e '^\(public\|private\|protected\) .* enum ' \
234
+ -e '^\(public\|private\|protected\) .*(.*)' \
235
+ -e '^class ' \
236
+ -e '^fun ' \
237
+ -e '^suspend fun ' \
238
+ -e '^data class ' \
239
+ -e '^object ' \
240
+ -e '^interface ' \
241
+ -e '^package ' \
242
+ "$file" 2>/dev/null | \
243
+ sed 's/{.*//;s/:.*//' | \
244
+ head -40 || true
245
+ }
246
+
247
+ # --- PHP: function, class ---
248
+ extract_php() {
249
+ local file="$1"
250
+ grep -n \
251
+ -e '^\(public\|private\|protected\) function ' \
252
+ -e '^function ' \
253
+ -e '^class ' \
254
+ -e '^interface ' \
255
+ -e '^trait ' \
256
+ -e '^namespace ' \
257
+ "$file" 2>/dev/null | \
258
+ sed 's/{.*//' | \
259
+ head -40 || true
260
+ }
261
+
262
+ # --- Ruby: def, class, module ---
263
+ extract_ruby() {
264
+ local file="$1"
265
+ grep -n \
266
+ -e '^ def ' \
267
+ -e '^def ' \
268
+ -e '^class ' \
269
+ -e '^module ' \
270
+ "$file" 2>/dev/null | \
271
+ head -40 || true
272
+ }
273
+
274
+ # --- C/C++: function declarations, struct, class ---
275
+ extract_c_cpp() {
276
+ local file="$1"
277
+ grep -n \
278
+ -e '^[a-zA-Z_].*(.*) {' \
279
+ -e '^[a-zA-Z_].*(.*);' \
280
+ -e '^struct ' \
281
+ -e '^class ' \
282
+ -e '^typedef ' \
283
+ -e '^#define ' \
284
+ -e '^namespace ' \
285
+ "$file" 2>/dev/null | \
286
+ sed 's/{.*//' | \
287
+ head -40 || true
288
+ }
289
+
290
+ # --- Swift: func, class, struct, protocol ---
291
+ extract_swift() {
292
+ local file="$1"
293
+ grep -n \
294
+ -e '^func ' \
295
+ -e '^class ' \
296
+ -e '^struct ' \
297
+ -e '^protocol ' \
298
+ -e '^enum ' \
299
+ -e '^ func ' \
300
+ -e '^ static func ' \
301
+ -e '^extension ' \
302
+ "$file" 2>/dev/null | \
303
+ sed 's/{.*//' | \
304
+ head -40 || true
305
+ }
306
+
307
+ # =============================================================================
308
+ # MAIN EXTRACTION LOOP
309
+ # =============================================================================
310
+
311
+ extract_file() {
312
+ local file="$1"
313
+ local ext="${file##*.}"
314
+
315
+ case "$ext" in
316
+ ts|tsx|js|jsx|mjs|cjs|vue|svelte)
317
+ extract_ts_js "$file"
318
+ ;;
319
+ py)
320
+ extract_python "$file"
321
+ ;;
322
+ go)
323
+ extract_go "$file"
324
+ ;;
325
+ rs)
326
+ extract_rust "$file"
327
+ ;;
328
+ java|kt|kts)
329
+ extract_java_kt "$file"
330
+ ;;
331
+ php)
332
+ extract_php "$file"
333
+ ;;
334
+ rb)
335
+ extract_ruby "$file"
336
+ ;;
337
+ c|cpp|cc|cxx|h|hpp)
338
+ extract_c_cpp "$file"
339
+ ;;
340
+ swift)
341
+ extract_swift "$file"
342
+ ;;
343
+ esac
344
+ }
345
+
346
+ # =============================================================================
347
+ # GENERATE SKELETON
348
+ # =============================================================================
349
+
350
+ echo -e "${CYAN}🦴 CodyMaster Skeleton Indexer${NC}"
351
+ echo -e "${CYAN} Scanning: ${PROJECT_ROOT}${NC}"
352
+
353
+ START_TIME=$(date +%s%N 2>/dev/null || python3 -c "import time; print(int(time.time()*1e9))" 2>/dev/null || echo 0)
354
+
355
+ TOTAL_FILES=$(total_source_files)
356
+ LANGUAGES=$(detect_languages)
357
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
358
+
359
+ # --- Detect framework & config ---
360
+ FRAMEWORK="unknown"
361
+ [ -f "$PROJECT_ROOT/package.json" ] && FRAMEWORK="node"
362
+ [ -f "$PROJECT_ROOT/next.config.js" ] || [ -f "$PROJECT_ROOT/next.config.ts" ] || [ -f "$PROJECT_ROOT/next.config.mjs" ] && FRAMEWORK="next.js" || true
363
+ [ -f "$PROJECT_ROOT/vite.config.ts" ] || [ -f "$PROJECT_ROOT/vite.config.js" ] && FRAMEWORK="vite" || true
364
+ [ -f "$PROJECT_ROOT/astro.config.mjs" ] || [ -f "$PROJECT_ROOT/astro.config.ts" ] && FRAMEWORK="astro" || true
365
+ [ -f "$PROJECT_ROOT/nuxt.config.ts" ] && FRAMEWORK="nuxt" || true
366
+ [ -f "$PROJECT_ROOT/requirements.txt" ] || [ -f "$PROJECT_ROOT/pyproject.toml" ] && FRAMEWORK="python" || true
367
+ [ -f "$PROJECT_ROOT/manage.py" ] && FRAMEWORK="django" || true
368
+ [ -f "$PROJECT_ROOT/go.mod" ] && FRAMEWORK="go" || true
369
+ [ -f "$PROJECT_ROOT/Cargo.toml" ] && FRAMEWORK="rust" || true
370
+ [ -f "$PROJECT_ROOT/pom.xml" ] && FRAMEWORK="maven" || true
371
+ [ -f "$PROJECT_ROOT/build.gradle" ] || [ -f "$PROJECT_ROOT/build.gradle.kts" ] && FRAMEWORK="gradle" || true
372
+ [ -f "$PROJECT_ROOT/Gemfile" ] && FRAMEWORK="ruby" || true
373
+ [ -f "$PROJECT_ROOT/composer.json" ] && FRAMEWORK="php/composer" || true
374
+ [ -f "$PROJECT_ROOT/wrangler.toml" ] && FRAMEWORK="${FRAMEWORK}+cloudflare" || true
375
+ [ -f "$PROJECT_ROOT/hooks.py" ] && FRAMEWORK="frappe" || true
376
+
377
+ # --- Write header ---
378
+ {
379
+ echo "# 🦴 Skeleton Index: ${PROJECT_NAME}"
380
+ echo ""
381
+ echo "| Meta | Value |"
382
+ echo "|------|-------|"
383
+ echo "| Generated | ${TIMESTAMP} |"
384
+ echo "| Source Files | ${TOTAL_FILES} |"
385
+ echo "| Languages | ${LANGUAGES} |"
386
+ echo "| Framework | ${FRAMEWORK} |"
387
+ echo ""
388
+
389
+ # --- Entry points ---
390
+ echo "## Entry Points"
391
+ echo ""
392
+ for entry in \
393
+ "src/index.ts" "src/index.js" "src/main.ts" "src/main.js" \
394
+ "src/App.tsx" "src/App.jsx" "src/app.ts" "src/app.js" \
395
+ "app/layout.tsx" "app/page.tsx" "pages/index.tsx" "pages/_app.tsx" \
396
+ "main.py" "app.py" "manage.py" "main.go" "cmd/main.go" \
397
+ "src/main.rs" "src/lib.rs" "index.php" "config/app.php"; do
398
+ if [ -f "$PROJECT_ROOT/$entry" ]; then
399
+ echo "- \`$entry\`"
400
+ fi
401
+ done
402
+ echo ""
403
+
404
+ # --- Key config files ---
405
+ echo "## Config Files"
406
+ echo ""
407
+ for cfg in \
408
+ "package.json" "tsconfig.json" "wrangler.toml" \
409
+ "next.config.js" "next.config.ts" "next.config.mjs" \
410
+ "vite.config.ts" "vite.config.js" \
411
+ "astro.config.mjs" "nuxt.config.ts" \
412
+ "pyproject.toml" "requirements.txt" "setup.py" \
413
+ "go.mod" "Cargo.toml" "pom.xml" "build.gradle" "build.gradle.kts" \
414
+ "Gemfile" "composer.json" \
415
+ "Dockerfile" "docker-compose.yml" "docker-compose.yaml" \
416
+ ".env.example" "AGENTS.md"; do
417
+ if [ -f "$PROJECT_ROOT/$cfg" ]; then
418
+ echo "- \`$cfg\`"
419
+ fi
420
+ done
421
+ echo ""
422
+
423
+ # --- Directory tree (depth 2) ---
424
+ echo "## Directory Structure"
425
+ echo ""
426
+ echo '```'
427
+ # Use find to create a clean tree
428
+ find "$PROJECT_ROOT" -maxdepth 2 -type d \
429
+ -not -path "*/node_modules*" \
430
+ -not -path "*/.git*" \
431
+ -not -path "*/dist*" \
432
+ -not -path "*/build*" \
433
+ -not -path "*/.next*" \
434
+ -not -path "*/vendor*" \
435
+ -not -path "*/__pycache__*" \
436
+ -not -path "*/target*" \
437
+ -not -path "*/.cm*" \
438
+ -not -path "*/.codegraph*" \
439
+ 2>/dev/null | \
440
+ sed "s|$PROJECT_ROOT/||;s|$PROJECT_ROOT||" | \
441
+ sort | \
442
+ head -60 | \
443
+ awk '{
444
+ depth = gsub(/\//, "/")
445
+ indent = ""
446
+ for (i = 0; i < depth; i++) indent = indent " "
447
+ n = split($0, parts, "/")
448
+ if (NR == 1) print parts[n] "/"
449
+ else print indent parts[n] "/"
450
+ }'
451
+ echo '```'
452
+ echo ""
453
+
454
+ # --- Module-by-module skeleton ---
455
+ echo "## Code Skeleton"
456
+ echo ""
457
+
458
+ # Get all source directories sorted
459
+ prev_dir=""
460
+ dir_file_count=0
461
+ total_lines=0
462
+ find "$PROJECT_ROOT" \
463
+ \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \
464
+ -o -name "*.py" -o -name "*.go" -o -name "*.rs" -o -name "*.java" \
465
+ -o -name "*.php" -o -name "*.rb" -o -name "*.c" -o -name "*.cpp" \
466
+ -o -name "*.h" -o -name "*.swift" -o -name "*.kt" \
467
+ -o -name "*.vue" -o -name "*.svelte" \) \
468
+ "${FIND_EXCLUDES[@]}" \
469
+ -type f 2>/dev/null | \
470
+ sort | \
471
+ while IFS= read -r file; do
472
+ # Stop if total output exceeds line cap
473
+ if [ "$total_lines" -ge "$MAX_TOTAL_LINES" ]; then
474
+ echo ""
475
+ echo "_... output capped at ${MAX_TOTAL_LINES} lines. Run with larger MAX_TOTAL_LINES for full index._"
476
+ break
477
+ fi
478
+
479
+ relpath="${file#$PROJECT_ROOT/}"
480
+ dir=$(dirname "$relpath")
481
+ fname=$(basename "$relpath")
482
+
483
+ # Print directory header when directory changes
484
+ if [ "$dir" != "$prev_dir" ]; then
485
+ echo "### \`${dir}/\`"
486
+ echo ""
487
+ prev_dir="$dir"
488
+ dir_file_count=0
489
+ total_lines=$((total_lines + 2))
490
+ fi
491
+
492
+ # Cap files per directory
493
+ dir_file_count=$((dir_file_count + 1))
494
+ if [ "$dir_file_count" -gt "$MAX_FILES_PER_DIR" ]; then
495
+ if [ "$dir_file_count" -eq "$((MAX_FILES_PER_DIR + 1))" ]; then
496
+ echo "_... and more files in this directory_"
497
+ echo ""
498
+ total_lines=$((total_lines + 2))
499
+ fi
500
+ continue
501
+ fi
502
+
503
+ # Extract signatures
504
+ sigs=$(extract_file "$file" | head -"$MAX_SIGS_PER_FILE")
505
+
506
+ if [ -n "$sigs" ]; then
507
+ sig_lines=$(echo "$sigs" | wc -l | tr -d ' ')
508
+ echo "**${fname}**"
509
+ echo '```'
510
+ echo "$sigs"
511
+ echo '```'
512
+ echo ""
513
+ total_lines=$((total_lines + sig_lines + 4))
514
+ else
515
+ # File exists but no extractable signatures — just note it
516
+ lines=$(wc -l < "$file" 2>/dev/null | tr -d ' ')
517
+ echo "- \`${fname}\` (${lines} lines)"
518
+ total_lines=$((total_lines + 1))
519
+ fi
520
+ done
521
+
522
+ } > "$OUTPUT_FILE"
523
+
524
+ # --- Calculate timing ---
525
+ END_TIME=$(date +%s%N 2>/dev/null || python3 -c "import time; print(int(time.time()*1e9))" 2>/dev/null || echo 0)
526
+ if [ "$START_TIME" != "0" ] && [ "$END_TIME" != "0" ]; then
527
+ ELAPSED_MS=$(( (END_TIME - START_TIME) / 1000000 ))
528
+ echo -e "${GREEN}✅ Done in ${ELAPSED_MS}ms${NC}"
529
+ else
530
+ echo -e "${GREEN}✅ Done${NC}"
531
+ fi
532
+
533
+ # --- Stats ---
534
+ OUTPUT_LINES=$(wc -l < "$OUTPUT_FILE" | tr -d ' ')
535
+ OUTPUT_BYTES=$(wc -c < "$OUTPUT_FILE" | tr -d ' ')
536
+ OUTPUT_TOKENS_EST=$((OUTPUT_BYTES / 4))
537
+
538
+ echo -e " 📄 ${OUTPUT_FILE}"
539
+ echo -e " 📊 ${TOTAL_FILES} source files → ${OUTPUT_LINES} lines (~${OUTPUT_TOKENS_EST} tokens)"
540
+ echo -e " 🗣️ Languages: ${LANGUAGES}"
541
+ echo -e " 🏗️ Framework: ${FRAMEWORK}"
542
+
543
+ # --- Intelligence level recommendation ---
544
+ if [ "$TOTAL_FILES" -lt 20 ]; then
545
+ echo -e " 🎯 Intelligence Level: ${CYAN}MINIMAL${NC} (skeleton sufficient)"
546
+ elif [ "$TOTAL_FILES" -lt 50 ]; then
547
+ echo -e " 🎯 Intelligence Level: ${CYAN}LITE${NC} (skeleton + diagram recommended)"
548
+ elif [ "$TOTAL_FILES" -lt 200 ]; then
549
+ echo -e " 🎯 Intelligence Level: ${CYAN}STANDARD${NC} (consider CodeGraph for deep analysis)"
550
+ else
551
+ echo -e " 🎯 Intelligence Level: ${CYAN}FULL${NC} (CodeGraph + qmd strongly recommended)"
552
+ fi