claude-git-hooks 2.19.0 → 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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,34 @@ 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
+
8
36
  ## [2.19.0] - 2026-03-06
9
37
 
10
38
  ### ✨ Added
package/CLAUDE.md CHANGED
@@ -63,13 +63,15 @@ claude-git-hooks/
63
63
  │ │ ├── telemetry-cmd.js # Telemetry commands - show/clear statistics
64
64
  │ │ ├── bump-version.js # Version management - bump with commit, CHANGELOG and tags
65
65
  │ │ ├── generate-changelog.js # CHANGELOG generation - standalone command
66
+ │ │ ├── diff-batch-info.js # Batch info - orchestration config + speed telemetry (v2.20.0)
66
67
  │ │ └── help.js # Help, AI help, and report-issue commands
67
68
  │ ├── hooks/ # Git hooks - Node.js implementations
68
69
  │ │ ├── pre-commit.js # Pre-commit analysis - code quality gate
69
70
  │ │ └── prepare-commit-msg.js # Message generation - auto commit messages
70
71
  │ └── utils/ # Reusable modules - shared logic
71
- │ ├── analysis-engine.js # Shared analysis logic - file data, orchestration, results (v2.13.0)
72
- │ ├── 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
73
75
  │ ├── prompt-builder.js # Prompt construction - load templates, replace vars
74
76
  │ ├── git-operations.js # Git abstractions - staged files, diff, repo root, push, commit
75
77
  │ ├── file-utils.js # File operations - repo-relative paths
@@ -80,6 +82,7 @@ claude-git-hooks/
80
82
  │ ├── github-client.js # GitHub helpers - CODEOWNERS parsing, reviewers
81
83
  │ ├── task-id.js # Task ID extraction - Jira, GitHub, Linear patterns
82
84
  │ ├── interactive-ui.js # CLI UI components - previews, prompts, spinners
85
+ │ ├── judge.js # Auto-fix judge - LLM verdict + search/replace fixes (v2.20.0)
83
86
  │ ├── resolution-prompt.js # Issue resolution - AI-friendly fix prompts
84
87
  │ ├── installation-diagnostics.js # Installation diagnostics - error context
85
88
  │ ├── claude-diagnostics.js # Claude errors - rate limit, auth, formatting
@@ -95,9 +98,10 @@ claude-git-hooks/
95
98
  │ ├── check-version.sh # Version check - auto-update prompt
96
99
  │ ├── CLAUDE_PRE_COMMIT.md # Analysis criteria - evaluation guidelines
97
100
  │ ├── CLAUDE_ANALYSIS_PROMPT.md # Analysis prompt - code review template
98
- │ ├── CLAUDE_RESOLUTION_PROMPT.md # Resolution prompt - issue fix template
101
+ │ ├── CLAUDE_RESOLUTION_PROMPT.md # Resolution prompt - structured JSON output for judge + manual use
99
102
  │ ├── ANALYZE_DIFF.md # PR analysis - diff review template
100
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)
101
105
  │ ├── HELP_QUERY.md # AI help - question answering with NEED_MORE_CONTEXT protocol (v2.18.0)
102
106
  │ ├── HELP_REPORT_ISSUE.md # Report issue - question generation from templates (v2.18.0)
103
107
  │ ├── HELP_COMPOSE_ISSUE.md # Report issue - issue body composition from answers (v2.18.0)
@@ -126,8 +130,9 @@ lib/utils/git-operations.js → getStagedFiles()
126
130
  lib/utils/file-operations.js → filterFiles()
127
131
  ↓ (builds file data + runs analysis)
128
132
  lib/utils/analysis-engine.js → buildFilesData(), runAnalysis()
129
- ↓ (orchestrates parallel/sequential Claude CLI calls)
130
- 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]
131
136
  ↓ (displays results)
132
137
  lib/utils/analysis-engine.js → displayResults()
133
138
  ↓ (if blocking issues found)
@@ -165,23 +170,34 @@ preset config (.claude/presets/{name}/config.json) ← HIGHEST PRIORITY
165
170
  "verifyRemote": true // Verify remote exists (v2.11.0)
166
171
  }
167
172
  },
168
- "subagents": { "batchSize": 2 }
169
173
  }
170
174
  }
