ai-consultants 2.10.5 → 2.14.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 (63) hide show
  1. package/.claude/commands/ai-consultants:consult.md +18 -15
  2. package/.claude/commands/ai-consultants:debate.md +14 -15
  3. package/CLAUDE.md +155 -18
  4. package/README.md +22 -26
  5. package/SKILL.md +2 -2
  6. package/bin/ai-consultants +99 -1
  7. package/docs/COST_RATES.md +21 -19
  8. package/docs/SMART_ROUTING.md +62 -15
  9. package/docs/cost_rates.json +34 -26
  10. package/docs/releases/v2.10.6.md +59 -0
  11. package/docs/releases/v2.10.7.md +53 -0
  12. package/docs/releases/v2.10.8.md +58 -0
  13. package/docs/releases/v2.10.9.md +123 -0
  14. package/docs/releases/v2.11.0.md +163 -0
  15. package/docs/releases/v2.12.0.md +182 -0
  16. package/docs/releases/v2.13.0.md +179 -0
  17. package/docs/releases/v2.13.1.md +133 -0
  18. package/docs/releases/v2.14.0.md +124 -0
  19. package/docs/releases/v2.14.1.md +70 -0
  20. package/package.json +6 -1
  21. package/references/affinity.json +57 -0
  22. package/references/configuration.md +89 -1
  23. package/references/details.md +13 -0
  24. package/scripts/build_context.sh +96 -36
  25. package/scripts/config.sh +83 -28
  26. package/scripts/configure.sh +32 -30
  27. package/scripts/consult_all.sh +41 -7
  28. package/scripts/doctor.sh +468 -9
  29. package/scripts/hooks/pre-commit +39 -0
  30. package/scripts/install-hooks.sh +49 -0
  31. package/scripts/install.sh +1 -1
  32. package/scripts/lib/api.sh +6 -6
  33. package/scripts/lib/api_query.sh +1 -0
  34. package/scripts/lib/cache.sh +1 -1
  35. package/scripts/lib/chunking.sh +4 -3
  36. package/scripts/lib/code_optimizer.sh +2 -2
  37. package/scripts/lib/common.sh +7 -5
  38. package/scripts/lib/costs.sh +2 -2
  39. package/scripts/lib/progress.sh +2 -2
  40. package/scripts/lib/reflection.sh +2 -2
  41. package/scripts/lib/routing.sh +104 -189
  42. package/scripts/lib/session.sh +4 -3
  43. package/scripts/lib/symbol_map.sh +2 -0
  44. package/scripts/lib/test_helpers.sh +82 -0
  45. package/scripts/lib/user_config.sh +161 -0
  46. package/scripts/lib/voting.sh +1 -1
  47. package/scripts/peer_review.sh +5 -4
  48. package/scripts/preflight_check.sh +19 -442
  49. package/scripts/query_kilo.sh +7 -5
  50. package/scripts/query_ollama.sh +1 -0
  51. package/scripts/setup_wizard.sh +1 -1
  52. package/scripts/test_all.sh +65 -0
  53. package/scripts/test_bin.sh +139 -0
  54. package/scripts/test_context_optimization.sh +300 -0
  55. package/scripts/test_doctor.sh +264 -0
  56. package/scripts/test_fixtures/context/sample.json +13 -0
  57. package/scripts/test_fixtures/context/sample.py +90 -0
  58. package/scripts/test_fixtures/context/sample.sh +66 -0
  59. package/scripts/test_fixtures/context/sample.txt +11 -0
  60. package/scripts/test_routing_parity.sh +180 -0
  61. package/scripts/test_set_e_safety.sh +118 -0
  62. package/scripts/test_suite.sh +4 -4
  63. package/scripts/test_user_config.sh +316 -0
@@ -14,26 +14,28 @@ Query multiple AI models for expert opinions on a coding question.
14
14
 
15
15
  1. If no question provided in $ARGUMENTS, ask the user what they want to consult about.
16
16
 
17
- 2. **File context handling**: Check if $ARGUMENTS contains file paths (tokens containing `/` or extensions like `.ts`, `.js`, `.py`, `.sh`, `.json`, `.yaml`, `.yml`, `.md`, `.go`, `.rs`, `.java`, `.rb`, `.css`, `.html`, `.tsx`, `.jsx`, `.c`, `.cpp`, `.h`).
18
- If file paths are found:
19
- - Extract each file path token from $ARGUMENTS
20
- - Read each file using the **Read** tool
21
- - Build an enriched query by replacing file path tokens with their inline contents:
22
- ```
23
- <original question text without file paths>
17
+ 2. **File context handling**: Identify which strings in $ARGUMENTS refer to files the user wants the consultants to look at. Use your judgment — verify existence via `Glob` or `Bash ls` when uncertain. This replaces fragile regex detection: a `Makefile`, `Dockerfile`, dotfile, or path without a common extension is still a file; an URL or regex pattern in the question text is not.
24
18
 
25
- --- File: path/to/file.ts ---
26
- <file contents>
27
- --- End File ---
28
- ```
29
- - Use this enriched query in step 3 instead of raw $ARGUMENTS
19
+ For each file you identify:
20
+ - Strip the file path from the question text.
21
+ - Decide its relevance tag: `PRIMARY` (the focus of the question — what the consultants should critique) or `CONTEXT` (ambient reference — the consultants should read but not necessarily critique). Default to `PRIMARY` if every referenced file is central.
22
+ - Pass each path as a positional argument to `consult_all.sh` with the syntax `path/to/file@TAG` (omit `@TAG` to default to `PRIMARY`).
23
+
24
+ **Do not inline file contents into the query string.** `build_context.sh` reads files directly from the filesystem and runs the AST optimization pipeline — passing file paths as arguments is what enables it. Inlining defeats the optimization and inflates the consultants' context.
25
+
26
+ **Note (Claude only):** Do not use your `Read` tool to dump file contents into the query. `build_context.sh` handles file reading itself, without the `N\t` line-number prefix that `Read` adds.
30
27
 
31
28
  3. **Run the consultation**:
32
29
  ```bash
33
- cd "${AI_CONSULTANTS_DIR:-$HOME/.claude/skills/ai-consultants}" && INVOKING_AGENT=claude ./scripts/consult_all.sh '<query>'
30
+ cd "${AI_CONSULTANTS_DIR:-$HOME/.claude/skills/ai-consultants}" && INVOKING_AGENT=claude ./scripts/consult_all.sh '<question>' <file1[@TAG]> <file2[@TAG]> ...
34
31
  ```
35
- Replace `<query>` with the enriched query from step 2 (or $ARGUMENTS if no files were detected). Use single quotes around the query to prevent shell expansion of special characters.
36
- **Capture the last line of stdout** — it contains the output directory path (e.g., `/tmp/ai_consultations/20260315_143022_12345/`).
32
+ - `<question>` is the question text with file paths stripped. Use single quotes to prevent shell expansion.
33
+ - Each `<fileN>` is a file path, optionally suffixed with `@PRIMARY` or `@CONTEXT`.
34
+ - **If the question text exceeds ~8KB or contains awkward quoting**, write it to a tmpfile and use `--query-file <path>` instead:
35
+ ```bash
36
+ cd "${AI_CONSULTANTS_DIR:-$HOME/.claude/skills/ai-consultants}" && INVOKING_AGENT=claude ./scripts/consult_all.sh --query-file /tmp/question.txt <file1[@TAG]> ...
37
+ ```
38
+ - **Capture the last line of stdout** — it contains the output directory path (e.g., `/tmp/ai_consultations/20260315_143022_12345/`).
37
39
 
