claude-git-hooks 2.6.3 → 2.7.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,66 @@ 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.7.1] - 2025-12-22
9
+
10
+ ### 🐛 Fixed
11
+
12
+ - **Improved reliability with automatic retry logic** - Fixed intermittent "Execution error" failures from Claude API
13
+ - **What was broken**: Claude CLI occasionally returned "Execution error" (15 chars) with exit code 0, causing commits to fail ~50% of the time
14
+ - **Root cause**: Claude API rate limiting or temporary backend issues returned error text instead of valid JSON, but was treated as success due to exit code 0
15
+ - **Fix**: Added detection for "Execution error" responses and automatic retry logic with 2-second delay
16
+ - **Files changed**:
17
+ - `lib/utils/claude-diagnostics.js:22-29,47-57,122-170,307-310` - Added EXECUTION_ERROR type detection and formatting
18
+ - `lib/utils/claude-client.js:24,246-270,620-679` - Check for error even with exit code 0, added retry logic
19
+ - **Impact**: Significantly improved reliability - transient API errors now automatically retry once, reducing failure rate
20
+ - **User experience**: Clear error messages explain the issue, automatic retry happens transparently with "⏳ Retrying..." message
21
+
22
+ ### 🎯 User Experience
23
+
24
+ - **Before**: Commits failed ~50% of the time with cryptic "No valid JSON found" error, requiring manual retries
25
+ - **After**: System automatically detects and retries recoverable errors, with helpful messages explaining what's happening
26
+ - **Error messages**: Now include specific guidance for "Execution error" (likely rate limiting, try haiku model, commit fewer files)
27
+
28
+ ## [2.7.0] - 2025-12-19
29
+
30
+ ### 🎨 Changed
31
+
32
+ - **Simplified code analysis output format** - Replaced fake SonarQube metrics with issue count summary (#47)
33
+ - **What changed**: Removed BLOCKER/CRITICAL/MAJOR/MINOR severity labels and A-E reliability/security/maintainability ratings
34
+ - **Why**: Metrics were Claude's opinion presented as facts, causing confusion and false sense of precision
35
+ - **New format**: Simple summary "X issue(s) found across Y file(s)" or "✅ No issues found!"
36
+ - **Files changed**:
37
+ - `lib/hooks/pre-commit.js:67-100` - Replaced metrics display with issue count summary
38
+ - `templates/CLAUDE_PRE_COMMIT_SONAR.md` → `templates/CLAUDE_PRE_COMMIT.md` (renamed)
39
+ - `templates/CLAUDE_ANALYSIS_PROMPT_SONAR.md` → `templates/CLAUDE_ANALYSIS_PROMPT.md` (renamed)
40
+ - `lib/config.js:58-59` - Updated template paths to remove SONAR suffix
41
+ - `bin/claude-hooks:387-407` - Installer now removes old SONAR template files
42
+ - **Impact**: Cleaner output focused on actual issues, not fake quality scores
43
+
44
+ - **Added false-positive prevention guidance** - Pre-commit hook now avoids reporting improvements as issues (#47)
45
+ - **What was broken**: Hook reported routine improvements (better formatting, added docs) as CODE_SMELL issues
46
+ - **Root cause**: Prompts lacked explicit guidance to distinguish problems from improvements
47
+ - **Fix**: Added clear instructions to only report actual bugs, security issues, or quality degradations
48
+ - **New guidance in templates**:
49
+ - "Only report actual problems, bugs, security issues, or code quality concerns"
50
+ - "Do NOT report improvements, positive changes, or routine maintenance as issues"
51
+ - "It is perfectly acceptable to find ZERO issues - this is a positive outcome"
52
+ - "When in doubt, err on the side of NOT reporting it"
53
+ - **Files changed**:
54
+ - `templates/CLAUDE_PRE_COMMIT.md` - Added false-positive prevention section at top
55
+ - `templates/CLAUDE_ANALYSIS_PROMPT.md` - Updated instructions before JSON schema
56
+ - **Compatibility**: Existing configurations continue to work, but users get fewer false positives
57
+
58
+ ### 🔧 Fixed
59
+
60
+ - **Pre-commit hook no longer reports improvements as issues** - Documentation additions and formatting improvements now correctly pass analysis (#47)
61
+
62
+ ### ⚠️ Breaking Changes (Minor)
63
+
64
+ - **Template file renames**: `CLAUDE_PRE_COMMIT_SONAR.md` → `CLAUDE_PRE_COMMIT.md`, `CLAUDE_ANALYSIS_PROMPT_SONAR.md` → `CLAUDE_ANALYSIS_PROMPT.md`
65
+ - **Migration**: Installer automatically removes old files and installs new ones on `claude-hooks install --force`
66
+ - **Impact**: Low - most users don't customize these files. Custom templates need manual rename.
67
+
8
68
  ## [2.6.3]
9
69
 
10
70
  ### 🐛 Fixed
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Pre-commit Hook con Claude CLI
2
2
 
3
- 🚀 **Transforma tu flujo de desarrollo con IA**: análisis de código instantáneo, mensajes de commit automáticos y generación de PRs perfectas. Claude revisa tu código antes de cada commit, detecta issues críticos al estilo SonarQube, y genera toda la documentación que necesitas. ¿Lo mejor? Se ejecuta localmente sin contaminar tu CI/CD.
3
+ 🚀 **Transforma tu flujo de desarrollo con IA**: análisis de código instantáneo, mensajes de commit automáticos y generación de PRs perfectas. Claude revisa tu código antes de cada commit, detecta issues críticos con análisis estructurado, y genera toda la documentación que necesitas. ¿Lo mejor? Se ejecuta localmente sin contaminar tu CI/CD.
4
+
5
+ ## ✨ Novedad v2.7.1 - Improved Reliability
6
+
7
+ **Nuevo v2.7.1**: Sistema de reintentos automáticos para errores transitorios de Claude API. Cuando Claude devuelve "Execution error" (típicamente por rate limiting), el sistema ahora reintenta automáticamente después de 2 segundos.
4
8
 
5
9
  ## ✨ Novedad v2.0.0 - Ahora Cross-Platform
6
10
 
@@ -22,6 +26,7 @@
22
26
  - 🚀 **Parallel Analysis**: Multiple Claude CLI processes analyzing file batches simultaneously (v2.2.0+)
23
27
  - 🔄 **Auto-actualización**: Se mantiene actualizado automáticamente
24
28
  - 🌍 **Cross-platform**: Windows, WSL, macOS, Linux sin configuración especial
29
+ - ♻️ **Reintentos automáticos**: Recuperación automática de errores transitorios de API (v2.7.1+)
25
30
 
26
31
  ## 📋 CHEATSHEET
27
32
 
@@ -207,8 +212,8 @@ Toda idea es bienvenida, aunque parezca espantosa. Si hay bugs, incluirlos tambi
207
212
  # Configuración vía .claude/config.json
208
213
  .claude/
209
214
  ├── config.json # Configuración principal (v2.2.0+)
210
- ├── CLAUDE_PRE_COMMIT_SONAR.md # Personalizar criterios (override)
211
- └── CLAUDE_ANALYSIS_PROMPT_SONAR.md # Modificar prompt (override)
215
+ ├── CLAUDE_PRE_COMMIT.md # Personalizar criterios (override)
216
+ └── CLAUDE_ANALYSIS_PROMPT.md # Modificar prompt (override)
212
217
 
213
218
  # Ejemplo de config.json (todas las opciones son opcionales)
214
219
  cat > .claude/config.json << 'EOF'
@@ -418,8 +423,8 @@ git commit -m "fix: resolver issues"
418
423
  **Archivos clave para modificar:**
419
424
 
420
425
  - `.claude/config.json` - Configuración principal (v2.2.0+)
421
- - `.claude/CLAUDE_PRE_COMMIT_SONAR.md` - Criterios (backend/frontend/data/db)
422
- - `.claude/CLAUDE_ANALYSIS_PROMPT_SONAR.md` - Template del prompt
426
+ - `.claude/CLAUDE_PRE_COMMIT.md` - Criterios (backend/frontend/data/db)
427
+ - `.claude/CLAUDE_ANALYSIS_PROMPT.md` - Template del prompt
423
428
 
424
429
  **Crear o modificar presets personalizados:**
425
430
 
@@ -434,7 +439,7 @@ cat templates/CUSTOMIZATION_GUIDE.md
434
439
  **Ejemplo:**
435
440
 
436
441
  ```bash
437
- vim .claude/CLAUDE_PRE_COMMIT_SONAR.md # Agregar reglas API REST/Spring Boot
442
+ vim .claude/CLAUDE_PRE_COMMIT.md # Agregar reglas API REST/Spring Boot
438
443
  ```
439
444
 
440
445
  ## 🔧 Configuración Previa Importante
@@ -501,8 +506,8 @@ El comando `claude-hooks install` crea los siguientes archivos y directorios:
501
506
  2. **`.git/hooks/prepare-commit-msg`** - Hook de generación de mensajes
502
507
  3. **`.git/hooks/check-version.sh`** - Script de verificación de versión
503
508
  4. **`.claude/`** - Directorio para archivos de configuración
504
- - `CLAUDE_PRE_COMMIT_SONAR.md` - Pautas de evaluación SonarQube
505
- - `CLAUDE_ANALYSIS_PROMPT_SONAR.md` - Template de prompt para análisis SonarQube
509
+ - `CLAUDE_PRE_COMMIT.md` - Criterios de evaluación de calidad
510
+ - `CLAUDE_ANALYSIS_PROMPT.md` - Template de prompt para análisis
506
511
  - `CLAUDE_RESOLUTION_PROMPT.md` - Template para prompt de resolución AI
507
512
 
508
513
  ### Actualización automática de .gitignore
@@ -621,11 +626,11 @@ En `lib/hooks/prepare-commit-msg.js`:
621
626
 
622
627
  ### Pautas de Evaluación
623
628
 
624
- - **`CLAUDE_PRE_COMMIT_SONAR.md`** - Criterios para modo SonarQube
629
+ - **`CLAUDE_PRE_COMMIT.md`** - Criterios de evaluación de calidad
625
630
 
626
631
  ### Templates de Prompts
627
632
 
628
- - **`CLAUDE_ANALYSIS_PROMPT_SONAR.md`** - Estructura del prompt SonarQube
633
+ - **`CLAUDE_ANALYSIS_PROMPT.md`** - Estructura del prompt de análisis
629
634
  - **`CLAUDE_RESOLUTION_PROMPT.md`** - Template para generar prompts de resolución
630
635
 
631
636
  Todos estos archivos son personalizables y específicos de tu proyecto. Puedes:
@@ -672,8 +677,8 @@ claude-git-hooks/
672
677
  │ ├── pre-commit # Bash wrapper (llama a lib/hooks/pre-commit.js)
673
678
  │ ├── prepare-commit-msg # Bash wrapper (llama a lib/hooks/prepare-commit-msg.js)
674
679
  │ ├── check-version.sh # Script de verificación de versión
675
- │ ├── CLAUDE_PRE_COMMIT_SONAR.md # Pautas SonarQube
676
- │ ├── CLAUDE_ANALYSIS_PROMPT_SONAR.md # Template de prompt para análisis
680
+ │ ├── CLAUDE_PRE_COMMIT.md # Criterios de evaluación
681
+ │ ├── CLAUDE_ANALYSIS_PROMPT.md # Template de prompt para análisis
677
682
  │ ├── CLAUDE_RESOLUTION_PROMPT.md # Template para resolución de issues
678
683
  │ ├── ANALYZE_DIFF.md # Template para análisis de diff (PR metadata)
679
684
  │ ├── CREATE_GITHUB_PR.md # Template para creación de PR
package/bin/claude-hooks CHANGED
@@ -384,6 +384,20 @@ async function install(args) {
384
384
  success('.claude directory created');
385
385
  }
386
386
 
387
+ // Remove old SONAR template files if they exist (migration from v2.6.x to v2.7.0+)
388
+ const oldSonarFiles = [
389
+ 'CLAUDE_PRE_COMMIT_SONAR.md',
390
+ 'CLAUDE_ANALYSIS_PROMPT_SONAR.md'
391
+ ];
392
+
393
+ oldSonarFiles.forEach(oldFile => {
394
+ const oldPath = path.join(claudeDir, oldFile);
395
+ if (fs.existsSync(oldPath)) {
396
+ fs.unlinkSync(oldPath);
397
+ info(`Removed old template: ${oldFile}`);
398
+ }
399
+ });
400
+
387
401
  // Copy ALL template files (.md and .json) to .claude directory
388
402
  const templateFiles = fs.readdirSync(templatesPath)
389
403
  .filter(file => {
@@ -1455,7 +1469,7 @@ function status() {
1455
1469
 
1456
1470
  // Check guidelines files
1457
1471
  console.log('\nGuidelines files:');
1458
- const guidelines = ['CLAUDE_PRE_COMMIT_SONAR.md'];
1472
+ const guidelines = ['CLAUDE_PRE_COMMIT.md'];
1459
1473
  guidelines.forEach(guideline => {
1460
1474
  const claudePath = path.join('.claude', guideline);
1461
1475
  if (fs.existsSync(claudePath)) {
@@ -1683,7 +1697,7 @@ Customization:
1683
1697
  Override prompts by copying to .claude/:
1684
1698
  cp templates/COMMIT_MESSAGE.md .claude/
1685
1699
  cp templates/ANALYZE_DIFF.md .claude/
1686
- cp templates/CLAUDE_PRE_COMMIT_SONAR.md .claude/
1700
+ cp templates/CLAUDE_PRE_COMMIT.md .claude/
1687
1701
  # Edit as needed - system uses .claude/ version if exists
1688
1702
 
1689
1703
  More information: https://github.com/pablorovito/claude-git-hooks
package/lib/config.js CHANGED
@@ -55,8 +55,8 @@ const defaults = {
55
55
  // Template paths
56
56
  templates: {
57
57
  baseDir: '.claude', // Base directory for all templates
58
- analysis: 'CLAUDE_ANALYSIS_PROMPT_SONAR.md', // Pre-commit analysis prompt
59
- guidelines: 'CLAUDE_PRE_COMMIT_SONAR.md', // Analysis guidelines
58
+ analysis: 'CLAUDE_ANALYSIS_PROMPT.md', // Pre-commit analysis prompt
59
+ guidelines: 'CLAUDE_PRE_COMMIT.md', // Analysis guidelines
60
60
  commitMessage: 'COMMIT_MESSAGE.md', // Commit message prompt
61
61
  analyzeDiff: 'ANALYZE_DIFF.md', // PR analysis prompt
62
62
  resolution: 'CLAUDE_RESOLUTION_PROMPT.md', // Issue resolution prompt
@@ -9,7 +9,7 @@
9
9
  * 2. Build analysis prompt with file diffs
10
10
  * 3. Send to Claude CLI for analysis
11
11
  * 4. Parse JSON response
12
- * 5. Display SonarQube-style results
12
+ * 5. Display structured analysis results
13
13
  * 6. Generate resolution prompt if issues found
14
14
  * 7. Block commit if quality gate fails
15
15
  *
@@ -52,8 +52,8 @@ import { getConfig } from '../config.js';
52
52
  */
53
53
 
54
54
  /**
55
- * Displays SonarQube-style analysis results
56
- * Why: Provides structured, visual feedback about code quality
55
+ * Displays structured analysis results
56
+ * Why: Provides clear, visual feedback about code quality
57
57
  *
58
58
  * @param {Object} result - Analysis result from Claude
59
59
  */
@@ -73,19 +73,16 @@ const displayResults = (result) => {
73
73
  }
74
74
  console.log();
75
75
 
76
- // Metrics
77
- if (result.metrics && typeof result.metrics === 'object') {
78
- console.log('📊 METRICS');
79
- console.log(`├─ Reliability: ${result.metrics.reliability || '?'}`);
80
- console.log(`├─ Security: ${result.metrics.security || '?'}`);
81
- console.log(`├─ Maintainability: ${result.metrics.maintainability || '?'}`);
82
- console.log(`├─ Coverage: ${result.metrics.coverage || '?'}%`);
83
- console.log(`├─ Duplications: ${result.metrics.duplications || '?'}%`);
84
- console.log(`└─ Complexity: ${result.metrics.complexity || '?'}`);
85
- console.log();
76
+ // Issues Summary - Simple count
77
+ if (Array.isArray(result.details) && result.details.length > 0) {
78
+ const fileCount = new Set(result.details.map(i => i.file)).size;
79
+ console.log(`📊 ${result.details.length} issue(s) found across ${fileCount} file(s)`);
80
+ } else {
81
+ console.log('✅ No issues found!');
86
82
  }
83
+ console.log();
87
84
 
88
- // Issues Summary
85
+ // Issues Breakdown (severity counts)
89
86
  if (result.issues && typeof result.issues === 'object') {
90
87
  console.log('📋 ISSUES SUMMARY');
91
88
 
@@ -21,7 +21,7 @@ import path from 'path';
21
21
  import os from 'os';
22
22
  import logger from './logger.js';
23
23
  import config from '../config.js';
24
- import { detectClaudeError, formatClaudeError, ClaudeErrorType } from './claude-diagnostics.js';
24
+ import { detectClaudeError, formatClaudeError, ClaudeErrorType, isRecoverableError } from './claude-diagnostics.js';
25
25
  import { which } from './which-command.js';
26
26
 
27
27
  /**
@@ -243,6 +243,33 @@ const executeClaude = (prompt, { timeout = 120000, allowedTools = [] } = {}) =>
243
243
  claude.on('close', (code) => {
244
244
  const duration = Date.now() - startTime;
245
245
 
246
+ // Check for "Execution error" even when exit code is 0
247
+ // Why: Claude CLI sometimes returns "Execution error" with exit code 0
248
+ // This occurs during API rate limiting or temporary backend issues
249
+ // IMPORTANT: Only check for EXACT match to avoid false positives
250
+ if (stdout.trim() === 'Execution error') {
251
+ const errorInfo = detectClaudeError(stdout, stderr, code);
252
+
253
+ logger.error(
254
+ 'claude-client - executeClaude',
255
+ `Claude CLI returned execution error (exit ${code})`,
256
+ new ClaudeClientError(`Claude CLI error: ${errorInfo.type}`, {
257
+ output: { stdout, stderr },
258
+ context: { exitCode: code, duration, errorType: errorInfo.type }
259
+ })
260
+ );
261
+
262
+ // Show formatted error to user
263
+ const formattedError = formatClaudeError(errorInfo);
264
+ console.error(`\n${ formattedError }\n`);
265
+
266
+ reject(new ClaudeClientError(`Claude CLI error: ${errorInfo.type}`, {
267
+ output: { stdout, stderr },
268
+ context: { exitCode: code, duration, errorInfo }
269
+ }));
270
+ return;
271
+ }
272
+
246
273
  if (code === 0) {
247
274
  logger.debug(
248
275
  'claude-client - executeClaude',
@@ -591,11 +618,16 @@ const saveDebugResponse = async (prompt, response, filename = config.output.debu
591
618
  * @returns {Promise<Object>} Parsed analysis result
592
619
  * @throws {ClaudeClientError} If analysis fails
593
620
  */
594
- const analyzeCode = async (prompt, { timeout = 120000, saveDebug = config.system.debug } = {}) => {
621
+ const analyzeCode = async (prompt, { timeout = 120000, saveDebug = config.system.debug, retryCount = 0 } = {}) => {
622
+ const maxRetries = 3; // Retry up to 3 times for recoverable errors
623
+ const baseRetryDelay = 2000; // Base delay: 2 seconds
624
+ // Exponential backoff: 2s, 4s, 8s
625
+ const retryDelay = baseRetryDelay * Math.pow(2, retryCount);
626
+
595
627
  logger.debug(
596
628
  'claude-client - analyzeCode',
597
629
  'Starting code analysis',
598
- { promptLength: prompt.length, timeout, saveDebug }
630
+ { promptLength: prompt.length, timeout, saveDebug, retryCount }
599
631
  );
600
632
 
601
633
  try {
@@ -623,6 +655,45 @@ const analyzeCode = async (prompt, { timeout = 120000, saveDebug = config.system
623
655
  return result;
624
656
 
625
657
  } catch (error) {
658
+ // Check if error is recoverable and we haven't exceeded retry limit
659
+ const hasContext = !!error.context;
660
+ const hasErrorInfo = !!error.context?.errorInfo;
661
+ const isRecoverable = hasErrorInfo ? isRecoverableError(error.context.errorInfo) : false;
662
+ const canRetry = retryCount < maxRetries;
663
+
664
+ logger.debug(
665
+ 'claude-client - analyzeCode',
666
+ 'Retry check',
667
+ {
668
+ retryCount,
669
+ maxRetries,
670
+ hasContext,
671
+ hasErrorInfo,
672
+ isRecoverable,
673
+ canRetry,
674
+ errorType: error.context?.errorInfo?.type,
675
+ errorName: error.name
676
+ }
677
+ );
678
+
679
+ const shouldRetry = canRetry && hasContext && hasErrorInfo && isRecoverable;
680
+
681
+ if (shouldRetry) {
682
+ logger.debug(
683
+ 'claude-client - analyzeCode',
684
+ `Recoverable error detected, retrying in ${retryDelay}ms (attempt ${retryCount + 1}/${maxRetries})`,
685
+ { errorType: error.context.errorInfo.type }
686
+ );
687
+
688
+ console.log(`\n⏳ Retrying in ${retryDelay / 1000} seconds due to ${error.context.errorInfo.type}...\n`);
689
+
690
+ // Wait before retry
691
+ await new Promise(resolve => setTimeout(resolve, retryDelay));
692
+
693
+ // Retry with incremented count
694
+ return analyzeCode(prompt, { timeout, saveDebug, retryCount: retryCount + 1 });
695
+ }
696
+
626
697
  logger.error('claude-client - analyzeCode', 'Code analysis failed', error);
627
698
  throw error;
628
699
  }
@@ -25,6 +25,7 @@ export const ClaudeErrorType = {
25
25
  TIMEOUT: 'TIMEOUT',
26
26
  NETWORK: 'NETWORK',
27
27
  INVALID_RESPONSE: 'INVALID_RESPONSE',
28
+ EXECUTION_ERROR: 'EXECUTION_ERROR',
28
29
  GENERIC: 'GENERIC'
29
30
  };
30
31
 
@@ -44,7 +45,20 @@ export const ClaudeErrorType = {
44
45
  * @returns {Object|null} Error information or null if no specific error detected
45
46
  */
46
47
  export const detectClaudeError = (stdout = '', stderr = '', exitCode = 1) => {
47
- // 1. Rate limit detection
48
+ // 1. Execution error detection (Claude CLI internal error)
49
+ // This occurs when Claude API returns an error instead of valid response
50
+ // Often caused by rate limiting, API errors, or temporary backend issues
51
+ // IMPORTANT: Only match EXACT "Execution error" response, not partial matches
52
+ const trimmedStdout = stdout.trim();
53
+ if (trimmedStdout === 'Execution error') {
54
+ return {
55
+ type: ClaudeErrorType.EXECUTION_ERROR,
56
+ exitCode,
57
+ stdout: stdout.substring(0, 100)
58
+ };
59
+ }
60
+
61
+ // 2. Rate limit detection
48
62
  const rateLimitMatch = stdout.match(/Claude AI usage limit reached\|(\d+)/);
49
63
  if (rateLimitMatch) {
50
64
  const resetTimestamp = parseInt(rateLimitMatch[1], 10);
@@ -61,7 +75,7 @@ export const detectClaudeError = (stdout = '', stderr = '', exitCode = 1) => {
61
75
  };
62
76
  }
63
77
 
64
- // 2. Authentication failure detection
78
+ // 3. Authentication failure detection
65
79
  if (stdout.includes('not authenticated') || stderr.includes('not authenticated') ||
66
80
  stdout.includes('authentication failed') || stderr.includes('authentication failed')) {
67
81
  return {
@@ -70,7 +84,7 @@ export const detectClaudeError = (stdout = '', stderr = '', exitCode = 1) => {
70
84
  };
71
85
  }
72
86
 
73
- // 3. Network errors
87
+ // 4. Network errors
74
88
  if (stderr.includes('ENOTFOUND') || stderr.includes('ECONNREFUSED') ||
75
89
  stderr.includes('network error') || stderr.includes('connection refused')) {
76
90
  return {
@@ -79,7 +93,7 @@ export const detectClaudeError = (stdout = '', stderr = '', exitCode = 1) => {
79
93
  };
80
94
  }
81
95
 
82
- // 4. Invalid response (JSON parsing errors)
96
+ // 5. Invalid response (JSON parsing errors)
83
97
  if (stdout.includes('SyntaxError') || stdout.includes('Unexpected token')) {
84
98
  return {
85
99
  type: ClaudeErrorType.INVALID_RESPONSE,
@@ -87,7 +101,7 @@ export const detectClaudeError = (stdout = '', stderr = '', exitCode = 1) => {
87
101
  };
88
102
  }
89
103
 
90
- // 5. Generic error
104
+ // 6. Generic error
91
105
  return {
92
106
  type: ClaudeErrorType.GENERIC,
93
107
  exitCode,
@@ -107,6 +121,9 @@ export const formatClaudeError = (errorInfo) => {
107
121
  const lines = [];
108
122
 
109
123
  switch (errorInfo.type) {
124
+ case ClaudeErrorType.EXECUTION_ERROR:
125
+ return formatExecutionError(errorInfo);
126
+
110
127
  case ClaudeErrorType.RATE_LIMIT:
111
128
  return formatRateLimitError(errorInfo);
112
129
 
@@ -125,6 +142,35 @@ export const formatClaudeError = (errorInfo) => {
125
142
  }
126
143
  };
127
144
 
145
+ /**
146
+ * Format execution error
147
+ */
148
+ const formatExecutionError = ({ exitCode, stdout }) => {
149
+ const lines = [];
150
+
151
+ lines.push('❌ Claude CLI execution error');
152
+ lines.push('');
153
+ lines.push('Claude returned "Execution error" instead of valid response.');
154
+ lines.push('');
155
+ lines.push('Common causes:');
156
+ lines.push(' 1. API rate limiting (burst limits)');
157
+ lines.push(' 2. Temporary Claude API backend issues');
158
+ lines.push(' 3. Request/response size limits exceeded');
159
+ lines.push('');
160
+ lines.push('Solutions:');
161
+ lines.push(' 1. Wait 10-30 seconds and try again');
162
+ lines.push(' 2. Reduce prompt size by committing fewer files at once');
163
+ lines.push(' 3. Switch to haiku model (faster, higher rate limits):');
164
+ lines.push(' Edit .claude/config.json:');
165
+ lines.push(' { "subagents": { "model": "haiku" } }');
166
+ lines.push(' 4. Skip analysis for now:');
167
+ lines.push(' git commit --no-verify -m "your message"');
168
+ lines.push('');
169
+ lines.push('The hook will automatically retry once after 2 seconds.');
170
+
171
+ return lines.join('\n');
172
+ };
173
+
128
174
  /**
129
175
  * Format rate limit error
130
176
  */
@@ -261,6 +307,7 @@ const formatGenericError = ({ exitCode, stdout, stderr }) => {
261
307
  * @returns {boolean} True if error might resolve with retry
262
308
  */
263
309
  export const isRecoverableError = (errorInfo) => {
264
- return errorInfo.type === ClaudeErrorType.RATE_LIMIT ||
310
+ return errorInfo.type === ClaudeErrorType.EXECUTION_ERROR ||
311
+ errorInfo.type === ClaudeErrorType.RATE_LIMIT ||
265
312
  errorInfo.type === ClaudeErrorType.NETWORK;
266
313
  };
@@ -215,8 +215,8 @@ const formatFileSection = ({ path, diff, content, isNew }) => {
215
215
  * }
216
216
  */
217
217
  const buildAnalysisPrompt = async ({
218
- templateName = 'CLAUDE_ANALYSIS_PROMPT_SONAR.md',
219
- guidelinesName = 'CLAUDE_PRE_COMMIT_SONAR.md',
218
+ templateName = 'CLAUDE_ANALYSIS_PROMPT.md',
219
+ guidelinesName = 'CLAUDE_PRE_COMMIT.md',
220
220
  files = [],
221
221
  metadata = {},
222
222
  subagentConfig = null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-git-hooks",
3
- "version": "2.6.3",
3
+ "version": "2.7.1",
4
4
  "description": "Git hooks with Claude CLI for code analysis and automatic commit messages",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,4 +1,4 @@
1
- ROLE:SeniorCodeReviewer,SonarQube-experienced
1
+ ROLE:SeniorCodeReviewer,CodeQualityExpert
2
2
  TASK:Analyze code->JSON only
3
3
  CRITICAL:NoTextOutsideJSON,ValidJSON
4
4
 
@@ -44,6 +44,7 @@ OUTPUT_SCHEMA:
44
44
  ```
45
45
 
46
46
  RULES:
47
+ - **FALSE_POSITIVE_PREVENTION**: Only report actual problems. Do not report improvements, positive changes, or routine maintenance as issues. Zero issues is a valid and positive outcome.
47
48
  - blockingIssues=ALWAYS_ARRAY_OF_OBJECTS(never_strings)
48
49
  - blockingIssues=ALL(details.severity∈{BLOCKER,CRITICAL})
49
50
  - Each_blockingIssue_MUST_have:description,file,line,method,severity
@@ -1,4 +1,13 @@
1
- # SONARQUBE_EVAL_CRITERIA
1
+ # CODE_QUALITY_EVALUATION_CRITERIA
2
+
3
+ ## FALSE_POSITIVE_PREVENTION
4
+
5
+ **IMPORTANT**: Only report actual problems, bugs, security issues, or code quality concerns.
6
+
7
+ - Do NOT report improvements, positive changes, or routine maintenance as issues
8
+ - It is perfectly acceptable to find ZERO issues - this is a positive outcome
9
+ - When in doubt about whether something is an issue, err on the side of NOT reporting it
10
+ - Focus on what could break, harm security, or degrade quality - not what could be "better"
2
11
 
3
12
  ## EXCEPTIONS_AND_ALLOWED_PATTERNS
4
13
  ### Spring Framework Patterns (NOT blocking issues)
@@ -149,7 +149,7 @@ A preset is a **self-contained package** that customizes claude-hooks for a spec
149
149
 
150
150
  ┌────────────────────────▼────────────────────────────────────┐
151
151
  │ 8. RESPONSE PROCESSED │
152
- │ - JSON format (SonarQube-style)
152
+ │ - JSON format with structured results
153
153
  │ - Quality gate: PASSED/FAILED │
154
154
  │ - Issues by severity: blocker, critical, major, minor │
155
155
  │ - Commit proceeds or blocked │
@@ -382,7 +382,7 @@ Perform a comprehensive code quality analysis focusing on these areas:
382
382
  **Template**:
383
383
 
384
384
  ````markdown
385
- # SonarQube-Style Evaluation Criteria
385
+ # Code Quality Evaluation Criteria
386
386
 
387
387
  ## Severity Levels
388
388
 
@@ -599,7 +599,7 @@ Please generate the following files:
599
599
  - This preset will be installed at: `templates/presets/{preset-name}/`
600
600
  - It should follow the same structure as existing presets in `templates/presets/backend/`
601
601
  - Users will select it with: `claude-hooks --set-preset {preset-name}`
602
- - The preset must output JSON in SonarQube format
602
+ - The preset must output JSON with structured analysis results
603
603
 
604
604
  **Format**: Return each file's content as a separate code block with clear file headers.
605
605
  ```
@@ -18,8 +18,8 @@
18
18
  },
19
19
  "templates": {
20
20
  "baseDir": ".claude",
21
- "analysis": "CLAUDE_ANALYSIS_PROMPT_SONAR.md",
22
- "guidelines": "CLAUDE_PRE_COMMIT_SONAR.md",
21
+ "analysis": "CLAUDE_ANALYSIS_PROMPT.md",
22
+ "guidelines": "CLAUDE_PRE_COMMIT.md",
23
23
  "commitMessage": "COMMIT_MESSAGE.md",
24
24
  "analyzeDiff": "ANALYZE_DIFF.md",
25
25
  "resolution": "CLAUDE_RESOLUTION_PROMPT.md",
@@ -83,7 +83,7 @@ Perform a comprehensive code quality analysis focusing on these areas:
83
83
 
84
84
  ## Output Format
85
85
 
86
- Respond with a valid JSON following the SonarQube format:
86
+ Respond with a valid JSON following the structured JSON format:
87
87
 
88
88
  ```json
89
89
  {
@@ -45,7 +45,7 @@ Perform a comprehensive code quality analysis focusing on these areas:
45
45
 
46
46
  ## Output Format
47
47
 
48
- Respond with a valid JSON following the SonarQube format:
48
+ Respond with a valid JSON following the structured JSON format:
49
49
 
50
50
  ```json
51
51
  {
@@ -64,7 +64,7 @@ Perform a comprehensive database code quality analysis focusing on these areas:
64
64
 
65
65
  ## Output Format
66
66
 
67
- Respond with a valid JSON following the SonarQube format:
67
+ Respond with a valid JSON following the structured JSON format:
68
68
 
69
69
  ```json
70
70
  {
@@ -56,7 +56,7 @@ Perform a comprehensive code quality analysis focusing on these areas:
56
56
 
57
57
  ## Output Format
58
58
 
59
- Respond with a valid JSON following the SonarQube format:
59
+ Respond with a valid JSON following the structured JSON format:
60
60
 
61
61
  ```json
62
62
  {
@@ -57,7 +57,7 @@ Check these consistency issues first:
57
57
 
58
58
  ## Output Format
59
59
 
60
- Respond with a valid JSON following the SonarQube format:
60
+ Respond with a valid JSON following the structured JSON format:
61
61
 
62
62
  ```json
63
63
  {
@@ -46,7 +46,7 @@ Evaluate the code changes across these dimensions:
46
46
 
47
47
  ## Output Format
48
48
 
49
- Respond with a valid JSON following the SonarQube format:
49
+ Respond with a valid JSON following the structured JSON format:
50
50
 
51
51
  ```json
52
52
  {