claude-git-hooks 2.18.1 → 2.20.0

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 (54) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/CLAUDE.md +85 -38
  3. package/README.md +52 -18
  4. package/bin/claude-hooks +75 -89
  5. package/lib/cli-metadata.js +306 -0
  6. package/lib/commands/analyze-diff.js +12 -10
  7. package/lib/commands/analyze.js +9 -5
  8. package/lib/commands/bump-version.js +56 -40
  9. package/lib/commands/create-pr.js +71 -34
  10. package/lib/commands/debug.js +4 -7
  11. package/lib/commands/diff-batch-info.js +105 -0
  12. package/lib/commands/generate-changelog.js +3 -2
  13. package/lib/commands/help.js +47 -27
  14. package/lib/commands/helpers.js +66 -43
  15. package/lib/commands/hooks.js +15 -13
  16. package/lib/commands/install.js +546 -49
  17. package/lib/commands/migrate-config.js +8 -11
  18. package/lib/commands/presets.js +6 -13
  19. package/lib/commands/setup-github.js +12 -3
  20. package/lib/commands/telemetry-cmd.js +8 -6
  21. package/lib/commands/update.js +1 -2
  22. package/lib/config.js +36 -52
  23. package/lib/hooks/pre-commit.js +70 -64
  24. package/lib/hooks/prepare-commit-msg.js +35 -75
  25. package/lib/utils/analysis-engine.js +77 -54
  26. package/lib/utils/changelog-generator.js +63 -37
  27. package/lib/utils/claude-client.js +447 -438
  28. package/lib/utils/claude-diagnostics.js +20 -10
  29. package/lib/utils/diff-analysis-orchestrator.js +332 -0
  30. package/lib/utils/file-operations.js +51 -79
  31. package/lib/utils/file-utils.js +6 -7
  32. package/lib/utils/git-operations.js +140 -123
  33. package/lib/utils/git-tag-manager.js +24 -23
  34. package/lib/utils/github-api.js +85 -61
  35. package/lib/utils/github-client.js +12 -14
  36. package/lib/utils/installation-diagnostics.js +4 -4
  37. package/lib/utils/interactive-ui.js +29 -17
  38. package/lib/utils/judge.js +195 -0
  39. package/lib/utils/logger.js +4 -1
  40. package/lib/utils/package-info.js +0 -11
  41. package/lib/utils/pr-metadata-engine.js +67 -33
  42. package/lib/utils/preset-loader.js +20 -62
  43. package/lib/utils/prompt-builder.js +57 -68
  44. package/lib/utils/resolution-prompt.js +34 -52
  45. package/lib/utils/sanitize.js +20 -19
  46. package/lib/utils/task-id.js +27 -40
  47. package/lib/utils/telemetry.js +73 -25
  48. package/lib/utils/version-manager.js +147 -70
  49. package/lib/utils/which-command.js +23 -12
  50. package/package.json +1 -1
  51. package/templates/CLAUDE_RESOLUTION_PROMPT.md +17 -9
  52. package/templates/DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md +70 -0
  53. package/templates/config.advanced.example.json +15 -31
  54. package/templates/config.example.json +0 -11
package/CHANGELOG.md CHANGED
@@ -5,6 +5,58 @@ Todos los cambios notables en este proyecto se documentarán en este archivo.
5
5
  El formato está basado en [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.20.0] - 2026-03-09