171
175
  ```
172
176
 
173
- **Hardcoded defaults (v2.8.0):**
177
+ **Hardcoded defaults (v2.8.0+):**
174
178
 
175
- | Parameter | Value | Notes |
176
- | -------------------- | ------- | ---------------------------- |
177
- | Max file size | 1MB | Files larger are skipped |
178
- | Max files per commit | 20 | Excess files trigger warning |
179
- | Parallel analysis | enabled | Always on for 3+ files |
180
- | Parallel model | haiku | Fast, cost-effective |
181
- | Parallel batch size | 3 | Files per Claude process |
182
- | Analysis timeout | 300s | Per-batch timeout |
183
- | Commit msg timeout | 300s | Message generation timeout |
184
- | 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
185
201
 
186
202
  **3. Presets System**
187
203
 
@@ -194,21 +210,36 @@ preset config (.claude/presets/{name}/config.json) ← HIGHEST PRIORITY
194
210
  | `ai` | `.js`, `.json`, `.md`, `.sh` | Node.js + Claude API | Prompts, API key security, cross-platform |
195
211
  | `default` | `.js`, `.sh`, `.py`, `.rb`, `.pl`, `.sql`, `.yaml`, `.json`, `.xml`, `.md` | Multiple | Quality and security fundamentals |
196
212
 
197
- **4. Parallel Analysis (v2.2.0+)**
213
+ **4. Analysis Routing (v2.20.0)**
214
+
215
+ Three-tier strategy based on file count:
198
216
 
199
- 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):**
200
223
 
201
224
  ```
202
- 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 }] }
203
230
 
204
- Batch 1: [file1, file2] → claude CLI process #1 (parallel)
205
- 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]
206
235
 
