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 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": 150000,
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 | Tech Stack |
153
- | ------------- | -------------------------------------------------------------------------- | ---------------- | ---------------------------- |
154
- | **backend** | `.java`, `.xml`, `.yml`, `.yaml` | APIs Spring Boot | Spring Boot, JPA, SQL Server |
155
- | **frontend** | `.js`, `.jsx`, `.ts`, `.tsx`, `.css`, `.scss`, `.html` | Apps React | React, Redux, Material-UI |
156
- | **fullstack** | Todos backend + frontend | Apps full-stack | Spring Boot + React |
157
- | **database** | `.sql` | Scripts de BD | SQL Server, T-SQL |
158
- | **ai** | `.js`, `.json`, `.md`, `.sh` | Herramientas CLI | Node.js, Claude API |
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 > 100KB
265
- 6. **Límite de archivos**: Máximo 10 archivos por commit (configurable)
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 100KB
439
- - Límite de 10 archivos por commit
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 < 100KB
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**: `DEBUG=1 git commit` guarda respuestas en `debug-claude-response.json`
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: 100KB)
534
- - **`MAX_FILES`**: Número máximo de archivos por commit (default: 10)
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: 100KB)
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 | Purpose | Key Exports | Usage Context |
614
- |--------|---------|-------------|---------------|
615
- | **`config.js`** | Centralized configuration management | `getConfig()`, `defaults` | Priority merging: defaults < user < preset |
616
- | **`logger.js`** | Structured logging with debug support | `info()`, `warning()`, `error()`, `debug()` | Console output with context tracking |
617
- | **`git-operations.js`** | Git command abstractions | `getRepoRoot()`, `getStagedFiles()`, `getDiff()` | Safe git operations with error handling |
618
- | **`file-utils.js`** | File system operations | `ensureDir()`, `writeFile()` | Repo-root-relative path handling |
619
- | **`claude-client.js`** | Claude CLI integration | `analyzeCode()`, `analyzeCodeParallel()` | Prompt execution with timeout/retry |
620
- | **`prompt-builder.js`** | Template-based prompts | `buildAnalysisPrompt()`, `loadTemplate()` | Dynamic prompt construction from .md files |
621
- | **`preset-loader.js`** | Preset system | `loadPreset()`, `listPresets()`, `loadTemplate()` | Metadata, config, template loading |
622
- | **`resolution-prompt.js`** | Issue resolution prompts | `generateResolutionPrompt()` | AI-friendly error remediation prompts |
623
- | **`installation-diagnostics.js`** | Installation error diagnostics | `formatError()`, `getInstallationDiagnostics()` | Installation error formatting with remediation |
624
- | **`claude-diagnostics.js`** | Claude CLI error diagnostics | `detectClaudeError()`, `formatClaudeError()` | Rate limit, auth, network error detection |
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
- // ... operation that may fail
641
+ // ... operation that may fail
634
642
  } catch (error) {
635
- console.error(formatError('Operation failed', ['Additional context line']));
636
- process.exit(1);
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
- templateName: 'CUSTOM_PROMPT.md',
662
- files: filesData,
663
- metadata: { REPO_NAME: 'my-repo' }
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 authentication verification (--skip-auth)');
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, Claude CLI runs in WSL, so we need 'wsl claude'
531
+ // Why: On Windows, try native Claude first, then WSL as fallback
533
532
  function getClaudeCommand() {
534
- return isWindows() ? 'wsl claude' : 'claude';
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
- try {
1293
- // Verify preset exists
1294
- const presets = await listPresets();
1295
- const preset = presets.find(p => p.name === presetName);
1296
-
1297
- if (!preset) {
1298
- error(`Preset "${presetName}" not found`);
1299
- info('Available presets:');
1300
- presets.forEach(p => console.log(` - ${p.name}`));
1301
- process.exit(1);
1302
- }
1303
-
1304
- // Update .claude/config.json
1305
- const repoRoot = execSync('git rev-parse --show-toplevel', { encoding: 'utf8' }).trim();
1306
- const configDir = path.join(repoRoot, '.claude');
1307
- const configPath = path.join(configDir, 'config.json');
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: 100000, // 100KB - max file size to analyze
30
- maxFiles: 10, // Max number of files per commit
31
- timeout: 120000, // 2 minutes - Claude analysis 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: 180000,
40
+ timeout: 300000,
41
41
  },
42
42
 
43
43
  // Subagent configuration (parallel analysis)
44
44
  subagents: {
45
- enabled: true, // Enable parallel file analysis
45
+ enabled: false, // Enable parallel file analysis
46
46
  model: 'haiku', // haiku (fast), sonnet (balanced), opus (thorough)
47
- batchSize: 3, // Parallel subagents per batch
47
+ batchSize: 1, // Parallel subagents per batch
48
48
  },
49
49
 
50
50
  // Template paths
@@ -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);