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.
- package/CHANGELOG.md +52 -0
- package/CLAUDE.md +85 -38
- package/README.md +52 -18
- package/bin/claude-hooks +75 -89
- package/lib/cli-metadata.js +306 -0
- package/lib/commands/analyze-diff.js +12 -10
- package/lib/commands/analyze.js +9 -5
- package/lib/commands/bump-version.js +56 -40
- package/lib/commands/create-pr.js +71 -34
- package/lib/commands/debug.js +4 -7
- package/lib/commands/diff-batch-info.js +105 -0
- package/lib/commands/generate-changelog.js +3 -2
- package/lib/commands/help.js +47 -27
- package/lib/commands/helpers.js +66 -43
- package/lib/commands/hooks.js +15 -13
- package/lib/commands/install.js +546 -49
- package/lib/commands/migrate-config.js +8 -11
- package/lib/commands/presets.js +6 -13
- package/lib/commands/setup-github.js +12 -3
- package/lib/commands/telemetry-cmd.js +8 -6
- package/lib/commands/update.js +1 -2
- package/lib/config.js +36 -52
- package/lib/hooks/pre-commit.js +70 -64
- package/lib/hooks/prepare-commit-msg.js +35 -75
- package/lib/utils/analysis-engine.js +77 -54
- package/lib/utils/changelog-generator.js +63 -37
- package/lib/utils/claude-client.js +447 -438
- package/lib/utils/claude-diagnostics.js +20 -10
- package/lib/utils/diff-analysis-orchestrator.js +332 -0
- package/lib/utils/file-operations.js +51 -79
- package/lib/utils/file-utils.js +6 -7
- package/lib/utils/git-operations.js +140 -123
- package/lib/utils/git-tag-manager.js +24 -23
- package/lib/utils/github-api.js +85 -61
- package/lib/utils/github-client.js +12 -14
- package/lib/utils/installation-diagnostics.js +4 -4
- package/lib/utils/interactive-ui.js +29 -17
- package/lib/utils/judge.js +195 -0
- package/lib/utils/logger.js +4 -1
- package/lib/utils/package-info.js +0 -11
- package/lib/utils/pr-metadata-engine.js +67 -33
- package/lib/utils/preset-loader.js +20 -62
- package/lib/utils/prompt-builder.js +57 -68
- package/lib/utils/resolution-prompt.js +34 -52
- package/lib/utils/sanitize.js +20 -19
- package/lib/utils/task-id.js +27 -40
- package/lib/utils/telemetry.js +73 -25
- package/lib/utils/version-manager.js +147 -70
- package/lib/utils/which-command.js +23 -12
- package/package.json +1 -1
- package/templates/CLAUDE_RESOLUTION_PROMPT.md +17 -9
- package/templates/DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md +70 -0
- package/templates/config.advanced.example.json +15 -31
- 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 -
|
|
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,
|
|
71
|
-
│ ├──
|
|
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 -
|
|
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
|
-
↓ (
|
|
129
|
-
lib/utils/
|
|
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
|
|
175
|
-
|
|
|
176
|
-
| Max file size
|
|
177
|
-
| Max files per commit
|
|
178
|
-
|
|
|
179
|
-
|
|
|
180
|
-
|
|
|
181
|
-
| Analysis timeout
|
|
182
|
-
| Commit msg timeout
|
|
183
|
-
| PR metadata timeout
|
|
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.
|
|
213
|
+
**4. Analysis Routing (v2.20.0)**
|
|
214
|
+
|
|
215
|
+
Three-tier strategy based on file count:
|
|
197
216
|
|
|
198
|
-
|
|
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
|
-
|
|
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
|
-
|
|
204
|
-
|
|
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
|
-
|
|
236
|
+
consolidateResults()
|
|
207
237
|
```
|
|
208
238
|
|
|
209
|
-
- **
|
|
210
|
-
- **
|
|
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
|
-
| `
|
|
241
|
-
| `
|
|
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
|
|
260
|
-
2. **
|
|
261
|
-
3. **
|
|
262
|
-
4. **
|
|
263
|
-
5. **
|
|
264
|
-
6. **
|
|
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
|
|
276
|
-
→
|
|
277
|
-
|
|
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
|
-
| `
|
|
273
|
-
| `
|
|
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
|
-
→
|
|
296
|
-
|
|
297
|
-
|
|
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**: `
|
|
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
|
-
│ ├──
|
|
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
|
-
###
|
|
434
|
+
### Analysis Routing (v2.20.0)
|
|
435
|
+
|
|
436
|
+
Two-tier strategy based on file count:
|
|
414
437
|
|
|
415
|
-
Files
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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:
|
|
424
|
-
-
|
|
425
|
-
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
await
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
});
|