9
+
10
+ ### ✨ Added
11
+ - Intelligent batch orchestration for commits with 3+ files using Opus to semantically group files, assign per-batch models, and inject shared commit context
12
+ - Auto-fix judge that evaluates all issues at any severity level, auto-applies search/replace fixes, and dismisses false positives - any unresolved issue blocks the commit (#85)
13
+ - New `batch-info` command to display orchestration configuration and per-model average analysis speed from telemetry
14
+ - Per-call model override capability in `analyzeCode()` for different Claude models per analysis batch
15
+ - New `diff-analysis-orchestrator.js` module for semantic batch grouping via Opus
16
+ - New `judge.js` module for LLM verdict and search/replace auto-fixes
17
+ - Cross-file dependency detection for JavaScript, TypeScript, Java, and Python files
18
+ - DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md template for Opus batch grouping
19
+
20
+ ### 🔧 Changed
21
+ - Analysis routing now uses three-tier strategy: 1-2 files use sequential single call, 3+ files trigger intelligent orchestration
22
+ - Judge now runs on all issues regardless of severity (previously only CRITICAL/BLOCKER blocked commits)
23
+ - Resolution prompt file is only generated if issues remain after judge evaluation
24
+ - Updated documentation to clarify that judge blocks commits when any issue remains unresolved
25
+ - Orchestrator threshold set to 3 files as internal constant in `analysis-engine.js`
26
+ - Each batch prompt now includes commit overview, dependency graph, and batch rationale for better cross-file reasoning
27
+ - Judge failures (timeout, JSON parse error, module load) now warn user and block commit
28
+ - Configurable judge model via `config.judge.model` (default: opus)
29
+ - Judge can be disabled via `config.judge.enabled: false` to fall back to original quality gate
30
+
31
+ ### 🗑️ Removed
32
+ - Removed `subagents.batchSize` configuration option (orchestration now handled by Opus intelligence)
33
+ - Removed `analyzeCodeParallel()` function from `claude-client.js` (replaced by orchestration-driven parallel execution)
34
+
35
+
36
+ ## [2.19.0] - 2026-03-06
37
+
38
+ ### ✨ Added
39
+ - Shell autocompletion for all CLI commands, flags, and arguments — Bash, Zsh, Fish, and PowerShell (#78)
40
+ - Command registry (`lib/cli-metadata.js`) — single source of truth for commands, flags, descriptions, and completion metadata
41
+ - Four shell completion generators with per-command flag/arg awareness and dynamic branch completion for `analyze-diff` and `create-pr`
42
+ - Completions auto-install during `claude-hooks install` and auto-remove during `claude-hooks uninstall`
43
+ - Self-healing RC file updates — reinstall detects and replaces stale source lines (e.g., Windows backslash paths) automatically
44
+
45
+ ### 🔧 Changed
46
+ - Refactored `bin/claude-hooks` — replaced 130-line switch/case with declarative command registry lookup via `buildCommandMap()`
47
+ - Shell source lines now use `$HOME`-relative paths for cross-platform compatibility (MINGW64, WSL, native Linux/macOS)
48
+ - Completion source lines written to both `~/.bashrc` and `~/.bash_profile` (MINGW64 reads `.bash_profile` first)
49
+ - PowerShell profile detection now queries `$PROFILE` directly via `powershell.exe`/`pwsh`, handling OneDrive-redirected and locale-specific Documents folders
50
+ - PowerShell completion script uses fully qualified .NET type names (`System.Management.Automation.CompletionResult`) for compatibility with dot-sourced scripts
51
+ - Updated CLAUDE.md with cli-metadata.js documentation, exports table, and Command Registry design pattern
52
+
53
+ ### 🐛 Fixed
54
+ - Bash completions failing on MINGW64/Git Bash due to Windows backslash paths in source lines
55
+ - PowerShell completions failing due to hardcoded Unix profile paths on Windows
56
+ - PowerShell 5.1 `-Native` completers not firing for npm `.ps1` shims — added proxy function wrapper that re-exposes the command as `Function` type
57
+ - PowerShell `[CompletionResult]` type accelerator not resolving in dot-sourced profile scripts
58
+
59
+
8
60
  ## [2.18.1] - 2026-03-04
9
61
 
10
62
  ### ✨ Added
package/CLAUDE.md CHANGED
@@ -45,8 +45,9 @@ This separation enables:
45
45
  ```
46
46
  claude-git-hooks/
47
47
  ├── bin/
48
- │ └── claude-hooks # Thin CLI router - argument parsing, command dispatch
48
+ │ └── claude-hooks # Thin CLI router - uses cli-metadata.js registry for dispatch
49
49
  ├── lib/
50
+ │ ├── cli-metadata.js # Command registry - single source of truth for CLI commands, flags, descriptions
50
51
  │ ├── config.js # Config system - load/merge with priority
51
52
  │ ├── commands/ # Command modules - one file per CLI command
52
53
  │ │ ├── helpers.js # Shared CLI utilities - colors, output, platform
@@ -62,13 +63,15 @@ claude-git-hooks/
62
63
  │ │ ├── telemetry-cmd.js # Telemetry commands - show/clear statistics
63
64
  │ │ ├── bump-version.js # Version management - bump with commit, CHANGELOG and tags
64
65
  │ │ ├── generate-changelog.js # CHANGELOG generation - standalone command
66
+ │ │ ├── diff-batch-info.js # Batch info - orchestration config + speed telemetry (v2.20.0)
65
67
  │ │ └── help.js # Help, AI help, and report-issue commands
66
68
  │ ├── hooks/ # Git hooks - Node.js implementations
67
69
  │ │ ├── pre-commit.js # Pre-commit analysis - code quality gate
68
70
  │ │ └── prepare-commit-msg.js # Message generation - auto commit messages
69
71
  │ └── utils/ # Reusable modules - shared logic
70
- │ ├── analysis-engine.js # Shared analysis logic - file data, orchestration, results (v2.13.0)
71
- │ ├── claude-client.js # Claude CLI wrapper - spawn, retry, parallel
72
+ │ ├── analysis-engine.js # Shared analysis logic - file data, 3-tier routing, results (v2.13.0+)
73
+ │ ├── diff-analysis-orchestrator.js # Intelligent batch orchestration via Opus (v2.20.0)
74
+ │ ├── claude-client.js # Claude CLI wrapper - spawn, retry, model override
72
75
  │ ├── prompt-builder.js # Prompt construction - load templates, replace vars
73
76
  │ ├── git-operations.js # Git abstractions - staged files, diff, repo root, push, commit
74
77
  │ ├── file-utils.js # File operations - repo-relative paths
@@ -79,6 +82,7 @@ claude-git-hooks/
79
82
  │ ├── github-client.js # GitHub helpers - CODEOWNERS parsing, reviewers
80
83
  │ ├── task-id.js # Task ID extraction - Jira, GitHub, Linear patterns
81
84
  │ ├── interactive-ui.js # CLI UI components - previews, prompts, spinners
85
+ │ ├── judge.js # Auto-fix judge - LLM verdict + search/replace fixes (v2.20.0)
82
86
  │ ├── resolution-prompt.js # Issue resolution - AI-friendly fix prompts
83
87
  │ ├── installation-diagnostics.js # Installation diagnostics - error context
84
88
  │ ├── claude-diagnostics.js # Claude errors - rate limit, auth, formatting
@@ -94,9 +98,10 @@ claude-git-hooks/
94
98
  │ ├── check-version.sh # Version check - auto-update prompt
95
99
  │ ├── CLAUDE_PRE_COMMIT.md # Analysis criteria - evaluation guidelines
96
100
  │ ├── CLAUDE_ANALYSIS_PROMPT.md # Analysis prompt - code review template
97
- │ ├── CLAUDE_RESOLUTION_PROMPT.md # Resolution prompt - issue fix template
101
+ │ ├── CLAUDE_RESOLUTION_PROMPT.md # Resolution prompt - structured JSON output for judge + manual use
98
102
  │ ├── ANALYZE_DIFF.md # PR analysis - diff review template
99
103
  │ ├── GENERATE_CHANGELOG.md # CHANGELOG generation - commit analysis template (v2.12.0)
104
+ │ ├── DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md # Orchestration prompt - Opus batch grouping (v2.20.0)
100
105
  │ ├── HELP_QUERY.md # AI help - question answering with NEED_MORE_CONTEXT protocol (v2.18.0)
101
106
  │ ├── HELP_REPORT_ISSUE.md # Report issue - question generation from templates (v2.18.0)
102
107
  │ ├── HELP_COMPOSE_ISSUE.md # Report issue - issue body composition from answers (v2.18.0)
@@ -125,8 +130,9 @@ lib/utils/git-operations.js → getStagedFiles()
125
130
  lib/utils/file-operations.js → filterFiles()
126
131
  ↓ (builds file data + runs analysis)
127
132
  lib/utils/analysis-engine.js → buildFilesData(), runAnalysis()
128
- ↓ (orchestrates parallel/sequential Claude CLI calls)
129
- lib/utils/claude-client.js → analyzeCode() or analyzeCodeParallel()
133
+ ↓ (2-tier routing: 1-2 files→sequential, 3+→Opus orchestration)
134
+ lib/utils/diff-analysis-orchestrator.js → orchestrateBatches() [if N ≥ 3]
135
+ lib/utils/claude-client.js → analyzeCode(prompt, { model }) per batch [parallel]
130
136
  ↓ (displays results)
131
137
  lib/utils/analysis-engine.js → displayResults()
132
138
  ↓ (if blocking issues found)
@@ -164,23 +170,34 @@ preset config (.claude/presets/{name}/config.json) ← HIGHEST PRIORITY
164
170
  "verifyRemote": true // Verify remote exists (v2.11.0)
165
171
  }
166
172
  },
167
- "subagents": { "batchSize": 2 }
168
173
  }
169
174
  }
170
175
  ```
171
176
 
172
- **Hardcoded defaults (v2.8.0):**
177
+ **Hardcoded defaults (v2.8.0+):**
173
178
 
174
- | Parameter | Value | Notes |
175
- | -------------------- | ------- | ---------------------------- |
176
- | Max file size | 1MB | Files larger are skipped |
177
- | Max files per commit | 20 | Excess files trigger warning |
178
- | Parallel analysis | enabled | Always on for 3+ files |
179
- | Parallel model | haiku | Fast, cost-effective |
180
- | Parallel batch size | 3 | Files per Claude process |
181
- | Analysis timeout | 300s | Per-batch timeout |
182
- | Commit msg timeout | 300s | Message generation timeout |
183
- | PR metadata timeout | 180s | Engine default (reads config)|
179
+ | Parameter | Value | Notes |
180
+ | ----------------------- | ------- | -------------------------------------------------- |
181
+ | Max file size | 1MB | Files larger are skipped |
182
+ | Max files per commit | 30 | Excess files trigger warning |
183
+ | Orchestrator threshold | 3 files | Commits with 3 files use Opus orchestration |
184
+ | Orchestrator model | opus | Internal constant — not user-configurable |
185
+ | Orchestrator timeout | 60s | Lightweight call (file overview only) |
186
+ | Analysis timeout | 300s | Per-batch timeout |
187
+ | Commit msg timeout | 300s | Message generation timeout |
188
+ | PR metadata timeout | 180s | Engine default (reads config) |
189
+ | Judge model | opus | Default, configurable via `config.judge.model` |
190
+ | Judge timeout | 120s | Per-judge call timeout |
191
+
192
+ **Judge behavior (v2.20.0):**
193
+
194
+ - Enabled by default (`config.judge?.enabled !== false`)
195
+ - Runs on **all issues** (any severity), not just blockers
196
+ - **Any unresolved issue blocks the commit** — no issue passes without judge approval
197
+ - Judge failure (timeout, JSON parse error, module load) → user warned → commit blocked
198
+ - No retries — failed fixes stay as unresolved issues
199
+ - When disabled (`config.judge.enabled: false`), falls back to original quality gate (blocks on CRITICAL/BLOCKER only)
200
+ - Resolution prompt file is only generated if issues remain after the judge
184
201
 
185
202
  **3. Presets System**
186
203
 
@@ -193,21 +210,36 @@ preset config (.claude/presets/{name}/config.json) ← HIGHEST PRIORITY
193
210
  | `ai` | `.js`, `.json`, `.md`, `.sh` | Node.js + Claude API | Prompts, API key security, cross-platform |
194
211
  | `default` | `.js`, `.sh`, `.py`, `.rb`, `.pl`, `.sql`, `.yaml`, `.json`, `.xml`, `.md` | Multiple | Quality and security fundamentals |
195
212
 
196
- **4. Parallel Analysis (v2.2.0+)**
213
+ **4. Analysis Routing (v2.20.0)**
214
+
215
+ Three-tier strategy based on file count:
197
216
 
198
- When 3+ files are present, the system divides into batches and executes multiple `claude` CLI processes in parallel:
217
+ | Files | Strategy |
218
+ |-------|----------|
219
+ | 1–2 | Sequential — single Claude call |
220
+ | **3+** | **Intelligent orchestration** — Opus orchestrator, semantic grouping, per-batch model, shared context |
221
+
222
+ **Orchestration flow (3+ files):**
199
223
 
200
224
  ```
201
- 4 files + batchSize=2
225
+ staged files (N ≥ 3)
226
+
227
+ [ORCHESTRATOR — Opus, 60s timeout]
228
+ Input: file overview table + detected cross-file deps (JS/TS/Java/Python regex)
229
+ Output: { batches: [{ filePaths, rationale, model }] }
202
230
 
203
- Batch 1: [file1, file2] → claude CLI process #1 (parallel)
204
- Batch 2: [file3, file4] claude CLI process #2 (parallel)
231
+ For each batch:
232
+ buildAnalysisPrompt(batchFiles + commonContext + batchRationale)
233
+ → analyzeCode(prompt, { model: batch.model }) ← per-batch model
234
+ [all batches run in parallel via Promise.all]
205
235
 
206
- Wait for both → consolidate results
236
+ consolidateResults()
207
237
  ```
208
238
 
209
- - **Configuration**: `.claude/config.json` `subagents.batchSize`, `subagents.model` (haiku/sonnet/opus)
210
- - **Speed-up**: ~4x faster with batch=1 (1 file per process)
239
+ - **Orchestration model**: `opus` hardcoded internal constant, not user-configurable
240
+ - **Threshold**: `ORCHESTRATOR_THRESHOLD = 3` internal constant in `analysis-engine.js`
241
+ - **Fallback**: any orchestration failure → one-file-per-batch with haiku
242
+ - **Common context**: each batch prompt prefixed with commit overview, dep graph, and batch rationale
211
243
 
212
244
  ### Key Module Exports
213
245
 
@@ -229,16 +261,19 @@ Wait for both → consolidate results
229
261
  | `migrate-config.js` | Config migration | `runMigrateConfig()` |
230
262
  | `debug.js` | Debug toggle | `runSetDebug()` |
231
263
  | `telemetry-cmd.js` | Telemetry commands | `runShowTelemetry()`, `runClearTelemetry()` |
264
+ | `diff-batch-info.js` | Batch info display | `runDiffBatchInfo()` |
232
265
  | `help.js` | Help, AI help, report-issue | `runShowHelp()`, `showStaticHelp()`, `runShowVersion()` |
233
266
 
234
267
  **Utility Modules (`lib/utils/`):**
235
268
 
236
269
  | Module | Purpose | Key Exports |
237
270
  | ------------------------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
271
+ | `lib/cli-metadata.js` | Command registry | `commands`, `buildCommandMap()`, `generateCompletionData()`, `PRESET_NAMES`, `HOOK_NAMES`, `BUMP_TYPES` |
238
272
  | `lib/config.js` | Config system | `getConfig()` |
239
- | `analysis-engine.js` | Shared analysis logic | `buildFileData()`, `buildFilesData()`, `runAnalysis()`, `consolidateResults()`, `hasBlockingIssues()`, `hasAnyIssues()`, `displayResults()`, `displayIssueSummary()` (v2.13.0) |
240
- | `claude-client.js` | Claude CLI wrapper | `analyzeCode()`, `analyzeCodeParallel()`, `executeClaudeWithRetry()` |
241
- | `prompt-builder.js` | Prompt construction | `buildAnalysisPrompt()`, `loadPrompt()` |
273
+ | `analysis-engine.js` | Shared analysis logic | `buildFileData()`, `buildFilesData()`, `runAnalysis()`, `consolidateResults()`, `hasBlockingIssues()`, `hasAnyIssues()`, `displayResults()`, `displayIssueSummary()` (v2.13.0+) |
274
+ | `diff-analysis-orchestrator.js` | Intelligent batch orchestration | `orchestrateBatches()`, `buildFileOverview()`, `detectDependencies()` (v2.20.0) |
275
+ | `claude-client.js` | Claude CLI wrapper | `analyzeCode()`, `executeClaudeWithRetry()`, `extractJSON()` — spawn, retry, model override |
276
+ | `prompt-builder.js` | Prompt construction | `buildAnalysisPrompt()`, `loadPrompt()` — accepts `commonContext`, `batchRationale` |
242
277
  | `git-operations.js` | Git abstractions | `getStagedFiles()`, `getUnstagedFiles()`, `getAllTrackedFiles()`, `getDiff()`, `getRepoRoot()`, `getBranchPushStatus()`, `pushBranch()`, `createCommit()`, `fetchRemote()`, `branchExists()`, `getRemoteBranches()`, `resolveBaseBranch()`, `getChangedFilesBetweenRefs()`, `getDiffBetweenRefs()`, `getCommitsBetweenRefs()` |
243
278
  | `file-utils.js` | File operations | `ensureDir()`, `ensureOutputDir()`, `writeOutputFile()`, `walkDirectoryTree()` |
244
279
  | `pr-metadata-engine.js` | PR metadata generation | `getBranchContext()`, `buildDiffPayload()`, `generatePRMetadata()`, `analyzeBranchForPR()` (v2.14.0) |
@@ -250,18 +285,21 @@ Wait for both → consolidate results
250
285
  | `preset-loader.js` | Preset system | `loadPreset()`, `listPresets()` |
251
286
  | `task-id.js` | Task ID extraction | `getOrPromptTaskId()`, `formatWithTaskId()` |
252
287
  | `logger.js` | Logging system | `info()`, `warning()`, `error()`, `debug()` |
288
+ | `judge.js` | Auto-fix judge | `judgeAndFix()`, `applyFix()` — LLM verdict + search/replace fixes (v2.20.0) |
253
289
  | `resolution-prompt.js` | Issue resolution | `generateResolutionPrompt()` |
254
290
  | `interactive-ui.js` | CLI UI components | `showPRPreview()`, `promptConfirmation()`, `promptMenu()`, `promptToggleList()`, `promptEditField()`, `promptUserConfirmation()` |
255
291
  | `telemetry.js` | Local telemetry | `recordEvent()`, `displayStatistics()` |
256
292
 
257
293
  ### Design Patterns
258
294
 
259
- 1. **Command Pattern**: `lib/commands/*.js` - each CLI command is a self-contained module
260
- 2. **Factory Pattern**: `preset-loader.js` loads configurations dynamically per tech-stack
261
- 3. **Template Method**: `prompt-builder.js` builds prompts from markdown templates
262
- 4. **Strategy Pattern**: `claude-client.js` selects between sequential or parallel analysis
263
- 5. **Adapter Pattern**: `git-operations.js` abstracts git commands into JS functions
264
- 6. **Singleton Pattern**: `config.js` loads configuration once per execution
295
+ 1. **Command Registry**: `lib/cli-metadata.js` - single source of truth for CLI commands, flags, and descriptions. When adding CLI commands, add an entry to `lib/cli-metadata.js` — routing, completions, and help derive from it.
296
+ 2. **Command Pattern**: `lib/commands/*.js` - each CLI command is a self-contained module
297
+ 3. **Factory Pattern**: `preset-loader.js` loads configurations dynamically per tech-stack
298
+ 4. **Template Method**: `prompt-builder.js` builds prompts from markdown templates
299
+ 5. **Strategy Pattern**: `analysis-engine.js` selects between sequential (1–2 files) or orchestrated (3+ files) analysis based on file count threshold
300
+ 6. **Orchestrator Pattern**: `diff-analysis-orchestrator.js` Opus decides semantic grouping and model assignment; workers (analyzeCode per batch) execute in parallel
301
+ 7. **Adapter Pattern**: `git-operations.js` abstracts git commands into JS functions
302
+ 8. **Singleton Pattern**: `config.js` loads configuration once per execution
265
303
 
266
304
  ### Key Data Flows
267
305
 
@@ -272,9 +310,15 @@ git commit
272
310
  → hook reads staged files
273
311
  → filters by preset extensions
274
312
  → builds prompt with diff
275
- → Claude analyzes → detects SQL injection (CRITICAL)
276
- generates resolution prompt
277
- exit 1 COMMIT BLOCKED
313
+ → Claude analyzes → detects issues
314
+ judge evaluates ALL issues (any severity):
315
+ TRUE_ISSUE: applies search/replace fix + git add
316
+ → FALSE_POSITIVE: dismissed
317
+ → if ALL resolved: exit 0 → COMMIT PROCEEDS
318
+ → if ANY unresolved: generates resolution prompt → exit 1 → COMMIT BLOCKED
319
+ → if judge fails (timeout, parse error): user warned → exit 1 → COMMIT BLOCKED
320
+ → judge disabled (config.judge.enabled: false):
321
+ → falls back to original quality gate (blocks on CRITICAL/BLOCKER only)
278
322
  ```
279
323
 
280
324
  **Flow 1.5: Interactive analysis command (v2.13.0)**
@@ -645,6 +689,9 @@ claude-hooks generate-changelog # Generate CHANGELOG only
645
689
  claude-hooks help "how do presets work?" # AI-powered help (uses CLAUDE.md)
646
690
  claude-hooks help --report-issue # Interactive issue creation
647
691
 
692
+ # Orchestration diagnostics
693
+ claude-hooks batch-info # Orchestration config + per-model speed telemetry
694
+
648
695
  # Debugging
649
696
  claude-hooks --debug true # Enable debug mode
650
697
  claude-hooks --debug false # Disable debug mode
package/README.md CHANGED
@@ -218,6 +218,14 @@ claude-hooks help --report-issue # Interactive GitHub issue creation
218
218
  claude-hooks --help # Static command reference
219
219
  ```
220
220
 
221
+ ### Batch Info
222
+
223
+ ```bash
224
+ claude-hooks batch-info
225
+ # Shows: orchestration model, threshold, default analysis model
226
+ # Shows: per-model average analysis time and orchestration overhead (from telemetry)
227
+ ```
228
+
221
229
  ### Other Commands
222
230
 
223
231
  ```bash
@@ -262,6 +270,7 @@ claude-hooks update # Update to latest version
262
270
  | `migrate-config.js` | **Config migration** - legacy to v2.8.0 format | `runMigrateConfig()` |
263
271
  | `debug.js` | **Debug toggle** - enable/disable verbose logging | `runSetDebug()` |
264
272
  | `telemetry-cmd.js` | **Telemetry commands** - show/clear statistics | `runShowTelemetry()`, `runClearTelemetry()` |
273
+ | `diff-batch-info.js` | **Batch info** - orchestration config + per-model speed telemetry | `runDiffBatchInfo()` |
265
274
  | `help.js` | **Help, AI help, report-issue** | `runShowHelp()`, `showStaticHelp()`, `runShowVersion()` |
266
275
 
267
276
  ### Utility Modules (`lib/utils/`)
@@ -269,14 +278,16 @@ claude-hooks update # Update to latest version
269
278
  | Module | Purpose | Key Exports |
270
279
  |--------|---------|-------------|
271
280
  | `analysis-engine.js` | **Shared analysis logic** - file data, orchestration, results (v2.13.0) | `buildFilesData()`, `runAnalysis()`, `consolidateResults()`, `displayResults()` |
272
- | `claude-client.js` | **Claude CLI wrapper** - spawn, retry, parallel execution | `analyzeCode()`, `analyzeCodeParallel()`, `executeClaudeWithRetry()` |
273
- | `prompt-builder.js` | **Prompt construction** - load templates, replace variables | `buildAnalysisPrompt()`, `loadPrompt()` |
281
+ | `diff-analysis-orchestrator.js` | **Intelligent orchestration** - semantic batch grouping via Opus (v2.20.0) | `orchestrateBatches()`, `buildFileOverview()`, `detectDependencies()` |
282
+ | `claude-client.js` | **Claude CLI wrapper** - spawn, retry, model override | `analyzeCode()`, `executeClaudeWithRetry()`, `extractJSON()` |
283
+ | `prompt-builder.js` | **Prompt construction** - load templates, replace variables, inject commit context | `buildAnalysisPrompt()`, `loadPrompt()` |
274
284
  | `git-operations.js` | **Git abstractions** - staged files, diff, branch comparison | `getStagedFiles()`, `getDiff()`, `getRepoRoot()`, `resolveBaseBranch()`, `getDiffBetweenRefs()` |
275
285
  | `pr-metadata-engine.js` | **PR metadata generation** - branch context, diff reduction (v2.14.0) | `getBranchContext()`, `buildDiffPayload()`, `generatePRMetadata()`, `analyzeBranchForPR()` |
276
286
  | `github-api.js` | **Octokit integration** - PR creation, token validation, content fetching | `createPullRequest()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()` |
277
287
  | `github-client.js` | **GitHub helpers** - CODEOWNERS parsing, reviewers | `getReviewersForFiles()`, `parseGitHubRepo()` |
278
288
  | `preset-loader.js` | **Preset system** - load tech-stack configurations | `loadPreset()`, `listPresets()` |
279
289
  | `task-id.js` | **Task ID extraction** - Jira, GitHub, Linear patterns | `getOrPromptTaskId()`, `formatWithTaskId()` |
290
+ | `judge.js` | **Auto-fix judge** - LLM verdict + search/replace fixes (v2.20.0) | `judgeAndFix()`, `applyFix()` |
280
291
  | `resolution-prompt.js` | **Issue resolution** - AI-friendly fix prompts | `generateResolutionPrompt()` |
281
292
  | `logger.js` | **Logging system** - centralized output with debug mode | `info()`, `warning()`, `error()`, `debug()` |
282
293
  | `interactive-ui.js` | **CLI UI components** - previews, prompts, spinners | `showPRPreview()`, `promptConfirmation()`, `promptMenu()` |
@@ -292,9 +303,13 @@ git commit → templates/pre-commit (bash wrapper)
292
303
  → getStagedFiles() → filterFiles() by preset extensions + size
293
304
  → buildFilesData() → runAnalysis() (via analysis-engine.js)
294
305
  → displayResults() → show quality gate status
295
- if blocking issues (critical/blocker):
296
- generates claude_resolution_prompt.md exit 1 (block)
297
- if non-blocking or no issues: exit 0 (pass)
306
+ judge evaluates ALL issues (any severity):
307
+ TRUE_ISSUE: auto-fix via search/replace + git add
308
+ FALSE_POSITIVE: dismissed
309
+ → ALL resolved: exit 0 (pass)
310
+ → ANY unresolved: generates resolution prompt → exit 1 (block)
311
+ → judge failure: user warned → exit 1 (block)
312
+ → judge disabled: original quality gate (blocks on critical/blocker only)
298
313
  ```
299
314
 
300
315
  **Note:** For interactive review of non-blocking issues, use `claude-hooks analyze` before committing.
@@ -350,7 +365,6 @@ Preset always wins - tech-stack specific has priority over user preferences.
350
365
  "verifyRemote": true // Verify remote exists (v2.11.0)
351
366
  }
352
367
  },
