claude-git-hooks 2.17.2 → 2.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md ADDED
@@ -0,0 +1,821 @@
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
+ | `file-utils.js` | File operations | `ensureDir()`, `ensureOutputDir()`, `writeOutputFile()`, `walkDirectoryTree()` |
244
+ | `pr-metadata-engine.js` | PR metadata generation | `getBranchContext()`, `buildDiffPayload()`, `generatePRMetadata()`, `analyzeBranchForPR()` (v2.14.0) |
245
+ | `git-tag-manager.js` | Git tag operations | `createTag()`, `pushTags()`, `getLocalTags()`, `getRemoteTags()`, `compareLocalAndRemoteTags()`, `tagExists()` (v2.12.0) |
246
+ | `version-manager.js` | Version management | `discoverVersionFiles()`, `getDiscoveryResult()`, `readVersionFromFile()`, `writeVersionToFile()`, `updateVersionFiles()`, `modifySuffix()`, `incrementVersion()`, `parseVersion()`, `validateVersionFormat()`, `compareVersions()`, `validateVersionAlignment()` (v2.15.5) |
247
+ | `changelog-generator.js` | CHANGELOG generation | `generateChangelogEntry()`, `updateChangelogFile()`, `getLastFinalVersionTag()`, `getCommitsSinceTag()`, `discoverChangelogFiles()`, `selectChangelogFile()` (v2.12.0) |
248
+ | `github-api.js` | Octokit integration | `createPullRequest()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()` |
249
+ | `github-client.js` | GitHub helpers | `getReviewersForFiles()`, `parseGitHubRepo()` |
250
+ | `preset-loader.js` | Preset system | `loadPreset()`, `listPresets()` |
251
+ | `task-id.js` | Task ID extraction | `getOrPromptTaskId()`, `formatWithTaskId()` |
252
+ | `logger.js` | Logging system | `info()`, `warning()`, `error()`, `debug()` |
253
+ | `resolution-prompt.js` | Issue resolution | `generateResolutionPrompt()` |
254
+ | `interactive-ui.js` | CLI UI components | `showPRPreview()`, `promptConfirmation()`, `promptMenu()`, `promptToggleList()`, `promptEditField()`, `promptUserConfirmation()` |
255
+ | `telemetry.js` | Local telemetry | `recordEvent()`, `displayStatistics()` |
256
+
257
+ ### Design Patterns
258
+
259
+ 1. **Command Pattern**: `lib/commands/*.js` - each CLI command is a self-contained module
260
+ 2. **Factory Pattern**: `preset-loader.js` loads configurations dynamically per tech-stack
261
+ 3. **Template Method**: `prompt-builder.js` builds prompts from markdown templates
262
+ 4. **Strategy Pattern**: `claude-client.js` selects between sequential or parallel analysis
263
+ 5. **Adapter Pattern**: `git-operations.js` abstracts git commands into JS functions
264
+ 6. **Singleton Pattern**: `config.js` loads configuration once per execution
265
+
266
+ ### Key Data Flows
267
+
268
+ **Flow 1: Pre-commit with blocking**
269
+
270
+ ```
271
+ git commit
272
+ → hook reads staged files
273
+ → filters by preset extensions
274
+ → builds prompt with diff
275
+ → Claude analyzes → detects SQL injection (CRITICAL)
276
+ → generates resolution prompt
277
+ → exit 1 → COMMIT BLOCKED
278
+ ```
279
+
280
+ **Flow 1.5: Interactive analysis command (v2.13.0)**
281
+
282
+ ```
283
+ claude-hooks analyze
284
+ → runs outside git hook context (stdin works)
285
+ → getStagedFiles() → buildFilesData() → runAnalysis()
286
+ → displayIssueSummary() → shows all severity levels (or "No issues found")
287
+ → promptUserConfirmation() → interactive menu:
288
+ → [y] Continue - executes createCommit('auto', { noVerify: true })
289
+ → [n] Abort - generates resolution prompt
290
+ → [v] View - shows detailed issues → returns to menu
291
+ → on continue: git commit -m "auto" --no-verify
292
+ → prepare-commit-msg hook generates message via Claude
293
+ → commit created with auto-generated message
294
+ ```
295
+
296
+ **Flow 2: Commit with automatic message**
297
+
298
+ ```
299
+ git commit -m "auto"
300
+ → hook extracts task-id from branch (feature/IX-123-add-auth)
301
+ → Claude generates message → "[IX-123] feat: add user authentication"
302
+ → writes to .git/COMMIT_EDITMSG
303
+ → commit proceeds with generated message
304
+ ```
305
+
306
+ **Flow 3: Analyze diff (v2.14.0)**
307
+
308
+ ```
309
+ claude-hooks analyze-diff develop
310
+ → lib/commands/analyze-diff.js (thin wrapper)
311
+ → analyzeBranchForPR() (pr-metadata-engine.js)
312
+ → fetchRemote() → resolveBaseBranch() (suggests similar branches if not found)
313
+ → getChangedFilesBetweenRefs() → getCommitsBetweenRefs()
314
+ → buildDiffPayload() → tiered reduction (context → proportional → stat-only)
315
+ → executeClaudeWithRetry() → parses PRMetadata
316
+ → formats metadata to console
317
+ → saves to .claude/out/pr-analysis.json
318
+ ```
319
+
320
+ **Flow 4: PR creation (with auto-push v2.11.0, engine v2.14.0)**
321
+
322
+ ```
323
+ claude-hooks create-pr develop
324
+ → checks branch push status (unpublished/unpushed commits)
325
+ → shows commit preview → prompts for confirmation
326
+ → pushes branch to remote (if needed)
327
+ → reads CODEOWNERS → detects reviewers
328
+ → reads config → applies label rules per preset
329
+ → analyzeBranchForPR() (pr-metadata-engine.js) → generates metadata
330
+ → interactive preview → user confirms
331
+ → Octokit creates PR on GitHub
332
+ ```
333
+
334
+ **Flow 5: Version bump with per-file editing (v2.16.0)**
335
+
336
+ ```
337
+ claude-hooks bump-version patch --interactive
338
+ → validatePrerequisites() → clean working directory, valid branch, remote
339
+ → discoverVersionFiles() → recursive scan (max 3 levels)
340
+ → displayDiscoveryTable() → shows all discovered files with versions
341
+ → promptFileSelection() → interactive menu:
342
+ → [a] Update all files - all files get same newVersion
343
+ → [s] Select files - toggle list to pick subset
344
+ → [e] Edit per file - promptEditField() per file:
345
+ → user enters custom version per file (Enter keeps calculated version)
346
+ → validateVersionFormat() → rejects invalid entries
347
+ → stores file.targetVersion on each descriptor
348
+ → [c] Cancel
349
+ → incrementVersion() / modifySuffix() → calculates newVersion (used for tag + commit)
350
+ → updateVersionFiles() → uses file.targetVersion || newVersion per file
351
+ → createTag(newVersion) → tag reflects primary release version
352
+ → commit message uses newVersion
353
+ ```
354
+
355
+ **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`.
356
+
357
+ ## Code Conventions
358
+
359
+ ### General Style
360
+
361
+ - **Format**: Prettier (config in `.prettierrc.json`)
362
+ - **Linting**: ESLint 8.57.0 (config in `.eslintrc.json`)
363
+ - **Indentation**: 4 spaces
364
+ - **Quotes**: Single quotes (strings), double quotes (HTML/imports)
365
+ - **Semicolons**: Required
366
+
367
+ ### Naming
368
+
369
+ - **Files**: `kebab-case.js` (e.g., `claude-client.js`, `git-operations.js`)
370
+ - **Functions**: `camelCase()` (e.g., `getStagedFiles()`, `buildAnalysisPrompt()`)
371
+ - **Constants**: `UPPER_SNAKE_CASE` (e.g., `MAX_FILE_SIZE`, `ALLOWED_EXTENSIONS`)
372
+ - **Classes**: Not applicable (no classes, only exported functions)
373
+ - **Private variables**: `_` prefix (e.g., `_internalHelper()`)
374
+
375
+ ### Exports
376
+
377
+ **Preferred pattern - Named exports:**
378
+
379
+ ```javascript
380
+ // lib/utils/example.js
381
+ export function doSomething() { ... }
382
+ export function doOtherThing() { ... }
383
+
384
+ // consumer
385
+ import { doSomething, doOtherThing } from './utils/example.js';
386
+ ```
387
+
388
+ **Avoid default exports** (except in `bin/claude-hooks` per CLI convention).
389
+
390
+ ### Error Handling
391
+
392
+ **Standard pattern:**
393
+
394
+ ```javascript
395
+ import { error } from './utils/logger.js';
396
+
397
+ try {
398
+ const result = dangerousOperation();
399
+ return result;
400
+ } catch (err) {
401
+ error(`Failed to perform operation: ${err.message}`);
402
+ process.exit(1); // In hooks and CLI commands
403
+ // or throw err; // In library functions
404
+ }
405
+ ```
406
+
407
+ **Specific errors:**
408
+
409
+ - Git operations → `execSync()` with try-catch, log and exit
410
+ - Claude CLI → retry logic in `claude-client.js`, configurable timeout
411
+ - GitHub API → catch `@octokit/request-error`, user-friendly formatting
412
+
413
+ ### Logging
414
+
415
+ ```javascript
416
+ import { info, warning, error, debug } from './utils/logger.js';
417
+
418
+ info('✅ Operation completed'); // User-facing messages
419
+ warning('⚠️ Non-blocking issue detected'); // Warnings
420
+ error('❌ Critical failure'); // Errors
421
+ debug('Detailed diagnostic info'); // Only shown when debug=true
422
+ ```
423
+
424
+ **Debug mode**: Activate with `claude-hooks --debug true` or in `.claude/config.json`.
425
+
426
+ ### Async/Await
427
+
428
+ **Prefer async/await over callbacks:**
429
+
430
+ ```javascript
431
+ // ✅ GOOD
432
+ async function analyzeCode(prompt) {
433
+ const result = await spawnClaude(prompt);
434
+ return result;
435
+ }
436
+
437
+ // ❌ BAD
438
+ function analyzeCode(prompt, callback) {
439
+ spawnClaude(prompt, callback);
440
+ }
441
+ ```
442
+
443
+ ### Reusable Modules
444
+
445
+ All modules in `lib/utils/` must:
446
+
447
+ 1. Export pure functions (no global side effects)
448
+ 2. Include inline JSDoc documentation
449
+ 3. Accept configuration via parameters (no globals)
450
+ 4. Return structured results (objects or arrays)
451
+ 5. Log with `logger.js` (no direct `console.log`)
452
+
453
+ ## Workflow
454
+
455
+ ### Branching Strategy
456
+
457
+ This repository follows **simplified GitHub Flow**:
458
+
459
+ - **Main branch**: `main` (protected)
460
+ - **Feature branches**: `feature/issue-description` or `feature/TASK-ID-description`
461
+ - **Fix branches**: `fix/issue-description`
462
+ - **Hotfix branches**: `hotfix/urgent-description`
463
+
464
+ **Rules:**
465
+
466
+ 1. All changes require PR to `main`
467
+ 2. No direct commits to `main`
468
+ 3. PRs require review (auto-merge NOT allowed)
469
+
470
+ ### Development Process
471
+
472
+ **1. Initial setup (first time)**
473
+
474
+ ```bash
475
+ git clone https://github.com/mscope-S-L/git-hooks.git
476
+ cd git-hooks
477
+ npm install
478
+ npm link # Install globally as symlink for development
479
+ ```
480
+
481
+ **2. Create feature branch**
482
+
483
+ ```bash
484
+ git checkout -b feature/new-functionality
485
+ # or with task-id: feature/IX-123-new-functionality
486
+ ```
487
+
488
+ **3. Iterative development**
489
+
490
+ ```bash
491
+ # Make changes...
492
+ npm run lint # Check linting
493
+ npm run test # Run tests
494
+ git add .
495
+ git commit -m "feat: add new functionality"
496
+ # Hooks execute automatically
497
+ ```
498
+
499
+ **4. Local testing**
500
+
501
+ Test changes in a test repository:
502
+
503
+ ```bash
504
+ # In test repo
505
+ cd /path/to/test-repo
506
+ claude-hooks install --force --skip-auth # Reinstall from symlink
507
+ git commit -m "test" # Test hook
508
+ ```
509
+
510
+ **5. Create PR**
511
+
512
+ ```bash
513
+ git push -u origin feature/new-functionality
514
+ claude-hooks analyze-diff main # Generate PR metadata
515
+ # or directly:
516
+ claude-hooks create-pr main # Create PR on GitHub (if MCP configured)
517
+ ```
518
+
519
+ ### CI/CD
520
+
521
+ **Currently**: No automated CI/CD (GitHub Actions pending).
522
+
523
+ **Manual verifications before merge:**
524
+
525
+ 1. `npm run lint` → passes
526
+ 2. `npm run test` → all tests pass
527
+ 3. Manual testing in test repo
528
+ 4. Peer code review
529
+ 5. CHANGELOG.md updated
530
+
531
+ ### Versioning
532
+
533
+ We follow **Semantic Versioning** (MAJOR.MINOR.PATCH):
534
+
535
+ - **MAJOR**: Breaking changes (e.g., 1.x → 2.0 with ES6 migration)
536
+ - **MINOR**: New features without breaking changes (e.g., 2.2 → 2.3 with presets)
537
+ - **PATCH**: Bug fixes (e.g., 2.6.0 → 2.6.1 with spawn ENOENT fix)
538
+
539
+ **Update version:**
540
+
541
+ ```bash
542
+ npm version patch # 2.6.1 → 2.6.2
543
+ npm version minor # 2.6.1 → 2.7.0
544
+ npm version major # 2.6.1 → 3.0.0
545
+ ```
546
+
547
+ **Publish to NPM:**
548
+
549
+ ```bash
550
+ npm publish
551
+ ```
552
+
553
+ ### Conventional Commits
554
+
555
+ Format: `<type>(<scope>): <subject>`
556
+
557
+ **Types:**
558
+
559
+ - `feat`: New functionality
560
+ - `fix`: Bug fix
561
+ - `docs`: Documentation only
562
+ - `style`: Formatting (no logic change)
563
+ - `refactor`: Refactoring without functional change
564
+ - `test`: Add or modify tests
565
+ - `chore`: Maintenance (deps, config)
566
+ - `perf`: Performance improvements
567
+
568
+ **Optional scopes:**
569
+
570
+ - `hooks`: Changes in pre-commit or prepare-commit-msg
571
+ - `presets`: Preset system
572
+ - `github`: GitHub integration
573
+ - `cli`: Main CLI commands
574
+ - `config`: Configuration system
575
+ - `windows`: Windows-specific fixes
576
+
577
+ **Examples:**
578
+
579
+ ```
580
+ feat(presets): add database preset for SQL analysis
581
+ fix(windows): resolve spawn ENOENT with .cmd files
582
+ docs: update CLAUDE.md with architecture details
583
+ chore(deps): upgrade @octokit/rest to v21
584
+ ```
585
+
586
+ ## Useful Commands
587
+
588
+ ### Development
589
+
590
+ ```bash
591
+ # Installation and setup
592
+ npm install # Install dependencies
593
+ npm link # Install globally as symlink
594
+ npm unlink # Uninstall global symlink
595
+
596
+ # Testing
597
+ npm test # Run all tests (Jest)
598
+ npm run test:watch # Tests in watch mode
599
+ npm run test:coverage # Coverage report
600
+
601
+ # Linting and formatting
602
+ npm run lint # Check ESLint
603
+ npm run lint:fix # Auto-fix ESLint issues
604
+ npm run format # Format with Prettier
605
+
606
+ # Versioning
607
+ npm version patch|minor|major # Bump version
608
+ npm publish # Publish to NPM
609
+ ```
610
+
611
+ ### Package CLI
612
+
613
+ ```bash
614
+ # Hook installation in a repo
615
+ claude-hooks install # Interactive installation
616
+ claude-hooks install --force # Reinstall without confirmation
617
+ claude-hooks install --skip-auth # Skip Claude verification
618
+
619
+ # Hook management
620
+ claude-hooks status # View current status
621
+ claude-hooks enable [hook] # Enable all or specific hook
622
+ claude-hooks disable [hook] # Disable all or specific hook
623
+ claude-hooks uninstall # Completely uninstall
624
+
625
+ # Presets
626
+ claude-hooks presets # List available presets
627
+ claude-hooks --set-preset backend # Change preset
628
+ claude-hooks preset current # View current preset
629
+
630
+ # Analysis and PRs
631
+ claude-hooks analyze-diff [branch] # Analyze diff for PR
632
+ claude-hooks create-pr [branch] # Create PR on GitHub
633
+ claude-hooks setup-github # Configure GitHub token
634
+
635
+ # Version management
636
+ claude-hooks bump-version patch # Bump version (commits, tags locally)
637
+ claude-hooks bump-version minor --suffix SNAPSHOT # With suffix
638
+ claude-hooks bump-version major --update-changelog # With CHANGELOG
639
+ claude-hooks bump-version patch --push # Push tag immediately
640
+ claude-hooks bump-version patch --no-commit # Manual workflow
641
+ claude-hooks bump-version patch --interactive # Force file selection menu
642
+ claude-hooks generate-changelog # Generate CHANGELOG only
643
+
644
+ # Help and issue reporting
645
+ claude-hooks help "how do presets work?" # AI-powered help (uses CLAUDE.md)
646
+ claude-hooks help --report-issue # Interactive issue creation
647
+
648
+ # Debugging
649
+ claude-hooks --debug true # Enable debug mode
650
+ claude-hooks --debug false # Disable debug mode
651
+ claude-hooks --debug status # View debug status
652
+
653
+ # Auto-update
654
+ claude-hooks update # Update to latest version
655
+ ```
656
+
657
+ ### Git with Active Hooks
658
+
659
+ ```bash
660
+ # Normal commit with analysis
661
+ git commit -m "feat: new functionality"
662
+
663
+ # Commit with automatic message
664
+ git commit -m "auto" # Claude generates the message
665
+
666
+ # Skip analysis (emergencies)
667
+ git commit --no-verify -m "hotfix: urgent"
668
+
669
+ # Amend last commit
670
+ git commit --amend
671
+ ```
672
+
673
+ ### Local Testing in Test Repo
674
+
675
+ ```bash
676
+ # Initial setup
677
+ cd /path/to/test-repo
678
+ claude-hooks install --force --skip-auth
679
+
680
+ # After changes in claude-hooks
681
+ # (npm link is already active, no need to reinstall)
682
+ cd /path/to/test-repo
683
+ git add test.txt
684
+ git commit -m "test: validate changes"
685
+ # Hooks use local version automatically
686
+ ```
687
+
688
+ ## Testing
689
+
690
+ ### Test Framework
691
+
692
+ - **Framework**: Jest with ES6 modules (`--experimental-vm-modules`)
693
+ - **Location**: `test/unit/*.test.js`
694
+ - **Naming**: `{module-name}.test.js` matches `lib/utils/{module-name}.js`
695
+ - **Run**: `npm test` (all), `npm run test:watch` (watch mode)
696
+
697
+ ### Test Patterns
698
+
699
+ ```javascript
700
+ // test/unit/example.test.js
701
+ import { functionToTest } from '../../lib/utils/example.js';
702
+
703
+ describe('functionToTest', () => {
704
+ it('should handle normal input', () => {
705
+ const result = functionToTest('input');
706
+ expect(result).toBe('expected');
707
+ });
708
+
709
+ it('should throw on invalid input', () => {
710
+ expect(() => functionToTest(null)).toThrow('Invalid input');
711
+ });
712
+ });
713
+ ```
714
+
715
+ ### Mocking
716
+
717
+ ```javascript
718
+ // Mock child_process for git/claude commands
719
+ import { jest } from '@jest/globals';
720
+ import { execSync } from 'child_process';
721
+
722
+ jest.mock('child_process');
723
+ execSync.mockReturnValue('mocked output');
724
+ ```
725
+
726
+ ### Coverage
727
+
728
+ No enforced threshold. Focus on critical paths:
729
+
730
+ - `claude-client.js` - Claude CLI interaction
731
+ - `git-operations.js` - Git command abstraction
732
+ - `config.js` - Configuration merging
733
+
734
+ ## Restrictions
735
+
736
+ ### What Claude should NOT do in this repository
737
+
738
+ 1. **DO NOT add interactive prompts to git hooks**
739
+ - Git hooks run with stdin redirected from `/dev/null`
740
+ - Readline-based prompts cannot read user input in hook context
741
+ - Works in IDE integrations (VSCode, IntelliJ) but breaks in terminal
742
+ - **Solution**: Use `claude-hooks analyze` command instead (runs outside hook context)
743
+ - **Rationale**: Discovered through manual testing in Issue #20
744
+
745
+ 2. **DO NOT modify bash wrappers without corresponding Node.js changes**
746
+ - `templates/pre-commit` and `templates/prepare-commit-msg` are wrappers
747
+ - Real logic is in `lib/hooks/*.js`
748
+ - Changes to bash should be minimal (only Node.js invocation)
749
+
750
+ 3. **DO NOT use `shell: true` in `spawn()` calls**
751
+ - Deprecated in Node.js 24 (DEP0190)
752
+ - Use `which-command.js` to resolve executable paths
753
+ - **Exception**: Windows with `.cmd`/`.bat` requires `cmd.exe /c` wrapper
754
+
755
+ 4. **DO NOT modify config priority order**
756
+ - Maintain: defaults < user config < preset config
757
+ - Preset always wins (tech-stack specific has priority over user preferences)
758
+
759
+ 5. **DO NOT create duplicate config files**
760
+ - Single `.claude/config.json` per repo
761
+ - Presets live in `.claude/presets/{name}/`
762
+ - Do not create `.env` or similar files for configuration
763
+
764
+ 6. **DO NOT make breaking changes without MAJOR version bump**
765
+ - Changes in config.json structure → MAJOR
766
+ - Changes in CLI arguments → MAJOR
767
+ - Changes in template format → MINOR if backward compatible, otherwise MAJOR
768
+
769
+ 7. **DO NOT hardcode absolute paths**
770
+ - Use `getRepoRoot()` from `git-operations.js`
771
+ - All paths relative to repo root
772
+ - Exception: paths in `PATH` resolved with `which-command.js`
773
+
774
+ 8. **DO NOT use `console.log` directly**
775
+ - Always use `logger.js`: `info()`, `warning()`, `error()`, `debug()`
776
+ - Enables centralized output control and debug mode
777
+
778
+ 9. **DO NOT execute Claude CLI without timeout**
779
+ - Always configure timeout (default: 150s analysis, 180s commit msg)
780
+ - Timeout configurable in `.claude/config.json`
781
+
782
+ 10. **DO NOT ignore platform-specific issues**
783
+ - Test changes on Windows, Linux, and macOS
784
+ - Path separators: use `path.join()` (no hardcoded `/`)
785
+ - Line endings: templates use LF, convert on install if needed
786
+
787
+ 11. **DO NOT commit secrets**
788
+ - `.claude/settings.local.json` is in `.gitignore`
789
+ - GitHub tokens should go in settings.local or env vars
790
+ - Never in `.claude/config.json` (tracked)
791
+
792
+ 12. **DO NOT modify project `.gitignore` without consultation**
793
+ - `.claude/` is ignored by design (user-specific)
794
+ - `node_modules/` obvious
795
+ - New entries must be justified
796
+
797
+ 13. **DO NOT add dependencies without validation**
798
+ - Only 1 runtime dependency currently: `@octokit/rest`
799
+ - New deps must be justified (no built-in alternative?)
800
+ - Dev deps are OK if they improve DX (testing, linting)
801
+
802
+ 14. **DO NOT perform git operations add, commit, push unless asked to**
803
+ - Git flow associated with normal development must be left to human user
804
+
805
+ ### Technical Limitations
806
+
807
+ 1. **Node.js versions**: >=16.9.0 required (ES6 module features)
808
+ 2. **Claude CLI**: Must be installed and authenticated externally
809
+ 3. **Git**: Requires initialized repo (doesn't work outside git repos)
810
+ 4. **Parallel analysis**: Minimum 3 files to activate
811
+ 5. **File size**: Default max 1MB per file (configurable)
812
+ 6. **Max files**: Default 30 files per commit (configurable)
813
+ 7. **GitHub API**: Rate limits apply (5000 req/hour authenticated)
814
+
815
+ ### Security Considerations
816
+
817
+ 1. **Input sanitization**: Use `sanitize.js` for user inputs in shell commands
818
+ 2. **Token storage**: GitHub tokens in settings.local (gitignored) or env vars, NEVER tracked
819
+ 3. **Shell injection**: Avoid `shell: true`, use arrays in spawn()
820
+ 4. **Path traversal**: Validate relative paths before file operations
821
+ 5. **Secrets in diffs**: Hook should NOT prevent commits with secrets (user responsibility)