ai-consultants 2.10.1

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.
Files changed (62) hide show
  1. package/.claude/commands/ai-consultants:consult.md +94 -0
  2. package/.claude/commands/ai-consultants:debate.md +103 -0
  3. package/.claude/commands/ai-consultants:help.md +30 -0
  4. package/CLAUDE.md +839 -0
  5. package/LICENSE +21 -0
  6. package/README.md +758 -0
  7. package/SKILL.md +156 -0
  8. package/bin/ai-consultants +96 -0
  9. package/docs/COST_RATES.md +172 -0
  10. package/docs/JSON_SCHEMA.md +305 -0
  11. package/docs/SETUP.md +879 -0
  12. package/docs/SMART_ROUTING.md +219 -0
  13. package/docs/cost_rates.json +143 -0
  14. package/package.json +47 -0
  15. package/references/configuration.md +141 -0
  16. package/references/details.md +60 -0
  17. package/scripts/build_context.sh +562 -0
  18. package/scripts/classify_question.sh +148 -0
  19. package/scripts/config.sh +753 -0
  20. package/scripts/configure.sh +1093 -0
  21. package/scripts/consult_all.sh +934 -0
  22. package/scripts/debate_round.sh +421 -0
  23. package/scripts/doctor.sh +642 -0
  24. package/scripts/followup.sh +197 -0
  25. package/scripts/install.sh +319 -0
  26. package/scripts/lib/api.sh +640 -0
  27. package/scripts/lib/api_query.sh +228 -0
  28. package/scripts/lib/cache.sh +338 -0
  29. package/scripts/lib/chunking.sh +880 -0
  30. package/scripts/lib/code_optimizer.sh +671 -0
  31. package/scripts/lib/common.sh +1088 -0
  32. package/scripts/lib/costs.sh +674 -0
  33. package/scripts/lib/personas.sh +372 -0
  34. package/scripts/lib/progress.sh +251 -0
  35. package/scripts/lib/reflection.sh +447 -0
  36. package/scripts/lib/routing.sh +566 -0
  37. package/scripts/lib/schema.json +165 -0
  38. package/scripts/lib/session.sh +327 -0
  39. package/scripts/lib/symbol_map.sh +445 -0
  40. package/scripts/lib/voting.sh +495 -0
  41. package/scripts/peer_review.sh +460 -0
  42. package/scripts/preflight_check.sh +452 -0
  43. package/scripts/query_aider.sh +83 -0
  44. package/scripts/query_amp.sh +67 -0
  45. package/scripts/query_claude.sh +99 -0
  46. package/scripts/query_codex.sh +92 -0
  47. package/scripts/query_cursor.sh +72 -0
  48. package/scripts/query_deepseek.sh +17 -0
  49. package/scripts/query_gemini.sh +85 -0
  50. package/scripts/query_glm.sh +17 -0
  51. package/scripts/query_grok.sh +17 -0
  52. package/scripts/query_kilo.sh +140 -0
  53. package/scripts/query_kimi.sh +67 -0
  54. package/scripts/query_minimax.sh +17 -0
  55. package/scripts/query_mistral.sh +97 -0
  56. package/scripts/query_ollama.sh +328 -0
  57. package/scripts/query_qwen3.sh +93 -0
  58. package/scripts/setup_wizard.sh +367 -0
  59. package/scripts/skillport-install.sh +196 -0
  60. package/scripts/synthesize.sh +332 -0
  61. package/templates/consultation_report.md +323 -0
  62. package/templates/synthesis_prompt.md +120 -0