38
40
  4. **Read the results** from the output directory captured in step 3:
39
41
  - Read `<output_dir>/report.md` using the **Read** tool
@@ -85,6 +87,7 @@ Query multiple AI models for expert opinions on a coding question.
85
87
  | `ENABLE_DEBATE=true` | Enable multi-round debate for deeper analysis |
86
88
  | `ENABLE_SMART_ROUTING=true` | Auto-select best consultants for the question type |
87
89
  | `DEBATE_ROUNDS=2` | Number of debate rounds (1-3) |
90
+ | `FORCE_PROJECT_TREE=true` | Include the project tree even for pointed categories (SECURITY, QUICK_SYNTAX, etc.) |
88
91
 
89
92
  ## Follow-up
90
93
 
@@ -21,26 +21,25 @@ Run a multi-round debate where AI consultants critique each other's responses an
21
21
 
22
22
  1. If no question provided in $ARGUMENTS, ask the user what they want to debate.
23
23
 
24
- 2. **File context handling**: Check if $ARGUMENTS contains file paths (tokens containing `/` or extensions like `.ts`, `.js`, `.py`, `.sh`, `.json`, `.yaml`, `.yml`, `.md`, `.go`, `.rs`, `.java`, `.rb`, `.css`, `.html`, `.tsx`, `.jsx`, `.c`, `.cpp`, `.h`).
25
- If file paths are found:
26
- - Extract each file path token from $ARGUMENTS
27
- - Read each file using the **Read** tool
28
- - Build an enriched query by replacing file path tokens with their inline contents:
29
- ```
30
- <original question text without file paths>
24
+ 2. **File context handling**: Identify which strings in $ARGUMENTS refer to files the user wants the consultants to debate over. Use your judgment — verify existence via `Glob` or `Bash ls` when uncertain. A `Makefile`, `Dockerfile`, dotfile, or path without a common extension is still a file; an URL or regex pattern in the question text is not.
31
25
 
32
- --- File: path/to/file.ts ---
33
- <file contents>
34
- --- End File ---
35
- ```
36
- - Use this enriched query in step 3 instead of raw $ARGUMENTS
26
+ For each file you identify:
27
+ - Strip the file path from the question text.
28
+ - Decide its relevance tag: `PRIMARY` (the focus of the debate — what the consultants should critique) or `CONTEXT` (ambient reference — read but not necessarily critiqued). Default to `PRIMARY` if every referenced file is central.
29
+ - Pass each path as a positional argument to `consult_all.sh` with the syntax `path/to/file@TAG` (omit `@TAG` to default to `PRIMARY`).
30
+
31
+ **Do not inline file contents into the query string.** `build_context.sh` reads files directly from the filesystem and runs the AST optimization pipeline.
32
+
33
+ **Note (Claude only):** Do not use your `Read` tool to dump file contents into the query. `build_context.sh` handles file reading itself, without the `N\t` line-number prefix that `Read` adds.
37
34
 
38
35
  3. **Run the debate consultation**:
39
36
  ```bash
40
- cd "${AI_CONSULTANTS_DIR:-$HOME/.claude/skills/ai-consultants}" && INVOKING_AGENT=claude ENABLE_DEBATE=true DEBATE_ROUNDS="${DEBATE_ROUNDS:-2}" ./scripts/consult_all.sh '<query>'
37
+ cd "${AI_CONSULTANTS_DIR:-$HOME/.claude/skills/ai-consultants}" && INVOKING_AGENT=claude ENABLE_DEBATE=true DEBATE_ROUNDS="${DEBATE_ROUNDS:-2}" ./scripts/consult_all.sh '<question>' <file1[@TAG]> <file2[@TAG]> ...
41
38
  ```
42
- Replace `<query>` with the enriched query from step 2 (or $ARGUMENTS if no files were detected). Use single quotes around the query to prevent shell expansion of special characters.
43
- **Capture the last line of stdout** — it contains the output directory path.
39
+ - `<question>` is the question text with file paths stripped. Use single quotes to prevent shell expansion.
40
+ - Each `<fileN>` is a file path, optionally suffixed with `@PRIMARY` or `@CONTEXT`.
41
+ - **If the question text exceeds ~8KB or contains awkward quoting**, write it to a tmpfile and pass `--query-file <path>` instead of the inline question.
42
+ - **Capture the last line of stdout** — it contains the output directory path.
44
43
 
45
44
  4. **Read the results** from the output directory captured in step 3:
46
45
  - Read `<output_dir>/report.md` using the **Read** tool
package/CLAUDE.md CHANGED
@@ -6,7 +6,7 @@ AI Consultants is a multi-model AI deliberation system that queries up to 15 AI
6
6
 
7
7
  **Self-Exclusion**: The invoking agent is automatically excluded from the panel to prevent self-consultation. Claude Code won't query Claude, Codex CLI won't query Codex, etc.
8
8
 
9
- **Version**: 2.10.5
9
+ **Version**: 2.14.1
10
10
 
11
11
  ## Distribution
12
12
 
@@ -47,7 +47,7 @@ ai-consultants/
47
47
  │ ├── debate_round.sh # Multi-Agent Debate
48
48
  │ ├── classify_question.sh # Question classifier
49
49
  │ ├── followup.sh # Follow-up queries
50
- │ ├── preflight_check.sh # Health check
50
+ │ ├── preflight_check.sh # DEPRECATED v2.10.9 (thin wrapper -> doctor.sh)
51
51
  │ └── lib/
52
52
  │ ├── common.sh # Shared utilities (logging, panic mode)
53
53
  │ ├── personas.sh # Consultant persona definitions
@@ -414,9 +414,9 @@ Three tiers of models are available for each consultant, configurable via `apply
414
414
 
415
415
  | Tier | Description | Example Models |
416
416
  |------|-------------|----------------|
417
- | **premium** | Latest flagship models | opus-4.6, gemini-3.1-pro-preview, gpt-5.3-codex |
418
- | **standard** | Good quality at reasonable cost | sonnet-4.6, gemini-3-flash-preview, gpt-5.3 |
419
- | **economy** | Optimized for speed and low cost | haiku-4.5, gemini-2.0-flash, gpt-4o-mini |
417
+ | **premium** | Latest flagship models | claude-opus-4-7, gemini-3.1-pro-preview, gpt-5.5 |
418
+ | **standard** | Good quality at reasonable cost | claude-sonnet-4-6, gemini-3-flash-preview, gpt-5.3 |
419
+ | **economy** | Optimized for speed and low cost | claude-haiku-4-5, gemini-2.0-flash, gpt-4o-mini |
420
420
 
421
421
  **Default models are now premium tier** for maximum quality.
422
422
 
@@ -429,7 +429,7 @@ apply_model_tier "economy" # Set all consultants to economy models
429
429
 
430
430
  # Get model for a specific consultant and tier (v2.8.1)
431
431
  get_model_for_tier "gemini" "premium" # → gemini-3.1-pro-preview
432
- get_model_for_tier "claude" "economy" # → haiku-4.5
432
+ get_model_for_tier "claude" "economy" # → claude-haiku-4-5
433
433
  ```