353
- "subagents": { "batchSize": 2 }
354
368
  }
355
369
  }
356
370
  ```
@@ -359,7 +373,7 @@ Preset always wins - tech-stack specific has priority over user preferences.
359
373
 
360
374
  - **Factory**: `preset-loader.js` - dynamic config per tech-stack
361
375
  - **Template Method**: `prompt-builder.js` - prompts from .md templates
362
- - **Strategy**: `claude-client.js` - sequential vs parallel analysis
376
+ - **Strategy**: `analysis-engine.js` - sequential vs orchestrated analysis
363
377
  - **Adapter**: `git-operations.js` - git commands to JS functions
364
378
  - **Command**: `lib/commands/*.js` - one module per CLI command
365
379
 
@@ -377,6 +391,9 @@ Preset always wins - tech-stack specific has priority over user preferences.
377
391
  | Config defaults | `lib/config.js` |
378
392
  | GitHub integration | `lib/utils/github-api.js` |
379
393
  | Claude CLI calls | `lib/utils/claude-client.js` |
394
+ | Batch orchestration logic | `lib/utils/diff-analysis-orchestrator.js` |
395
+ | Orchestration prompt | `templates/DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md` |
396
+ | Auto-fix judge logic | `lib/utils/judge.js` |
380
397
 
381
398
  ### File Structure
382
399
 
@@ -397,33 +414,50 @@ claude-git-hooks/
397
414
  │ │ ├── migrate-config.js # Migration - legacy to v2.8.0
398
415
  │ │ ├── debug.js # Debug mode - toggle verbose
399
416
  │ │ ├── telemetry-cmd.js # Telemetry - show/clear stats
417
+ │ │ ├── diff-batch-info.js # Batch info - orchestration config
400
418
  │ │ └── help.js # Help display - usage info
401
419
  │ ├── hooks/ # Git hooks - Node.js logic
402
420
  │ │ ├── pre-commit.js # Pre-commit analysis
403
421
  │ │ └── prepare-commit-msg.js # Message generation
404
422
  │ └── utils/ # Reusable modules - shared logic
423
+ │ ├── diff-analysis-orchestrator.js # Intelligent batch orchestration
424
+ │ └── judge.js # Auto-fix judge (v2.20.0)
405
425
  ├── templates/
406
426
  │ ├── pre-commit # Bash wrapper - invokes Node.js
407
427
  │ ├── prepare-commit-msg # Bash wrapper - invokes Node.js
408
- │ ├── *.md # Prompt templates
428
+ │ ├── DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md # Opus orchestration prompt
429
+ │ ├── *.md # Other prompt templates
409
430
  │ └── presets/ # Preset configurations
410
431
  └── test/unit/ # Jest tests
411
432
  ```
412
433
 
413
- ### Parallel Analysis (3+ files)
434
+ ### Analysis Routing (v2.20.0)
435
+
436
+ Two-tier strategy based on file count:
414
437
 
415
- Files split into batches, each batch runs in separate Claude CLI process:
416
- - `batchSize: 1` → Maximum parallelism (1 file per process)
417
- - `batchSize: 2` Balanced (2 files per process)
418
- - Results consolidated automatically
438
+ | Files | Strategy | Details |
439
+ |-------|----------|---------|
440
+ | 1–2 | Sequential | Single Claude call, full context |
441
+ | 3+ | **Intelligent orchestration** | Opus groups files semantically, assigns model per batch, shared commit context |
442
+
443
+ **Orchestration flow (3+ files):**
444
+ 1. Opus reads a lightweight file overview + detected cross-file dependencies
445
+ 2. Groups related files into semantically coherent batches
446
+ 3. Assigns model per batch: `haiku` (config/docs), `sonnet` (business logic), `opus` (security-critical)
447
+ 4. All batches run in parallel; each receives a shared commit overview header
448
+ 5. Falls back to one-file-per-batch if orchestration fails
449
+
450
+ **Inspect orchestration settings:**
451
+ ```bash
452
+ claude-hooks batch-info # Shows config + per-model avg speed from telemetry
453
+ ```
419
454
 
420
- ### Hardcoded Defaults (v2.8.0)
455
+ ### Hardcoded Defaults (v2.8.0+)
421
456
 
422
457
  - Max file size: 1MB
423
- - Max files per commit: 20
424
- - Parallel analysis: enabled
425
- - Parallel model: haiku
426
- - Parallel batch size: 3
458
+ - Max files per commit: 30
459
+ - Orchestrator threshold: 3 files
460
+ - Orchestrator model: opus (internal, not configurable)
427
461
 
428
462
  ---
429
463
 
package/bin/claude-hooks CHANGED
@@ -4,27 +4,12 @@
4
4
  * File: claude-hooks
5
5
  * Purpose: Main CLI entry point - thin router to command modules
6
6
  *
7
+ * Routes commands via cli-metadata.js registry.
7
8
  * All command implementations are in lib/commands/
8
- * This file only handles argument parsing and routing.
9
9
  */