@@ -0,0 +1,562 @@
1
+ #!/bin/bash
2
+ # build_context.sh - Automatically generates a context file for AI consultation
3
+ #
4
+ # Usage: ./build_context.sh <output_file> "Your question" [file1] [file2] ...
5
+ #
6
+ # Example:
7
+ # ./build_context.sh /tmp/context.md "How to optimize this function?" src/utils.py src/main.py
8
+ #
9
+ # Token Optimization Modes (v2.2):
10
+ # - none: Include file contents as-is (no optimization)
11
+ # - basic: Simple byte-based truncation (legacy behavior)
12
+ # - ast: Extract code skeleton using AST (default)
13
+ # - full: AST + symbol compression + semantic chunking
14
+
15
+ set -euo pipefail
16
+
17
+ # Load common functions for validation
18
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19
+ source "$SCRIPT_DIR/lib/common.sh"
20
+
21
+ # =============================================================================
22
+ # TOKEN OPTIMIZATION CONFIGURATION (v2.2)
23
+ # =============================================================================
24
+
25
+ # Optimization mode: "none", "basic", "ast", "full"
26
+ TOKEN_OPTIMIZATION_MODE="${TOKEN_OPTIMIZATION_MODE:-ast}"
27
+
28
+ # Enable AST-based code skeleton extraction
29
+ ENABLE_AST_EXTRACTION="${ENABLE_AST_EXTRACTION:-true}"
30
+
31
+ # Enable symbol compression (replaces long identifiers with short tokens)
32
+ # Note: Opt-in because it requires the symbol map to decode
33
+ ENABLE_SYMBOL_COMPRESSION="${ENABLE_SYMBOL_COMPRESSION:-false}"
34
+
35
+ # Enable semantic chunking (splits large files into meaningful chunks)
36
+ ENABLE_SEMANTIC_CHUNKING="${ENABLE_SEMANTIC_CHUNKING:-true}"
37
+
38
+ # Maximum bytes per context file before optimization kicks in
39
+ MAX_CONTEXT_FILE_BYTES="${MAX_CONTEXT_FILE_BYTES:-8000}"
40
+
41
+ # =============================================================================
42
+ # MODULE LOADING WITH FALLBACK
43
+ # =============================================================================
44
+
45
+ # Track which optimization modules are available
46
+ _HAS_CODE_OPTIMIZER=false
47
+ _HAS_CHUNKING=false
48
+ _HAS_SYMBOL_MAP=false
49
+
50
+ # Try to source optimization modules (optional dependencies)
51
+ if [[ -f "$SCRIPT_DIR/lib/code_optimizer.sh" ]]; then
52
+ source "$SCRIPT_DIR/lib/code_optimizer.sh"
53
+ _HAS_CODE_OPTIMIZER=true
54
+ log_debug "Loaded code_optimizer.sh module"
55
+ fi
56
+
57
+ if [[ -f "$SCRIPT_DIR/lib/chunking.sh" ]]; then
58
+ source "$SCRIPT_DIR/lib/chunking.sh"
59
+ _HAS_CHUNKING=true
60
+ log_debug "Loaded chunking.sh module"
61
+ fi
62
+
63
+ if [[ -f "$SCRIPT_DIR/lib/symbol_map.sh" ]]; then
64
+ source "$SCRIPT_DIR/lib/symbol_map.sh"
65
+ _HAS_SYMBOL_MAP=true
66
+ log_debug "Loaded symbol_map.sh module"
67
+ fi
68
+
69
+ # Determine effective optimization mode based on available modules
70
+ _determine_effective_mode() {
71
+ local mode="$1"
72
+
73
+ case "$mode" in
74
+ none|basic)
75
+ echo "$mode"
76
+ ;;
77
+ ast|full)
78
+ if [[ "$_HAS_CODE_OPTIMIZER" != "true" ]]; then
79
+ log_warn "Mode '$mode' requires code_optimizer.sh, falling back to basic"
80
+ echo "basic"
81
+ return
82
+ fi
83
+ # Disable features if modules unavailable
84
+ [[ "$mode" == "full" && "$ENABLE_SYMBOL_COMPRESSION" == "true" && "$_HAS_SYMBOL_MAP" != "true" ]] && ENABLE_SYMBOL_COMPRESSION="false"
85
+ [[ "$mode" == "full" && "$ENABLE_SEMANTIC_CHUNKING" == "true" && "$_HAS_CHUNKING" != "true" ]] && ENABLE_SEMANTIC_CHUNKING="false"
86
+ echo "$mode"
87
+ ;;
88
+ *)
89
+ log_warn "Unknown mode '$mode', using basic"
90
+ echo "basic"
91
+ ;;
92
+ esac
93
+ }
94
+
95
+ # =============================================================================
96
+ # OPTIMIZATION STATISTICS TRACKING
97
+ # =============================================================================
98
+
99
+ # Global counters for statistics
100
+ _TOTAL_FILES_PROCESSED=0
101
+ _TOTAL_ORIGINAL_BYTES=0
102
+ _TOTAL_OPTIMIZED_BYTES=0
103
+ _FILES_OPTIMIZED=0
104
+ _FILES_PASSED_THROUGH=0
105
+
106
+ # Per-file tracking (using map functions from common.sh)
107
+ # Maps: ORIGINAL_SIZES, OPTIMIZED_SIZES, OPTIMIZATION_APPLIED
108
+
109
+ # Reset statistics
110
+ _reset_stats() {
111
+ _TOTAL_FILES_PROCESSED=0
112
+ _TOTAL_ORIGINAL_BYTES=0
113
+ _TOTAL_OPTIMIZED_BYTES=0
114
+ _FILES_OPTIMIZED=0
115
+ _FILES_PASSED_THROUGH=0
116
+ map_clear "ORIGINAL_SIZES"
117
+ map_clear "OPTIMIZED_SIZES"
118
+ map_clear "OPTIMIZATION_APPLIED"
119
+ }
120
+
121
+ # Record file statistics
122
+ # Usage: _record_file_stats "filename" original_size optimized_size "optimization_type"
123
+ _record_file_stats() {
124
+ local filename="$1"
125
+ local original_size="$2"
126
+ local optimized_size="$3"
127
+ local opt_type="$4"
128
+
129
+ local safe_name
130
+ safe_name=$(echo "$filename" | tr '/' '_' | tr '.' '_')
131
+
132
+ map_set "ORIGINAL_SIZES" "$safe_name" "$original_size"
133
+ map_set "OPTIMIZED_SIZES" "$safe_name" "$optimized_size"
134
+ map_set "OPTIMIZATION_APPLIED" "$safe_name" "$opt_type"
135
+
136
+ _TOTAL_FILES_PROCESSED=$((_TOTAL_FILES_PROCESSED + 1))
137
+ _TOTAL_ORIGINAL_BYTES=$((_TOTAL_ORIGINAL_BYTES + original_size))
138
+ _TOTAL_OPTIMIZED_BYTES=$((_TOTAL_OPTIMIZED_BYTES + optimized_size))
139
+
140
+ if [[ "$opt_type" != "none" && "$opt_type" != "passthrough" ]]; then
141
+ _FILES_OPTIMIZED=$((_FILES_OPTIMIZED + 1))
142
+ else
143
+ _FILES_PASSED_THROUGH=$((_FILES_PASSED_THROUGH + 1))
144
+ fi
145
+ }
146
+
147
+ # Log optimization statistics summary
148
+ _log_optimization_stats() {
149
+ if [[ $_TOTAL_FILES_PROCESSED -eq 0 ]]; then
150
+ return
151
+ fi
152
+
153
+ local savings_bytes=$((_TOTAL_ORIGINAL_BYTES - _TOTAL_OPTIMIZED_BYTES))
154
+ local savings_pct=0
155
+ if [[ $_TOTAL_ORIGINAL_BYTES -gt 0 ]]; then
156
+ savings_pct=$((savings_bytes * 100 / _TOTAL_ORIGINAL_BYTES))
157
+ fi
158
+
159
+ local original_tokens=$((_TOTAL_ORIGINAL_BYTES / 4))
160
+ local optimized_tokens=$((_TOTAL_OPTIMIZED_BYTES / 4))
161
+ local tokens_saved=$((original_tokens - optimized_tokens))
162
+
163
+ log_info "Context optimization summary:"
164
+ log_info " Files processed: $_TOTAL_FILES_PROCESSED (optimized: $_FILES_OPTIMIZED, passed through: $_FILES_PASSED_THROUGH)"
165
+ log_info " Original size: $_TOTAL_ORIGINAL_BYTES bytes (~$original_tokens tokens)"
166
+ log_info " Optimized size: $_TOTAL_OPTIMIZED_BYTES bytes (~$optimized_tokens tokens)"
167
+ log_info " Savings: $savings_bytes bytes (~$tokens_saved tokens, ${savings_pct}%)"
168
+ }
169
+
170
+ # =============================================================================
171
+ # FILE CONTENT OPTIMIZATION
172
+ # =============================================================================
173
+
174
+ # Get language identifier for a file extension
175
+ # Usage: _get_lang_for_extension "py"
176
+ _get_lang_for_extension() {
177
+ local extension="$1"
178
+ case "$extension" in
179
+ py) echo "python" ;;
180
+ js) echo "javascript" ;;
181
+ ts|tsx) echo "typescript" ;;
182
+ rb) echo "ruby" ;;
183
+ go) echo "go" ;;
184
+ rs) echo "rust" ;;
185
+ java|kt) echo "java" ;;
186
+ sh|bash|zsh) echo "bash" ;;
187
+ json) echo "json" ;;
188
+ yaml|yml) echo "yaml" ;;
189
+ toml) echo "toml" ;;
190
+ md) echo "markdown" ;;
191
+ sql) echo "sql" ;;
192
+ c) echo "c" ;;
193
+ cpp|cc|cxx) echo "cpp" ;;
194
+ h|hpp) echo "cpp" ;;
195
+ cs) echo "csharp" ;;
196
+ swift) echo "swift" ;;
197
+ php) echo "php" ;;
198
+ *) echo "$extension" ;;
199
+ esac
200
+ }
201
+
202
+ # Check if file type supports AST extraction
203
+ # Usage: _supports_ast_extraction "python"
204
+ _supports_ast_extraction() {
205
+ local lang="$1"
206
+ # Languages that typically support AST-based extraction
207
+ case "$lang" in
208
+ python|javascript|typescript|go|rust|java|cpp|c|csharp|ruby|php|swift)
209
+ return 0
210
+ ;;
211
+ *)
212
+ return 1
213
+ ;;
214
+ esac
215
+ }
216
+
217
+ # Generate truncated content with header
218
+ _truncate_file() {
219
+ local file_path="$1"
220
+ local original_size="$2"
221
+ echo "# File: $file_path (truncated: ${original_size} bytes, showing first ${MAX_CONTEXT_FILE_BYTES})
222
+ $(head -c "$MAX_CONTEXT_FILE_BYTES" -- "$file_path")
223
+ # ... [truncated] ..."
224
+ }
225
+
226
+ # Optimize file content based on mode
227
+ _optimize_file_content() {
228
+ local file_path="$1"
229
+ local mode="$2"
230
+ local lang="$3"
231
+
232
+ local original_size
233
+ original_size=$(wc -c < "$file_path" | tr -d ' ')
234
+ local optimized_content=""
235
+ local opt_type="none"
236
+
237
+ # Small files pass through unchanged
238
+ if [[ "$mode" != "none" && $original_size -le $MAX_CONTEXT_FILE_BYTES ]]; then
239
+ optimized_content=$(cat -- "$file_path")
240
+ opt_type="passthrough"
241
+ else
242
+ case "$mode" in
243
+ none)
244
+ optimized_content=$(cat -- "$file_path")
245
+ opt_type="none"
246
+ ;;
247
+
248
+ basic)
249
+ optimized_content=$(_truncate_file "$file_path" "$original_size")
250
+ opt_type="truncated"
251
+ ;;
252
+
253
+ ast)
254
+ if _supports_ast_extraction "$lang" && [[ "$_HAS_CODE_OPTIMIZER" == "true" ]]; then
255
+ local extracted=""
256
+ if extracted=$(optimize_code_file "$file_path" 2>/dev/null) && [[ -n "$extracted" ]]; then
257
+ optimized_content="# File: $file_path (AST skeleton: ${original_size} bytes -> optimized)
258
+ $extracted"
259
+ opt_type="ast_skeleton"
260
+ fi
261
+ fi
262
+ # Fallback to truncation
263
+ if [[ -z "$optimized_content" ]]; then
264
+ optimized_content=$(_truncate_file "$file_path" "$original_size")
265
+ opt_type="truncated"
266
+ fi
267
+ ;;
268
+
269
+ full)
270
+ local temp_content=""
271
+ local applied_opts=""
272
+
273
+ # Step 1: AST extraction
274
+ if _supports_ast_extraction "$lang" && [[ "$_HAS_CODE_OPTIMIZER" == "true" ]]; then
275
+ if temp_content=$(optimize_code_file "$file_path" 2>/dev/null) && [[ -n "$temp_content" ]]; then
276
+ applied_opts="ast"
277
+ fi
278
+ fi
279
+ [[ -z "$temp_content" ]] && temp_content=$(cat -- "$file_path")
280
+
281
+ # Step 2: Symbol compression
282
+ if [[ "$ENABLE_SYMBOL_COMPRESSION" == "true" && "$_HAS_SYMBOL_MAP" == "true" ]]; then
283
+ local compressed=""
284
+ if compressed=$(compress_symbols "$temp_content" "$lang" 2>/dev/null) && [[ -n "$compressed" ]]; then
285
+ temp_content="$compressed"
286
+ applied_opts="${applied_opts:+$applied_opts+}symbol_compression"
287
+ fi
288
+ fi
289
+
290
+ # Step 3: Semantic chunking if still too large
291
+ local temp_size
292
+ temp_size=$(echo -n "$temp_content" | wc -c | tr -d ' ')
293
+ if [[ "$ENABLE_SEMANTIC_CHUNKING" == "true" && "$_HAS_CHUNKING" == "true" && $temp_size -gt $MAX_CONTEXT_FILE_BYTES ]]; then
294
+ local chunks_json=""
295
+ chunks_json=$(chunk_file_semantically "$file_path" 2>/dev/null) || chunks_json="[]"
296
+ if [[ -n "$chunks_json" && "$chunks_json" != "[]" ]]; then
297
+ local chunked_content=""
298
+ chunked_content=$(echo "$chunks_json" | jq -r '
299
+ sort_by(-.priority) | .[0:5] |
300
+ map("# Chunk: \(.id) (priority: \(.priority))\n\(.content)") |
301
+ join("\n\n---\n\n")
302
+ ' 2>/dev/null) || chunked_content=""
303
+ if [[ -n "$chunked_content" ]]; then
304
+ temp_content="$chunked_content"
305
+ applied_opts="${applied_opts:+$applied_opts+}chunking"
306
+ fi
307
+ fi
308
+ fi
309
+
310
+ # Final truncation if still too large
311
+ temp_size=$(echo -n "$temp_content" | wc -c | tr -d ' ')
312
+ if [[ $temp_size -gt $MAX_CONTEXT_FILE_BYTES ]]; then
313
+ temp_content=$(echo "$temp_content" | head -c "$MAX_CONTEXT_FILE_BYTES")
314
+ applied_opts="${applied_opts:+$applied_opts+}truncated"
315
+ fi
316
+
317
+ opt_type="${applied_opts:-truncated}"
318
+ optimized_content="# File: $file_path (optimized: ${original_size} bytes -> ${temp_size} bytes, mode: $opt_type)
319
+ $temp_content"
320
+ ;;
321
+ esac
322
+ fi
323
+
324
+ # Record statistics and output
325
+ local optimized_size
326
+ optimized_size=$(echo -n "$optimized_content" | wc -c | tr -d ' ')
327
+ _record_file_stats "$file_path" "$original_size" "$optimized_size" "$opt_type"
328
+ log_debug "Optimized $file_path: $original_size -> $optimized_size bytes (mode: $opt_type)"
329
+ echo "$optimized_content"
330
+ }
331
+
332
+ # =============================================================================
333
+ # SYMBOL MAP GENERATION
334
+ # =============================================================================
335
+
336
+ # Generate symbol map section for manifest
337
+ # Only included if symbol compression was used
338
+ _generate_symbol_map_section() {
339
+ if [[ "$ENABLE_SYMBOL_COMPRESSION" != "true" || "$_HAS_SYMBOL_MAP" != "true" ]]; then
340
+ return
341
+ fi
342
+
343
+ # Check if get_last_symbol_map function exists and returns content
344
+ if type get_last_symbol_map &>/dev/null; then
345
+ local map_content
346
+ if map_content=$(get_last_symbol_map 2>/dev/null) && [[ -n "$map_content" ]]; then
347
+ echo ""
348
+ echo "### Symbol Map"
349
+ echo "The following symbols were compressed. Use this map to decode:"
350
+ echo '```json'
351
+ echo "$map_content"
352
+ echo '```'
353
+ fi
354
+ fi
355
+ }
356
+
357
+ # =============================================================================
358
+ # CONTEXT MANIFEST GENERATION
359
+ # =============================================================================
360
+
361
+ # Generate the context manifest header
362
+ # Usage: _generate_manifest "mode"
363
+ _generate_manifest() {
364
+ local mode="$1"
365
+
366
+ local original_tokens=$((_TOTAL_ORIGINAL_BYTES / 4))
367
+ local optimized_tokens=$((_TOTAL_OPTIMIZED_BYTES / 4))
368
+ local savings_pct=0
369
+ if [[ $_TOTAL_ORIGINAL_BYTES -gt 0 ]]; then
370
+ savings_pct=$(((_TOTAL_ORIGINAL_BYTES - _TOTAL_OPTIMIZED_BYTES) * 100 / _TOTAL_ORIGINAL_BYTES))
371
+ fi
372
+
373
+ echo "## Context Manifest"
374
+ echo ""
375
+ echo "| Property | Value |"
376
+ echo "|----------|-------|"
377
+ echo "| Files Processed | $_TOTAL_FILES_PROCESSED |"
378
+ echo "| Optimization Mode | $mode |"
379
+ echo "| Token Estimate (before) | ~$original_tokens |"
380
+ echo "| Token Estimate (after) | ~$optimized_tokens |"
381
+ echo "| Token Savings | ${savings_pct}% |"
382
+
383
+ # Add detailed breakdown if there are files
384
+ if [[ $_TOTAL_FILES_PROCESSED -gt 0 ]]; then
385
+ echo ""
386
+ echo "### Optimization Details"
387
+ echo "| File | Original | Optimized | Method |"
388
+ echo "|------|----------|-----------|--------|"
389
+
390
+ # Iterate through tracked files
391
+ for key in $(map_keys "ORIGINAL_SIZES"); do
392
+ local orig
393
+ local opt
394
+ local method
395
+ orig=$(map_get "ORIGINAL_SIZES" "$key")
396
+ opt=$(map_get "OPTIMIZED_SIZES" "$key")
397
+ method=$(map_get "OPTIMIZATION_APPLIED" "$key")
398
+ # Convert key back to something readable (approximate)
399
+ local display_name
400
+ display_name=$(echo "$key" | tr '_' '/')
401
+ echo "| $display_name | ${orig}B | ${opt}B | $method |"
402
+ done
403
+ fi
404
+
405
+ # Add symbol map if compression was used
406
+ _generate_symbol_map_section
407
+
408
+ echo ""
409
+ }
410
+
411
+ # =============================================================================
412
+ # PARAMETERS VALIDATION
413
+ # =============================================================================
414
+
415
+ if [[ $# -lt 2 ]]; then
416
+ echo "Usage: $0 <output_file> \"question\" [file1] [file2] ..." >&2
417
+ echo "" >&2
418
+ echo "Environment variables:" >&2
419
+ echo " TOKEN_OPTIMIZATION_MODE - none, basic, ast, full (default: ast)" >&2
420
+ echo " ENABLE_AST_EXTRACTION - true/false (default: true)" >&2
421
+ echo " ENABLE_SYMBOL_COMPRESSION - true/false (default: false)" >&2
422
+ echo " ENABLE_SEMANTIC_CHUNKING - true/false (default: true)" >&2
423
+ echo " MAX_CONTEXT_FILE_BYTES - threshold in bytes (default: 8000)" >&2
424
+ exit 1
425
+ fi
426
+
427
+ OUTPUT_FILE="$1"
428
+ shift
429
+ QUERY="$1"
430
+ shift
431
+
432
+ # Validate output file path (allow /tmp for output)
433
+ if [[ "$OUTPUT_FILE" == /tmp/* ]]; then
434
+ : # Allow /tmp paths for output
435
+ elif ! validate_file_path "$OUTPUT_FILE" "true"; then
436
+ log_error "Invalid output file path: $OUTPUT_FILE"
437
+ exit 1
438
+ fi
439
+
440
+ # FILES array handling (compatible with set -u)
441
+ # Validate each file path
442
+ FILES=()
443
+ while [[ $# -gt 0 ]]; do
444
+ file_arg="$1"
445
+ shift
446
+ # Allow relative paths and /tmp paths for context files
447
+ if [[ "$file_arg" == /tmp/* ]] || validate_file_path "$file_arg" "false" 2>/dev/null; then
448
+ FILES+=("$file_arg")
449
+ else
450
+ log_warn "Skipping invalid file path: $file_arg"
451
+ fi
452
+ done
453
+
454
+ # =============================================================================
455
+ # BUILD CONTEXT
456
+ # =============================================================================
457
+
458
+ # Determine effective optimization mode
459
+ EFFECTIVE_MODE=$(_determine_effective_mode "$TOKEN_OPTIMIZATION_MODE")
460
+ log_info "Building context with optimization mode: $EFFECTIVE_MODE"
461
+
462
+ # Reset statistics
463
+ _reset_stats
464
+
465
+ {
466
+ echo "# Project Context"
467
+ echo ""
468
+
469
+ # Working directory
470
+ echo "## Working Directory"
471
+ echo '```'
472
+ pwd
473
+ echo '```'
474
+ echo ""
475
+
476
+ # Project structure (relevant files, excluding noise)
477
+ echo "## Project Structure"
478
+ echo '```'
479
+ find . -maxdepth 4 -type f \( \
480
+ -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.tsx" \
481
+ -o -name "*.go" -o -name "*.rs" -o -name "*.java" -o -name "*.kt" \
482
+ -o -name "*.rb" -o -name "*.php" -o -name "*.swift" -o -name "*.c" \
483
+ -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" -o -name "*.cs" \
484
+ -o -name "*.sh" -o -name "*.bash" -o -name "*.zsh" \
485
+ -o -name "Dockerfile" -o -name "docker-compose*.yml" \
486
+ -o -name "Makefile" -o -name "CMakeLists.txt" \
487
+ -o -name "*.json" -o -name "*.toml" -o -name "*.yaml" -o -name "*.yml" \
488
+ -o -name "*.md" \
489
+ \) \
490
+ -not -path '*/node_modules/*' \
491
+ -not -path '*/.git/*' \
492
+ -not -path '*/dist/*' \
493
+ -not -path '*/build/*' \
494
+ -not -path '*/__pycache__/*' \
495
+ -not -path '*/.venv/*' \
496
+ -not -path '*/venv/*' \
497
+ -not -path '*/target/*' \
498
+ -not -path '*/.next/*' \
499
+ 2>/dev/null | sort | head -100 || true
500
+ echo '```'
501
+ echo ""
502
+
503
+ # Content of specific files
504
+ if [[ ${#FILES[@]} -gt 0 ]]; then
505
+ echo "## Relevant Files"
506
+ echo ""
507
+
508
+ for file_path in "${FILES[@]}"; do
509
+ if [[ -f "$file_path" ]]; then
510
+ # Extract extension for syntax highlighting
511
+ extension="${file_path##*.}"
512
+ lang=$(_get_lang_for_extension "$extension")
513
+
514
+ echo "### File: \`$file_path\`"
515
+ echo ""
516
+
517
+ echo "\`\`\`$lang"
518
+ # Use intelligent optimization
519
+ _optimize_file_content "$file_path" "$EFFECTIVE_MODE" "$lang"
520
+ echo ""
521
+ echo "\`\`\`"
522
+ echo ""
523
+ else
524
+ echo "### File: \`$file_path\`"
525
+ echo ""
526
+ echo "*File not found*"
527
+ echo ""
528
+ fi
529
+ done
530
+ fi
531
+
532
+ # Question
533
+ echo "---"
534
+ echo ""
535
+ echo "# Question"
536
+ echo ""
537
+ echo "$QUERY"
538
+ echo ""
539
+
540
+ } > "${OUTPUT_FILE}.tmp"
541
+
542
+ # Now prepend the manifest to the output
543
+ {
544
+ echo "# Project Context"
545
+ echo ""
546
+
547
+ # Generate manifest with statistics
548
+ _generate_manifest "$EFFECTIVE_MODE"
549
+
550
+ # Append the rest of the content (skip the first "# Project Context" line)
551
+ tail -n +3 "${OUTPUT_FILE}.tmp"
552
+
553
+ } > "$OUTPUT_FILE"
554
+
555
+ # Clean up temp file
556
+ rm -f "${OUTPUT_FILE}.tmp"
557
+
558
+ # Log final statistics
559
+ _log_optimization_stats
560
+
561
+ # Output: path of created file (for use in scripts)
562
+ echo "$OUTPUT_FILE"