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,372 @@
1
+ #!/bin/bash
2
+ # personas.sh - Consultant personality definitions for AI Consultants v2.0
3
+ #
4
+ # Each consultant has a unique persona that shapes their response style:
5
+ # - Gemini: The Architect - Focus on design, scalability, enterprise patterns
6
+ # - Codex: The Pragmatist - Focus on simplicity, quick wins, proven solutions
7
+ # - Mistral: The Devil's Advocate - Actively seeks problems, edge cases, risks
8
+ # - Kilo: The Innovator - Creative solutions, unconventional approaches
9
+ # - Cursor: The Integrator - Full-stack perspective, cross-cutting concerns
10
+
11
+ # =============================================================================
12
+ # PERSONA DEFINITIONS
13
+ # =============================================================================
14
+
15
+ # System prompt prefix for Gemini - The Architect (token-optimized v2.1)
16
+ PERSONA_GEMINI='Role: The Architect. Focus: scalable design, enterprise patterns, modularity, performance, security.
17
+ Priorities: long-term maintainability, industry standards, separation of concerns.
18
+ Always address: scaling trade-offs, integration points, architectural impact.'
19
+
20
+ # System prompt prefix for Codex - The Pragmatist (token-optimized v2.1)
21
+ PERSONA_CODEX='Role: The Pragmatist. Focus: simplicity, quick wins, proven solutions, clean code.
22
+ Priorities: YAGNI, readability, incremental implementation, battle-tested approaches.
23
+ Always prefer: simplest working solution, avoiding over-engineering and premature optimization.'
24
+
25
+ # System prompt prefix for Mistral - The Devil's Advocate (token-optimized v2.1)
26
+ PERSONA_MISTRAL='Role: The Devil'\''s Advocate. Focus: finding problems, edge cases, security vulnerabilities, risks.
27
+ Priorities: challenge assumptions, identify failure scenarios, expose technical debt.
28
+ Always ask: what could go wrong? unvalidated assumptions? single points of failure? attack vectors?'
29
+
30
+ # System prompt prefix for Kilo - The Innovator (token-optimized v2.1)
31
+ PERSONA_KILO='Role: The Innovator. Focus: creative solutions, emerging tech, unconventional approaches.
32
+ Priorities: elegant simplification, modern patterns, bold ideas, alternative paradigms.
33
+ Always explore: novel approaches others overlook, ways to rethink the problem, future trends.'
34
+
35
+ # System prompt prefix for Cursor - The Integrator (token-optimized v2.1)
36
+ PERSONA_CURSOR='Role: The Integrator. Focus: full-stack perspective, cross-cutting concerns, system-wide consistency.
37
+ Priorities: logging/monitoring/error handling, frontend-backend integration, developer experience.
38
+ Always consider: system-wide impact, integration points, testing across layers, onboarding.'
39
+
40
+ # System prompt prefix for Aider - The Pair Programmer (token-optimized v2.1)
41
+ PERSONA_AIDER='Role: The Pair Programmer. Focus: collaborative coding, step-by-step implementation, code organization.
42
+ Priorities: clear explanations, atomic commits, git-aware changes, reviewable diffs.
43
+ Always: explain changes, keep code clean, make small incremental steps.'
44
+
45
+ # System prompt prefix for Claude - The Synthesizer (token-optimized v2.2)
46
+ PERSONA_CLAUDE='Role: The Synthesizer. Focus: big picture thinking, connecting ideas across domains, distilling complexity.
47
+ Priorities: coherent synthesis, holistic understanding, actionable insights, nuanced analysis.
48
+ Always: see connections others miss, bridge different perspectives, provide clear summaries.'
49
+
50
+ # System prompt prefix for Amp - The Systems Thinker (token-optimized v2.8)
51
+ PERSONA_AMP='Role: The Systems Thinker. Focus: holistic system design, component interactions, emergent behaviors.
52
+ Priorities: understand dependencies, identify feedback loops, predict cascading effects.
53
+ Always consider: how parts interact, system boundaries, resilience patterns, failure propagation.'
54
+
55
+ # System prompt prefix for Kimi - The Eastern Sage (token-optimized v2.9)
56
+ PERSONA_KIMI='Role: The Eastern Sage. Focus: holistic understanding, balance of perspectives, wisdom from diverse viewpoints.
57
+ Priorities: consider multiple angles, find harmony in contradictions, synthesize Eastern and Western approaches.
58
+ Always seek: deeper patterns, balanced solutions, wisdom that transcends immediate technical concerns.'
59
+
60
+ # System prompt prefix for Qwen3 - The Analyst (API-based, token-optimized v2.1)
61
+ PERSONA_QWEN3='Role: The Analyst. Focus: data-driven decisions, pattern recognition, performance profiling.
62
+ Priorities: measurable outcomes, quantitative comparisons, evidence-based recommendations.
63
+ Always provide: metrics, benchmarks, statistical reasoning, data-backed trade-offs.'
64
+
65
+ # System prompt prefix for GLM - The Methodologist (API-based, token-optimized v2.1)
66
+ PERSONA_GLM='Role: The Methodologist. Focus: systematic approaches, structured problem-solving, process standardization.
67
+ Priorities: clear procedural steps, verification checkpoints, edge case coverage.
68
+ Always emphasize: reproducible workflows, documentation of assumptions, validation criteria.'
69
+
70
+ # System prompt prefix for Grok - The Provocateur (API-based, token-optimized v2.1)
71
+ PERSONA_GROK='Role: The Provocateur. Focus: challenging conventions, radical alternatives, paradigm shifts.
72
+ Priorities: question "best practices", expose hidden complexity, break rules when beneficial.
73
+ Always consider: why conventional approach might be wrong, hidden costs of following the crowd.'
74
+
75
+ # System prompt prefix for DeepSeek - The Code Specialist (API-based, token-optimized v2.1)
76
+ PERSONA_DEEPSEEK='Role: The Code Specialist. Focus: code generation, algorithm design, multi-language best practices.
77
+ Priorities: clean efficient code, right data structures, language-specific idioms.
78
+ Always provide: working code examples, reasoning behind implementation choices.'
79
+
80
+ # System prompt prefix for MiniMax - The Pragmatic Optimizer (API-based, token-optimized v2.10)
81
+ PERSONA_MINIMAX='Role: The Pragmatic Optimizer. Focus: practical efficiency, performance optimization, real-world constraints.
82
+ Priorities: measurable results, avoiding over-engineering, quick implementations, cost-effectiveness.
83
+ Always consider: performance impact, memory usage, implementation complexity vs benefit.'
84
+
85
+ # System prompt prefix for The Mentor (token-optimized v2.1)
86
+ PERSONA_MENTOR='Role: The Mentor. Focus: teaching, knowledge transfer, building understanding.
87
+ Priorities: explain why not just how, build mental models, identify learning opportunities.
88
+ Always: progress from simple to complex, highlight common pitfalls, empower future problem-solving.'
89
+
90
+ # System prompt prefix for The Optimizer (token-optimized v2.1)
91
+ PERSONA_OPTIMIZER='Role: The Optimizer. Focus: performance, efficiency, bottleneck identification.
92
+ Priorities: time/space complexity, memory patterns, caching strategies, parallelization.
93
+ Always analyze: CPU/memory/IO characteristics, performance vs readability trade-offs, profiling strategies.'
94
+
95
+ # System prompt prefix for The Security Expert (token-optimized v2.1)
96
+ PERSONA_SECURITY='Role: The Security Expert. Focus: threat modeling, attack surface analysis, secure coding.
97
+ Priorities: input validation, auth patterns, defense in depth, least privilege.
98
+ Always evaluate: OWASP Top 10, data exposure, crypto choices, compliance requirements.'
99
+
100
+ # System prompt prefix for The Minimalist (token-optimized v2.1)
101
+ PERSONA_MINIMALIST='Role: The Minimalist. Focus: eliminating complexity, questioning every abstraction.
102
+ Priorities: prefer deletion over addition, simplest working solution, code that fits in your head.
103
+ Always ask: what can we remove? is this earning its complexity? are we solving the right problem?'
104
+
105
+ # System prompt prefix for The DX Advocate (token-optimized v2.1)
106
+ PERSONA_DX='Role: The DX Advocate. Focus: developer experience, intuitive APIs, helpful error messages.
107
+ Priorities: reduce friction, guide developers to solutions, smooth onboarding paths.
108
+ Always consider: learning curves, common mistakes prevention, IDE support, debugging experience.'
109
+
110
+ # System prompt prefix for The Debugger (token-optimized v2.1)
111
+ PERSONA_DEBUGGER='Role: The Debugger. Focus: root cause analysis, systematic hypothesis testing, log interpretation.
112
+ Priorities: reproduce-isolate-fix methodology, identify real problem vs symptoms.
113
+ Always ask: what changed? can we reproduce? what do logs say? which assumptions are wrong?'
114
+
115
+ # System prompt prefix for The Reviewer (token-optimized v2.1)
116
+ PERSONA_REVIEWER='Role: The Reviewer. Focus: code quality, project conventions, constructive feedback.
117
+ Priorities: maintainability, test coverage, documentation completeness, future developer experience.
118
+ Always evaluate: follows patterns? easy to modify? edge cases handled? intent clear? new team member perspective?'
119
+
120
+ # =============================================================================
121
+ # OUTPUT FORMAT INSTRUCTION
122
+ # =============================================================================
123
+
124
+ # Instruction to force structured JSON output with confidence (token-optimized v2.1)
125
+ OUTPUT_FORMAT_INSTRUCTION='Respond ONLY in valid JSON:
126
+ {"response":{"summary":"<2-3 sentences max 500 chars>","detailed":"<full response>","approach":"<name>","pros":[],"cons":[],"caveats":[]},"confidence":{"score":<1-10>,"reasoning":"<why>"}}
127
+ Score: 1-3=uncertain, 4-6=moderate, 7-9=confident, 10=certain.
128
+ Optional fields: code_snippets[{language,code,description}], alternatives[{name,reason_not_chosen}], uncertainty_factors[].
129
+ No text outside JSON.'
130
+
131
+ # =============================================================================
132
+ # PERSONA CATALOG
133
+ # =============================================================================
134
+
135
+ # Complete catalog of available personas
136
+ # Format: ID|Name|Variable|Short description
137
+ PERSONA_CATALOG="
138
+ 1|The Architect|PERSONA_GEMINI|Design patterns, scalability, enterprise
139
+ 2|The Pragmatist|PERSONA_CODEX|Simplicity, quick wins, proven solutions
140
+ 3|The Devil's Advocate|PERSONA_MISTRAL|Edge cases, risks, security
141
+ 4|The Innovator|PERSONA_KILO|Creative solutions, new technologies
142
+ 5|The Integrator|PERSONA_CURSOR|Full-stack, cross-cutting concerns
143
+ 6|The Analyst|PERSONA_QWEN3|Data-driven, metrics, performance
144
+ 7|The Methodologist|PERSONA_GLM|Structured approaches, processes
145
+ 8|The Provocateur|PERSONA_GROK|Challenge conventions, radical alternatives
146
+ 9|The Mentor|PERSONA_MENTOR|Teaching, explanations, learning focus
147
+ 10|The Optimizer|PERSONA_OPTIMIZER|Performance, efficiency, resource usage
148
+ 11|The Security Expert|PERSONA_SECURITY|Security-first, vulnerabilities, hardening
149
+ 12|The Minimalist|PERSONA_MINIMALIST|Less is more, essential features only
150
+ 13|The DX Advocate|PERSONA_DX|Developer experience, ergonomics, tooling
151
+ 14|The Debugger|PERSONA_DEBUGGER|Root cause analysis, troubleshooting
152
+ 15|The Reviewer|PERSONA_REVIEWER|Code review, best practices, quality
153
+ 16|The Pair Programmer|PERSONA_AIDER|Collaborative coding, step-by-step
154
+ 17|The Code Specialist|PERSONA_DEEPSEEK|Code generation, algorithms, multi-language
155
+ 18|The Synthesizer|PERSONA_CLAUDE|Big picture, connecting ideas, synthesis
156
+ 19|The Systems Thinker|PERSONA_AMP|System design, interactions, emergent behavior
157
+ 20|The Eastern Sage|PERSONA_KIMI|Holistic understanding, balanced perspectives
158
+ 21|The Pragmatic Optimizer|PERSONA_MINIMAX|Performance, efficiency, pragmatism
159
+ "
160
+
161
+ # =============================================================================
162
+ # CATALOG FUNCTIONS
163
+ # =============================================================================
164
+
165
+ # List all available personas
166
+ # Usage: list_personas
167
+ list_personas() {
168
+ echo "Available Personas:"
169
+ echo ""
170
+ echo "$PERSONA_CATALOG" | grep -v '^$' | while IFS='|' read -r id name var desc; do
171
+ printf " %2s) %-22s - %s\n" "$id" "$name" "$desc"
172
+ done
173
+ }
174
+
175
+ # Get persona info by ID
176
+ # Usage: get_persona_by_id <id> [field]
177
+ # Fields: name, var, desc, all (default: all)
178
+ get_persona_by_id() {
179
+ local id="$1"
180
+ local field="${2:-all}"
181
+
182
+ local match
183
+ match=$(echo "$PERSONA_CATALOG" | grep "^${id}|" | head -1)
184
+
185
+ if [[ -z "$match" ]]; then
186
+ return 1
187
+ fi
188
+
189
+ case "$field" in
190
+ name) echo "$match" | cut -d'|' -f2 ;;
191
+ var) echo "$match" | cut -d'|' -f3 ;;
192
+ desc) echo "$match" | cut -d'|' -f4 ;;
193
+ all) echo "$match" ;;
194
+ esac
195
+ }
196
+
197
+ # Get persona ID by name
198
+ # Usage: get_persona_id_by_name "The Architect"
199
+ get_persona_id_by_name() {
200
+ local name="$1"
201
+ local match
202
+ match=$(echo "$PERSONA_CATALOG" | grep "|${name}|" | head -1)
203
+
204
+ if [[ -n "$match" ]]; then
205
+ echo "$match" | cut -d'|' -f1
206
+ else
207
+ return 1
208
+ fi
209
+ }
210
+
211
+ # Get persona prompt content by ID
212
+ # Usage: get_persona_content_by_id <id>
213
+ get_persona_content_by_id() {
214
+ local id="$1"
215
+ local var_name
216
+ var_name=$(get_persona_by_id "$id" "var")
217
+
218
+ if [[ -n "$var_name" ]]; then
219
+ echo "${!var_name}"
220
+ else
221
+ return 1
222
+ fi
223
+ }
224
+
225
+ # =============================================================================
226
+ # HELPER FUNCTIONS
227
+ # =============================================================================
228
+
229
+ # Internal lookup table for agent defaults (maps agent to default persona ID)
230
+ _AGENT_DEFAULT_PERSONAS="
231
+ GEMINI|1
232
+ CODEX|2
233
+ MISTRAL|3
234
+ KILO|4
235
+ CURSOR|5
236
+ AIDER|16
237
+ AMP|19
238
+ KIMI|20
239
+ CLAUDE|18
240
+ QWEN3|6
241
+ GLM|17
242
+ GROK|8
243
+ DEEPSEEK|7
244
+ MINIMAX|21
245
+ "
246
+
247
+ # Internal: Resolve persona ID for a consultant
248
+ # Returns the effective persona ID (explicit, or default)
249
+ # Usage: _resolve_persona_id "GEMINI"
250
+ _resolve_persona_id() {
251
+ local upper="$1"
252
+
253
+ # Check explicit persona ID
254
+ local persona_id_var="${upper}_PERSONA_ID"
255
+ local persona_id="${!persona_id_var:-}"
256
+ if [[ -n "$persona_id" ]]; then
257
+ echo "$persona_id"
258
+ return 0
259
+ fi
260
+
261
+ # Check default
262
+ local default_match
263
+ default_match=$(echo "$_AGENT_DEFAULT_PERSONAS" | grep "^${upper}|" | head -1)
264
+ if [[ -n "$default_match" ]]; then
265
+ echo "$default_match" | cut -d'|' -f2
266
+ return 0
267
+ fi
268
+
269
+ return 1
270
+ }
271
+
272
+ # Internal: Normalize consultant name to uppercase
273
+ _normalize_name() {
274
+ echo "$1" | tr '[:lower:]' '[:upper:]' | tr -d ' -'
275
+ }
276
+
277
+ # Get the persona prompt for a specific consultant
278
+ # Usage: get_persona "Gemini"
279
+ # Priority: 1) {AGENT}_PERSONA_ID, 2) {AGENT}_PERSONA, 3) default from catalog
280
+ get_persona() {
281
+ local consultant="$1"
282
+ local upper
283
+ upper=$(_normalize_name "$consultant")
284
+
285
+ # Check for explicit persona ID first
286
+ local persona_id
287
+ persona_id=$(_resolve_persona_id "$upper")
288
+ if [[ -n "$persona_id" ]]; then
289
+ local content
290
+ content=$(get_persona_content_by_id "$persona_id")
291
+ if [[ -n "$content" ]]; then
292
+ echo "$content"
293
+ return
294
+ fi
295
+ fi
296
+
297
+ # Check for custom persona text
298
+ local persona_var="${upper}_PERSONA"
299
+ local custom_persona="${!persona_var:-}"
300
+ if [[ -n "$custom_persona" ]]; then
301
+ echo "$custom_persona"
302
+ return
303
+ fi
304
+
305
+ # Fallback: generic persona
306
+ echo "You are an AI consultant providing expert technical advice.
307
+ Focus on clarity, accuracy, and actionable recommendations.
308
+ Consider trade-offs and provide balanced analysis."
309
+ }
310
+
311
+ # Get persona name/title for a consultant
312
+ # Usage: get_persona_name "Gemini"
313
+ get_persona_name() {
314
+ local consultant="$1"
315
+ local upper
316
+ upper=$(_normalize_name "$consultant")
317
+
318
+ # Check for explicit persona ID
319
+ local persona_id
320
+ persona_id=$(_resolve_persona_id "$upper")
321
+ if [[ -n "$persona_id" ]]; then
322
+ local name
323
+ name=$(get_persona_by_id "$persona_id" "name")
324
+ if [[ -n "$name" ]]; then
325
+ echo "$name"
326
+ return
327
+ fi
328
+ fi
329
+
330
+ # Check for custom persona name
331
+ local name_var="${upper}_PERSONA_NAME"
332
+ local custom_name="${!name_var:-}"
333
+ if [[ -n "$custom_name" ]]; then
334
+ echo "$custom_name"
335
+ return
336
+ fi
337
+
338
+ echo "External Consultant"
339
+ }
340
+
341
+ # Get persona ID for a consultant (for configuration display)
342
+ # Usage: get_persona_id "Gemini"
343
+ get_persona_id() {
344
+ local upper
345
+ upper=$(_normalize_name "$1")
346
+ _resolve_persona_id "$upper"
347
+ }
348
+
349
+ # Build complete system prompt with persona + output format
350
+ # Usage: build_system_prompt "Gemini"
351
+ build_system_prompt() {
352
+ local consultant="$1"
353
+ local persona=$(get_persona "$consultant")
354
+
355
+ echo "${persona}
356
+
357
+ ${OUTPUT_FORMAT_INSTRUCTION}"
358
+ }
359
+
360
+ # Build complete query with system prompt prepended
361
+ # Usage: build_query_with_persona "Gemini" "original query"
362
+ build_query_with_persona() {
363
+ local consultant="$1"
364
+ local query="$2"
365
+ local system_prompt=$(build_system_prompt "$consultant")
366
+
367
+ echo "# System Instructions
368
+ ${system_prompt}
369
+
370
+ # User Query
371
+ ${query}"
372
+ }
@@ -0,0 +1,251 @@
1
+ #!/bin/bash
2
+ # progress.sh - Progress bars and interactive display for AI Consultants v2.0
3
+ #
4
+ # Shows progress bars for each consultant during consultations.
5
+
6
+ # =============================================================================
7
+ # CONFIGURATION
8
+ # =============================================================================
9
+
10
+ # Characters for progress bar
11
+ BAR_FILLED="█"
12
+ BAR_EMPTY="░"
13
+ BAR_WIDTH=20
14
+
15
+ # Colors (ANSI)
16
+ COLOR_RESET="\033[0m"
17
+ COLOR_GREEN="\033[0;32m"
18
+ COLOR_YELLOW="\033[0;33m"
19
+ COLOR_RED="\033[0;31m"
20
+ COLOR_BLUE="\033[0;34m"
21
+ COLOR_CYAN="\033[0;36m"
22
+ COLOR_DIM="\033[0;90m"
23
+
24
+ # =============================================================================
25
+ # PROGRESS STATE
26
+ # =============================================================================
27
+ # Using map_* functions from common.sh for bash 3.2 compatibility
28
+ # Maps: PROGRESS_PERCENT, PROGRESS_STATUS, PROGRESS_START_TIME
29
+
30
+ # Initialize progress for a consultant
31
+ # Usage: init_progress <consultant>
32
+ init_progress() {
33
+ local consultant="$1"
34
+ map_set "PROGRESS_PERCENT" "$consultant" "0"
35
+ map_set "PROGRESS_STATUS" "$consultant" "starting"
36
+ map_set "PROGRESS_START_TIME" "$consultant" "$(date +%s)"
37
+ }
38
+
39
+ # Update progress
40
+ # Usage: update_progress <consultant> <percent> [status]
41
+ update_progress() {
42
+ local consultant="$1"
43
+ local percent="$2"
44
+ local status="${3:-running}"
45
+
46
+ map_set "PROGRESS_PERCENT" "$consultant" "$percent"
47
+ map_set "PROGRESS_STATUS" "$consultant" "$status"
48
+ }
49
+
50
+ # =============================================================================
51
+ # DISPLAY FUNCTIONS
52
+ # =============================================================================
53
+
54
+ # Generate progress bar string
55
+ # Usage: generate_bar <percent>
56
+ generate_bar() {
57
+ local percent=$1
58
+ local filled=$((percent * BAR_WIDTH / 100))
59
+ local empty=$((BAR_WIDTH - filled))
60
+
61
+ local bar=""
62
+ for ((i=0; i<filled; i++)); do
63
+ bar+="$BAR_FILLED"
64
+ done
65
+ for ((i=0; i<empty; i++)); do
66
+ bar+="$BAR_EMPTY"
67
+ done
68
+
69
+ echo "$bar"
70
+ }
71
+
72
+ # Get status icon
73
+ # Usage: get_status_icon <status>
74
+ get_status_icon() {
75
+ local status="$1"
76
+ case "$status" in
77
+ starting) echo "⏳" ;;
78
+ running) echo "🔄" ;;
79
+ success) echo "✅" ;;
80
+ failed) echo "❌" ;;
81
+ timeout) echo "⏰" ;;
82
+ skipped) echo "⏭️" ;;
83
+ *) echo "❓" ;;
84
+ esac
85
+ }
86
+
87
+ # Get color for status
88
+ # Usage: get_status_color <status>
89
+ get_status_color() {
90
+ local status="$1"
91
+ case "$status" in
92
+ success) echo "$COLOR_GREEN" ;;
93
+ failed|timeout) echo "$COLOR_RED" ;;
94
+ running) echo "$COLOR_BLUE" ;;
95
+ starting) echo "$COLOR_YELLOW" ;;
96
+ *) echo "$COLOR_RESET" ;;
97
+ esac
98
+ }
99
+
100
+ # Calculate elapsed time
101
+ # Usage: get_elapsed <consultant>
102
+ get_elapsed() {
103
+ local consultant="$1"
104
+ local start
105
+ start=$(map_get "PROGRESS_START_TIME" "$consultant")
106
+ start="${start:-$(date +%s)}"
107
+ local now=$(date +%s)
108
+ local elapsed=$((now - start))
109
+ echo "${elapsed}s"
110
+ }
111
+
112
+ # Render a single progress line
113
+ # Usage: render_progress_line <consultant>
114
+ render_progress_line() {
115
+ local consultant="$1"
116
+ local percent status
117
+ percent=$(map_get "PROGRESS_PERCENT" "$consultant")
118
+ percent="${percent:-0}"
119
+ status=$(map_get "PROGRESS_STATUS" "$consultant")
120
+ status="${status:-starting}"
121
+
122
+ local bar=$(generate_bar "$percent")
123
+ local icon=$(get_status_icon "$status")
124
+ local color=$(get_status_color "$status")
125
+ local elapsed=$(get_elapsed "$consultant")
126
+
127
+ printf " ${color}[%-8s]${COLOR_RESET} %s %3d%% %s ${COLOR_DIM}(%s)${COLOR_RESET}\n" \
128
+ "$consultant" "$bar" "$percent" "$icon" "$elapsed"
129
+ }
130
+
131
+ # Render all progress bars
132
+ # Usage: render_all_progress
133
+ render_all_progress() {
134
+ local consultants=("Gemini" "Codex" "Mistral" "Kilo" "Cursor")
135
+
136
+ echo ""
137
+ echo " Progress:"
138
+ echo ""
139
+
140
+ for c in "${consultants[@]}"; do
141
+ local status
142
+ status=$(map_get "PROGRESS_STATUS" "$c")
143
+ if [[ -n "$status" ]]; then
144
+ render_progress_line "$c"
145
+ fi
146
+ done
147
+
148
+ echo ""
149
+ }
150
+
151
+ # Update display in-place (for terminals that support ANSI)
152
+ # Usage: update_display
153
+ update_display() {
154
+ # Save cursor position, move up, render, restore
155
+ local num_lines=6 # Header + 4 consultants + footer
156
+
157
+ # Move cursor up
158
+ printf "\033[${num_lines}A"
159
+
160
+ # Clear lines and re-render
161
+ for ((i=0; i<num_lines; i++)); do
162
+ printf "\033[2K" # Clear line
163
+ printf "\033[1B" # Move down
164
+ done
165
+
166
+ # Move back up
167
+ printf "\033[${num_lines}A"
168
+
169
+ # Render
170
+ render_all_progress
171
+ }
172
+
173
+ # =============================================================================
174
+ # SPINNER
175
+ # =============================================================================
176
+
177
+ SPINNER_CHARS=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
178
+ SPINNER_INDEX=0
179
+
180
+ # Advance spinner
181
+ spin() {
182
+ SPINNER_INDEX=$(( (SPINNER_INDEX + 1) % ${#SPINNER_CHARS[@]} ))
183
+ echo "${SPINNER_CHARS[$SPINNER_INDEX]}"
184
+ }
185
+
186
+ # Show spinner with message
187
+ # Usage: show_spinner <message>
188
+ show_spinner() {
189
+ local message="$1"
190
+ printf "\r %s %s" "$(spin)" "$message"
191
+ }
192
+
193
+ # =============================================================================
194
+ # SUMMARY DISPLAY
195
+ # =============================================================================
196
+
197
+ # Show final summary
198
+ # Usage: show_summary <success_count> <total_count> <total_time>
199
+ show_summary() {
200
+ local success="$1"
201
+ local total="$2"
202
+ local time="$3"
203
+
204
+ echo ""
205
+ echo "╔══════════════════════════════════════════════════════════════╗"
206
+ echo "║ Consultation Summary ║"
207
+ echo "╚══════════════════════════════════════════════════════════════╝"
208
+ echo ""
209
+ printf " Consultants: ${COLOR_GREEN}%d${COLOR_RESET}/%d successful\n" "$success" "$total"
210
+ printf " Total time: ${COLOR_CYAN}%s${COLOR_RESET}\n" "$time"
211
+ echo ""
212
+
213
+ # Details per consultant
214
+ for c in Gemini Codex Mistral Kilo Cursor; do
215
+ local status
216
+ status=$(map_get "PROGRESS_STATUS" "$c")
217
+ if [[ -n "$status" ]]; then
218
+ local icon=$(get_status_icon "$status")
219
+ local elapsed=$(get_elapsed "$c")
220
+ printf " %s %-8s: %s (%s)\n" "$icon" "$c" "$status" "$elapsed"
221
+ fi
222
+ done
223
+
224
+ echo ""
225
+ }
226
+
227
+ # =============================================================================
228
+ # INTERACTIVE MODE HELPERS
229
+ # =============================================================================
230
+
231
+ # Show header for interactive consultation
232
+ show_consultation_header() {
233
+ local question="$1"
234
+ local truncated="${question:0:60}"
235
+ [[ ${#question} -gt 60 ]] && truncated+="..."
236
+
237
+ echo ""
238
+ echo "╔══════════════════════════════════════════════════════════════╗"
239
+ echo "║ AI Consultants v2.0 - Live Consultation ║"
240
+ echo "╚══════════════════════════════════════════════════════════════╝"
241
+ echo ""
242
+ echo " Query: $truncated"
243
+ echo ""
244
+ }
245
+
246
+ # Show early termination option message
247
+ show_early_termination_hint() {
248
+ echo ""
249
+ echo " ${COLOR_DIM}Press Ctrl+C to stop early with available responses${COLOR_RESET}"
250
+ echo ""
251
+ }