434
434
 
435
435
  ### Quality Tier Presets
@@ -451,17 +451,17 @@ All consultants now use premium models by default:
451
451
 
452
452
  | Consultant | Default Model |
453
453
  |------------|---------------|
454
- | Claude | opus-4.6 |
454
+ | Claude | claude-opus-4-7 |
455
455
  | Gemini | gemini-3.1-pro-preview |
456
- | Codex | gpt-5.3-codex |
456
+ | Codex | gpt-5.5 |
457
457
  | Mistral | mistral-large-3 |
458
- | Cursor | composer-1.5 |
459
- | DeepSeek | deepseek-reasoner |
458
+ | Cursor | composer-2 |
459
+ | DeepSeek | deepseek-v4-pro |
460
460
  | GLM | glm-5.1 |
461
- | Grok | grok-4.20-0309-reasoning |
461
+ | Grok | grok-4.3 |
462
462
  | Qwen3 | qwen3.6-plus |
463
463
  | Kimi | kimi-code/kimi-for-coding |
464
- | Aider | gpt-5.3-codex |
464
+ | Aider | nvidia/nemotron-3-super-120b-a12b:free |
465
465
  | MiniMax | MiniMax-M2.7 |
466
466
  | Kilo | auto |
467
467
  | Ollama | qwen2.5-coder:32b |
