codymaster 4.5.1 → 4.5.2
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.
- package/package.json +2 -1
- package/scripts/gate-0-secrets.js +63 -0
- package/scripts/gate-1-syntax.js +53 -0
- package/scripts/gate-5-dist-verify.js +55 -0
- package/scripts/gate-6-smoke-test.js +30 -0
- package/scripts/index-codebase.sh +552 -0
- package/scripts/mcp-bridge.js +284 -0
- package/scripts/postinstall.js +301 -0
- package/scripts/security-fixer.js +143 -0
- package/scripts/security-scan.js +55 -0
- package/scripts/test-gemini.js +13 -0
- package/scripts/todo-bridge.js +112 -0
|
@@ -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
|