claude-git-hooks 2.17.2 → 2.18.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/CLAUDE.md ADDED
@@ -0,0 +1,820 @@
1
+ # Repository Context
2
+
3
+ ## Purpose
4
+
5
+ `claude-git-hooks` is an intelligent Git hooks system that integrates Claude CLI to automate code analysis, commit message generation, and PR creation. It functions as a pre-commit code quality tool (for pre-commit code quality checks) that blocks commits with critical issues and assists throughout the development workflow.
6
+
7
+ **Main use cases:**
8
+
9
+ 1. **Pre-commit analysis**: Detects security issues, bugs, and code smells before each commit (blocks on CRITICAL/BLOCKER only)
10
+ 2. **Interactive analysis**: `claude-hooks analyze` - review all issues (INFO to BLOCKER) interactively before committing
11
+ 3. **Automatic messages**: Write `git commit -m "auto"` and Claude generates the message in Conventional Commits format with task-id extracted from branch
12
+ 4. **PR analysis**: `claude-hooks analyze-diff [branch]` generates title, description, and test plan for PRs
13
+ 5. **PR creation**: `claude-hooks create-pr [branch]` creates the PR on GitHub with automatic metadata (reviewers from CODEOWNERS, labels by preset)
14
+
15
+ ## Architecture
16
+
17
+ ### Technology Stack
18
+
19
+ - **Runtime**: Node.js >=16.9.0 (compatible up to 24+)
20
+ - **Module type**: ES6 modules (`"type": "module"` in package.json)
21
+ - **Main dependencies**:
22
+ - `@octokit/rest`: GitHub client for PR creation (v2.5.0+)
23
+ - **Dev dependencies**: Jest, ESLint, Prettier
24
+ - **Distribution**: NPM global package (`npm install -g claude-git-hooks`)
25
+
26
+ ### Design Philosophy
27
+
28
+ **Modular, decoupled, reusable code.** Each component has a single responsibility:
29
+
30
+ - **bin/claude-hooks**: Thin CLI router - only argument parsing and command dispatch
31
+ - **lib/commands/**: Command modules - one file per CLI command, self-contained logic
32
+ - **lib/hooks/**: Git hook logic - Node.js implementations invoked by bash wrappers
33
+ - **lib/utils/**: Reusable utilities - shared across commands, no CLI dependencies
34
+ - **templates/**: Static assets - copied during installation, user-customizable
35
+
36
+ This separation enables:
37
+
38
+ - **Testability**: Each module can be unit tested independently
39
+ - **Maintainability**: Changes to one command don't risk breaking others
40
+ - **Discoverability**: Find code by filename matching command name
41
+ - **Extensibility**: Add new commands by creating new module files
42
+
43
+ ### Directory Structure
44
+
45
+ ```
46
+ claude-git-hooks/
47
+ ├── bin/
48
+ │ └── claude-hooks # Thin CLI router - argument parsing, command dispatch
49
+ ├── lib/
50
+ │ ├── config.js # Config system - load/merge with priority
51
+ │ ├── commands/ # Command modules - one file per CLI command
52
+ │ │ ├── helpers.js # Shared CLI utilities - colors, output, platform
53
+ │ │ ├── install.js # Install command - dependencies, hooks, templates
54
+ │ │ ├── hooks.js # Hook management - enable, disable, status, uninstall
55
+ │ │ ├── analyze-diff.js # Diff analysis - generate PR metadata from git diff
56
+ │ │ ├── create-pr.js # PR creation - full Octokit workflow
57
+ │ │ ├── setup-github.js # Token setup - interactive GitHub configuration
58
+ │ │ ├── presets.js # Preset management - list, set, show current
59
+ │ │ ├── update.js # Self-update - check and install latest version
60
+ │ │ ├── migrate-config.js # Config migration - legacy to v2.8.0 format
61
+ │ │ ├── debug.js # Debug toggle - enable/disable verbose logging
62
+ │ │ ├── telemetry-cmd.js # Telemetry commands - show/clear statistics
63
+ │ │ ├── bump-version.js # Version management - bump with commit, CHANGELOG and tags
64
+ │ │ ├── generate-changelog.js # CHANGELOG generation - standalone command
65
+ │ │ └── help.js # Help, AI help, and report-issue commands
66
+ │ ├── hooks/ # Git hooks - Node.js implementations
67
+ │ │ ├── pre-commit.js # Pre-commit analysis - code quality gate
68
+ │ │ └── prepare-commit-msg.js # Message generation - auto commit messages
69
+ │ └── 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
+ │ ├── prompt-builder.js # Prompt construction - load templates, replace vars
73
+ │ ├── git-operations.js # Git abstractions - staged files, diff, repo root, push, commit
74
+ │ ├── file-utils.js # File operations - repo-relative paths
75
+ │ ├── logger.js # Logging system - centralized output, debug mode
76
+ │ ├── preset-loader.js # Preset system - load tech-stack configurations
77
+ │ ├── pr-metadata-engine.js # PR metadata generation - branch context, diff reduction, metadata (v2.14.0)
78
+ │ ├── github-api.js # Octokit integration - PR creation, token validation
79
+ │ ├── github-client.js # GitHub helpers - CODEOWNERS parsing, reviewers
80
+ │ ├── task-id.js # Task ID extraction - Jira, GitHub, Linear patterns
81
+ │ ├── interactive-ui.js # CLI UI components - previews, prompts, spinners
82
+ │ ├── resolution-prompt.js # Issue resolution - AI-friendly fix prompts
83
+ │ ├── installation-diagnostics.js # Installation diagnostics - error context
84
+ │ ├── claude-diagnostics.js # Claude errors - rate limit, auth, formatting
85
+ │ ├── which-command.js # Executable resolution - cross-platform paths
86
+ │ ├── sanitize.js # Input sanitization - shell safety
87
+ │ ├── telemetry.js # Local telemetry - track JSON parsing, retries
88
+ │ ├── version-manager.js # Version detection - parse, increment, validate, per-file targets (v2.12.0)
89
+ │ ├── git-tag-manager.js # Git tag operations - create, list, compare, push, isSemverTag (v2.12.0)
90
+ │ └── changelog-generator.js # CHANGELOG generation - Claude-powered analysis (v2.12.0)
91
+ ├── templates/ # Static assets - copied during install
92
+ │ ├── pre-commit # Bash wrapper - invokes lib/hooks/pre-commit.js
93
+ │ ├── prepare-commit-msg # Bash wrapper - invokes lib/hooks/prepare-commit-msg.js
94
+ │ ├── check-version.sh # Version check - auto-update prompt
95
+ │ ├── CLAUDE_PRE_COMMIT.md # Analysis criteria - evaluation guidelines
96
+ │ ├── CLAUDE_ANALYSIS_PROMPT.md # Analysis prompt - code review template
97
+ │ ├── CLAUDE_RESOLUTION_PROMPT.md # Resolution prompt - issue fix template
98
+ │ ├── ANALYZE_DIFF.md # PR analysis - diff review template
99
+ │ ├── GENERATE_CHANGELOG.md # CHANGELOG generation - commit analysis template (v2.12.0)
100
+ │ ├── HELP_QUERY.md # AI help - question answering with NEED_MORE_CONTEXT protocol (v2.18.0)
101
+ │ ├── HELP_REPORT_ISSUE.md # Report issue - question generation from templates (v2.18.0)
102
+ │ ├── HELP_COMPOSE_ISSUE.md # Report issue - issue body composition from answers (v2.18.0)
103
+ │ ├── config.example.json # Config example - minimal setup
104
+ │ ├── config.advanced.example.json # Config advanced - all options documented
105
+ │ ├── settings.local.example.json # Local settings - token storage template
106
+ │ └── CUSTOMIZATION_GUIDE.md # Customization - preset creation guide
107
+ └── test/ # Tests - Jest with ES6 modules
108
+ └── unit/
109
+ └── *.test.js
110
+ ```
111
+
112
+ ### Execution Architecture
113
+
114
+ **1. Git Hooks (bash wrappers → Node.js)**
115
+
116
+ ```
117
+ .git/hooks/pre-commit (bash)
118
+
119
+ node lib/hooks/pre-commit.js
120
+ ↓ (reads config + preset)
121
+ lib/config.js → merges: defaults < user config < preset config
122
+ ↓ (gets staged files)
123
+ lib/utils/git-operations.js → getStagedFiles()
124
+ ↓ (filters by preset extensions + size)
125
+ lib/utils/file-operations.js → filterFiles()
126
+ ↓ (builds file data + runs analysis)
127
+ lib/utils/analysis-engine.js → buildFilesData(), runAnalysis()
128
+ ↓ (orchestrates parallel/sequential Claude CLI calls)
129
+ lib/utils/claude-client.js → analyzeCode() or analyzeCodeParallel()
130
+ ↓ (displays results)
131
+ lib/utils/analysis-engine.js → displayResults()
132
+ ↓ (if blocking issues found)
133
+ lib/utils/resolution-prompt.js → generates claude_resolution_prompt.md
134
+
135
+ exit 1 (blocks commit) or exit 0 (allows commit)
136
+ ```
137
+
138
+ **2. Configuration System (priorities)**
139
+
140
+ ```
141
+ defaults (lib/config.js)
142
+ ↓ overridden by
143
+ user config (.claude/config.json)
144
+ ↓ overridden by
145
+ preset config (.claude/presets/{name}/config.json) ← HIGHEST PRIORITY
146
+ ```
147
+
148
+ **Rationale**: User configures general preferences, preset provides tech-stack-specific overrides.
149
+
150
+ **Config format (v2.8.0):**
151
+
152
+ ```json
153
+ {
154
+ "version": "2.8.0",
155
+ "preset": "backend",
156
+ "overrides": {
157
+ "github": {
158
+ "pr": {
159
+ "defaultBase": "develop",
160
+ "reviewers": ["user"],
161
+ "autoPush": true, // Auto-push unpublished branches (v2.11.0)
162
+ "pushConfirm": true, // Prompt before push (v2.11.0)
163
+ "showCommits": true, // Show commit preview (v2.11.0)
164
+ "verifyRemote": true // Verify remote exists (v2.11.0)
165
+ }
166
+ },
167
+ "subagents": { "batchSize": 2 }
168
+ }
169
+ }
170
+ ```
171
+
172
+ **Hardcoded defaults (v2.8.0):**
173
+
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)|
184
+
185
+ **3. Presets System**
186
+
187
+ | Preset | Extensions | Stack | Key Verifications |
188
+ | ----------- | -------------------------------------------------------------------------- | ------------------------ | --------------------------------------------------- |
189
+ | `backend` | `.java`, `.xml`, `.yml`, `.yaml` | Spring Boot + SQL Server | REST API, JPA, OWASP Top 10, SQL injection |
190
+ | `frontend` | `.js`, `.jsx`, `.ts`, `.tsx`, `.css`, `.scss`, `.html` | React + Material-UI | Hooks, XSS, a11y, performance |
191
+ | `fullstack` | backend + frontend | Spring Boot + React | **API contract consistency** (priority) |
192
+ | `database` | `.sql` | SQL Server | SQL injection, UPDATE/DELETE without WHERE, indexes |
193
+ | `ai` | `.js`, `.json`, `.md`, `.sh` | Node.js + Claude API | Prompts, API key security, cross-platform |
194
+ | `default` | `.js`, `.sh`, `.py`, `.rb`, `.pl`, `.sql`, `.yaml`, `.json`, `.xml`, `.md` | Multiple | Quality and security fundamentals |
195
+
196
+ **4. Parallel Analysis (v2.2.0+)**
197
+
198
+ When 3+ files are present, the system divides into batches and executes multiple `claude` CLI processes in parallel:
199
+
200
+ ```
201
+ 4 files + batchSize=2
202
+
203
+ Batch 1: [file1, file2] → claude CLI process #1 (parallel)
204
+ Batch 2: [file3, file4] → claude CLI process #2 (parallel)
205
+
206
+ Wait for both → consolidate results
207
+ ```
208
+
209
+ - **Configuration**: `.claude/config.json` → `subagents.batchSize`, `subagents.model` (haiku/sonnet/opus)
210
+ - **Speed-up**: ~4x faster with batch=1 (1 file per process)
211
+
212
+ ### Key Module Exports
213
+
214
+ **Command Modules (`lib/commands/`):**
215
+
216
+ | Module | Purpose | Key Exports |
217
+ | ----------------------- | ------------------------- | ----------------------------------------------------------------------------- |
218
+ | `helpers.js` | Shared CLI utilities | `colors`, `error()`, `success()`, `info()`, `checkGitRepo()`, `getGitHooksPath()`, `Entertainment` |
219
+ | `install.js` | Installation logic | `runInstall()`, `extractLegacySettings()` |
220
+ | `hooks.js` | Hook management | `runEnable()`, `runDisable()`, `runStatus()`, `runUninstall()` |
221
+ | `analyze.js` | Interactive code analysis | `runAnalyze()` |
222
+ | `analyze-diff.js` | Diff analysis | `runAnalyzeDiff()` |
223
+ | `create-pr.js` | PR creation | `runCreatePr()` |
224
+ | `bump-version.js` | Version management | `runBumpVersion()` |
225
+ | `generate-changelog.js` | CHANGELOG generation | `runGenerateChangelog()` |
226
+ | `setup-github.js` | Token setup | `runSetupGitHub()` |
227
+ | `presets.js` | Preset management | `runShowPresets()`, `runSetPreset()`, `runCurrentPreset()` |
228
+ | `update.js` | Self-update | `runUpdate()` |
229
+ | `migrate-config.js` | Config migration | `runMigrateConfig()` |
230
+ | `debug.js` | Debug toggle | `runSetDebug()` |
231
+ | `telemetry-cmd.js` | Telemetry commands | `runShowTelemetry()`, `runClearTelemetry()` |
232
+ | `help.js` | Help, AI help, report-issue | `runShowHelp()`, `showStaticHelp()`, `runShowVersion()` |
233
+
234
+ **Utility Modules (`lib/utils/`):**
235
+
236
+ | Module | Purpose | Key Exports |
237
+ | ------------------------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
238
+ | `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()` |
242
+ | `git-operations.js` | Git abstractions | `getStagedFiles()`, `getUnstagedFiles()`, `getAllTrackedFiles()`, `getDiff()`, `getRepoRoot()`, `getBranchPushStatus()`, `pushBranch()`, `createCommit()`, `fetchRemote()`, `branchExists()`, `getRemoteBranches()`, `resolveBaseBranch()`, `getChangedFilesBetweenRefs()`, `getDiffBetweenRefs()`, `getCommitsBetweenRefs()` |
243
+ | `pr-metadata-engine.js` | PR metadata generation | `getBranchContext()`, `buildDiffPayload()`, `generatePRMetadata()`, `analyzeBranchForPR()` (v2.14.0) |
244
+ | `git-tag-manager.js` | Git tag operations | `createTag()`, `pushTags()`, `getLocalTags()`, `getRemoteTags()`, `compareLocalAndRemoteTags()`, `tagExists()` (v2.12.0) |
245
+ | `version-manager.js` | Version management | `discoverVersionFiles()`, `getDiscoveryResult()`, `readVersionFromFile()`, `writeVersionToFile()`, `updateVersionFiles()`, `modifySuffix()`, `incrementVersion()`, `parseVersion()`, `validateVersionFormat()`, `compareVersions()`, `validateVersionAlignment()` (v2.15.5) |
246
+ | `changelog-generator.js` | CHANGELOG generation | `generateChangelogEntry()`, `updateChangelogFile()`, `getLastFinalVersionTag()`, `getCommitsSinceTag()` (v2.12.0) |
247
+ | `github-api.js` | Octokit integration | `createPullRequest()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()` |
248
+ | `github-client.js` | GitHub helpers | `getReviewersForFiles()`, `parseGitHubRepo()` |
249
+ | `preset-loader.js` | Preset system | `loadPreset()`, `listPresets()` |
250
+ | `task-id.js` | Task ID extraction | `getOrPromptTaskId()`, `formatWithTaskId()` |
251
+ | `logger.js` | Logging system | `info()`, `warning()`, `error()`, `debug()` |
252
+ | `resolution-prompt.js` | Issue resolution | `generateResolutionPrompt()` |
253
+ | `interactive-ui.js` | CLI UI components | `showPRPreview()`, `promptConfirmation()`, `promptMenu()`, `promptToggleList()`, `promptEditField()`, `promptUserConfirmation()` |
254
+ | `telemetry.js` | Local telemetry | `recordEvent()`, `displayStatistics()` |
255
+
256
+ ### Design Patterns
257
+
258
+ 1. **Command Pattern**: `lib/commands/*.js` - each CLI command is a self-contained module
259
+ 2. **Factory Pattern**: `preset-loader.js` loads configurations dynamically per tech-stack
260
+ 3. **Template Method**: `prompt-builder.js` builds prompts from markdown templates
261
+ 4. **Strategy Pattern**: `claude-client.js` selects between sequential or parallel analysis
262
+ 5. **Adapter Pattern**: `git-operations.js` abstracts git commands into JS functions
263
+ 6. **Singleton Pattern**: `config.js` loads configuration once per execution
264
+
265
+ ### Key Data Flows
266
+
267
+ **Flow 1: Pre-commit with blocking**
268
+
269
+ ```
270
+ git commit
271
+ → hook reads staged files
272
+ → filters by preset extensions
273
+ → builds prompt with diff
274
+ → Claude analyzes → detects SQL injection (CRITICAL)
275
+ → generates resolution prompt
276
+ → exit 1 → COMMIT BLOCKED
277
+ ```
278
+
279
+ **Flow 1.5: Interactive analysis command (v2.13.0)**
280
+
281
+ ```
282
+ claude-hooks analyze
283
+ → runs outside git hook context (stdin works)
284
+ → getStagedFiles() → buildFilesData() → runAnalysis()
285
+ → displayIssueSummary() → shows all severity levels (or "No issues found")
286
+ → promptUserConfirmation() → interactive menu:
287
+ → [y] Continue - executes createCommit('auto', { noVerify: true })
288
+ → [n] Abort - generates resolution prompt
289
+ → [v] View - shows detailed issues → returns to menu
290
+ → on continue: git commit -m "auto" --no-verify
291
+ → prepare-commit-msg hook generates message via Claude
292
+ → commit created with auto-generated message
293
+ ```
294
+
295
+ **Flow 2: Commit with automatic message**
296
+
297
+ ```
298
+ git commit -m "auto"
299
+ → hook extracts task-id from branch (feature/IX-123-add-auth)
300
+ → Claude generates message → "[IX-123] feat: add user authentication"
301
+ → writes to .git/COMMIT_EDITMSG
302
+ → commit proceeds with generated message
303
+ ```
304
+
305
+ **Flow 3: Analyze diff (v2.14.0)**
306
+
307
+ ```
308
+ claude-hooks analyze-diff develop
309
+ → lib/commands/analyze-diff.js (thin wrapper)
310
+ → analyzeBranchForPR() (pr-metadata-engine.js)
311
+ → fetchRemote() → resolveBaseBranch() (suggests similar branches if not found)
312
+ → getChangedFilesBetweenRefs() → getCommitsBetweenRefs()
313
+ → buildDiffPayload() → tiered reduction (context → proportional → stat-only)
314
+ → executeClaudeWithRetry() → parses PRMetadata
315
+ → formats metadata to console
316
+ → saves to .claude/out/pr-analysis.json
317
+ ```
318
+
319
+ **Flow 4: PR creation (with auto-push v2.11.0, engine v2.14.0)**
320
+
321
+ ```
322
+ claude-hooks create-pr develop
323
+ → checks branch push status (unpublished/unpushed commits)
324
+ → shows commit preview → prompts for confirmation
325
+ → pushes branch to remote (if needed)
326
+ → reads CODEOWNERS → detects reviewers
327
+ → reads config → applies label rules per preset
328
+ → analyzeBranchForPR() (pr-metadata-engine.js) → generates metadata
329
+ → interactive preview → user confirms
330
+ → Octokit creates PR on GitHub
331
+ ```
332
+
333
+ **Flow 5: Version bump with per-file editing (v2.16.0)**
334
+
335
+ ```
336
+ claude-hooks bump-version patch --interactive
337
+ → validatePrerequisites() → clean working directory, valid branch, remote
338
+ → discoverVersionFiles() → recursive scan (max 3 levels)
339
+ → displayDiscoveryTable() → shows all discovered files with versions
340
+ → promptFileSelection() → interactive menu:
341
+ → [a] Update all files - all files get same newVersion
342
+ → [s] Select files - toggle list to pick subset
343
+ → [e] Edit per file - promptEditField() per file:
344
+ → user enters custom version per file (Enter keeps calculated version)
345
+ → validateVersionFormat() → rejects invalid entries
346
+ → stores file.targetVersion on each descriptor
347
+ → [c] Cancel
348
+ → incrementVersion() / modifySuffix() → calculates newVersion (used for tag + commit)
349
+ → updateVersionFiles() → uses file.targetVersion || newVersion per file
350
+ → createTag(newVersion) → tag reflects primary release version
351
+ → commit message uses newVersion
352
+ ```
353
+
354
+ **Per-file version design**: `VersionFileDescriptor` gains an optional `targetVersion` property at runtime, set only by option 'e'. When present, `updateVersionFiles()` writes `targetVersion` instead of the global `newVersion`. The tag and commit message always use the calculated `newVersion`.
355
+
356
+ ## Code Conventions
357
+
358
+ ### General Style
359
+
360
+ - **Format**: Prettier (config in `.prettierrc.json`)
361
+ - **Linting**: ESLint 8.57.0 (config in `.eslintrc.json`)
362
+ - **Indentation**: 4 spaces
363
+ - **Quotes**: Single quotes (strings), double quotes (HTML/imports)
364
+ - **Semicolons**: Required
365
+
366
+ ### Naming
367
+
368
+ - **Files**: `kebab-case.js` (e.g., `claude-client.js`, `git-operations.js`)
369
+ - **Functions**: `camelCase()` (e.g., `getStagedFiles()`, `buildAnalysisPrompt()`)
370
+ - **Constants**: `UPPER_SNAKE_CASE` (e.g., `MAX_FILE_SIZE`, `ALLOWED_EXTENSIONS`)
371
+ - **Classes**: Not applicable (no classes, only exported functions)
372
+ - **Private variables**: `_` prefix (e.g., `_internalHelper()`)
373
+
374
+ ### Exports
375
+
376
+ **Preferred pattern - Named exports:**
377
+
378
+ ```javascript
379
+ // lib/utils/example.js
380
+ export function doSomething() { ... }
381
+ export function doOtherThing() { ... }
382
+
383
+ // consumer
384
+ import { doSomething, doOtherThing } from './utils/example.js';
385
+ ```
386
+
387
+ **Avoid default exports** (except in `bin/claude-hooks` per CLI convention).
388
+
389
+ ### Error Handling
390
+
391
+ **Standard pattern:**
392
+
393
+ ```javascript
394
+ import { error } from './utils/logger.js';
395
+
396
+ try {
397
+ const result = dangerousOperation();
398
+ return result;
399
+ } catch (err) {
400
+ error(`Failed to perform operation: ${err.message}`);
401
+ process.exit(1); // In hooks and CLI commands
402
+ // or throw err; // In library functions
403
+ }
404
+ ```
405
+
406
+ **Specific errors:**
407
+
408
+ - Git operations → `execSync()` with try-catch, log and exit
409
+ - Claude CLI → retry logic in `claude-client.js`, configurable timeout
410
+ - GitHub API → catch `@octokit/request-error`, user-friendly formatting
411
+
412
+ ### Logging
413
+
414
+ ```javascript
415
+ import { info, warning, error, debug } from './utils/logger.js';
416
+
417
+ info('✅ Operation completed'); // User-facing messages
418
+ warning('⚠️ Non-blocking issue detected'); // Warnings
419
+ error('❌ Critical failure'); // Errors
420
+ debug('Detailed diagnostic info'); // Only shown when debug=true
421
+ ```
422
+
423
+ **Debug mode**: Activate with `claude-hooks --debug true` or in `.claude/config.json`.
424
+
425
+ ### Async/Await
426
+
427
+ **Prefer async/await over callbacks:**
428
+
429
+ ```javascript
430
+ // ✅ GOOD
431
+ async function analyzeCode(prompt) {
432
+ const result = await spawnClaude(prompt);
433
+ return result;
434
+ }
435
+
436
+ // ❌ BAD
437
+ function analyzeCode(prompt, callback) {
438
+ spawnClaude(prompt, callback);
439
+ }
440
+ ```
441
+
442
+ ### Reusable Modules
443
+
444
+ All modules in `lib/utils/` must:
445
+
446
+ 1. Export pure functions (no global side effects)
447
+ 2. Include inline JSDoc documentation
448
+ 3. Accept configuration via parameters (no globals)
449
+ 4. Return structured results (objects or arrays)
450
+ 5. Log with `logger.js` (no direct `console.log`)
451
+
452
+ ## Workflow
453
+
454
+ ### Branching Strategy
455
+
456
+ This repository follows **simplified GitHub Flow**:
457
+
458
+ - **Main branch**: `main` (protected)
459
+ - **Feature branches**: `feature/issue-description` or `feature/TASK-ID-description`
460
+ - **Fix branches**: `fix/issue-description`
461
+ - **Hotfix branches**: `hotfix/urgent-description`
462
+
463
+ **Rules:**
464
+
465
+ 1. All changes require PR to `main`
466
+ 2. No direct commits to `main`
467
+ 3. PRs require review (auto-merge NOT allowed)
468
+
469
+ ### Development Process
470
+
471
+ **1. Initial setup (first time)**
472
+
473
+ ```bash
474
+ git clone https://github.com/mscope-S-L/git-hooks.git
475
+ cd git-hooks
476
+ npm install
477
+ npm link # Install globally as symlink for development
478
+ ```
479
+
480
+ **2. Create feature branch**
481
+
482
+ ```bash
483
+ git checkout -b feature/new-functionality
484
+ # or with task-id: feature/IX-123-new-functionality
485
+ ```
486
+
487
+ **3. Iterative development**
488
+
489
+ ```bash
490
+ # Make changes...
491
+ npm run lint # Check linting
492
+ npm run test # Run tests
493
+ git add .
494
+ git commit -m "feat: add new functionality"
495
+ # Hooks execute automatically
496
+ ```
497
+
498
+ **4. Local testing**
499
+
500
+ Test changes in a test repository:
501
+
502
+ ```bash
503
+ # In test repo
504
+ cd /path/to/test-repo
505
+ claude-hooks install --force --skip-auth # Reinstall from symlink
506
+ git commit -m "test" # Test hook
507
+ ```
508
+
509
+ **5. Create PR**
510
+
511
+ ```bash
512
+ git push -u origin feature/new-functionality
513
+ claude-hooks analyze-diff main # Generate PR metadata
514
+ # or directly:
515
+ claude-hooks create-pr main # Create PR on GitHub (if MCP configured)
516
+ ```
517
+
518
+ ### CI/CD
519
+
520
+ **Currently**: No automated CI/CD (GitHub Actions pending).
521
+
522
+ **Manual verifications before merge:**
523
+
524
+ 1. `npm run lint` → passes
525
+ 2. `npm run test` → all tests pass
526
+ 3. Manual testing in test repo
527
+ 4. Peer code review
528
+ 5. CHANGELOG.md updated
529
+
530
+ ### Versioning
531
+
532
+ We follow **Semantic Versioning** (MAJOR.MINOR.PATCH):
533
+
534
+ - **MAJOR**: Breaking changes (e.g., 1.x → 2.0 with ES6 migration)
535
+ - **MINOR**: New features without breaking changes (e.g., 2.2 → 2.3 with presets)
536
+ - **PATCH**: Bug fixes (e.g., 2.6.0 → 2.6.1 with spawn ENOENT fix)
537
+
538
+ **Update version:**
539
+
540
+ ```bash
541
+ npm version patch # 2.6.1 → 2.6.2
542
+ npm version minor # 2.6.1 → 2.7.0
543
+ npm version major # 2.6.1 → 3.0.0
544
+ ```
545
+
546
+ **Publish to NPM:**
547
+
548
+ ```bash
549
+ npm publish
550
+ ```
551
+
552
+ ### Conventional Commits
553
+
554
+ Format: `<type>(<scope>): <subject>`
555
+
556
+ **Types:**
557
+
558
+ - `feat`: New functionality
559
+ - `fix`: Bug fix
560
+ - `docs`: Documentation only
561
+ - `style`: Formatting (no logic change)
562
+ - `refactor`: Refactoring without functional change
563
+ - `test`: Add or modify tests
564
+ - `chore`: Maintenance (deps, config)
565
+ - `perf`: Performance improvements
566
+
567
+ **Optional scopes:**
568
+
569
+ - `hooks`: Changes in pre-commit or prepare-commit-msg
570
+ - `presets`: Preset system
571
+ - `github`: GitHub integration
572
+ - `cli`: Main CLI commands
573
+ - `config`: Configuration system
574
+ - `windows`: Windows-specific fixes
575
+
576
+ **Examples:**
577
+
578
+ ```
579
+ feat(presets): add database preset for SQL analysis
580
+ fix(windows): resolve spawn ENOENT with .cmd files
581
+ docs: update CLAUDE.md with architecture details
582
+ chore(deps): upgrade @octokit/rest to v21
583
+ ```
584
+
585
+ ## Useful Commands
586
+
587
+ ### Development
588
+
589
+ ```bash
590
+ # Installation and setup
591
+ npm install # Install dependencies
592
+ npm link # Install globally as symlink
593
+ npm unlink # Uninstall global symlink
594
+
595
+ # Testing
596
+ npm test # Run all tests (Jest)
597
+ npm run test:watch # Tests in watch mode
598
+ npm run test:coverage # Coverage report
599
+
600
+ # Linting and formatting
601
+ npm run lint # Check ESLint
602
+ npm run lint:fix # Auto-fix ESLint issues
603
+ npm run format # Format with Prettier
604
+
605
+ # Versioning
606
+ npm version patch|minor|major # Bump version
607
+ npm publish # Publish to NPM
608
+ ```
609
+
610
+ ### Package CLI
611
+
612
+ ```bash
613
+ # Hook installation in a repo
614
+ claude-hooks install # Interactive installation
615
+ claude-hooks install --force # Reinstall without confirmation
616
+ claude-hooks install --skip-auth # Skip Claude verification
617
+
618
+ # Hook management
619
+ claude-hooks status # View current status
620
+ claude-hooks enable [hook] # Enable all or specific hook
621
+ claude-hooks disable [hook] # Disable all or specific hook
622
+ claude-hooks uninstall # Completely uninstall
623
+
624
+ # Presets
625
+ claude-hooks presets # List available presets
626
+ claude-hooks --set-preset backend # Change preset
627
+ claude-hooks preset current # View current preset
628
+
629
+ # Analysis and PRs
630
+ claude-hooks analyze-diff [branch] # Analyze diff for PR
631
+ claude-hooks create-pr [branch] # Create PR on GitHub
632
+ claude-hooks setup-github # Configure GitHub token
633
+
634
+ # Version management
635
+ claude-hooks bump-version patch # Bump version (commits, tags locally)
636
+ claude-hooks bump-version minor --suffix SNAPSHOT # With suffix
637
+ claude-hooks bump-version major --update-changelog # With CHANGELOG
638
+ claude-hooks bump-version patch --push # Push tag immediately
639
+ claude-hooks bump-version patch --no-commit # Manual workflow
640
+ claude-hooks bump-version patch --interactive # Force file selection menu
641
+ claude-hooks generate-changelog # Generate CHANGELOG only
642
+
643
+ # Help and issue reporting
644
+ claude-hooks help "how do presets work?" # AI-powered help (uses CLAUDE.md)
645
+ claude-hooks help --report-issue # Interactive issue creation
646
+
647
+ # Debugging
648
+ claude-hooks --debug true # Enable debug mode
649
+ claude-hooks --debug false # Disable debug mode
650
+ claude-hooks --debug status # View debug status
651
+
652
+ # Auto-update
653
+ claude-hooks update # Update to latest version
654
+ ```
655
+
656
+ ### Git with Active Hooks
657
+
658
+ ```bash
659
+ # Normal commit with analysis
660
+ git commit -m "feat: new functionality"
661
+
662
+ # Commit with automatic message
663
+ git commit -m "auto" # Claude generates the message
664
+
665
+ # Skip analysis (emergencies)
666
+ git commit --no-verify -m "hotfix: urgent"
667
+
668
+ # Amend last commit
669
+ git commit --amend
670
+ ```
671
+
672
+ ### Local Testing in Test Repo
673
+
674
+ ```bash
675
+ # Initial setup
676
+ cd /path/to/test-repo
677
+ claude-hooks install --force --skip-auth
678
+
679
+ # After changes in claude-hooks
680
+ # (npm link is already active, no need to reinstall)
681
+ cd /path/to/test-repo
682
+ git add test.txt
683
+ git commit -m "test: validate changes"
684
+ # Hooks use local version automatically
685
+ ```
686
+
687
+ ## Testing
688
+
689
+ ### Test Framework
690
+
691
+ - **Framework**: Jest with ES6 modules (`--experimental-vm-modules`)
692
+ - **Location**: `test/unit/*.test.js`
693
+ - **Naming**: `{module-name}.test.js` matches `lib/utils/{module-name}.js`
694
+ - **Run**: `npm test` (all), `npm run test:watch` (watch mode)
695
+
696
+ ### Test Patterns
697
+
698
+ ```javascript
699
+ // test/unit/example.test.js
700
+ import { functionToTest } from '../../lib/utils/example.js';
701
+
702
+ describe('functionToTest', () => {
703
+ it('should handle normal input', () => {
704
+ const result = functionToTest('input');
705
+ expect(result).toBe('expected');
706
+ });
707
+
708
+ it('should throw on invalid input', () => {
709
+ expect(() => functionToTest(null)).toThrow('Invalid input');
710
+ });
711
+ });
712
+ ```
713
+
714
+ ### Mocking
715
+
716
+ ```javascript
717
+ // Mock child_process for git/claude commands
718
+ import { jest } from '@jest/globals';
719
+ import { execSync } from 'child_process';
720
+
721
+ jest.mock('child_process');
722
+ execSync.mockReturnValue('mocked output');
723
+ ```
724
+
725
+ ### Coverage
726
+
727
+ No enforced threshold. Focus on critical paths:
728
+
729
+ - `claude-client.js` - Claude CLI interaction
730
+ - `git-operations.js` - Git command abstraction
731
+ - `config.js` - Configuration merging
732
+
733
+ ## Restrictions
734
+
735
+ ### What Claude should NOT do in this repository
736
+
737
+ 1. **DO NOT add interactive prompts to git hooks**
738
+ - Git hooks run with stdin redirected from `/dev/null`
739
+ - Readline-based prompts cannot read user input in hook context
740
+ - Works in IDE integrations (VSCode, IntelliJ) but breaks in terminal
741
+ - **Solution**: Use `claude-hooks analyze` command instead (runs outside hook context)
742
+ - **Rationale**: Discovered through manual testing in Issue #20
743
+
744
+ 2. **DO NOT modify bash wrappers without corresponding Node.js changes**
745
+ - `templates/pre-commit` and `templates/prepare-commit-msg` are wrappers
746
+ - Real logic is in `lib/hooks/*.js`
747
+ - Changes to bash should be minimal (only Node.js invocation)
748
+
749
+ 3. **DO NOT use `shell: true` in `spawn()` calls**
750
+ - Deprecated in Node.js 24 (DEP0190)
751
+ - Use `which-command.js` to resolve executable paths
752
+ - **Exception**: Windows with `.cmd`/`.bat` requires `cmd.exe /c` wrapper
753
+
754
+ 4. **DO NOT modify config priority order**
755
+ - Maintain: defaults < user config < preset config
756
+ - Preset always wins (tech-stack specific has priority over user preferences)
757
+
758
+ 5. **DO NOT create duplicate config files**
759
+ - Single `.claude/config.json` per repo
760
+ - Presets live in `.claude/presets/{name}/`
761
+ - Do not create `.env` or similar files for configuration
762
+
763
+ 6. **DO NOT make breaking changes without MAJOR version bump**
764
+ - Changes in config.json structure → MAJOR
765
+ - Changes in CLI arguments → MAJOR
766
+ - Changes in template format → MINOR if backward compatible, otherwise MAJOR
767
+
768
+ 7. **DO NOT hardcode absolute paths**
769
+ - Use `getRepoRoot()` from `git-operations.js`
770
+ - All paths relative to repo root
771
+ - Exception: paths in `PATH` resolved with `which-command.js`
772
+
773
+ 8. **DO NOT use `console.log` directly**
774
+ - Always use `logger.js`: `info()`, `warning()`, `error()`, `debug()`
775
+ - Enables centralized output control and debug mode
776
+
777
+ 9. **DO NOT execute Claude CLI without timeout**
778
+ - Always configure timeout (default: 150s analysis, 180s commit msg)
779
+ - Timeout configurable in `.claude/config.json`
780
+
781
+ 10. **DO NOT ignore platform-specific issues**
782
+ - Test changes on Windows, Linux, and macOS
783
+ - Path separators: use `path.join()` (no hardcoded `/`)
784
+ - Line endings: templates use LF, convert on install if needed
785
+
786
+ 11. **DO NOT commit secrets**
787
+ - `.claude/settings.local.json` is in `.gitignore`
788
+ - GitHub tokens should go in settings.local or env vars
789
+ - Never in `.claude/config.json` (tracked)
790
+
791
+ 12. **DO NOT modify project `.gitignore` without consultation**
792
+ - `.claude/` is ignored by design (user-specific)
793
+ - `node_modules/` obvious
794
+ - New entries must be justified
795
+
796
+ 13. **DO NOT add dependencies without validation**
797
+ - Only 1 runtime dependency currently: `@octokit/rest`
798
+ - New deps must be justified (no built-in alternative?)
799
+ - Dev deps are OK if they improve DX (testing, linting)
800
+
801
+ 14. **DO NOT perform git operations add, commit, push unless asked to**
802
+ - Git flow associated with normal development must be left to human user
803
+
804
+ ### Technical Limitations
805
+
806
+ 1. **Node.js versions**: >=16.9.0 required (ES6 module features)
807
+ 2. **Claude CLI**: Must be installed and authenticated externally
808
+ 3. **Git**: Requires initialized repo (doesn't work outside git repos)
809
+ 4. **Parallel analysis**: Minimum 3 files to activate
810
+ 5. **File size**: Default max 1MB per file (configurable)
811
+ 6. **Max files**: Default 30 files per commit (configurable)
812
+ 7. **GitHub API**: Rate limits apply (5000 req/hour authenticated)
813
+
814
+ ### Security Considerations
815
+
816
+ 1. **Input sanitization**: Use `sanitize.js` for user inputs in shell commands
817
+ 2. **Token storage**: GitHub tokens in settings.local (gitignored) or env vars, NEVER tracked
818
+ 3. **Shell injection**: Avoid `shell: true`, use arrays in spawn()
819
+ 4. **Path traversal**: Validate relative paths before file operations
820
+ 5. **Secrets in diffs**: Hook should NOT prevent commits with secrets (user responsibility)