@@ -653,9 +653,9 @@ for f in scripts/*.sh scripts/lib/*.sh; do bash -n "$f" && echo "OK: $f"; done
653
653
  | `PANIC_CONFIDENCE_THRESHOLD` | 5 | Panic threshold (v2.2) |
654
654
  | `ENABLE_OLLAMA` | false | Local model support (v2.2) |
655
655
  | `OLLAMA_MODEL` | qwen2.5-coder:32b | Ollama model (v2.5 - premium default) |
656
- | `CLAUDE_MODEL` | opus-4.6 | Claude model (v2.5) |
656
+ | `CLAUDE_MODEL` | claude-opus-4-7 | Claude model (v2.5) |
657
657
  | `GEMINI_MODEL` | gemini-3.1-pro-preview | Gemini model (v2.5) |
658
- | `CODEX_MODEL` | gpt-5.3-codex | Codex model (v2.5) |
658
+ | `CODEX_MODEL` | gpt-5.5 | Codex model (v2.5) |
659
659
  | `MISTRAL_MODEL` | mistral-large-3 | Mistral model (v2.5) |
660
660
  | `SYNTHESIS_STRATEGY` | majority | Synthesis strategy (v2.2) |
661
661
  | `ENABLE_SEMANTIC_CACHE` | true | Semantic response caching (v2.3) |
@@ -732,16 +732,36 @@ For detailed information, see:
732
732
 
733
733
  Use [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`, `perf:`, `ci:`. Scope is optional (e.g., `feat(routing): add fallback escalation`).
734
734
 
735
+ ### Pre-commit hook (v2.14.1+)
736
+
737
+ A git pre-commit hook runs `shellcheck` on staged `.sh` files using the exact CI invocation. Install it once per checkout:
738
+
739
+ ```bash
740
+ npm run install-hooks # copies scripts/hooks/pre-commit into .git/hooks/
741
+ ```
742
+
743
+ Manual lint of the full repo: `npm run lint`. Bypass the hook: `git commit --no-verify` (use sparingly — CI will catch the same warnings).
744
+
735
745
  ## Release Process
736
746
 
737
747
  Every version bump **must** include a release note in `docs/releases/v<VERSION>.md`. Use the template below.
738
748
 
739
749
  ### Steps
740
750
 
741
- 1. Update version in all files: `package.json`, `SKILL.md` (frontmatter + title), `README.md` (title + badge), `CLAUDE.md` (`**Version**`), `docs/cost_rates.json`, `docs/COST_RATES.md` (title)
742
- 2. Add changelog entry in CLAUDE.md under `## Changelog`
743
- 3. Create `docs/releases/v<VERSION>.md` using the template below
744
- 4. Commit, push, and optionally create a GitHub release pointing to the release note
751
+ 1. **Update version** in all files: `package.json`, `scripts/config.sh` (`AI_CONSULTANTS_VERSION`), `SKILL.md` (frontmatter + title), `README.md` (title + badge), `CLAUDE.md` (`**Version**`), `docs/cost_rates.json`, `docs/COST_RATES.md` (title)
752
+ 2. **Add `## Changelog` entry** in CLAUDE.md (developer-facing, long-form, rationale + line-level commentary)
753
+ 3. **Add `CHANGELOG.md` entry** at the top of `CHANGELOG.md` (Keep a Changelog format: `## [VERSION] - YYYY-MM-DD` with `### Added/Changed/Fixed/Removed/Deprecated/Security` subsections — user-facing, one-line bullets)
754
+ 4. **Create `docs/releases/v<VERSION>.md`** using the template below (highlights + upgrade guide — for GitHub releases / users)
755
+ 5. **Update workspace sync surfaces** if applicable: `aiconsultants.sh/index.html` (`softwareVersion` schema + badge), `../CLAUDE.md` workspace guide ("Latest at time of last sync" + Recent release line)
756
+ 6. **Run tests**: `npm test` must pass before committing
757
+ 7. **Commit, push**, and optionally create a GitHub release pointing to the release note
758
+
759
+ **Why three changelog surfaces?** They serve different audiences:
760
+ - `CLAUDE.md ## Changelog` — what the *next maintainer* needs (file/line references, rationale, latent bugs uncovered)
761
+ - `CHANGELOG.md` — what *users on a specific version* need (concise, categorized, scannable)
762
+ - `docs/releases/v<VERSION>.md` — what *people deciding to upgrade* need (highlights, breaking changes, upgrade guide)
763
+
764
+ Drift between these is the most common release-process bug. Keep them in sync per release.
745
765
 
746
766
  ### Release Note Template
747
767
 
@@ -802,6 +822,123 @@ curl -fsSL https://raw.githubusercontent.com/matteoscurati/ai-consultants/main/s
802
822
 
803
823
  ## Changelog
804
824
 
825
+ ### v2.14.1
826
+ - **Pre-commit hook**: `scripts/hooks/pre-commit` runs `shellcheck` on staged `.sh` files under `scripts/` using the exact CI invocation (`-S warning -x -e SC1091,SC1090,SC2034,SC2155`). Mirrors `.github/workflows/ci.yml:32` so the same warnings that fail CI also fail the local commit. Filtered with the regex `^scripts/(lib/)?[^/]+\.sh$` to match the CI glob exactly (test fixtures under `scripts/test_fixtures/` are correctly excluded). Bypass: `git commit --no-verify`.
827
+ - **`scripts/install-hooks.sh`**: idempotent installer wired to `npm run install-hooks`. Backs up any existing different hook to `.git/hooks/pre-commit.backup.<timestamp>` to avoid clobbering contributor customizations (`FORCE=1` skips backup). Silent no-op outside a git checkout, so it's safe to wire to npm `prepare` or similar lifecycle hooks if ever needed.
828
+ - **`npm run lint`**: convenience wrapper for the full-repo shellcheck invocation. Useful pre-push when you want to validate without staging.
829
+ - **Motivation**: v2.14.0 push to `main` failed CI due to SC2164 in `scripts/test_context_optimization.sh:18` (`cd "$PROJECT_ROOT"` lacked `|| exit`). The new script passed `bash -n` locally but `bash -n` is purely a parser check — it doesn't run any linter. The pre-commit hook closes that gap. Documented in `CONTRIBUTING.md` Development Environment Setup section and briefly in `## Git Conventions` here.
830
+ - **No runtime behavior change**: this is contributor-only tooling. Tests still pass (7 suites, ~510 assertions).
831
+
832
+ ### v2.14.0
833
+ - **Context handoff: AST optimization pipeline now engages on the primary slash-command path**. Pre-fix, `/ai-consultants:consult` instructed the invoking agent (Claude/Codex/Gemini) to inline file contents into the query string, which meant `build_context.sh` ran with zero `FILES` and the entire `lib/code_optimizer.sh` + `lib/chunking.sh` + `lib/symbol_map.sh` stack was dead code. The three `.{claude,codex,gemini}/commands/ai-consultants:{consult,debate}.md` slash commands now instruct agents to pass file paths as positional arguments to `consult_all.sh`; `build_context.sh` does the file reading and runs the optimizer.
834
+ - **`build_context.sh` reads exported `QUESTION_CATEGORY`** to decide whether to include the project tree section. SECURITY, QUICK_SYNTAX, ALGORITHM, BUG_DEBUG, DATABASE, TESTING categories skip it (noise for pointed questions); ARCHITECTURE, CODE_REVIEW, API_DESIGN, GENERAL include it; unknown categories default to "include" (conservative). New env var `FORCE_PROJECT_TREE=true` bypasses the heuristic. Categories source: `classify_question.sh` already exports `QUESTION_CATEGORY` in `consult_all.sh:241-242` — zero new code path, just consumes existing signal.
835
+ - **File relevance tags**: `path/to/file@PRIMARY` (focus of the question) vs `path/to/file@CONTEXT` (ambient reference). Default `PRIMARY` when omitted. Unknown tags fall back to PRIMARY with a `log_warn`. New parallel `FILE_TAGS` array in `build_context.sh`. Rendered as `### File: \`path\` (TAG)` in the `## Relevant Files` section, with a header explaining the two values to consultants. Downstream synthesis/debate/peer_review unaffected (they don't read `context.md`).
836
+ - **`--query-file <path>` flag in `consult_all.sh`** as escape hatch for queries exceeding shell ARG_MAX (~256KB on macOS) or containing mixed-quote payloads. Conflicts with positional question arg (parser-level error). Validates file existence at parse time.
837
+ - **Slash-command file detection**: replaced the hardcoded extension regex + `/`-in-token heuristic with "use your judgment, verify via Glob/Bash when uncertain". Pre-fix missed `Makefile`, `Dockerfile`, dotfiles; false-positive on URLs and regex patterns in question text. The invoking agent has full conversation context so it's better placed than a regex.
838
+ - **Claude-only note in `.claude/commands/ai-consultants:consult.md`**: explicit instruction not to use `Read` tool output (which carries `N\t` line-number prefix) since `build_context.sh` reads files itself. Codex and Gemini variants don't carry this note (their tools don't add the prefix).
839
+ - **First test coverage for `lib/code_optimizer.sh` and `lib/chunking.sh`**: new `scripts/test_context_optimization.sh` (17 assertions, 14 tests). Covers: @TAG default/explicit/unknown, QUESTION_CATEGORY routing (SECURITY drops, ARCHITECTURE keeps, unknown includes), FORCE_PROJECT_TREE override, Python AST extraction over MAX_CONTEXT_FILE_BYTES threshold, `optimize_code_file` smoke, `chunk_file_semantically` JSON shape, --query-file parsing (valid/missing/conflict), legacy no-FILES path preservation. Picked up automatically by `test_all.sh`'s `find`-based discovery — no manual wire-up needed. Total: 7 suites, ~510 assertions.
840
+ - **Test fixtures**: new `scripts/test_fixtures/context/` with `sample.py` (Python class + methods + main), `sample.sh` (Bash with functions), `sample.json` (config), `sample.txt` (plain text). Deterministic, no timestamps or randomness.
841
+ - **Help text updates**: `consult_all.sh --help` documents `--query-file` and `@TAG` syntax; `build_context.sh` usage error documents `QUESTION_CATEGORY` and `FORCE_PROJECT_TREE`.
842
+ - **Known gap surfaced**: `_supports_ast_extraction` declares 13 languages (Python, JS, TS, Go, Rust, Java, C++, C, C#, Ruby, PHP, Swift) but `lib/code_optimizer.sh` has dedicated extractors for only 4 (Python, JS/TS, Bash, Go); the other 9 fall back to `_extract_generic` (grep-based). Documented in release note; tracked for future tree-sitter-backed extraction.
843
+ - **Backwards compat**: agents that still inline file contents into the query (pinned old slash commands) keep working — `build_context.sh` degrades to no-FILES branch, just without the optimization benefit. Direct bash users of `./scripts/consult_all.sh "q" file1 file2` get the same behavior plus the new optimization.
844
+
845
+ ### v2.13.1
846
+ - **Perf**: XDG roots resolved once at first `config.sh` source and **exported** as `_AI_CONSULTANTS_XDG_{CACHE,STATE,DATA}` — child query subshells inherit the values and skip ~6 subshells/child × 14 children = ~84 forks per consultation (~200-400ms saving on macOS).
847
+ - **Perf**: `apply_launch_stagger()` switched from `awk "BEGIN{printf}"` to pure-bash `printf '%d.%03d'` — 14 forks eliminated per consultation (~50-70ms aggregate).
848
+ - **Perf/DRY**: `_count_available_consultants` entries pre-uppercased (`"GEMINI|ENABLE_GEMINI|gemini"`) — 15 `to_upper` subshells eliminated per `--suggest-preset` invocation. Also fixes the latent self-exclusion case-mismatch the round-2 review caught.
849
+ - **Latent bug fix**: 5 `lib/*.sh` files (`cache.sh`, `session.sh`, `api.sh`, `chunking.sh`, `costs.sh`) had hardcoded `/tmp/...` defaults that drifted from the v2.13 XDG migration. Their fallbacks now reference `${_AI_CONSULTANTS_XDG_*}` so they stay aligned even if sourced standalone (e.g. from a future test). `lib/session.sh::cleanup_old_sessions` no longer hardcodes `/tmp/ai_consultations` either — uses `$DEFAULT_OUTPUT_DIR_BASE`.
850
+ - **DRY**: extracted `scripts/lib/test_helpers.sh` (~80 LOC) — `assert_eq`, `assert_match`, `run_test`, `test_summary`, `_reset_state` hook. Eliminates the ~90 LOC of triplication across `test_user_config.sh`, `test_doctor.sh`, `test_bin.sh`. Future test suites just `source lib/test_helpers.sh`.
851
+ - **CI**: `scripts/test_all.sh` (master runner introduced post-v2.13.0) now also includes `test_suite.sh` — adds 258 library assertions to `npm test`, closing the "tests on disk but not gating CI" gap. Total: 6 suites, ~493 assertions.
852
+ - **Style**: 37 → 0 shellcheck warnings under the project exclusions (`-e SC2034,SC2086,SC1091,SC2155,SC2154`). Touches: `configure.sh` (26 SC2004 + 1 SC2129), `lib/routing.sh` (4 SC2004/2321), `lib/code_optimizer.sh` (2 SC2001 sed → param expansion), `lib/chunking.sh` (2 SC2001), `lib/voting.sh` (1 SC2126), `lib/common.sh` (1 SC2005, 1 SC2317 annotated), `lib/api_query.sh` (1 SC2317 annotated), `lib/symbol_map.sh` (2 SC1090 annotated), `config.sh` (1 SC2317 annotated), `test_set_e_safety.sh` (1 SC2001 annotated).
853
+ - **Code quality**: `consult_all.sh` `_MODEL` var resolution switched from inline `tr` to `to_upper()` helper for consistency. Stale `name_upper` variable in `_count_available_consultants` renamed to `name`. `find_user_config_file` redundant `|| echo ""` simplified to `|| true`.
854
+ - All 6 test suites pass (493 assertions). Zero behavioral change for end users; XDG cache export is the only new env-var contract.
855
+
856
+ ### v2.13.0
857
+ - New `doctor --suggest-preset --question "..."` recommends a preset + strategy combo for a question, based on category classification (`classify_question.sh`) and the count of available consultants (gated by `ENABLE_*` flags and self-exclusion). Outputs a one-line `ai-consultants` command + reasoning, or structured JSON via `--json` for tooling/automation.
858
+ - Classifier failures now surface explicitly as `Warning: classification of your question failed` (with the underlying error). Pre-fix the failure was masked by `2>/dev/null` and silently degraded to `GENERAL`.
859
+ - `--suggest-preset` short-circuits to "install more CLIs" hint when fewer than 2 consultants are usable — previously could recommend e.g. `minimal` preset with 0 consultants.
860
+ - `_count_available_consultants()` now respects `ENABLE_*` flags and subtracts the invoking agent (self-exclusion). Pre-fix the count included disabled consultants, leading `_recommend_combo` boundaries to fire on a phantom panel size.
861
+ - `ENABLE_DEBATE_OPTIMIZATION` promoted from opt-in to default `true` based on operator experience over 4 stable releases — debate is auto-skipped when confidence spread < `DEBATE_CONFIDENCE_SPREAD_THRESHOLD` (default 2). SECURITY and ARCHITECTURE remain mandatory-debate. No empirical benchmark in-tree yet; tracked for v2.14.
862
+ - XDG Base Directory compliance for transient and persistent paths (per freedesktop.org spec):
863
+ - `DEFAULT_OUTPUT_DIR_BASE`: `/tmp/ai_consultations` → `$XDG_CACHE_HOME/ai-consultants/consultations` (typically `~/.cache/...`)
864
+ - `CACHE_DIR`: `/tmp/ai_consultants_cache` → `$XDG_CACHE_HOME/ai-consultants/cache`
865
+ - `RATE_LIMIT_DIR`, `CHUNK_TEMP_DIR`: `/tmp/ai_consultants_*` → `$XDG_CACHE_HOME/ai-consultants/{ratelimit,chunks}`
866
+ - `SESSION_DIR`: `/tmp/ai_consultants_sessions` → `$XDG_STATE_HOME/ai-consultants/sessions` (`~/.local/state/...`)
867
+ - `COST_TRACKING_FILE`: `/tmp/ai_consultants_costs.json` → `$XDG_DATA_HOME/ai-consultants/costs.json` (`~/.local/share/...`)
868
+ - All env vars still respected; restore old behavior with `export DEFAULT_OUTPUT_DIR_BASE=/tmp/ai_consultations` etc.
869
+ - New `lib/user_config.sh::get_xdg_dir()` helper — single source of truth for XDG resolution; falls back to `$HOME/.{cache,local/state,local/share}` then `/tmp/ai-consultants-{kind}` for distroless containers.
870
+ - README slimmed: env-var section now points to `references/configuration.md` for the full ~150-var list and recommends `ai-consultants init` as the primary onboarding path.
871
+ - `RATE_LIMIT_DIR` and `CHUNK_TEMP_DIR` lifted to `config.sh` for consistency (were lib-only defaults).
872
+ - `config.sh` now hard-fails with `FATAL: ... get_xdg_dir()` if `lib/user_config.sh` is missing — pre-fix the v2.13 XDG defaults silently regressed to `/tmp/ai_consultants/...` when the helper was absent (corrupt install, refactor regression).
873
+ - New `scripts/test_doctor.sh` — 25 assertions in 12 tests: `--suggest-preset` across categories (SECURITY, QUICK_SYNTAX, ARCHITECTURE, ALGORITHM, GENERAL), no-question default, long-question truncation, short-circuit behavior, **+ review fixes**: `--json` output schema, count<2 install hint, classifier failure warning, `config.sh` FATAL on missing helper, count respects ENABLE_* flags.
874
+ - `scripts/test_user_config.sh` extended to 38 assertions in 18 tests — added: `get_xdg_dir` cache/state/data resolution, fallback to `~/.{cache,local/state,local/share}`, distroless `/tmp/ai-consultants-*` fallback, invalid kind handling, `config.sh` XDG path defaults, explicit env var override precedence, `ENABLE_DEBATE_OPTIMIZATION=true` default assertion.
875
+ - Round-2 review fix: `_count_available_consultants` self-exclusion was dead code due to UPPERCASE vs MixedCase mismatch — counter compared `Claude` to `get_self_consultant_name`'s `CLAUDE`. Now uppercases the entry name via `to_upper`; `INVOKING_AGENT` correctly drops 1 from the count. Regression test added.
876
+ - Round-2 fix: `--suggest-preset --json` pre-flights `jq` with a clear error message instead of aborting under `set -e` with `command not found` (the main `check_dependencies` jq probe doesn't run when `--suggest-preset` short-circuits).
877
+ - Round-2 fix: `--json` schema gains `schema_version: 1` and `recommended_command` fields — tooling no longer has to reconstruct the invocation client-side and has a signal for future schema evolution.
878
+ - Round-2 fix: `_count_available_consultants` no longer hardcodes a "default-true" list that drifted from `config.sh` (claimed Aider default-true; actually false). Removed; relies solely on `config.sh` defaults via `${!flag:-false}`.
879
+ - New `scripts/test_all.sh` master runner aggregates all 5 standalone test suites; `npm test` wired in `package.json`. Closes the "tests on disk but not gating CI" gap from v2.11/v2.12 review carryovers.
880
+ - `scripts/test_doctor.sh` extended to 31 assertions: + self-exclusion regression, + jq preflight, + schema_version/recommended_command shape.
881
+
882
+ ### v2.12.0
883
+ - New persistent user-config dir at `~/.config/ai-consultants/` (XDG-compliant; honors `AI_CONSULTANTS_CONFIG_DIR` and `XDG_CONFIG_HOME`)
884
+ - New `lib/user_config.sh` with `load_user_config()` — sourced from `config.sh` at the very top, before any defaults are applied
885
+ - `load_user_config` is **idempotent** via a process-wide guard `_AI_CONSULTANTS_USER_CONFIG_LOADED` — `config.sh` is sourced 15-30 times per consultation transitively, and without the guard non-idempotent user config (PATH appends, counters, log appends) would compound silently
886
+ - `.env` (KEY=value) and `config.sh` (full bash) both supported; existing env vars always win over user config (precedence: CLI > env > user config > defaults > hardcoded)
887
+ - `.env` parser **strips trailing CR** so Windows CR-LF line endings don't silently corrupt values (`ENABLE_DEBATE=true\r` would otherwise break every `[[ "$X" == "true" ]]` comparison downstream)
888
+ - New `ai-consultants init [--force]` subcommand scaffolds the user config dir with `.env` (copied from `.env.example`, chmod 600) and `config.sh` (minimal sourceable template); refuses to scaffold into a symlinked dir (root + hostile symlink protection); pre-flights write permission with a friendly error pointing to `AI_CONSULTANTS_CONFIG_DIR`
889
+ - `bin/ai-consultants` no longer hardcodes the version (was stuck at 2.10.0 since v2.10.0 release); reads `AI_CONSULTANTS_VERSION` from `scripts/config.sh` and **validates it as semver** — falls back to `vunknown` instead of `vAI_CONSULTANTS_VERSION=2.12.0` when the parse fails
890
+ - `get_user_config_dir` returns empty + exit 1 when both `HOME` and `XDG_CONFIG_HOME` are unset (e.g. distroless container) instead of computing the broken path `/.config/ai-consultants`; callers (`doctor.sh`, `bin/init`) handle this with a clear error
891
+ - Single source of truth for user-dir resolution: `lib/user_config.sh::get_user_config_dir()`; `routing.sh`, `doctor.sh`, and `bin/ai-consultants` now all source it instead of duplicating the precedence ladder (was DRY-violated 4x)
892
+ - `lib/routing.sh::_load_affinity_data` extended with search path: `AFFINITY_FILE` env > `~/.config/ai-consultants/affinity.json` > bundled default — drops a custom matrix in the user dir without setting any env var
893
+ - `doctor.sh` adds `check_user_config()` reporting dir presence, files loaded, and warns on `.env` lax permissions — total checks now 22
894
+ - New regression test `scripts/test_user_config.sh` — 20 assertions in 11 tests: .env loading + quote stripping, env precedence, edge cases (comments/blanks/`export`/quoted/indented), invalid keys, config.sh ordering, XDG fallback, missing-files silence (now also asserts no stderr output), AI_CONSULTANTS_CONFIG_DIR priority, **CR-LF stripping**, **idempotency guard**, **HOME-unset fallback**
895
+ - New `scripts/test_bin.sh` — 10 assertions in 8 tests covering `bin/ai-consultants version` (matches config.sh, semver-shaped, fallback to "unknown" on malformed config) and `init` (chmod 600 enforcement, both files created, idempotent without --force, --force overwrites, refuses symlinked dir)
896
+ - `scripts/test_routing_parity.sh` extended to 146 assertions (added user-dir branch of `_resolve_affinity_path`)
897
+
898
+ ### v2.11.0
899
+ - Externalized routing affinity matrix from nested `case` statements in `lib/routing.sh` to `references/affinity.json` (~190 lines of bash → 60 lines of JSON)
900
+ - Custom matrix at runtime via `AFFINITY_FILE=/path/to/custom.json` (e.g. tweak scores per project, disable consultants by category)
901
+ - `get_affinity()` now performs JSON lookup with two-level cache: file content cached on first read, per-(category, consultant) result cached after first lookup
902
+ - Cache uses leading-space delimiter to prevent substring collisions (e.g. `DEBUG|X=` would have falsely matched a cached `BUG_DEBUG|X=10` — caught in review pass before release)
903
+ - `doctor.sh` adds 3 new checks for affinity: file presence, JSON schema validity, coverage (every consultant in every category) — total checks now 21
904
+ - Golden parity test in `scripts/test_routing_parity.sh`: 144 assertions covering all 9 categories × 14 consultants + edge cases (unknown consultant, unknown category, AFFINITY_FILE override, cache auto-invalidation, cache substring-collision regression)
905
+ - `docs/SMART_ROUTING.md` rewritten: removed stale per-consultant table (was out of sync with code since v2.8/v2.9/v2.10 added Amp, Kimi, MiniMax), now points to JSON as source of truth and documents schema + override
906
+ - `references/affinity.json` `_comment` documents the asymmetric 3-tier fallback (unknown consultant → 5, unknown category → 8, missing cell → 5) and the rationale
907
+ - Bug class regression test in `scripts/test_set_e_safety.sh`: static lint covers `((var++))` AND `((var--))` AND `let var++` family, plus dynamic check on bash 4+ for the abort pattern fixed in v2.8.1, v2.10.1, v2.10.9
908
+ - `consult_all.sh` ENABLE_PREFLIGHT path no longer swallows doctor output — the diagnostic is now captured to a tmpfile and dumped on failure (previously `>/dev/null 2>&1` repeated the original preflight silent-failure bug)
909
+ - Cleaned `((attempt++)) || true || true` artifacts in `lib/api.sh` (introduced by the v2.10.9 mechanical sweep on lines that were already protected)
910
+
911
+ ### v2.10.9
912
+ - Fixed silent failure of `preflight_check.sh` under `set -euo pipefail`: helper functions like `check_cli_installed` returned non-zero on missing CLIs, and call sites lacked `|| true` — the script aborted after "Checking CLI installations..." with no diagnostic output
913
+ - Deprecated `preflight_check.sh` in favor of `doctor.sh` (stale v2.0 script covering only 6/15 consultants and missing CLI/API mode checks); `preflight_check.sh` is now a thin wrapper that prints a deprecation warning and execs `doctor.sh "$@"`
914
+ - Ported `--suggest-config` from preflight to `doctor.sh`, expanded coverage from 6 to 15 consultants (now also detects API-only consultants via API key presence)
915
+ - Added `--quick` flag to `doctor.sh` (accepted as no-op for backward compat with preflight)
916
+ - Updated `consult_all.sh` ENABLE_PREFLIGHT path to invoke `doctor.sh` directly
917
+ - Defensive sweep: protected 15 latent `((var++))` increments across `peer_review.sh`, `setup_wizard.sh`, `test_functions.sh`, `lib/api.sh`, `lib/common.sh`, `lib/reflection.sh`, and `doctor.sh` with `|| true` (matches v2.8.1/v2.10.1 codebase convention; latent because bash 3.2 doesn't abort but bash 4+ does)
918
+ - Fixed real shellcheck warnings: SC2059 unsafe printf format string in `lib/progress.sh`, SC2012 `ls | wc -l` race in `install.sh` (replaced with `find`), SC2329 false positive in `query_ollama.sh` cleanup trap (annotated), SC2016 intentional sed pattern in `peer_review.sh` (annotated)
919
+
920
+ ### v2.10.8
921
+ - Fixed `docs/cost_rates.json` drift introduced by v2.10.6: `consultant_fallbacks` (used at runtime by `lib/costs.sh`) and `model_tiers` were still pointing at the old IDs (`opus-4.6`, `gpt-5.3-codex`, `composer-1.5`, `deepseek-reasoner`, `sonnet-4.6`, `haiku-4.5`)
922
+ - Added price entries for the v2.10.6 model IDs: `claude-opus-4-7`, `claude-sonnet-4-6`, `claude-haiku-4-5`, `gpt-5.5`, `composer-2`, `deepseek-v4-pro`, `nvidia/nemotron-3-super-120b-a12b:free`
923
+ - Moved superseded IDs to the legacy section so cost calculation still works for historical responses or pinned overrides
924
+ - Synced `COST_RATES.md` tables to match
925
+ - Pricing for `nvidia/nemotron-3-super-120b-a12b:free` set to $0/$0 (OpenRouter free tier)
926
+
927
+ ### v2.10.7
928
+ - Grok premium upgraded from `grok-4.20-0309-reasoning` to `grok-4.3` (released 2026-04-30)
929
+ - ~75% cheaper input ($1.25/M vs $5.00/M) and ~83% cheaper output ($2.50/M vs $15.00/M)
930
+ - 1M-token context window
931
+ - Moved `grok-4.20-0309-reasoning` to legacy section in cost catalog
932
+ - Standard (`grok-3`) and economy (`grok-3-mini`) tiers unchanged
933
+
934
+ ### v2.10.6
935
+ - Codex premium upgraded from `gpt-5.3-codex` to `gpt-5.5`
936
+ - Cursor premium upgraded from `composer-1.5` to `composer-2`
937
+ - Aider switched provider: `gpt-5.3-codex` → `nvidia/nemotron-3-super-120b-a12b:free` (free tier)
938
+ - DeepSeek premium upgraded from `deepseek-reasoner` to `deepseek-v4-pro`
939
+ - Claude IDs migrated from short aliases to canonical model IDs across all tiers: `opus-4.6` → `claude-opus-4-7`, `sonnet-4.6` → `claude-sonnet-4-6`, `haiku-4.5` → `claude-haiku-4-5`
940
+ - Fixed Kilo SIGPIPE abort under `set -euo pipefail` (replaced `head -c` with parameter expansion)
941
+
805
942
  ### v2.10.5
806
943
  - Qwen3 premium model upgraded from `qwen3.5-plus` to `qwen3.6-plus` ($0.325/$1.95 per M tokens)
807
944
  - Qwen3 standard tier now uses open-weight `qwen3.6-35b-a3b` (MoE, 35B total / 3B active)
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # AI Consultants v2.10.5
1
+ # AI Consultants v2.14.1
2
2
 
3
3
  > Query multiple AI models simultaneously for expert opinions on coding questions. Get diverse perspectives, automatic synthesis, confidence-weighted recommendations, and multi-agent debate.
4
4
 
5
- [![Version](https://img.shields.io/badge/version-2.10.5-blue.svg)](https://github.com/matteoscurati/ai-consultants)
5
+ [![Version](https://img.shields.io/badge/version-2.14.1-blue.svg)](https://github.com/matteoscurati/ai-consultants)
6
6
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
7
  [![Claude Code Skill](https://img.shields.io/badge/Claude%20Code-Skill-orange.svg)](https://docs.anthropic.com/en/docs/claude-code/skills)
8
8
  [![GitHub stars](https://img.shields.io/github/stars/matteoscurati/ai-consultants?style=social)](https://github.com/matteoscurati/ai-consultants)
@@ -548,39 +548,35 @@ Control how responses are combined:
548
548
 
549
549
  ### Environment Variables
550
550
 
551
- ```bash
552
- # Core features
553
- ENABLE_DEBATE=true # Multi-agent debate
554
- ENABLE_SYNTHESIS=true # Automatic synthesis
555
- ENABLE_SMART_ROUTING=true # Intelligent consultant selection
556
- ENABLE_PANIC_MODE=auto # Automatic rigor for uncertainty
557
-
558
- # Defaults
559
- DEFAULT_PRESET=balanced # Preset when --preset not given
560
- DEFAULT_STRATEGY=majority # Strategy when --strategy not given
551
+ **Most users only need:**
561
552
 
562
- # Ollama (local models)
563
- ENABLE_OLLAMA=true # Enable Ollama consultant
564
- OLLAMA_MODEL=qwen2.5-coder:32b # Model to use (premium default)
565
- OLLAMA_HOST=http://localhost:11434
553
+ ```bash
554
+ ai-consultants init # creates ~/.config/ai-consultants/{config.sh,.env}
555
+ $EDITOR ~/.config/ai-consultants/.env
556
+ ```
566
557
 
567
- # Cost management
568
- MAX_SESSION_COST=1.00 # Budget limit in USD
569
- WARN_AT_COST=0.50 # Warning threshold
558
+ For ad-hoc overrides without persisting, the most common knobs:
570
559
 
571
- # Panic mode
572
- PANIC_CONFIDENCE_THRESHOLD=5 # Trigger threshold
573
- PANIC_EXTRA_DEBATE_ROUNDS=1 # Additional rounds in panic mode
560
+ ```bash
561
+ DEFAULT_PRESET=balanced # minimal | balanced | thorough | high-stakes | fast | local | security
562
+ DEFAULT_STRATEGY=majority # majority | risk_averse | security_first | cost_capped | compare_only
563
+ ENABLE_DEBATE=true # Multi-agent debate (auto-skipped when consensus is high since v2.13)
564
+ ENABLE_OLLAMA=true # Enable local Ollama consultant
565
+ MAX_SESSION_COST=1.00 # USD budget cap (paired with ENABLE_BUDGET_LIMIT=true to enforce)
574
566
  ```
575
567
 
568
+ Full reference (~150 vars): [`references/configuration.md`](references/configuration.md). For category-aware preset suggestions: `ai-consultants doctor --suggest-preset --question "..."`.
569
+
576
570
  ### Doctor Command
577
571
 
578
- Diagnose and fix configuration issues:
572
+ Diagnose, suggest, and fix:
579
573
 
580
574
  ```bash
581
- ./scripts/doctor.sh # Full diagnostic
582
- ./scripts/doctor.sh --fix # Auto-fix common issues
583
- ./scripts/doctor.sh --json # JSON output for automation
575
+ ai-consultants doctor # 22 health checks
576
+ ai-consultants doctor --fix # Auto-fix common issues
577
+ ai-consultants doctor --json # JSON for automation
578
+ ai-consultants doctor --suggest-config # Print recommended ENABLE_* based on detected CLIs
579
+ ai-consultants doctor --suggest-preset --question "..." # Recommend preset + strategy for a question
584
580
  ```
585
581
 
586
582
  ---
package/SKILL.md CHANGED
@@ -5,10 +5,10 @@ license: MIT
5
5
  compatibility: Requires bash, jq, and at least 2 AI CLI tools (gemini, codex, vibe, etc.). macOS and Linux.
6
6
  metadata:
7
7
  author: matteoscurati
8
- version: 2.10.5
8
+ version: 2.14.1
9
9
  ---
10
10
 
11
- # AI Consultants v2.10.5 - AI Expert Panel
11
+ # AI Consultants v2.14.1 - AI Expert Panel
12
12
 
13
13
  Simultaneously consult multiple AIs as "consultants" for coding questions. Each consultant has a **configurable persona** that influences their response style.
14
14
 
@@ -29,7 +29,16 @@ ensure_permissions() {
29
29
  ensure_permissions
30
30
 
31
31
  # --- Version ---
32
- VERSION="2.10.0"
32
+ # Single source of truth: scripts/config.sh AI_CONSULTANTS_VERSION.
33
+ # We grep instead of sourcing to avoid pulling in the full config (cost).
34
+ # The sed pipeline succeeds even when its regex doesn't match (it returns
35
+ # the input verbatim), so we explicitly validate the result is semver — else
36
+ # the help banner would print garbage like "vAI_CONSULTANTS_VERSION=2.12.0".
37
+ VERSION=$(grep -E '^AI_CONSULTANTS_VERSION=' "$SCRIPTS_DIR/config.sh" 2>/dev/null \
38
+ | head -1 | sed -E 's/.*"([^"]+)".*/\1/' || true)
39
+ if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
40
+ VERSION="unknown"
41
+ fi
33
42
 