10
10
 
11
11
  import { error } from '../lib/commands/helpers.js';
12
-
13
- // Import commands
14
- import { runInstall } from '../lib/commands/install.js';
15
- import { runEnable, runDisable, runStatus, runUninstall } from '../lib/commands/hooks.js';
16
- import { runAnalyze } from '../lib/commands/analyze.js';
17
- import { runAnalyzeDiff } from '../lib/commands/analyze-diff.js';
18
- import { runCreatePr } from '../lib/commands/create-pr.js';
19
- import { runSetupGitHub } from '../lib/commands/setup-github.js';
20
- import { runShowPresets, runSetPreset, runCurrentPreset } from '../lib/commands/presets.js';
21
- import { runUpdate } from '../lib/commands/update.js';
22
- import { runMigrateConfig } from '../lib/commands/migrate-config.js';
23
- import { runSetDebug } from '../lib/commands/debug.js';
24
- import { runShowTelemetry, runClearTelemetry } from '../lib/commands/telemetry-cmd.js';
25
- import { runShowHelp, runShowVersion } from '../lib/commands/help.js';
26
- import { runBumpVersion } from '../lib/commands/bump-version.js';
27
- import { runGenerateChangelog } from '../lib/commands/generate-changelog.js';
12
+ import { buildCommandMap } from '../lib/cli-metadata.js';
28
13
 