207
- Wait for both → consolidate results
236
+ consolidateResults()
208
237
  ```
209
238
 
210
- - **Configuration**: `.claude/config.json` `subagents.batchSize`, `subagents.model` (haiku/sonnet/opus)
211
- - **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
212
243
 
213
244
  ### Key Module Exports
214
245
 
@@ -230,6 +261,7 @@ Wait for both → consolidate results
230
261
  | `migrate-config.js` | Config migration | `runMigrateConfig()` |
231
262
  | `debug.js` | Debug toggle | `runSetDebug()` |
232
263
  | `telemetry-cmd.js` | Telemetry commands | `runShowTelemetry()`, `runClearTelemetry()` |
264
+ | `diff-batch-info.js` | Batch info display | `runDiffBatchInfo()` |
233
265
  | `help.js` | Help, AI help, report-issue | `runShowHelp()`, `showStaticHelp()`, `runShowVersion()` |
234
266
 
235
267
  **Utility Modules (`lib/utils/`):**
@@ -238,9 +270,10 @@ Wait for both → consolidate results
238
270
  | ------------------------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
239
271
  | `lib/cli-metadata.js` | Command registry | `commands`, `buildCommandMap()`, `generateCompletionData()`, `PRESET_NAMES`, `HOOK_NAMES`, `BUMP_TYPES` |
240
272
  | `lib/config.js` | Config system | `getConfig()` |
241
- | `analysis-engine.js` | Shared analysis logic | `buildFileData()`, `buildFilesData()`, `runAnalysis()`, `consolidateResults()`, `hasBlockingIssues()`, `hasAnyIssues()`, `displayResults()`, `displayIssueSummary()` (v2.13.0) |
242
- | `claude-client.js` | Claude CLI wrapper | `analyzeCode()`, `analyzeCodeParallel()`, `executeClaudeWithRetry()` |
243
- | `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` |
244
277
  | `git-operations.js` | Git abstractions | `getStagedFiles()`, `getUnstagedFiles()`, `getAllTrackedFiles()`, `getDiff()`, `getRepoRoot()`, `getBranchPushStatus()`, `pushBranch()`, `createCommit()`, `fetchRemote()`, `branchExists()`, `getRemoteBranches()`, `resolveBaseBranch()`, `getChangedFilesBetweenRefs()`, `getDiffBetweenRefs()`, `getCommitsBetweenRefs()` |
245
278
  | `file-utils.js` | File operations | `ensureDir()`, `ensureOutputDir()`, `writeOutputFile()`, `walkDirectoryTree()` |
246
279
  | `pr-metadata-engine.js` | PR metadata generation | `getBranchContext()`, `buildDiffPayload()`, `generatePRMetadata()`, `analyzeBranchForPR()` (v2.14.0) |
@@ -252,6 +285,7 @@ Wait for both → consolidate results
252
285
  | `preset-loader.js` | Preset system | `loadPreset()`, `listPresets()` |
253
286
  | `task-id.js` | Task ID extraction | `getOrPromptTaskId()`, `formatWithTaskId()` |
254
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) |
255
289
  | `resolution-prompt.js` | Issue resolution | `generateResolutionPrompt()` |
256
290
  | `interactive-ui.js` | CLI UI components | `showPRPreview()`, `promptConfirmation()`, `promptMenu()`, `promptToggleList()`, `promptEditField()`, `promptUserConfirmation()` |
257
291
  | `telemetry.js` | Local telemetry | `recordEvent()`, `displayStatistics()` |
@@ -262,9 +296,10 @@ Wait for both → consolidate results
262
296
  2. **Command Pattern**: `lib/commands/*.js` - each CLI command is a self-contained module
263
297
  3. **Factory Pattern**: `preset-loader.js` loads configurations dynamically per tech-stack
264
298
  4. **Template Method**: `prompt-builder.js` builds prompts from markdown templates
265
- 5. **Strategy Pattern**: `claude-client.js` selects between sequential or parallel analysis
266
- 6. **Adapter Pattern**: `git-operations.js` abstracts git commands into JS functions
267
- 7. **Singleton Pattern**: `config.js` loads configuration once per execution
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
268
303
 
269
304
  ### Key Data Flows
270
305
 
@@ -275,9 +310,15 @@ git commit
275
310
  → hook reads staged files
276
311
  → filters by preset extensions
277
312
  → builds prompt with diff
278
- → Claude analyzes → detects SQL injection (CRITICAL)
279
- generates resolution prompt
280
- 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)
281
322
  ```
282
323
 
283
324
  **Flow 1.5: Interactive analysis command (v2.13.0)**
@@ -648,6 +689,9 @@ claude-hooks generate-changelog # Generate CHANGELOG only
648
689
  claude-hooks help "how do presets work?" # AI-powered help (uses CLAUDE.md)
649
690
  claude-hooks help --report-issue # Interactive issue creation
650
691
 
692
+ # Orchestration diagnostics
693
+ claude-hooks batch-info # Orchestration config + per-model speed telemetry
694
+
651
695
  # Debugging
652
696
  claude-hooks --debug true # Enable debug mode
653
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
 
@@ -184,6 +184,11 @@ export const commands = [
184
184
  '--release': { description: 'Mark as released' }
185
185
  }
186
186
  },
187
+ {
188
+ name: 'batch-info',
189
+ description: 'Show intelligent diff-analysis orchestration configuration and speed telemetry',
190
+ handler: async () => (await import('./commands/diff-batch-info.js')).runDiffBatchInfo
191
+ },
187
192
  {
188
193
  name: 'telemetry',
189
194
  description: 'View or clear telemetry data',
@@ -0,0 +1,105 @@
1
+ /**
2
+ * File: diff-batch-info.js
3
+ * Purpose: Display intelligent diff-analysis orchestration config and speed telemetry
4
+ *
5
+ * Shows:
6
+ * - Orchestration model and threshold
7
+ * - Default analysis model from config
8
+ * - Per-model avg analysis times from telemetry
9
+ * - Avg orchestration overhead
10
+ * - Overall failure rate
11
+ */
12
+
13
+ import { getStatistics } from '../utils/telemetry.js';
14
+ import logger from '../utils/logger.js';
15
+
16
+ /**
17
+ * Runs the batch-info command
18
+ * Why: Surfaces orchestration configuration and speed telemetry so users can
19
+ * understand the adaptive batch system behavior without needing debug mode.
20
+ */
21
+ export async function runDiffBatchInfo() {
22
+ console.log(
23
+ '\n╔════════════════════════════════════════════════════════════════════╗'
24
+ );
25
+ console.log(
26
+ '║ INTELLIGENT ANALYSIS ORCHESTRATION INFO ║'
27
+ );
28
+ console.log(
29
+ '╚════════════════════════════════════════════════════════════════════╝\n'
30
+ );
31
+
32
+ console.log('━━━ ORCHESTRATION CONFIGURATION ━━━');
33
+ console.log(' Orchestration model: opus (internal, not user-configurable)');
34
+ console.log(' Orchestrator threshold: 3 files (commits with ≥3 files use intelligent grouping)');
35
+ console.log();
36
+
37
+ console.log('━━━ HOW IT WORKS ━━━');
38
+ console.log(' < 3 files: Sequential analysis (single Claude call)');
39
+ console.log(' ≥ 3 files: Orchestrator groups files semantically,');
40
+ console.log(' assigns model per batch, injects shared context');
41
+ console.log();
42
+
43
+ try {
44
+ const stats = await getStatistics(7);
45
+
46
+ if (!stats.enabled) {
47
+ console.log(' Telemetry is disabled — no speed data available.');
48
+ console.log(
49
+ ' To enable, ensure "system.telemetry" is not set to false in .claude/config.json'
50
+ );
51
+ console.log();
52
+ return;
53
+ }
54
+
55
+ if (stats.totalEvents === 0) {
56
+ console.log('━━━ SPEED TELEMETRY (last 7 days) ━━━');
57
+ console.log(' No telemetry data yet.');
58
+ console.log(
59
+ ' Run an analysis with ≥3 files to start collecting per-model timing data.'
60
+ );
61
+ console.log();
62
+ return;
63
+ }
64
+
65
+ console.log('━━━ SPEED TELEMETRY (last 7 days) ━━━');
66
+ console.log(` Total events: ${stats.totalEvents}`);
67
+ console.log(` Successful batches: ${stats.batchSuccesses}`);
68
+ console.log(` Failure rate: ${stats.failureRate}%`);
69
+ console.log();
70
+
71
+ if (Object.keys(stats.avgAnalysisTimeByModel).length > 0) {
72
+ console.log(' Average analysis time by model:');
73
+ for (const [model, ms] of Object.entries(stats.avgAnalysisTimeByModel)) {
74
+ const seconds = (ms / 1000).toFixed(1);
75
+ console.log(` ${model.padEnd(8)}: ${seconds}s`);
76
+ }
77
+ console.log();
78
+ }
79
+
80
+ if (stats.avgOrchestrationTime > 0) {
81
+ const orchSeconds = (stats.avgOrchestrationTime / 1000).toFixed(1);
82
+ console.log(` Avg orchestration overhead: ${orchSeconds}s`);
83
+ console.log(
84
+ ' (Orchestrator call for semantic grouping — one-time per commit)'
85
+ );
86
+ console.log();
87
+ }
88
+
89
+ if (Object.keys(stats.successesByHook).length > 0) {
90
+ console.log(' Successes by hook:');
91
+ for (const [hook, count] of Object.entries(stats.successesByHook)) {
92
+ console.log(` ${hook}: ${count}`);
93
+ }
94
+ console.log();
95
+ }
96
+ } catch (err) {
97
+ logger.debug('diff-batch-info - runDiffBatchInfo', 'Failed to load telemetry', err);
98
+ console.log(' Could not load telemetry data.');
99
+ console.log();
100
+ }
101
+
102
+ console.log('📂 Telemetry files: .claude/telemetry/');
103
+ console.log('💡 Use --debug true to see orchestrator decisions in real time');
104
+ console.log();
105
+ }
@@ -327,11 +327,6 @@ export function extractLegacySettings(rawConfig) {
327
327
  }
