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,1093 @@
1
+ #!/bin/bash
2
+ # configure.sh - Interactive configuration wizard for AI Consultants v2.0
3
+ #
4
+ # Detects available CLI agents, allows selection and API configuration,
5
+ # ensures minimum 2 agents are enabled, and saves configuration to .env
6
+ #
7
+ # Usage: ./configure.sh [--non-interactive] [--output FILE]
8
+ #
9
+ # Options:
10
+ # --non-interactive Skip prompts, detect and auto-enable available agents
11
+ # --output FILE Output file (default: .env in project root)
12
+
13
+ set -euo pipefail
14
+
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
17
+
18
+ # Load common utilities if available
19
+ if [[ -f "$SCRIPT_DIR/lib/common.sh" ]]; then
20
+ source "$SCRIPT_DIR/lib/common.sh"
21
+ else
22
+ # Fallback logging functions
23
+ log_info() { echo "[INFO] $*"; }
24
+ log_success() { echo "[OK] $*"; }
25
+ log_warn() { echo "[WARN] $*"; }
26
+ log_error() { echo "[ERROR] $*" >&2; }
27
+ fi
28
+
29
+ # Load personas library for persona catalog
30
+ if [[ -f "$SCRIPT_DIR/lib/personas.sh" ]]; then
31
+ source "$SCRIPT_DIR/lib/personas.sh"
32
+ fi
33
+
34
+ # =============================================================================
35
+ # CONFIGURATION
36
+ # =============================================================================
37
+
38
+ NON_INTERACTIVE=false
39
+ OUTPUT_FILE="$PROJECT_ROOT/.env"
40
+
41
+ # CLI Agents: name|command|install_hint|persona
42
+ CLI_AGENT_NAMES=("Gemini" "Codex" "Mistral" "Kilo" "Cursor" "Aider")
43
+ CLI_AGENT_CMDS=("gemini" "codex" "vibe" "kilocode" "agent" "aider")
44
+ CLI_AGENT_HINTS=("npm install -g @google/gemini-cli" "npm install -g @openai/codex" "pip install mistral-vibe" "npm install -g @kilocode/cli" "See: https://cursor.com/" "pip install aider-chat")
45
+ CLI_AGENT_PERSONAS=("The Architect" "The Pragmatist" "The Devil's Advocate" "The Innovator" "The Integrator" "The Pair Programmer")
46
+
47
+ # API Agents: name|key_var|api_url|model|persona
48
+ API_AGENT_NAMES=("Qwen3" "GLM" "Grok" "DeepSeek")
49
+ API_AGENT_KEY_VARS=("QWEN3_API_KEY" "GLM_API_KEY" "GROK_API_KEY" "DEEPSEEK_API_KEY")
50
+ API_AGENT_URLS=("https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation" "https://open.bigmodel.cn/api/paas/v4/chat/completions" "https://api.x.ai/v1/chat/completions" "https://api.deepseek.com/v1/chat/completions")
51
+ API_AGENT_MODELS=("qwen-max" "glm-4" "grok-4-1-fast-reasoning" "deepseek-reasoner")
52
+ API_AGENT_PERSONAS=("The Analyst" "The Methodologist" "The Provocateur" "The Code Specialist")
53
+
54
+ # State arrays (parallel to CLI_AGENT_NAMES)
55
+ CLI_DETECTED=() # "installed" or "missing"
56
+ CLI_ENABLED=() # "true" or "false"
57
+
58
+ # State arrays (parallel to API_AGENT_NAMES)
59
+ API_ENABLED=() # "true" or "false"
60
+ API_KEYS_VALUES=() # actual API key values
61
+
62
+ # Custom CLI agents
63
+ CUSTOM_NAMES=()
64
+ CUSTOM_CMDS=()
65
+ CUSTOM_PERSONAS=()
66
+
67
+ # Custom API agents
68
+ CUSTOM_API_NAMES=()
69
+ CUSTOM_API_URLS=()
70
+ CUSTOM_API_KEYS=()
71
+ CUSTOM_API_MODELS=()
72
+ CUSTOM_API_PERSONAS=()
73
+ CUSTOM_API_FORMATS=() # "openai" or "qwen"
74
+
75
+ # Persona assignments (maps agent name to persona ID)
76
+ # Parallel arrays for CLI and API agents
77
+ CLI_PERSONA_IDS=() # persona ID for each CLI agent
78
+ API_PERSONA_IDS=() # persona ID for each API agent
79
+ CUSTOM_PERSONA_IDS=() # persona ID for each custom CLI agent
80
+ CUSTOM_API_PERSONA_IDS=() # persona ID for each custom API agent
81
+
82
+ # Initialize state arrays
83
+ # Default persona IDs: 1=Architect, 2=Pragmatist, 3=Devil's Advocate, 4=Innovator, 5=Integrator, 16=Pair Programmer
84
+ CLI_DEFAULT_PERSONA_IDS=(1 2 3 4 5 16)
85
+ for i in "${!CLI_AGENT_NAMES[@]}"; do
86
+ CLI_DETECTED+=("missing")
87
+ CLI_ENABLED+=("false")
88
+ CLI_PERSONA_IDS+=("${CLI_DEFAULT_PERSONA_IDS[$i]}")
89
+ done
90
+
91
+ # Default persona IDs: 6=Analyst, 7=Methodologist, 8=Provocateur, 17=Code Specialist
92
+ API_DEFAULT_PERSONA_IDS=(6 7 8 17)
93
+ for i in "${!API_AGENT_NAMES[@]}"; do
94
+ API_ENABLED+=("false")
95
+ API_KEYS_VALUES+=("")
96
+ API_PERSONA_IDS+=("${API_DEFAULT_PERSONA_IDS[$i]}")
97
+ done
98
+
99
+ # =============================================================================
100
+ # ARGUMENT PARSING
101
+ # =============================================================================
102
+
103
+ while [[ $# -gt 0 ]]; do
104
+ case "$1" in
105
+ --non-interactive)
106
+ NON_INTERACTIVE=true
107
+ shift
108
+ ;;
109
+ --output)
110
+ OUTPUT_FILE="$2"
111
+ shift 2
112
+ ;;
113
+ -h|--help)
114
+ echo "Usage: $0 [--non-interactive] [--output FILE]"
115
+ echo ""
116
+ echo "Interactive configuration wizard for AI Consultants."
117
+ echo ""
118
+ echo "Options:"
119
+ echo " --non-interactive Auto-detect and enable available agents"
120
+ echo " --output FILE Output file (default: .env)"
121
+ exit 0
122
+ ;;
123
+ *)
124
+ shift
125
+ ;;
126
+ esac
127
+ done
128
+
129
+ # =============================================================================
130
+ # UTILITIES
131
+ # =============================================================================
132
+
133
+ # Normalize name to uppercase (removes spaces and hyphens)
134
+ to_upper() {
135
+ echo "$1" | tr '[:lower:]' '[:upper:]' | tr -d ' -'
136
+ }
137
+
138
+ # Print a header box
139
+ print_header() {
140
+ local title="$1"
141
+ local width=60
142
+ echo ""
143
+ printf '╔'; printf '═%.0s' $(seq 1 $width); printf '╗\n'
144
+ printf "║ %-$((width-1))s║\n" "$title"
145
+ printf '╚'; printf '═%.0s' $(seq 1 $width); printf '╝\n'
146
+ echo ""
147
+ }
148
+
149
+ # Print a section divider
150
+ print_section() {
151
+ local title="$1"
152
+ echo ""
153
+ echo "─── $title ───"
154
+ echo ""
155
+ }
156
+
157
+ # Emit a section header to .env file
158
+ # Usage: emit_env_section "SECTION TITLE" [file]
159
+ emit_env_section() {
160
+ local title="$1"
161
+ local file="${2:-$OUTPUT_FILE}"
162
+ {
163
+ echo ""
164
+ echo "# ============================================================================="
165
+ echo "# $title"
166
+ echo "# ============================================================================="
167
+ echo ""
168
+ } >> "$file"
169
+ }
170
+
171
+ # Prompt yes/no
172
+ confirm() {
173
+ local prompt="$1"
174
+ local default="${2:-n}"
175
+
176
+ if [[ "$NON_INTERACTIVE" == "true" ]]; then
177
+ [[ "$default" == "y" ]] && return 0 || return 1
178
+ fi
179
+
180
+ local yn
181
+ if [[ "$default" == "y" ]]; then
182
+ read -r -p "$prompt [Y/n]: " yn
183
+ yn=${yn:-y}
184
+ else
185
+ read -r -p "$prompt [y/N]: " yn
186
+ yn=${yn:-n}
187
+ fi
188
+
189
+ [[ "$yn" =~ ^[Yy] ]] && return 0 || return 1
190
+ }
191
+
192
+ # Prompt for input with default
193
+ prompt_input() {
194
+ local prompt="$1"
195
+ local default="${2:-}"
196
+
197
+ if [[ "$NON_INTERACTIVE" == "true" ]]; then
198
+ REPLY="$default"
199
+ return
200
+ fi
201
+
202
+ if [[ -n "$default" ]]; then
203
+ read -r -p "$prompt [$default]: " REPLY
204
+ REPLY=${REPLY:-$default}
205
+ else
206
+ read -r -p "$prompt: " REPLY
207
+ fi
208
+ }
209
+
210
+ # Prompt for secret (no echo)
211
+ prompt_secret() {
212
+ local prompt="$1"
213
+
214
+ if [[ "$NON_INTERACTIVE" == "true" ]]; then
215
+ REPLY=""
216
+ return
217
+ fi
218
+
219
+ read -r -s -p "$prompt: " REPLY
220
+ echo ""
221
+ }
222
+
223
+ # =============================================================================
224
+ # CLI AGENT DETECTION
225
+ # =============================================================================
226
+
227
+ detect_cli_agents() {
228
+ print_section "Detecting CLI Agents"
229
+
230
+ local found=0
231
+ for i in "${!CLI_AGENT_NAMES[@]}"; do
232
+ local name="${CLI_AGENT_NAMES[$i]}"
233
+ local cmd="${CLI_AGENT_CMDS[$i]}"
234
+ local persona="${CLI_AGENT_PERSONAS[$i]}"
235
+
236
+ if command -v "$cmd" &> /dev/null; then
237
+ CLI_DETECTED[$i]="installed"
238
+ local version
239
+ version=$("$cmd" --version 2>/dev/null | head -1 || echo "detected")
240
+ echo " [FOUND] $name ($persona) - $cmd"
241
+ ((found++)) || true
242
+ else
243
+ CLI_DETECTED[$i]="missing"
244
+ echo " [-----] $name ($persona) - not found"
245
+ fi
246
+ done
247
+
248
+ echo ""
249
+ echo "Found $found CLI agent(s) installed."
250
+ return 0
251
+ }
252
+
253
+ # =============================================================================
254
+ # CLI AGENT SELECTION
255
+ # =============================================================================
256
+
257
+ select_cli_agents() {
258
+ print_section "Select CLI Agents to Enable"
259
+
260
+ if [[ "$NON_INTERACTIVE" == "true" ]]; then
261
+ # Auto-enable all detected CLI agents
262
+ for i in "${!CLI_AGENT_NAMES[@]}"; do
263
+ if [[ "${CLI_DETECTED[$i]}" == "installed" ]]; then
264
+ CLI_ENABLED[$i]="true"
265
+ log_info "Auto-enabled: ${CLI_AGENT_NAMES[$i]}"
266
+ fi
267
+ done
268
+ return
269
+ fi
270
+
271
+ # Build list of detected agents
272
+ local detected_indices=()
273
+ for i in "${!CLI_AGENT_NAMES[@]}"; do
274
+ if [[ "${CLI_DETECTED[$i]}" == "installed" ]]; then
275
+ detected_indices+=("$i")
276
+ fi
277
+ done
278
+
279
+ if [[ ${#detected_indices[@]} -eq 0 ]]; then
280
+ echo " No CLI agents detected. You can add custom ones or use API agents."
281
+ echo ""
282
+ if confirm "Add a custom CLI agent?"; then
283
+ add_custom_cli_agent
284
+ fi
285
+ return
286
+ fi
287
+
288
+ # Pre-select all detected agents
289
+ for i in "${detected_indices[@]}"; do
290
+ CLI_ENABLED[$i]="true"
291
+ done
292
+
293
+ local done_selecting=false
294
+ while [[ "$done_selecting" != "true" ]]; do
295
+ echo ""
296
+ echo "Available CLI agents (x = selected):"
297
+ local menu_idx=1
298
+ for i in "${detected_indices[@]}"; do
299
+ local name="${CLI_AGENT_NAMES[$i]}"
300
+ local persona="${CLI_AGENT_PERSONAS[$i]}"
301
+ local mark=" "
302
+ [[ "${CLI_ENABLED[$i]}" == "true" ]] && mark="x"
303
+ echo " $menu_idx) [$mark] $name ($persona)"
304
+ ((menu_idx++)) || true
305
+ done
306
+ echo " a) Select all"
307
+ echo " n) Select none"
308
+ echo " c) Add custom CLI agent"
309
+ echo " d) Done"
310
+ echo ""
311
+
312
+ read -r -p "Choice: " choice
313
+
314
+ case "$choice" in
315
+ [1-9]|[1-9][0-9])
316
+ if [[ $choice -le ${#detected_indices[@]} ]]; then
317
+ local idx="${detected_indices[$((choice-1))]}"
318
+ if [[ "${CLI_ENABLED[$idx]}" == "true" ]]; then
319
+ CLI_ENABLED[$idx]="false"
320
+ else
321
+ CLI_ENABLED[$idx]="true"
322
+ fi
323
+ fi
324
+ ;;
325
+ a|A)
326
+ for i in "${detected_indices[@]}"; do
327
+ CLI_ENABLED[$i]="true"
328
+ done
329
+ ;;
330
+ n|N)
331
+ for i in "${detected_indices[@]}"; do
332
+ CLI_ENABLED[$i]="false"
333
+ done
334
+ ;;
335
+ c|C)
336
+ add_custom_cli_agent
337
+ ;;
338
+ d|D)
339
+ done_selecting=true
340
+ ;;
341
+ esac
342
+ done
343
+ }
344
+
345
+ # =============================================================================
346
+ # CUSTOM CLI AGENT
347
+ # =============================================================================
348
+
349
+ add_custom_cli_agent() {
350
+ print_section "Add Custom CLI Agent"
351
+
352
+ prompt_input "Agent name (e.g., 'Claude', 'GPT4All')" ""
353
+ local name="$REPLY"
354
+ [[ -z "$name" ]] && return
355
+
356
+ prompt_input "Command to execute (e.g., 'claude', 'gpt4all')" ""
357
+ local cmd="$REPLY"
358
+ [[ -z "$cmd" ]] && return
359
+
360
+ # Check if command exists
361
+ if ! command -v "$cmd" &> /dev/null; then
362
+ log_warn "Command '$cmd' not found in PATH."
363
+ if ! confirm "Add anyway?"; then
364
+ return
365
+ fi
366
+ fi
367
+
368
+ prompt_input "Persona/Role description" "Custom Agent"
369
+ local persona="$REPLY"
370
+
371
+ # Store custom agent
372
+ CUSTOM_NAMES+=("$name")
373
+ CUSTOM_CMDS+=("$cmd")
374
+ CUSTOM_PERSONAS+=("$persona")
375
+
376
+ log_success "Added custom CLI agent: $name ($cmd)"
377
+ }
378
+
379
+ # =============================================================================
380
+ # CUSTOM API AGENT
381
+ # =============================================================================
382
+
383
+ add_custom_api_agent() {
384
+ print_section "Add Custom API Agent"
385
+
386
+ echo "Add any OpenAI-compatible or custom API endpoint."
387
+ echo ""
388
+
389
+ prompt_input "Agent name (e.g., 'OpenRouter', 'Groq', 'Together')" ""
390
+ local name="$REPLY"
391
+ [[ -z "$name" ]] && return
392
+
393
+ prompt_input "API endpoint URL (e.g., https://api.openrouter.ai/api/v1/chat/completions)" ""
394
+ local url="$REPLY"
395
+ [[ -z "$url" ]] && return
396
+
397
+ prompt_secret "API key"
398
+ local key="$REPLY"
399
+ [[ -z "$key" ]] && { log_warn "API key required"; return; }
400
+
401
+ prompt_input "Model name (e.g., 'gpt-4', 'anthropic/claude-3')" "gpt-4"
402
+ local model="$REPLY"
403
+
404
+ prompt_input "Persona/Role description" "External API Consultant"
405
+ local persona="$REPLY"
406
+
407
+ echo ""
408
+ echo "Response format:"
409
+ echo " 1) OpenAI-compatible (most APIs - recommended)"
410
+ echo " 2) Qwen/DashScope format"
411
+ read -r -p "Choice [1]: " format_choice
412
+ local format="openai"
413
+ [[ "$format_choice" == "2" ]] && format="qwen"
414
+
415
+ # Store custom API agent
416
+ CUSTOM_API_NAMES+=("$name")
417
+ CUSTOM_API_URLS+=("$url")
418
+ CUSTOM_API_KEYS+=("$key")
419
+ CUSTOM_API_MODELS+=("$model")
420
+ CUSTOM_API_PERSONAS+=("$persona")
421
+ CUSTOM_API_FORMATS+=("$format")
422
+
423
+ log_success "Added custom API agent: $name ($url)"
424
+ }
425
+
426
+ # =============================================================================
427
+ # API AGENT CONFIGURATION
428
+ # =============================================================================
429
+
430
+ configure_api_agents() {
431
+ print_section "Configure API-Based Agents"
432
+
433
+ if [[ "$NON_INTERACTIVE" == "true" ]]; then
434
+ # Auto-enable API agents with existing keys
435
+ for i in "${!API_AGENT_NAMES[@]}"; do
436
+ local key_var="${API_AGENT_KEY_VARS[$i]}"
437
+ local existing_key="${!key_var:-}"
438
+ if [[ -n "$existing_key" ]]; then
439
+ API_ENABLED[$i]="true"
440
+ API_KEYS_VALUES[$i]="$existing_key"
441
+ log_info "Auto-enabled: ${API_AGENT_NAMES[$i]} (API key found)"
442
+ fi
443
+ done
444
+ # Also check for custom API agents via naming convention
445
+ # (e.g., CUSTOMAGENT_API_KEY, CUSTOMAGENT_API_URL, ENABLE_CUSTOMAGENT=true)
446
+ return
447
+ fi
448
+
449
+ echo "API-based agents require API keys but no CLI installation."
450
+ echo ""
451
+ echo "Predefined API agents:"
452
+ for i in "${!API_AGENT_NAMES[@]}"; do
453
+ local name="${API_AGENT_NAMES[$i]}"
454
+ local model="${API_AGENT_MODELS[$i]}"
455
+ local persona="${API_AGENT_PERSONAS[$i]}"
456
+ echo " - $name ($persona) - Model: $model"
457
+ done
458
+ echo ""
459
+ echo "You can also add custom API agents (OpenRouter, Groq, Together, etc.)"
460
+ echo ""
461
+
462
+ if ! confirm "Configure API-based agents?"; then
463
+ return
464
+ fi
465
+
466
+ local done_api_config=false
467
+ while [[ "$done_api_config" != "true" ]]; do
468
+ echo ""
469
+ echo "API Agent Configuration:"
470
+ echo " 1) Configure predefined agents (Qwen3, GLM, Grok)"
471
+ echo " 2) Add custom API agent"
472
+ echo " 3) Done with API configuration"
473
+ echo ""
474
+
475
+ read -r -p "Choice [1-3]: " api_choice
476
+
477
+ case "$api_choice" in
478
+ 1)
479
+ _configure_predefined_api_agents
480
+ ;;
481
+ 2)
482
+ add_custom_api_agent
483
+ ;;
484
+ 3|"")
485
+ done_api_config=true
486
+ ;;
487
+ esac
488
+ done
489
+ }
490
+
491
+ # Internal function to configure predefined API agents
492
+ _configure_predefined_api_agents() {
493
+ for i in "${!API_AGENT_NAMES[@]}"; do
494
+ local name="${API_AGENT_NAMES[$i]}"
495
+ local key_var="${API_AGENT_KEY_VARS[$i]}"
496
+ local persona="${API_AGENT_PERSONAS[$i]}"
497
+
498
+ echo ""
499
+ if confirm "Enable $name ($persona)?"; then
500
+ # Check for existing key in environment
501
+ local existing_key="${!key_var:-}"
502
+
503
+ if [[ -n "$existing_key" ]]; then
504
+ local masked="${existing_key:0:8}...${existing_key: -4}"
505
+ echo " Existing key found: $masked"
506
+ if confirm " Use existing key?" "y"; then
507
+ API_ENABLED[$i]="true"
508
+ API_KEYS_VALUES[$i]="$existing_key"
509
+ continue
510
+ fi
511
+ fi
512
+
513
+ # Prompt for new key
514
+ prompt_secret " Enter $name API key ($key_var)"
515
+ local api_key="$REPLY"
516
+
517
+ if [[ -n "$api_key" ]]; then
518
+ API_ENABLED[$i]="true"
519
+ API_KEYS_VALUES[$i]="$api_key"
520
+ log_success "$name enabled"
521
+ else
522
+ log_warn "$name skipped (no API key)"
523
+ fi
524
+ fi
525
+ done
526
+ }
527
+
528
+ # =============================================================================
529
+ # VALIDATION
530
+ # =============================================================================
531
+
532
+ validate_configuration() {
533
+ print_section "Validating Configuration"
534
+
535
+ local cli_count=0
536
+ local api_count=0
537
+ local custom_cli_count=${#CUSTOM_NAMES[@]}
538
+ local custom_api_count=${#CUSTOM_API_NAMES[@]}
539
+
540
+ # Count enabled CLI agents
541
+ for i in "${!CLI_AGENT_NAMES[@]}"; do
542
+ if [[ "${CLI_ENABLED[$i]}" == "true" ]]; then
543
+ ((cli_count++)) || true
544
+ fi
545
+ done
546
+
547
+ # Count enabled predefined API agents
548
+ for i in "${!API_AGENT_NAMES[@]}"; do
549
+ if [[ "${API_ENABLED[$i]}" == "true" ]]; then
550
+ ((api_count++)) || true
551
+ fi
552
+ done
553
+
554
+ local total_cli=$((cli_count + custom_cli_count))
555
+ local total_api=$((api_count + custom_api_count))
556
+ local total_enabled=$((total_cli + total_api))
557
+
558
+ echo "Summary:"
559
+ echo " CLI agents enabled: $total_cli (predefined: $cli_count, custom: $custom_cli_count)"
560
+ echo " API agents enabled: $total_api (predefined: $api_count, custom: $custom_api_count)"
561
+ echo " Total enabled: $total_enabled"
562
+ echo ""
563
+
564
+ # Validation: minimum 2 agents required
565
+ if [[ $total_enabled -lt 2 ]]; then
566
+ log_error "At least 2 agents must be enabled for AI Consultants to work."
567
+ echo ""
568
+ echo "The system requires multiple perspectives for:"
569
+ echo " - Comparison and voting"
570
+ echo " - Multi-Agent Debate"
571
+ echo " - Consensus building"
572
+ echo ""
573
+
574
+ if [[ "$NON_INTERACTIVE" == "true" ]]; then
575
+ return 1
576
+ fi
577
+
578
+ echo "Options:"
579
+ echo " 1) Add custom CLI agent"
580
+ echo " 2) Configure API agents"
581
+ echo " 3) Abort configuration"
582
+ echo ""
583
+
584
+ read -r -p "Choice [1-3]: " choice
585
+
586
+ case "$choice" in
587
+ 1)
588
+ add_custom_cli_agent
589
+ validate_configuration
590
+ return $?
591
+ ;;
592
+ 2)
593
+ configure_api_agents
594
+ validate_configuration
595
+ return $?
596
+ ;;
597
+ *)
598
+ return 1
599
+ ;;
600
+ esac
601
+ else
602
+ log_success "Configuration valid: $total_enabled agents enabled"
603
+ return 0
604
+ fi
605
+ }
606
+
607
+ # =============================================================================
608
+ # SAVE CONFIGURATION
609
+ # =============================================================================
610
+
611
+ save_configuration() {
612
+ print_section "Saving Configuration"
613
+
614
+ # Backup existing .env if present
615
+ if [[ -f "$OUTPUT_FILE" ]]; then
616
+ local backup="${OUTPUT_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
617
+ cp "$OUTPUT_FILE" "$backup"
618
+ chmod 600 "$backup" # Secure backup file too
619
+ log_info "Backed up existing config to: $backup"
620
+ fi
621
+
622
+ # Generate .env file with secure permissions
623
+ # Create file with restrictive permissions BEFORE writing secrets
624
+ touch "$OUTPUT_FILE"
625
+ chmod 600 "$OUTPUT_FILE"
626
+
627
+ cat > "$OUTPUT_FILE" << 'HEADER'
628
+ # =============================================================================
629
+ # AI Consultants v2.0 - Generated Configuration
630
+ # =============================================================================
631
+ # Generated by: ./scripts/configure.sh
632
+ #
633
+ # This file was auto-generated. You can edit it manually or re-run configure.sh
634
+ #
635
+ # Export variables before running:
636
+ # source .env && ./scripts/consult_all.sh "Your question"
637
+
638
+ HEADER
639
+
640
+ # CLI Agents
641
+ emit_env_section "ENABLED CONSULTANTS"
642
+ echo "# CLI-based consultants" >> "$OUTPUT_FILE"
643
+
644
+ for i in "${!CLI_AGENT_NAMES[@]}"; do
645
+ local name_upper
646
+ name_upper=$(to_upper "${CLI_AGENT_NAMES[$i]}")
647
+ echo "ENABLE_${name_upper}=${CLI_ENABLED[$i]}" >> "$OUTPUT_FILE"
648
+ done
649
+
650
+ echo -e "\n# API-based consultants" >> "$OUTPUT_FILE"
651
+
652
+ for i in "${!API_AGENT_NAMES[@]}"; do
653
+ local name_upper
654
+ name_upper=$(to_upper "${API_AGENT_NAMES[$i]}")
655
+ echo "ENABLE_${name_upper}=${API_ENABLED[$i]}" >> "$OUTPUT_FILE"
656
+ done
657
+
658
+ # API Keys
659
+ emit_env_section "API KEYS"
660
+
661
+ for i in "${!API_AGENT_NAMES[@]}"; do
662
+ if [[ -n "${API_KEYS_VALUES[$i]}" ]]; then
663
+ local key_var="${API_AGENT_KEY_VARS[$i]}"
664
+ echo "${key_var}=${API_KEYS_VALUES[$i]}" >> "$OUTPUT_FILE"
665
+ fi
666
+ done
667
+
668
+ # Custom CLI agents
669
+ if [[ ${#CUSTOM_NAMES[@]} -gt 0 ]]; then
670
+ emit_env_section "CUSTOM CLI AGENTS"
671
+
672
+ for i in "${!CUSTOM_NAMES[@]}"; do
673
+ local var_upper
674
+ var_upper=$(to_upper "${CUSTOM_NAMES[$i]}")
675
+ echo "# Custom CLI agent: ${CUSTOM_NAMES[$i]} (${CUSTOM_PERSONAS[$i]})" >> "$OUTPUT_FILE"
676
+ echo "${var_upper}_CMD=${CUSTOM_CMDS[$i]}" >> "$OUTPUT_FILE"
677
+ echo "ENABLE_${var_upper}=true" >> "$OUTPUT_FILE"
678
+ done
679
+ fi
680
+
681
+ # Custom API agents
682
+ if [[ ${#CUSTOM_API_NAMES[@]} -gt 0 ]]; then
683
+ emit_env_section "CUSTOM API AGENTS"
684
+
685
+ for i in "${!CUSTOM_API_NAMES[@]}"; do
686
+ local var_upper
687
+ var_upper=$(to_upper "${CUSTOM_API_NAMES[$i]}")
688
+ {
689
+ echo "# Custom API agent: ${CUSTOM_API_NAMES[$i]}"
690
+ echo "# Persona: ${CUSTOM_API_PERSONAS[$i]}"
691
+ echo "${var_upper}_API_KEY=${CUSTOM_API_KEYS[$i]}"
692
+ echo "${var_upper}_API_URL=${CUSTOM_API_URLS[$i]}"
693
+ echo "${var_upper}_MODEL=${CUSTOM_API_MODELS[$i]}"
694
+ echo "${var_upper}_TIMEOUT=180"
695
+ echo "${var_upper}_FORMAT=${CUSTOM_API_FORMATS[$i]}"
696
+ echo "${var_upper}_PERSONA=\"${CUSTOM_API_PERSONAS[$i]}\""
697
+ echo "ENABLE_${var_upper}=true"
698
+ echo ""
699
+ } >> "$OUTPUT_FILE"
700
+ done
701
+ fi
702
+
703
+ # Persona assignments (only output non-default assignments)
704
+ emit_env_section "PERSONA ASSIGNMENTS"
705
+ {
706
+ echo "# Default personas are used unless overridden here"
707
+ echo "# Persona IDs: 1=Architect, 2=Pragmatist, 3=Devil's Advocate, 4=Innovator,"
708
+ echo "# 5=Integrator, 6=Analyst, 7=Methodologist, 8=Provocateur, 9=Mentor,"
709
+ echo "# 10=Optimizer, 11=Security Expert, 12=Minimalist, 13=DX Advocate,"
710
+ echo "# 14=Debugger, 15=Reviewer"
711
+ echo ""
712
+ } >> "$OUTPUT_FILE"
713
+
714
+ # Helper to write persona assignment if non-default
715
+ _write_persona_if_changed() {
716
+ local name_upper="$1" persona_id="$2" default_id="$3" custom_text="$4"
717
+ if [[ "$persona_id" == "0" && -n "$custom_text" ]]; then
718
+ echo "${name_upper}_PERSONA=\"$custom_text\"" >> "$OUTPUT_FILE"
719
+ elif [[ "$persona_id" != "$default_id" ]]; then
720
+ echo "${name_upper}_PERSONA_ID=$persona_id" >> "$OUTPUT_FILE"
721
+ fi
722
+ }
723
+
724
+ # CLI agent personas
725
+ for i in "${!CLI_AGENT_NAMES[@]}"; do
726
+ [[ "${CLI_ENABLED[$i]}" != "true" ]] && continue
727
+ _write_persona_if_changed "$(to_upper "${CLI_AGENT_NAMES[$i]}")" \
728
+ "${CLI_PERSONA_IDS[$i]}" "${CLI_DEFAULT_PERSONA_IDS[$i]}" "${CLI_AGENT_PERSONAS[$i]:-}"
729
+ done
730
+
731
+ # API agent personas
732
+ for i in "${!API_AGENT_NAMES[@]}"; do
733
+ [[ "${API_ENABLED[$i]}" != "true" ]] && continue
734
+ _write_persona_if_changed "$(to_upper "${API_AGENT_NAMES[$i]}")" \
735
+ "${API_PERSONA_IDS[$i]}" "${API_DEFAULT_PERSONA_IDS[$i]}" "${API_AGENT_PERSONAS[$i]:-}"
736
+ done
737
+
738
+ # Custom CLI agent personas
739
+ for i in "${!CUSTOM_NAMES[@]}"; do
740
+ [[ ${#CUSTOM_PERSONA_IDS[@]} -le $i ]] && continue
741
+ _write_persona_if_changed "$(to_upper "${CUSTOM_NAMES[$i]}")" \
742
+ "${CUSTOM_PERSONA_IDS[$i]}" "1" "${CUSTOM_PERSONAS[$i]:-}"
743
+ done
744
+
745
+ # Default configuration from template
746
+ cat >> "$OUTPUT_FILE" << 'DEFAULTS'
747
+
748
+ # =============================================================================
749
+ # MODEL CONFIGURATION
750
+ # =============================================================================
751
+
752
+ GEMINI_MODEL=gemini-2.5-pro
753
+ GEMINI_TIMEOUT=180
754
+
755
+ CODEX_MODEL=
756
+ CODEX_TIMEOUT=180
757
+
758
+ MISTRAL_TIMEOUT=180
759
+
760
+ KILO_TIMEOUT=180
761
+
762
+ CURSOR_TIMEOUT=180
763
+
764
+ AIDER_MODEL=
765
+ AIDER_TIMEOUT=180
766
+
767
+ # API models
768
+ QWEN3_MODEL=qwen-max
769
+ QWEN3_TIMEOUT=180
770
+
771
+ GLM_MODEL=glm-4
772
+ GLM_TIMEOUT=180
773
+
774
+ GROK_MODEL=grok-4-1-fast-reasoning
775
+ GROK_TIMEOUT=180
776
+
777
+ DEEPSEEK_MODEL=deepseek-reasoner
778
+ DEEPSEEK_TIMEOUT=180
779
+
780
+ # =============================================================================
781
+ # FEATURES
782
+ # =============================================================================
783
+
784
+ ENABLE_PERSONA=true
785
+ ENABLE_SYNTHESIS=true
786
+ SYNTHESIS_CMD=claude
787
+
788
+ ENABLE_DEBATE=false
789
+ DEBATE_ROUNDS=1
790
+
791
+ ENABLE_REFLECTION=false
792
+ REFLECTION_CYCLES=1
793
+
794
+ # =============================================================================
795
+ # SMART ROUTING
796
+ # =============================================================================
797
+
798
+ ENABLE_CLASSIFICATION=true
799
+ CLASSIFICATION_MODE=pattern
800
+ ENABLE_SMART_ROUTING=false
801
+ MIN_AFFINITY=7
802
+
803
+ # =============================================================================
804
+ # COST & SESSION
805
+ # =============================================================================
806
+
807
+ ENABLE_COST_TRACKING=true
808
+ MAX_SESSION_COST=1.00
809
+ WARN_AT_COST=0.50
810
+
811
+ SESSION_DIR=/tmp/ai_consultants_sessions
812
+ SESSION_CLEANUP_DAYS=7
813
+
814
+ # =============================================================================
815
+ # OTHER
816
+ # =============================================================================
817
+
818
+ ENABLE_PROGRESS_BARS=true
819
+ ENABLE_EARLY_TERMINATION=true
820
+ ENABLE_PREFLIGHT=false
821
+ MAX_RETRIES=2
822
+ RETRY_DELAY_SECONDS=5
823
+ LOG_LEVEL=INFO
824
+ DEFAULTS
825
+
826
+ log_success "Configuration saved to: $OUTPUT_FILE"
827
+ echo ""
828
+ echo "To use this configuration:"
829
+ echo " source $OUTPUT_FILE && ./scripts/consult_all.sh \"Your question\""
830
+ }
831
+
832
+ # =============================================================================
833
+ # PERSONA CONFIGURATION
834
+ # =============================================================================
835
+
836
+ configure_personas() {
837
+ print_section "Configure Personas"
838
+
839
+ if [[ "$NON_INTERACTIVE" == "true" ]]; then
840
+ log_info "Using default personas (non-interactive mode)"
841
+ return
842
+ fi
843
+
844
+ echo "Each agent can have a different persona that shapes its response style."
845
+ echo "Default personas are pre-configured, but you can customize them."
846
+ echo ""
847
+
848
+ if ! confirm "Customize agent personas?" "n"; then
849
+ return
850
+ fi
851
+
852
+ local done_personas=false
853
+ while [[ "$done_personas" != "true" ]]; do
854
+ echo ""
855
+ echo "Enabled agents and their personas:"
856
+ echo ""
857
+
858
+ local menu_idx=1
859
+ local agent_list=() # Track: "type|index" (e.g., "cli|0", "api|2")
860
+
861
+ # List CLI agents
862
+ for i in "${!CLI_AGENT_NAMES[@]}"; do
863
+ if [[ "${CLI_ENABLED[$i]}" == "true" ]]; then
864
+ local name="${CLI_AGENT_NAMES[$i]}"
865
+ local persona_id="${CLI_PERSONA_IDS[$i]}"
866
+ local persona_name
867
+ persona_name=$(get_persona_by_id "$persona_id" "name" 2>/dev/null || echo "Unknown")
868
+ printf " %2s) %-12s - %s\n" "$menu_idx" "$name" "$persona_name"
869
+ agent_list+=("cli|$i")
870
+ ((menu_idx++)) || true
871
+ fi
872
+ done
873
+
874
+ # List API agents
875
+ for i in "${!API_AGENT_NAMES[@]}"; do
876
+ if [[ "${API_ENABLED[$i]}" == "true" ]]; then
877
+ local name="${API_AGENT_NAMES[$i]}"
878
+ local persona_id="${API_PERSONA_IDS[$i]}"
879
+ local persona_name
880
+ persona_name=$(get_persona_by_id "$persona_id" "name" 2>/dev/null || echo "Unknown")
881
+ printf " %2s) %-12s - %s\n" "$menu_idx" "$name" "$persona_name"
882
+ agent_list+=("api|$i")
883
+ ((menu_idx++)) || true
884
+ fi
885
+ done
886
+
887
+ # List custom CLI agents
888
+ for i in "${!CUSTOM_NAMES[@]}"; do
889
+ local name="${CUSTOM_NAMES[$i]}"
890
+ local persona_id="${CUSTOM_PERSONA_IDS[$i]:-1}"
891
+ local persona_name
892
+ persona_name=$(get_persona_by_id "$persona_id" "name" 2>/dev/null || echo "Custom")
893
+ printf " %2s) %-12s - %s (custom)\n" "$menu_idx" "$name" "$persona_name"
894
+ agent_list+=("custom_cli|$i")
895
+ ((menu_idx++)) || true
896
+ done
897
+
898
+ # List custom API agents
899
+ for i in "${!CUSTOM_API_NAMES[@]}"; do
900
+ local name="${CUSTOM_API_NAMES[$i]}"
901
+ local persona_id="${CUSTOM_API_PERSONA_IDS[$i]:-1}"
902
+ local persona_name
903
+ persona_name=$(get_persona_by_id "$persona_id" "name" 2>/dev/null || echo "Custom")
904
+ printf " %2s) %-12s - %s (custom API)\n" "$menu_idx" "$name" "$persona_name"
905
+ agent_list+=("custom_api|$i")
906
+ ((menu_idx++)) || true
907
+ done
908
+
909
+ echo ""
910
+ echo " d) Done with persona configuration"
911
+ echo ""
912
+
913
+ read -r -p "Select agent to change persona (or 'd' for done): " choice
914
+
915
+ if [[ "$choice" == "d" || "$choice" == "D" ]]; then
916
+ done_personas=true
917
+ continue
918
+ fi
919
+
920
+ # Validate selection
921
+ if ! [[ "$choice" =~ ^[0-9]+$ ]] || [[ $choice -lt 1 ]] || [[ $choice -gt ${#agent_list[@]} ]]; then
922
+ log_warn "Invalid selection"
923
+ continue
924
+ fi
925
+
926
+ # Get selected agent info
927
+ local selected="${agent_list[$((choice-1))]}"
928
+ local agent_type="${selected%%|*}"
929
+ local agent_idx="${selected##*|}"
930
+
931
+ local agent_name
932
+ case "$agent_type" in
933
+ cli) agent_name="${CLI_AGENT_NAMES[$agent_idx]}" ;;
934
+ api) agent_name="${API_AGENT_NAMES[$agent_idx]}" ;;
935
+ custom_cli) agent_name="${CUSTOM_NAMES[$agent_idx]}" ;;
936
+ custom_api) agent_name="${CUSTOM_API_NAMES[$agent_idx]}" ;;
937
+ esac
938
+
939
+ # Show persona selection menu
940
+ _select_persona_for_agent "$agent_type" "$agent_idx" "$agent_name"
941
+ done
942
+
943
+ log_success "Persona configuration complete"
944
+ }
945
+
946
+ # Internal: Select a persona for a specific agent
947
+ _select_persona_for_agent() {
948
+ local agent_type="$1"
949
+ local agent_idx="$2"
950
+ local agent_name="$3"
951
+
952
+ echo ""
953
+ echo "Select persona for $agent_name:"
954
+ echo ""
955
+
956
+ # Get current persona ID
957
+ local current_id
958
+ case "$agent_type" in
959
+ cli) current_id="${CLI_PERSONA_IDS[$agent_idx]}" ;;
960
+ api) current_id="${API_PERSONA_IDS[$agent_idx]}" ;;
961
+ custom_cli) current_id="${CUSTOM_PERSONA_IDS[$agent_idx]:-1}" ;;
962
+ custom_api) current_id="${CUSTOM_API_PERSONA_IDS[$agent_idx]:-1}" ;;
963
+ esac
964
+
965
+ # Display persona catalog
966
+ echo "$PERSONA_CATALOG" | grep -v '^$' | while IFS='|' read -r id name var desc; do
967
+ local marker=" "
968
+ [[ "$id" == "$current_id" ]] && marker="* "
969
+ printf " %s%2s) %-22s - %s\n" "$marker" "$id" "$name" "$desc"
970
+ done
971
+
972
+ echo ""
973
+ echo " c) Enter custom persona text"
974
+ echo ""
975
+
976
+ read -r -p "Choice [$current_id]: " persona_choice
977
+ persona_choice="${persona_choice:-$current_id}"
978
+
979
+ if [[ "$persona_choice" == "c" || "$persona_choice" == "C" ]]; then
980
+ prompt_input "Enter custom persona description" ""
981
+ local custom_text="$REPLY"
982
+ if [[ -n "$custom_text" ]]; then
983
+ # For custom text, we store it differently - use ID 0 to indicate custom
984
+ case "$agent_type" in
985
+ cli)
986
+ CLI_PERSONA_IDS[$agent_idx]="0"
987
+ CLI_AGENT_PERSONAS[$agent_idx]="$custom_text"
988
+ ;;
989
+ api)
990
+ API_PERSONA_IDS[$agent_idx]="0"
991
+ API_AGENT_PERSONAS[$agent_idx]="$custom_text"
992
+ ;;
993
+ custom_cli)
994
+ CUSTOM_PERSONA_IDS[$agent_idx]="0"
995
+ CUSTOM_PERSONAS[$agent_idx]="$custom_text"
996
+ ;;
997
+ custom_api)
998
+ CUSTOM_API_PERSONA_IDS[$agent_idx]="0"
999
+ CUSTOM_API_PERSONAS[$agent_idx]="$custom_text"
1000
+ ;;
1001
+ esac
1002
+ log_success "$agent_name: Custom persona set"
1003
+ fi
1004
+ return
1005
+ fi
1006
+
1007
+ # Validate persona ID selection
1008
+ if [[ "$persona_choice" =~ ^[0-9]+$ ]] && [[ $persona_choice -ge 1 ]] && [[ $persona_choice -le 15 ]]; then
1009
+ case "$agent_type" in
1010
+ cli) CLI_PERSONA_IDS[$agent_idx]="$persona_choice" ;;
1011
+ api) API_PERSONA_IDS[$agent_idx]="$persona_choice" ;;
1012
+ custom_cli)
1013
+ # Ensure array is large enough
1014
+ while [[ ${#CUSTOM_PERSONA_IDS[@]} -le $agent_idx ]]; do
1015
+ CUSTOM_PERSONA_IDS+=("1")
1016
+ done
1017
+ CUSTOM_PERSONA_IDS[$agent_idx]="$persona_choice"
1018
+ ;;
1019
+ custom_api)
1020
+ while [[ ${#CUSTOM_API_PERSONA_IDS[@]} -le $agent_idx ]]; do
1021
+ CUSTOM_API_PERSONA_IDS+=("1")
1022
+ done
1023
+ CUSTOM_API_PERSONA_IDS[$agent_idx]="$persona_choice"
1024
+ ;;
1025
+ esac
1026
+ local new_name
1027
+ new_name=$(get_persona_by_id "$persona_choice" "name")
1028
+ log_success "$agent_name: Persona changed to $new_name"
1029
+ else
1030
+ log_warn "Invalid selection, keeping current persona"
1031
+ fi
1032
+ }
1033
+
1034
+ # =============================================================================
1035
+ # MAIN
1036
+ # =============================================================================
1037
+
1038
+ main() {
1039
+ print_header "AI Consultants v2.0 - Configuration Wizard"
1040
+
1041
+ echo "This wizard will help you configure AI Consultants."
1042
+ echo "You need at least 2 agents enabled (CLI or API-based)."
1043
+ echo ""
1044
+
1045
+ # Step 1: Detect CLI agents
1046
+ detect_cli_agents
1047
+
1048
+ # Step 2: Select CLI agents
1049
+ select_cli_agents
1050
+
1051
+ # Step 3: Configure API agents
1052
+ configure_api_agents
1053
+
1054
+ # Step 4: Configure personas
1055
+ configure_personas
1056
+
1057
+ # Step 5: Validate (minimum 2 agents)
1058
+ if ! validate_configuration; then
1059
+ log_error "Configuration incomplete. At least 2 agents required."
1060
+ exit 1
1061
+ fi
1062
+
1063
+ # Step 6: Save
1064
+ if [[ "$NON_INTERACTIVE" == "true" ]] || confirm "Save configuration to $OUTPUT_FILE?" "y"; then
1065
+ save_configuration
1066
+ else
1067
+ log_warn "Configuration not saved."
1068
+ exit 1
1069
+ fi
1070
+
1071
+ print_header "Configuration Complete"
1072
+
1073
+ # Show summary
1074
+ echo "Enabled agents:"
1075
+ for i in "${!CLI_AGENT_NAMES[@]}"; do
1076
+ [[ "${CLI_ENABLED[$i]}" == "true" ]] && echo " [CLI] ${CLI_AGENT_NAMES[$i]}"
1077
+ done
1078
+ for name in ${CUSTOM_NAMES[@]+"${CUSTOM_NAMES[@]}"}; do echo " [CLI] $name (custom)"; done
1079
+ for i in "${!API_AGENT_NAMES[@]}"; do
1080
+ [[ "${API_ENABLED[$i]}" == "true" ]] && echo " [API] ${API_AGENT_NAMES[$i]}"
1081
+ done
1082
+ for name in ${CUSTOM_API_NAMES[@]+"${CUSTOM_API_NAMES[@]}"}; do echo " [API] $name (custom)"; done
1083
+
1084
+ echo ""
1085
+ echo "Next steps:"
1086
+ echo " 1. Review and edit $OUTPUT_FILE if needed"
1087
+ echo " 2. Run: source $OUTPUT_FILE"
1088
+ echo " 3. Test: ./scripts/preflight_check.sh"
1089
+ echo " 4. Start: ./scripts/consult_all.sh \"Your question\""
1090
+ echo ""
1091
+ }
1092
+
1093
+ main "$@"