29
14
  /**
30
15
  * Main CLI router
@@ -33,97 +18,98 @@ async function main() {
33
18
  const args = process.argv.slice(2);
34
19
  const command = args[0];
35
20
 
36
- switch (command) {
37
- case 'install':
38
- await runInstall(args.slice(1));
39
- break;
40
- case 'update':
41
- await runUpdate();
42
- break;
43
- case 'uninstall':
44
- runUninstall();
45
- break;
46
- case 'enable':
47
- runEnable(args[1]);
48
- break;
49
- case 'disable':
50
- runDisable(args[1]);
51
- break;
52
- case 'status':
53
- runStatus();
54
- break;
55
- case 'analyze':
56
- await runAnalyze({
21
+ const commandMap = buildCommandMap();
22
+ const entry = commandMap.get(command);
23
+
24
+ // help / --help / -h / no command
25
+ if (command === undefined || command === '--help' || command === '-h') {
26
+ const { runShowHelp } = await import('../lib/commands/help.js');
27
+ await runShowHelp();
28
+ return;
29
+ }
30
+
31
+ if (!entry) {
32
+ error(`Unknown command: ${command}`);
33
+ const { runShowHelp } = await import('../lib/commands/help.js');
34
+ runShowHelp();
35
+ return;
36
+ }
37
+
38
+ // --- Commands with special argument handling ---
39
+
40
+ // analyze: translate flags to options object
41
+ if (entry.name === 'analyze') {
42
+ const handler = await entry.handler();
43
+ await handler({
57
44
  staged: !args.includes('--unstaged') && !args.includes('--all'),
58
45
  unstaged: args.includes('--unstaged'),
59
46
  all: args.includes('--all')
60
47
  });
61
- break;
62
- case 'analyze-diff':
63
- await runAnalyzeDiff(args.slice(1));
64
- break;
65
- case 'create-pr':
66
- await runCreatePr(args.slice(1));
67
- break;
68
- case 'setup-github':
69
- await runSetupGitHub();
70
- break;
71
- case 'presets':
72
- await runShowPresets();
73
- break;
74
- case '--set-preset':
75
- await runSetPreset(args[1]);
76
- break;
77
- case 'preset':
78
- // Handle subcommands: preset current
48
+ return;
49
+ }
50
+
51
+ // preset: subcommand routing
52
+ if (entry.name === 'preset') {
79
53
  if (args[1] === 'current') {
54
+ const { runCurrentPreset } = await import('../lib/commands/presets.js');
80
55
  await runCurrentPreset();
81
56
  } else {
82
57
  error(`Unknown preset subcommand: ${args[1]}`);
83
58
  }
84
- break;
85
- case 'migrate-config':
86
- await runMigrateConfig();
87
- break;
88
- case 'bump-version':
89
- await runBumpVersion(args.slice(1));
90
- break;
91
- case 'generate-changelog':
92
- await runGenerateChangelog(args.slice(1));
93
- break;
94
- case 'telemetry':
95
- // Handle subcommands: telemetry show, telemetry clear
59
+ return;
60
+ }
61
+
62
+ // telemetry: subcommand routing
63
+ if (entry.name === 'telemetry') {
96
64
  if (args[1] === 'show' || args[1] === undefined) {
65
+ const { runShowTelemetry } = await import('../lib/commands/telemetry-cmd.js');
97
66
  await runShowTelemetry();
98
67
  } else if (args[1] === 'clear') {
68
+ const { runClearTelemetry } = await import('../lib/commands/telemetry-cmd.js');
99
69
  await runClearTelemetry();
100
70
  } else {
101
71
  error(`Unknown telemetry subcommand: ${args[1]}`);
102
72
  }
103
- break;
104
- case '--debug':
105
- await runSetDebug(args[1]);
106
- break;
107
- case '--version':
108
- case '-v':
109
- case 'version':
110
- runShowVersion();
111
- break;
112
- case 'help':
113
- await runShowHelp(args.slice(1));
114
- break;
115
- case '--help':
116
- case '-h':
117
- case undefined:
118
- runShowHelp();
119
- break;
120
- default:
121
- error(`Unknown command: ${command}`);
122
- runShowHelp();
73
+ return;
74
+ }
75
+
76
+ // --- Commands that take args[1] as single argument ---
77
+ // enable/disable take optional hook name
78
+ if (entry.name === 'enable' || entry.name === 'disable') {
79
+ const handler = await entry.handler();
80
+ handler(args[1]);
81
+ return;
123
82
  }
83
+
84
+ // --set-preset takes preset name, --debug takes value
85
+ if (entry.name === '--set-preset' || entry.name === '--debug') {
86
+ const handler = await entry.handler();
87
+ await handler(args[1]);
88
+ return;
89
+ }
90
+
91
+ // --- Commands that take args.slice(1) ---
92
+ if (
93
+ [
94
+ 'install',
95
+ 'analyze-diff',
96
+ 'create-pr',
97
+ 'bump-version',
98
+ 'generate-changelog',
99
+ 'help'
100
+ ].includes(entry.name)
101
+ ) {
102
+ const handler = await entry.handler();
103
+ await handler(args.slice(1));
104
+ return;
105
+ }
106
+
107
+ // --- Commands with no arguments ---
108
+ const handler = await entry.handler();
109
+ await handler();
124
110
  }
125
111
 
126
112
  // Execute main
127
- main().catch(err => {
113
+ main().catch((err) => {
128
114
  error(`Unexpected error: ${err.message}`);
129
115
  });