328
328
  }
329
329
 
330
- // Subagent batchSize (allowed)
331
- if (rawConfig.subagents?.batchSize !== undefined) {
332
- allowedOverrides.subagents = { batchSize: rawConfig.subagents.batchSize };
333
- }
334
-
335
330
  // Advanced params (preserved with warning in manual migration)
336
331
  if (rawConfig.analysis?.ignoreExtensions !== undefined) {
337
332
  if (!allowedOverrides.analysis) allowedOverrides.analysis = {};
@@ -343,11 +338,6 @@ export function extractLegacySettings(rawConfig) {
343
338
  allowedOverrides.commitMessage.taskIdPattern = rawConfig.commitMessage.taskIdPattern;
344
339
  }
345
340
 
346
- if (rawConfig.subagents?.model !== undefined) {
347
- if (!allowedOverrides.subagents) allowedOverrides.subagents = {};
348
- allowedOverrides.subagents.model = rawConfig.subagents.model;
349
- }
350
-
351
341
  return allowedOverrides;
352
342
  }
353
343
 
package/lib/config.js CHANGED
@@ -6,9 +6,8 @@
6
6
  *
7
7
  * v2.8.0 Changes:
8
8
  * - Removed 21 redundant parameters (hardcoded sensible defaults)
9
- * - Only 5 user-configurable parameters remain
10
- * - Preset can override: subagents.batchSize
11
- * - User can override: github.pr.*, subagents.batchSize
9
+ * - Only 4 user-configurable parameters remain
10
+ * - User can override: github.pr.*
12
11
  * - Advanced params moved to config.advanced.example.json
