claude-git-hooks 2.3.1 → 2.4.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/CHANGELOG.md +84 -0
- package/README.md +51 -40
- package/bin/claude-hooks +147 -45
- package/lib/config.js +6 -6
- package/lib/hooks/pre-commit.js +34 -0
- package/lib/hooks/prepare-commit-msg.js +5 -0
- package/lib/utils/claude-client.js +40 -11
- package/lib/utils/file-operations.js +38 -4
- package/lib/utils/logger.js +2 -2
- package/package.json +1 -1
- package/templates/CUSTOMIZATION_GUIDE.md +5 -5
- package/templates/config.example.json +41 -41
- package/templates/presets/ai/config.json +12 -12
- package/templates/presets/ai/preset.json +31 -36
- package/templates/presets/backend/ANALYSIS_PROMPT.md +23 -28
- package/templates/presets/backend/PRE_COMMIT_GUIDELINES.md +41 -3
- package/templates/presets/backend/config.json +12 -12
- package/templates/presets/database/config.json +12 -12
- package/templates/presets/default/config.json +12 -12
- package/templates/presets/frontend/config.json +12 -12
- package/templates/presets/fullstack/config.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,90 @@ 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.4.1] - 2025-11-19
|
|
9
|
+
|
|
10
|
+
### 🐛 Fixed
|
|
11
|
+
|
|
12
|
+
- **Git Bash Windows Support** - Claude hooks now works correctly on Git Bash in Windows
|
|
13
|
+
- **What changed**:
|
|
14
|
+
- `--skip-auth` now skips both Claude CLI verification AND authentication (previously only auth)
|
|
15
|
+
- Windows detection now tries native Claude first, WSL as fallback
|
|
16
|
+
- `spawn()` now uses `shell: true` to resolve `.cmd`/`.bat` executables
|
|
17
|
+
- **Why**:
|
|
18
|
+
- Installation with `--skip-auth` was failing before copying `.md` files and presets
|
|
19
|
+
- Code assumed Claude must always run via WSL on Windows, ignoring native installations
|
|
20
|
+
- Git Bash runs Node.js natively on Windows, not in WSL
|
|
21
|
+
- `spawn()` without shell couldn't find Windows batch files
|
|
22
|
+
- **Files updated**:
|
|
23
|
+
- `bin/claude-hooks:512-518` - Skip auth now skips Claude CLI check
|
|
24
|
+
- `bin/claude-hooks:532-544` - Native Windows Claude detection
|
|
25
|
+
- `lib/utils/claude-client.js:75-115` - Smart platform detection with fallback
|
|
26
|
+
- `lib/utils/claude-client.js:145-148` - Added `shell: true` for Windows compatibility
|
|
27
|
+
- **Impact**: Git Bash users on Windows can now use native Claude (via npm/NVM) instead of requiring WSL
|
|
28
|
+
|
|
29
|
+
### 🎯 User Experience
|
|
30
|
+
|
|
31
|
+
- **Installation**: `claude-hooks install --skip-auth` now completes successfully, installing all templates and presets
|
|
32
|
+
- **NVM Compatibility**: Works with Claude CLI installed via npm in current Node version (NVM managed)
|
|
33
|
+
- **Flexible Setup**: Automatically detects and uses best available Claude CLI method (native Windows or WSL)
|
|
34
|
+
|
|
35
|
+
## [2.4.0] - 2025-11-17
|
|
36
|
+
|
|
37
|
+
### ⚠️ BREAKING CHANGES
|
|
38
|
+
|
|
39
|
+
- **Debug Mode** - Environment variable `DEBUG` no longer supported
|
|
40
|
+
- **What changed**: Removed `DEBUG` environment variable support from `lib/utils/logger.js`
|
|
41
|
+
- **Why**: Aligns with project philosophy "no environment variables" and provides better user experience
|
|
42
|
+
- **Migration**: Use `claude-hooks --debug true` instead of `DEBUG=1 git commit`
|
|
43
|
+
- **Alternative**: Set `"system": { "debug": true }` in `.claude/config.json`
|
|
44
|
+
|
|
45
|
+
### 🔄 Changed
|
|
46
|
+
|
|
47
|
+
- **File Size Limit Increased** - Default `maxFileSize` increased from 100KB to 1MB
|
|
48
|
+
- **What changed**: `analysis.maxFileSize` now defaults to 1000000 (1MB) instead of 100000 (100KB)
|
|
49
|
+
- **Why**: Previous 100KB limit was too restrictive, rejected many legitimate source files
|
|
50
|
+
- **Files updated**:
|
|
51
|
+
- `lib/config.js:29` - Default configuration
|
|
52
|
+
- All preset configs in `templates/presets/*/config.json`
|
|
53
|
+
- `templates/config.example.json`
|
|
54
|
+
- **Impact**: More files will be analyzed without manual config adjustment
|
|
55
|
+
- **User action**: If you want stricter limits, set `"maxFileSize": 100000` in `.claude/config.json`
|
|
56
|
+
|
|
57
|
+
### ✨ Added
|
|
58
|
+
|
|
59
|
+
- **Debug CLI Command** - New `--debug` flag for managing debug mode
|
|
60
|
+
- **Usage**: `claude-hooks --debug <true|false|status>`
|
|
61
|
+
- **Purpose**: Enables detailed logging for troubleshooting
|
|
62
|
+
- **Implementation**: Generic `updateConfig()` function in `bin/claude-hooks:1262`
|
|
63
|
+
- **Benefits**: Consistent with `--set-preset` pattern, no need to remember env var syntax
|
|
64
|
+
|
|
65
|
+
- **Generic Config Updater** - Reusable `updateConfig()` function
|
|
66
|
+
- **Purpose**: Centralized config update logic for all CLI commands
|
|
67
|
+
- **Location**: `bin/claude-hooks:1262`
|
|
68
|
+
- **Features**: Dot notation path support, custom validators, custom success messages
|
|
69
|
+
- **Extensibility**: Easy to add new config commands (`--set-max-files`, `--set-timeout`, etc.)
|
|
70
|
+
|
|
71
|
+
### 🔄 Changed
|
|
72
|
+
|
|
73
|
+
- **setPreset() Refactored** - Now uses generic `updateConfig()` function
|
|
74
|
+
- **Effect**: Less code duplication, consistent error handling
|
|
75
|
+
- **Location**: `bin/claude-hooks:1349`
|
|
76
|
+
|
|
77
|
+
- **Debug Mode Activation** - Hooks now enable debug from config
|
|
78
|
+
- **Files**: `lib/hooks/pre-commit.js:185`, `lib/hooks/prepare-commit-msg.js:124`
|
|
79
|
+
- **Effect**: Debug logs appear when `config.system.debug` is true
|
|
80
|
+
|
|
81
|
+
### 📚 Documentation
|
|
82
|
+
|
|
83
|
+
- **Help Text Updated** - Added `--debug` command documentation
|
|
84
|
+
- **Location**: `bin/claude-hooks:1170`
|
|
85
|
+
- **Includes**: Command description, examples, debug mode section
|
|
86
|
+
|
|
87
|
+
- **README.md Updated** - Debug command documented in multiple sections
|
|
88
|
+
- **Cheatsheet**: Added debug commands to "Comandos Frecuentes" (line 52-56)
|
|
89
|
+
- **Tips**: Updated tip #4 with CLI command (line 269)
|
|
90
|
+
- **Features**: Updated debug mode description (line 492)
|
|
91
|
+
|
|
8
92
|
## [2.3.1] - 2025-11-13
|
|
9
93
|
|
|
10
94
|
### 🔄 Changed
|
package/README.md
CHANGED
|
@@ -48,6 +48,12 @@ claude-hooks --set-preset <name>
|
|
|
48
48
|
|
|
49
49
|
# Mostrar preset actual
|
|
50
50
|
claude-hooks preset current
|
|
51
|
+
|
|
52
|
+
# Activar modo debug
|
|
53
|
+
claude-hooks --debug true
|
|
54
|
+
|
|
55
|
+
# Ver estado de debug
|
|
56
|
+
claude-hooks --debug status
|
|
51
57
|
```
|
|
52
58
|
|
|
53
59
|
### 📦 Instalación y Gestión
|
|
@@ -96,6 +102,10 @@ git commit --no-verify -m "hotfix: corrección urgente"
|
|
|
96
102
|
git commit --amend
|
|
97
103
|
```
|
|
98
104
|
|
|
105
|
+
## 📆 Próximos Desarrollos
|
|
106
|
+
|
|
107
|
+
Toda idea es bienvenida, aunque parezca espantosa. Si hay bugs, incluirlos también. Dónde? en https://github.com/mscope-S-L/git-hooks/issues/new.
|
|
108
|
+
|
|
99
109
|
### ⚠️ Exclusión de Código del Análisis (EXPERIMENTAL/BROKEN)
|
|
100
110
|
|
|
101
111
|
```java
|
|
@@ -127,7 +137,7 @@ cat > .claude/config.json << 'EOF'
|
|
|
127
137
|
{
|
|
128
138
|
"preset": "backend",
|
|
129
139
|
"analysis": {
|
|
130
|
-
"maxFileSize":
|
|
140
|
+
"maxFileSize": 1000000,
|
|
131
141
|
"maxFiles": 12,
|
|
132
142
|
"timeout": 150000
|
|
133
143
|
},
|
|
@@ -149,14 +159,14 @@ EOF
|
|
|
149
159
|
|
|
150
160
|
#### 🎯 Presets Disponibles
|
|
151
161
|
|
|
152
|
-
| Preset | Extensiones de Archivo | Caso de Uso
|
|
153
|
-
| ------------- | -------------------------------------------------------------------------- |
|
|
154
|
-
| **backend** | `.java`, `.xml`, `.yml`, `.yaml` | APIs Spring Boot
|
|
155
|
-
| **frontend** | `.js`, `.jsx`, `.ts`, `.tsx`, `.css`, `.scss`, `.html` | Apps React
|
|
156
|
-
| **fullstack** | Todos backend + frontend | Apps full-stack
|
|
157
|
-
| **database** | `.sql` | Scripts de BD
|
|
158
|
-
| **ai** | `.js`, `.json`, `.md`, `.sh` | Herramientas CLI
|
|
159
|
-
| **default** | `.js`, `.sh`, `.py`, `.rb`, `.pl`, `.sql`, `.yaml`, `.json`, `.xml`, `.md` | Propósito general| Lenguajes mixtos |
|
|
162
|
+
| Preset | Extensiones de Archivo | Caso de Uso | Tech Stack |
|
|
163
|
+
| ------------- | -------------------------------------------------------------------------- | ----------------- | ---------------------------- |
|
|
164
|
+
| **backend** | `.java`, `.xml`, `.yml`, `.yaml` | APIs Spring Boot | Spring Boot, JPA, SQL Server |
|
|
165
|
+
| **frontend** | `.js`, `.jsx`, `.ts`, `.tsx`, `.css`, `.scss`, `.html` | Apps React | React, Redux, Material-UI |
|
|
166
|
+
| **fullstack** | Todos backend + frontend | Apps full-stack | Spring Boot + React |
|
|
167
|
+
| **database** | `.sql` | Scripts de BD | SQL Server, T-SQL |
|
|
168
|
+
| **ai** | `.js`, `.json`, `.md`, `.sh` | Herramientas CLI | Node.js, Claude API |
|
|
169
|
+
| **default** | `.js`, `.sh`, `.py`, `.rb`, `.pl`, `.sql`, `.yaml`, `.json`, `.xml`, `.md` | Propósito general | Lenguajes mixtos |
|
|
160
170
|
|
|
161
171
|
---
|
|
162
172
|
|
|
@@ -260,9 +270,9 @@ git commit -m "fix: resolver issues"
|
|
|
260
270
|
1. **Mensaje automático**: Usa `"auto"` como mensaje para que Claude lo genere
|
|
261
271
|
2. **Skip auth**: Usa `--skip-auth` en CI/CD o desarrollo local
|
|
262
272
|
3. **Force install**: Usa `--force` para reinstalar sin confirmación
|
|
263
|
-
4. **Debug**: Activa en `.claude/config.json`: `{"system": {"debug": true}}`
|
|
264
|
-
5. **Archivos grandes**: Se omiten automáticamente archivos >
|
|
265
|
-
6. **Límite de archivos**: Máximo
|
|
273
|
+
4. **Debug**: Activa con `claude-hooks --debug true` o en `.claude/config.json`: `{"system": {"debug": true}}`
|
|
274
|
+
5. **Archivos grandes**: Se omiten automáticamente archivos > 1MB
|
|
275
|
+
6. **Límite de archivos**: Máximo 30 archivos por commit (configurable)
|
|
266
276
|
|
|
267
277
|
### 🚀 Parallel Analysis (v2.2.0+)
|
|
268
278
|
|
|
@@ -415,9 +425,6 @@ Durante la instalación, Claude Hooks actualiza automáticamente tu `.gitignore`
|
|
|
415
425
|
```gitignore
|
|
416
426
|
# Claude Git Hooks
|
|
417
427
|
.claude/
|
|
418
|
-
debug-claude-response.json
|
|
419
|
-
claude_resolution_prompt.md
|
|
420
|
-
.claude-pr-analysis.json
|
|
421
428
|
```
|
|
422
429
|
|
|
423
430
|
Esto asegura que:
|
|
@@ -435,8 +442,8 @@ Si no existe un `.gitignore`, se creará uno nuevo. Si ya existe, las entradas s
|
|
|
435
442
|
1. **Intercepta cada intento de commit**
|
|
436
443
|
2. **Extrae y filtra archivos modificados**:
|
|
437
444
|
- Solo analiza: Java, XML, properties, yml, yaml
|
|
438
|
-
- Omite archivos mayores a
|
|
439
|
-
- Límite de
|
|
445
|
+
- Omite archivos mayores a 1MB
|
|
446
|
+
- Límite de 30 archivos por commit
|
|
440
447
|
3. **Construye prompt inteligente**:
|
|
441
448
|
- Usa template de prompt desde `.claude/CLAUDE_ANALYSIS_PROMPT*.md`
|
|
442
449
|
- Lee las pautas desde `.claude/CLAUDE_PRE_COMMIT*.md`
|
|
@@ -462,7 +469,7 @@ Si no existe un `.gitignore`, se creará uno nuevo. Si ya existe, las entradas s
|
|
|
462
469
|
- `"auto"`
|
|
463
470
|
2. **Analiza los cambios del staging area**:
|
|
464
471
|
- Lista archivos modificados con estadísticas
|
|
465
|
-
- Incluye diffs completos para archivos <
|
|
472
|
+
- Incluye diffs completos para archivos < 1MB
|
|
466
473
|
3. **Genera mensaje en formato Conventional Commits**:
|
|
467
474
|
- Determina tipo: feat, fix, docs, style, refactor, test, chore
|
|
468
475
|
- Crea título conciso y descriptivo
|
|
@@ -483,7 +490,7 @@ Si no existe un `.gitignore`, se creará uno nuevo. Si ya existe, las entradas s
|
|
|
483
490
|
- 📝 Archivo `.claude-pr-analysis.json`
|
|
484
491
|
- **Auto-actualización**: Verificación automática de versiones antes de cada commit con prompt interactivo para actualizar
|
|
485
492
|
- **Comando update**: `claude-hooks update` para actualizar manualmente a la última versión
|
|
486
|
-
- **Modo debug**: `
|
|
493
|
+
- **Modo debug**: `claude-hooks --debug true` activa logging detallado para troubleshooting
|
|
487
494
|
- **Análisis de PR**: Nuevo comando `analyze-diff` para generar información de Pull Requests
|
|
488
495
|
- **Validación de dependencias**: Verifica que Claude CLI esté autenticado antes de ejecutar
|
|
489
496
|
- **⚠️ Exclusión de código del análisis (EXPERIMENTAL/BROKEN)**: Los marcadores `// SKIP_ANALYSIS_LINE` y `// SKIP_ANALYSIS_BLOCK` no funcionan correctamente. El hook analiza git diff en lugar del archivo completo, por lo que marcadores agregados en commits anteriores no son detectados en cambios subsecuentes.
|
|
@@ -530,13 +537,13 @@ claude-hooks status
|
|
|
530
537
|
|
|
531
538
|
En `lib/hooks/pre-commit.js`:
|
|
532
539
|
|
|
533
|
-
- **`MAX_FILE_SIZE`**: Tamaño máximo de archivo a analizar (default:
|
|
534
|
-
- **`MAX_FILES`**: Número máximo de archivos por commit (default:
|
|
540
|
+
- **`MAX_FILE_SIZE`**: Tamaño máximo de archivo a analizar (default: 1MB)
|
|
541
|
+
- **`MAX_FILES`**: Número máximo de archivos por commit (default: 30)
|
|
535
542
|
- **`ALLOWED_EXTENSIONS`**: Extensiones permitidas (default: .java, .xml, .properties, .yml, .yaml)
|
|
536
543
|
|
|
537
544
|
En `lib/hooks/prepare-commit-msg.js`:
|
|
538
545
|
|
|
539
|
-
- **`MAX_FILE_SIZE`**: Tamaño máximo para incluir diff completo (default:
|
|
546
|
+
- **`MAX_FILE_SIZE`**: Tamaño máximo para incluir diff completo (default: 1MB)
|
|
540
547
|
|
|
541
548
|
### Pautas de Evaluación
|
|
542
549
|
|
|
@@ -610,34 +617,36 @@ claude-git-hooks/
|
|
|
610
617
|
|
|
611
618
|
#### Core Utilities
|
|
612
619
|
|
|
613
|
-
| Module
|
|
614
|
-
|
|
615
|
-
| **`config.js`**
|
|
616
|
-
| **`logger.js`**
|
|
617
|
-
| **`git-operations.js`**
|
|
618
|
-
| **`file-utils.js`**
|
|
619
|
-
| **`claude-client.js`**
|
|
620
|
-
| **`prompt-builder.js`**
|
|
621
|
-
| **`preset-loader.js`**
|
|
622
|
-
| **`resolution-prompt.js`**
|
|
623
|
-
| **`installation-diagnostics.js`** | Installation error diagnostics
|
|
624
|
-
| **`claude-diagnostics.js`**
|
|
620
|
+
| Module | Purpose | Key Exports | Usage Context |
|
|
621
|
+
| --------------------------------- | ------------------------------------- | ------------------------------------------------- | ---------------------------------------------- |
|
|
622
|
+
| **`config.js`** | Centralized configuration management | `getConfig()`, `defaults` | Priority merging: defaults < user < preset |
|
|
623
|
+
| **`logger.js`** | Structured logging with debug support | `info()`, `warning()`, `error()`, `debug()` | Console output with context tracking |
|
|
624
|
+
| **`git-operations.js`** | Git command abstractions | `getRepoRoot()`, `getStagedFiles()`, `getDiff()` | Safe git operations with error handling |
|
|
625
|
+
| **`file-utils.js`** | File system operations | `ensureDir()`, `writeFile()` | Repo-root-relative path handling |
|
|
626
|
+
| **`claude-client.js`** | Claude CLI integration | `analyzeCode()`, `analyzeCodeParallel()` | Prompt execution with timeout/retry |
|
|
627
|
+
| **`prompt-builder.js`** | Template-based prompts | `buildAnalysisPrompt()`, `loadTemplate()` | Dynamic prompt construction from .md files |
|
|
628
|
+
| **`preset-loader.js`** | Preset system | `loadPreset()`, `listPresets()`, `loadTemplate()` | Metadata, config, template loading |
|
|
629
|
+
| **`resolution-prompt.js`** | Issue resolution prompts | `generateResolutionPrompt()` | AI-friendly error remediation prompts |
|
|
630
|
+
| **`installation-diagnostics.js`** | Installation error diagnostics | `formatError()`, `getInstallationDiagnostics()` | Installation error formatting with remediation |
|
|
631
|
+
| **`claude-diagnostics.js`** | Claude CLI error diagnostics | `detectClaudeError()`, `formatClaudeError()` | Rate limit, auth, network error detection |
|
|
625
632
|
|
|
626
633
|
#### Using Utilities in Other Claude Instances
|
|
627
634
|
|
|
628
635
|
**Example: Check installation health**
|
|
636
|
+
|
|
629
637
|
```javascript
|
|
630
638
|
import { formatError } from './lib/utils/installation-diagnostics.js';
|
|
631
639
|
|
|
632
640
|
try {
|
|
633
|
-
|
|
641
|
+
// ... operation that may fail
|
|
634
642
|
} catch (error) {
|
|
635
|
-
|
|
636
|
-
|
|
643
|
+
console.error(formatError('Operation failed', ['Additional context line']));
|
|
644
|
+
process.exit(1);
|
|
637
645
|
}
|
|
638
646
|
```
|
|
639
647
|
|
|
640
648
|
**Example: Load configuration**
|
|
649
|
+
|
|
641
650
|
```javascript
|
|
642
651
|
import { getConfig } from './lib/config.js';
|
|
643
652
|
|
|
@@ -646,6 +655,7 @@ const maxFiles = config.analysis.maxFiles;
|
|
|
646
655
|
```
|
|
647
656
|
|
|
648
657
|
**Example: Execute git operations**
|
|
658
|
+
|
|
649
659
|
```javascript
|
|
650
660
|
import { getRepoRoot, getStagedFiles } from './lib/utils/git-operations.js';
|
|
651
661
|
|
|
@@ -654,13 +664,14 @@ const files = getStagedFiles({ extensions: ['.js', '.ts'] });
|
|
|
654
664
|
```
|
|
655
665
|
|
|
656
666
|
**Example: Build custom prompts**
|
|
667
|
+
|
|
657
668
|
```javascript
|
|
658
669
|
import { buildAnalysisPrompt } from './lib/utils/prompt-builder.js';
|
|
659
670
|
|
|
660
671
|
const prompt = await buildAnalysisPrompt({
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
672
|
+
templateName: 'CUSTOM_PROMPT.md',
|
|
673
|
+
files: filesData,
|
|
674
|
+
metadata: { REPO_NAME: 'my-repo' }
|
|
664
675
|
});
|
|
665
676
|
```
|
|
666
677
|
|
package/bin/claude-hooks
CHANGED
|
@@ -468,6 +468,7 @@ async function install(args) {
|
|
|
468
468
|
console.log(' 📝 Edit .claude/config.json to customize settings');
|
|
469
469
|
console.log(' 🎯 Use presets: backend, frontend, fullstack, database, ai, default');
|
|
470
470
|
console.log(' 🚀 Enable parallel analysis: set subagents.enabled = true');
|
|
471
|
+
console.log(' 🐛 Enable debug mode: claude-hooks --debug true');
|
|
471
472
|
console.log('\n📖 Example config.json:');
|
|
472
473
|
console.log(' {');
|
|
473
474
|
console.log(' "preset": "backend",');
|
|
@@ -508,14 +509,12 @@ async function checkAndInstallDependencies(sudoPassword = null, skipAuth = false
|
|
|
508
509
|
|
|
509
510
|
// v2.0.0+: Unix tools (sed, awk, grep, etc.) no longer needed (pure Node.js implementation)
|
|
510
511
|
|
|
511
|
-
// Check and install Claude CLI
|
|
512
|
-
await checkAndInstallClaude();
|
|
513
|
-
|
|
514
|
-
// Check Claude authentication (if not skipped)
|
|
512
|
+
// Check and install Claude CLI (skip if --skip-auth)
|
|
515
513
|
if (!skipAuth) {
|
|
514
|
+
await checkAndInstallClaude();
|
|
516
515
|
await checkClaudeAuth();
|
|
517
516
|
} else {
|
|
518
|
-
warning('Skipping Claude
|
|
517
|
+
warning('Skipping Claude CLI verification and authentication (--skip-auth)');
|
|
519
518
|
}
|
|
520
519
|
|
|
521
520
|
// Clear password from memory
|
|
@@ -529,9 +528,19 @@ function isWindows() {
|
|
|
529
528
|
}
|
|
530
529
|
|
|
531
530
|
// Get Claude command based on platform
|
|
532
|
-
// Why: On Windows,
|
|
531
|
+
// Why: On Windows, try native Claude first, then WSL as fallback
|
|
533
532
|
function getClaudeCommand() {
|
|
534
|
-
|
|
533
|
+
if (isWindows()) {
|
|
534
|
+
// Try native Windows Claude first
|
|
535
|
+
try {
|
|
536
|
+
execSync('claude --version', { stdio: 'ignore', timeout: 3000 });
|
|
537
|
+
return 'claude';
|
|
538
|
+
} catch (e) {
|
|
539
|
+
// Fallback to WSL
|
|
540
|
+
return 'wsl claude';
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return 'claude';
|
|
535
544
|
}
|
|
536
545
|
|
|
537
546
|
// Check if we need to install dependencies
|
|
@@ -1167,6 +1176,7 @@ Commands:
|
|
|
1167
1176
|
presets List all available presets
|
|
1168
1177
|
--set-preset <name> Set the active preset
|
|
1169
1178
|
preset current Show the current active preset
|
|
1179
|
+
--debug <value> Set debug mode (true, false, or status)
|
|
1170
1180
|
--version, -v Show the current version
|
|
1171
1181
|
help Show this help
|
|
1172
1182
|
|
|
@@ -1185,6 +1195,8 @@ Examples:
|
|
|
1185
1195
|
claude-hooks presets # List available presets
|
|
1186
1196
|
claude-hooks --set-preset backend # Set backend preset
|
|
1187
1197
|
claude-hooks preset current # Show current preset
|
|
1198
|
+
claude-hooks --debug true # Enable debug mode
|
|
1199
|
+
claude-hooks --debug status # Check debug status
|
|
1188
1200
|
|
|
1189
1201
|
Commit use cases:
|
|
1190
1202
|
git commit -m "message" # Manual message + blocking analysis
|
|
@@ -1236,6 +1248,12 @@ Parallel Analysis (v2.2.0+):
|
|
|
1236
1248
|
- batchSize: 4+ → Fewer API calls but slower
|
|
1237
1249
|
- Speed improvement: up to 4x faster with batchSize: 1
|
|
1238
1250
|
|
|
1251
|
+
Debug Mode:
|
|
1252
|
+
Enable detailed logging for troubleshooting:
|
|
1253
|
+
- CLI: claude-hooks --debug true
|
|
1254
|
+
- Config: "system": { "debug": true } in .claude/config.json
|
|
1255
|
+
- Check status: claude-hooks --debug status
|
|
1256
|
+
|
|
1239
1257
|
Customization:
|
|
1240
1258
|
Override prompts by copying to .claude/:
|
|
1241
1259
|
cp templates/COMMIT_MESSAGE.md .claude/
|
|
@@ -1247,6 +1265,68 @@ More information: https://github.com/pablorovito/claude-git-hooks
|
|
|
1247
1265
|
`);
|
|
1248
1266
|
}
|
|
1249
1267
|
|
|
1268
|
+
// Configuration Management Functions
|
|
1269
|
+
|
|
1270
|
+
/**
|
|
1271
|
+
* Updates a configuration value in .claude/config.json
|
|
1272
|
+
* Why: Centralized config update logic for all CLI commands
|
|
1273
|
+
*
|
|
1274
|
+
* @param {string} propertyPath - Dot notation path (e.g., 'preset', 'system.debug')
|
|
1275
|
+
* @param {any} value - Value to set
|
|
1276
|
+
* @param {Object} options - Optional settings
|
|
1277
|
+
* @param {Function} options.validator - Custom validation function, receives value, throws on invalid
|
|
1278
|
+
* @param {Function} options.successMessage - Function that receives value and returns success message
|
|
1279
|
+
*/
|
|
1280
|
+
async function updateConfig(propertyPath, value, options = {}) {
|
|
1281
|
+
const { validator, successMessage } = options;
|
|
1282
|
+
|
|
1283
|
+
try {
|
|
1284
|
+
// Validate value if validator provided
|
|
1285
|
+
if (validator) {
|
|
1286
|
+
await validator(value);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// Get repo root
|
|
1290
|
+
const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
|
|
1291
|
+
const configDir = path.join(repoRoot, '.claude');
|
|
1292
|
+
const configPath = path.join(configDir, 'config.json');
|
|
1293
|
+
|
|
1294
|
+
// Ensure .claude directory exists
|
|
1295
|
+
if (!fs.existsSync(configDir)) {
|
|
1296
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// Load existing config or create new
|
|
1300
|
+
let config = {};
|
|
1301
|
+
if (fs.existsSync(configPath)) {
|
|
1302
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// Set value at propertyPath (support dot notation like 'system.debug')
|
|
1306
|
+
const pathParts = propertyPath.split('.');
|
|
1307
|
+
let current = config;
|
|
1308
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
1309
|
+
const part = pathParts[i];
|
|
1310
|
+
if (!current[part] || typeof current[part] !== 'object') {
|
|
1311
|
+
current[part] = {};
|
|
1312
|
+
}
|
|
1313
|
+
current = current[part];
|
|
1314
|
+
}
|
|
1315
|
+
current[pathParts[pathParts.length - 1]] = value;
|
|
1316
|
+
|
|
1317
|
+
// Save config
|
|
1318
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1319
|
+
|
|
1320
|
+
// Show success message
|
|
1321
|
+
const message = successMessage ? await successMessage(value) : 'Configuration updated';
|
|
1322
|
+
success(message);
|
|
1323
|
+
info(`Configuration saved to ${configPath}`);
|
|
1324
|
+
} catch (err) {
|
|
1325
|
+
error(`Failed to update configuration: ${err.message}`);
|
|
1326
|
+
process.exit(1);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1250
1330
|
// Preset Management Functions
|
|
1251
1331
|
|
|
1252
1332
|
/**
|
|
@@ -1282,6 +1362,7 @@ async function showPresets() {
|
|
|
1282
1362
|
|
|
1283
1363
|
/**
|
|
1284
1364
|
* Sets the active preset
|
|
1365
|
+
* Why: Configures tech-stack specific analysis settings
|
|
1285
1366
|
*/
|
|
1286
1367
|
async function setPreset(presetName) {
|
|
1287
1368
|
if (!presetName) {
|
|
@@ -1289,45 +1370,24 @@ async function setPreset(presetName) {
|
|
|
1289
1370
|
return;
|
|
1290
1371
|
}
|
|
1291
1372
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
// Ensure .claude directory exists
|
|
1310
|
-
if (!fs.existsSync(configDir)) {
|
|
1311
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
|
-
// Load existing config or create new
|
|
1315
|
-
let config = {};
|
|
1316
|
-
if (fs.existsSync(configPath)) {
|
|
1317
|
-
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
1373
|
+
await updateConfig('preset', presetName, {
|
|
1374
|
+
validator: async (name) => {
|
|
1375
|
+
const presets = await listPresets();
|
|
1376
|
+
const preset = presets.find(p => p.name === name);
|
|
1377
|
+
if (!preset) {
|
|
1378
|
+
error(`Preset "${name}" not found`);
|
|
1379
|
+
info('Available presets:');
|
|
1380
|
+
presets.forEach(p => console.log(` - ${p.name}`));
|
|
1381
|
+
throw new Error(`Invalid preset: ${name}`);
|
|
1382
|
+
}
|
|
1383
|
+
return preset;
|
|
1384
|
+
},
|
|
1385
|
+
successMessage: async (name) => {
|
|
1386
|
+
const presets = await listPresets();
|
|
1387
|
+
const preset = presets.find(p => p.name === name);
|
|
1388
|
+
return `Preset '${preset.displayName}' activated`;
|
|
1318
1389
|
}
|
|
1319
|
-
|
|
1320
|
-
// Set preset
|
|
1321
|
-
config.preset = presetName;
|
|
1322
|
-
|
|
1323
|
-
// Save config
|
|
1324
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1325
|
-
|
|
1326
|
-
success(`Preset '${preset.displayName}' activated`);
|
|
1327
|
-
info(`Configuration saved to ${configPath}`);
|
|
1328
|
-
} catch (err) {
|
|
1329
|
-
error(`Failed to set preset: ${err.message}`);
|
|
1330
|
-
}
|
|
1390
|
+
});
|
|
1331
1391
|
}
|
|
1332
1392
|
|
|
1333
1393
|
/**
|
|
@@ -1354,6 +1414,45 @@ async function currentPreset() {
|
|
|
1354
1414
|
}
|
|
1355
1415
|
}
|
|
1356
1416
|
|
|
1417
|
+
/**
|
|
1418
|
+
* Sets debug mode
|
|
1419
|
+
* Why: Enables detailed logging for troubleshooting
|
|
1420
|
+
*/
|
|
1421
|
+
async function setDebug(value) {
|
|
1422
|
+
if (!value) {
|
|
1423
|
+
error('Please specify a value: claude-hooks --debug <true|false|status>');
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
const normalizedValue = value.toLowerCase();
|
|
1428
|
+
|
|
1429
|
+
// Handle status check
|
|
1430
|
+
if (normalizedValue === 'status') {
|
|
1431
|
+
try {
|
|
1432
|
+
const config = await getConfig();
|
|
1433
|
+
const isEnabled = config.system.debug || false;
|
|
1434
|
+
console.log('');
|
|
1435
|
+
info(`Debug mode: ${isEnabled ? colors.green + 'enabled' + colors.reset : colors.red + 'disabled' + colors.reset}`);
|
|
1436
|
+
console.log('');
|
|
1437
|
+
} catch (err) {
|
|
1438
|
+
error(`Failed to check debug status: ${err.message}`);
|
|
1439
|
+
}
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
// Validate and convert to boolean
|
|
1444
|
+
if (normalizedValue !== 'true' && normalizedValue !== 'false') {
|
|
1445
|
+
error('Invalid value. Use: true, false, or status');
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
const debugValue = normalizedValue === 'true';
|
|
1450
|
+
|
|
1451
|
+
await updateConfig('system.debug', debugValue, {
|
|
1452
|
+
successMessage: (val) => `Debug mode ${val ? 'enabled' : 'disabled'}`
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1357
1456
|
// Main
|
|
1358
1457
|
async function main() {
|
|
1359
1458
|
const args = process.argv.slice(2);
|
|
@@ -1395,6 +1494,9 @@ async function main() {
|
|
|
1395
1494
|
error(`Unknown preset subcommand: ${args[1]}`);
|
|
1396
1495
|
}
|
|
1397
1496
|
break;
|
|
1497
|
+
case '--debug':
|
|
1498
|
+
await setDebug(args[1]);
|
|
1499
|
+
break;
|
|
1398
1500
|
case '--version':
|
|
1399
1501
|
case '-v':
|
|
1400
1502
|
case 'version':
|
package/lib/config.js
CHANGED
|
@@ -26,9 +26,9 @@ const __dirname = path.dirname(__filename);
|
|
|
26
26
|
const defaults = {
|
|
27
27
|
// Analysis configuration
|
|
28
28
|
analysis: {
|
|
29
|
-
maxFileSize:
|
|
30
|
-
maxFiles:
|
|
31
|
-
timeout:
|
|
29
|
+
maxFileSize: 1000000, // 1MB - max file size to analyze
|
|
30
|
+
maxFiles: 20, // Max number of files per commit
|
|
31
|
+
timeout: 300000, // 3 minutes - Claude analysis timeout
|
|
32
32
|
contextLines: 3, // Git diff context lines
|
|
33
33
|
ignoreExtensions: [], // Extensions to exclude (e.g., ['.min.js', '.lock'])
|
|
34
34
|
// NOTE: allowedExtensions comes from preset/template, not here
|
|
@@ -37,14 +37,14 @@ const defaults = {
|
|
|
37
37
|
// Commit message generation
|
|
38
38
|
commitMessage: {
|
|
39
39
|
autoKeyword: 'auto', // Keyword to trigger auto-generation
|
|
40
|
-
timeout:
|
|
40
|
+
timeout: 300000,
|
|
41
41
|
},
|
|
42
42
|
|
|
43
43
|
// Subagent configuration (parallel analysis)
|
|
44
44
|
subagents: {
|
|
45
|
-
enabled:
|
|
45
|
+
enabled: false, // Enable parallel file analysis
|
|
46
46
|
model: 'haiku', // haiku (fast), sonnet (balanced), opus (thorough)
|
|
47
|
-
batchSize:
|
|
47
|
+
batchSize: 1, // Parallel subagents per batch
|
|
48
48
|
},
|
|
49
49
|
|
|
50
50
|
// Template paths
|
package/lib/hooks/pre-commit.js
CHANGED
|
@@ -181,12 +181,38 @@ const main = async () => {
|
|
|
181
181
|
// Load configuration
|
|
182
182
|
const config = await getConfig();
|
|
183
183
|
|
|
184
|
+
// Enable debug mode from config
|
|
185
|
+
if (config.system.debug) {
|
|
186
|
+
logger.setDebugMode(true);
|
|
187
|
+
}
|
|
188
|
+
|
|
184
189
|
// Display configuration info
|
|
185
190
|
const version = await getVersion();
|
|
186
191
|
console.log(`\n🤖 claude-git-hooks v${version}`);
|
|
187
192
|
|
|
188
193
|
logger.info('Starting code quality analysis...');
|
|
189
194
|
|
|
195
|
+
// DEBUG: Log working directories
|
|
196
|
+
const repoRoot = await import('../utils/git-operations.js').then(m => m.getRepoRoot());
|
|
197
|
+
const { getRepoRoot } = await import('../utils/git-operations.js');
|
|
198
|
+
|
|
199
|
+
// Normalize paths for comparison (handle Windows backslash vs forward slash)
|
|
200
|
+
const normalizePath = (p) => p.replace(/\\/g, '/').toLowerCase();
|
|
201
|
+
const cwdNormalized = normalizePath(process.cwd());
|
|
202
|
+
const repoRootNormalized = normalizePath(repoRoot);
|
|
203
|
+
|
|
204
|
+
logger.debug(
|
|
205
|
+
'pre-commit - main',
|
|
206
|
+
'Working directory info',
|
|
207
|
+
{
|
|
208
|
+
'process.cwd()': process.cwd(),
|
|
209
|
+
'repo root': repoRoot,
|
|
210
|
+
'cwd (normalized)': cwdNormalized,
|
|
211
|
+
'repo root (normalized)': repoRootNormalized,
|
|
212
|
+
'match': cwdNormalized === repoRootNormalized
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
|
|
190
216
|
logger.debug(
|
|
191
217
|
'pre-commit - main',
|
|
192
218
|
'Configuration',
|
|
@@ -237,6 +263,14 @@ const main = async () => {
|
|
|
237
263
|
});
|
|
238
264
|
|
|
239
265
|
const validFiles = filteredFiles.filter(f => f.valid);
|
|
266
|
+
const invalidFiles = filteredFiles.filter(f => !f.valid);
|
|
267
|
+
|
|
268
|
+
// Show user-facing warnings for rejected files
|
|
269
|
+
if (invalidFiles.length > 0) {
|
|
270
|
+
invalidFiles.forEach(file => {
|
|
271
|
+
logger.warning(`Skipping ${file.path}: ${file.reason}`);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
240
274
|
|
|
241
275
|
if (validFiles.length === 0) {
|
|
242
276
|
logger.warning('No valid files found to review');
|
|
@@ -120,6 +120,11 @@ const main = async () => {
|
|
|
120
120
|
// Load configuration (includes preset + user overrides)
|
|
121
121
|
const config = await getConfig();
|
|
122
122
|
|
|
123
|
+
// Enable debug mode from config
|
|
124
|
+
if (config.system.debug) {
|
|
125
|
+
logger.setDebugMode(true);
|
|
126
|
+
}
|
|
127
|
+
|
|
123
128
|
try {
|
|
124
129
|
// Get hook arguments
|
|
125
130
|
const args = process.argv.slice(2);
|