34
43
  # --- Subcommand routing ---
35
44
  case "${1:-}" in
@@ -46,6 +55,7 @@ Usage:
46
55
  ai-consultants --preset <name> "question" Use a configuration preset
47
56
  ai-consultants --strategy <name> "question" Use a synthesis strategy
48
57
  ai-consultants doctor [--fix] [--json] Run diagnostics
58
+ ai-consultants init [--force] Scaffold ~/.config/ai-consultants/{config.sh,.env}
49
59
  ai-consultants install Install slash commands to ~/.claude/commands/
50
60
  ai-consultants version Show version
51
61
  ai-consultants help Show this help
@@ -68,6 +78,94 @@ EOF
68
78
  shift
69
79
  exec "$SCRIPTS_DIR/doctor.sh" "$@"
70
80
  ;;
81
+ init)
82
+ shift
83
+ FORCE=false
84
+ for arg in "$@"; do
85
+ [ "$arg" = "--force" ] && FORCE=true
86
+ done
87
+
88
+ # Reuse the canonical resolution from lib/user_config.sh.
89
+ # shellcheck source=../scripts/lib/user_config.sh
90
+ source "$SCRIPTS_DIR/lib/user_config.sh"
91
+ USER_DIR=$(get_user_config_dir)
92
+ if [ -z "$USER_DIR" ]; then
93
+ echo "Error: cannot resolve user config dir (HOME and XDG_CONFIG_HOME both unset)" >&2
94
+ echo " export AI_CONSULTANTS_CONFIG_DIR=/path/to/your/config to override" >&2
95
+ exit 1
96
+ fi
97
+
98
+ # Refuse to write through a symlinked dir — protects against root running
99
+ # init when ~/.config/ai-consultants is a symlink to a sensitive path.
100
+ if [ -L "$USER_DIR" ]; then
101
+ echo "Error: $USER_DIR is a symlink. Refusing to scaffold into it." >&2
102
+ echo " Remove the symlink, or point AI_CONSULTANTS_CONFIG_DIR elsewhere." >&2
103
+ exit 1
104
+ fi
105
+
106
+ # Pre-flight a write check so the user gets a friendly error instead of a
107
+ # mid-scaffold mkdir/cp failure.
108
+ parent="$(dirname "$USER_DIR")"
109
+ if [ ! -w "$parent" ] && [ ! -d "$USER_DIR" ]; then
110
+ echo "Error: cannot write to $parent" >&2
111
+ echo " export AI_CONSULTANTS_CONFIG_DIR=/path/you/can/write to override" >&2
112
+ exit 1
113
+ fi
114
+
115
+ mkdir -p "$USER_DIR"
116
+ echo "User config dir: $USER_DIR"
117
+
118
+ # .env: copy from .env.example if present
119
+ DEST_ENV="$USER_DIR/.env"
120
+ SRC_ENV="$PROJECT_ROOT/.env.example"
121
+ if [ -f "$DEST_ENV" ] && [ "$FORCE" != true ]; then
122
+ echo " ○ .env already exists (use --force to overwrite)"
123
+ elif [ -f "$SRC_ENV" ]; then
124
+ cp "$SRC_ENV" "$DEST_ENV"
125
+ chmod 600 "$DEST_ENV"
126
+ echo " ✓ .env created from .env.example (chmod 600 — contains API keys)"
127
+ else
128
+ cat > "$DEST_ENV" <<'EOF'
129
+ # AI Consultants user environment
130
+ # KEY=value lines. Existing env vars take precedence.
131
+ # Uncomment what you want to override.
132
+
133
+ # ENABLE_DEBATE=true
134
+ # DEFAULT_PRESET=balanced
135
+ # DEFAULT_STRATEGY=majority
136
+ # MAX_SESSION_COST=2.00
137
+ # ENABLE_BUDGET_LIMIT=true
138
+ EOF
139
+ chmod 600 "$DEST_ENV"
140
+ echo " ✓ .env created (minimal template)"
141
+ fi
142
+
143
+ # config.sh: minimal sourceable bash starter
144
+ DEST_CFG="$USER_DIR/config.sh"
145
+ if [ -f "$DEST_CFG" ] && [ "$FORCE" != true ]; then
146
+ echo " ○ config.sh already exists (use --force to overwrite)"
147
+ else
148
+ cat > "$DEST_CFG" <<'EOF'
149
+ #!/bin/bash
150
+ # ~/.config/ai-consultants/config.sh
151
+ # Sourced after .env, before scripts/config.sh defaults are applied.
152
+ # Use full bash logic. To defer to env vars, use ${VAR:-value}.
153
+ #
154
+ # Examples:
155
+ # export DEFAULT_PRESET="${DEFAULT_PRESET:-balanced}"
156
+ # export ENABLE_DEBATE="${ENABLE_DEBATE:-true}"
157
+ # export AFFINITY_FILE="${AFFINITY_FILE:-$HOME/.config/ai-consultants/affinity.json}"
158
+ EOF
159
+ echo " ✓ config.sh created (minimal template)"
160
+ fi
161
+
162
+ echo ""
163
+ echo "Next steps:"
164
+ echo " 1. Edit $DEST_ENV to set API keys and overrides"
165
+ echo " 2. Run: ai-consultants doctor # verify config is loaded"
166
+ echo " 3. Run: ai-consultants \"your question\" # use the new defaults"
167
+ exit 0
168
+ ;;
71
169
  install)
72
170
  COMMANDS_SRC="$PROJECT_ROOT/.claude/commands"
73
171
  COMMANDS_DST="$HOME/.claude/commands"