13
12
  *
14
13
  * User-configurable:
@@ -16,12 +15,10 @@
16
15
  * - github.pr.defaultBase
17
16
  * - github.pr.reviewers
18
17
  * - github.pr.labelRules
19
- * - subagents.batchSize
20
18
  *
21
19
  * Advanced (in example file only):
22
20
  * - analysis.ignoreExtensions
23
21
  * - commitMessage.taskIdPattern
24
- * - subagents.model
25
22
  */
26
23
 
27
24
  import fs from 'fs';
@@ -35,7 +32,7 @@ import logger from './utils/logger.js';
35
32
  const HARDCODED = {
36
33
  analysis: {
37
34
  maxFileSize: 1000000, // 1MB - sufficient for most files
38
- maxFiles: 20, // Reasonable limit per commit
35
+ maxFiles: 30, // Reasonable limit per commit
39
36
  timeout: 300000, // 5 minutes - adequate for Claude API
40
37
  contextLines: 3, // Git default
41
38
  ignoreExtensions: [] // Can be set in advanced config only
@@ -46,9 +43,7 @@ const HARDCODED = {
46
43
  taskIdPattern: '([A-Z]{1,3}[-\\s]\\d{3,5})' // Jira/GitHub/Linear pattern
47
44
  },
48
45
  subagents: {
49
- enabled: true, // Enable by default (faster analysis)
50
- model: 'haiku', // Fast and cost-effective
51
- batchSize: 3 // Reasonable parallelization
46
+ enabled: true // Enable by default (faster analysis via orchestration)
52
47
  },
53
48
  templates: {
54
49
  baseDir: '.claude/prompts',
@@ -57,7 +52,6 @@ const HARDCODED = {
57
52
  commitMessage: 'COMMIT_MESSAGE.md',
58
53
  analyzeDiff: 'ANALYZE_DIFF.md',
59
54
  resolution: 'CLAUDE_RESOLUTION_PROMPT.md',
60
- subagentInstruction: 'SUBAGENT_INSTRUCTION.md',
61
55
  createGithubPR: 'CREATE_GITHUB_PR.md'
62
56
  },
63
57
  output: {
@@ -106,10 +100,6 @@ const defaults = {
106
100
  }
107
101
  },
108
102
 
109
- // Subagent configuration (preset can override)
110
- subagents: {
111
- batchSize: 3 // Files per parallel batch
112
- }
113
103
  };
114
104
 
115
105
  /**
@@ -196,8 +186,8 @@ const loadUserConfig = async (baseDir = process.cwd()) => {
196
186
 
197
187
  /**
198
188
  * Extracts only allowed parameters from legacy config
199
- * v2.8.0 only allows: github.pr.*, subagents.batchSize
200
- * Advanced: analysis.ignoreExtensions, commitMessage.taskIdPattern, subagents.model
189
+ * Allowed: github.pr.*
190
+ * Advanced: analysis.ignoreExtensions, commitMessage.taskIdPattern
201
191
  *
202
192
  * @param {Object} legacyConfig - Legacy format config
203
193
  * @returns {Object} Allowed parameters only
@@ -219,11 +209,6 @@ const extractAllowedParams = (legacyConfig) => {
219
209
  }
220
210
  }
221
211
 
222
- // Subagent batchSize (allowed)
223
- if (legacyConfig.subagents?.batchSize !== undefined) {
224
- allowed.subagents = { batchSize: legacyConfig.subagents.batchSize };
225
- }
226
-
227
212
  // Advanced params (allowed but warn)
228
213
  if (legacyConfig.analysis?.ignoreExtensions !== undefined) {
229
214
  if (!allowed.analysis) allowed.analysis = {};
@@ -237,12 +222,6 @@ const extractAllowedParams = (legacyConfig) => {
237
222
  logger.warning('ℹ️ Using advanced parameter: commitMessage.taskIdPattern');
238
223
  }
239
224
 
240
- if (legacyConfig.subagents?.model !== undefined) {
241
- if (!allowed.subagents) allowed.subagents = {};
242
- allowed.subagents.model = legacyConfig.subagents.model;
243
- logger.warning('ℹ️ Using advanced parameter: subagents.model');
244
- }
245
-
246
225
  return allowed;
247
226
  };
248
227