claude-git-hooks 2.3.0 → 2.3.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 +62 -0
- package/README.md +82 -4
- package/lib/config.js +7 -6
- package/lib/hooks/pre-commit.js +2 -1
- package/lib/utils/claude-client.js +14 -5
- package/lib/utils/claude-diagnostics.js +266 -0
- package/lib/utils/installation-diagnostics.js +145 -0
- package/lib/utils/preset-loader.js +6 -1
- package/package.json +1 -1
- package/templates/CUSTOMIZATION_GUIDE.md +656 -0
- package/templates/pre-commit +40 -2
- package/templates/prepare-commit-msg +40 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,68 @@ 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.3.1] - 2025-11-13
|
|
9
|
+
|
|
10
|
+
### 🔄 Changed
|
|
11
|
+
|
|
12
|
+
- **Configuration Priority** - Updated merge order: `defaults < user config < preset config`
|
|
13
|
+
- **Rationale**: User sets general preferences in `.claude/config.json`, preset provides tech-stack-specific overrides (highest priority)
|
|
14
|
+
- **Effect**: Presets now correctly override user settings (e.g., preset's `model: sonnet` wins over user's `model: haiku`)
|
|
15
|
+
- **Files updated**: `lib/config.js:116` (merge logic), README.md:222 (documentation)
|
|
16
|
+
|
|
17
|
+
### ✨ Added
|
|
18
|
+
|
|
19
|
+
- **Installation Diagnostics Utility** - New `lib/utils/installation-diagnostics.js`
|
|
20
|
+
- **Purpose**: Reusable error diagnostics with actionable remediation steps
|
|
21
|
+
- **Exports**: `formatError()`, `getInstallationDiagnostics()`, `isInstallationHealthy()`
|
|
22
|
+
- **Use case**: Detects installation in wrong directory (common cause of "presets not found" errors)
|
|
23
|
+
- **Extensible**: Documented future enhancements (file permissions, Claude CLI check, etc.)
|
|
24
|
+
|
|
25
|
+
- **Enhanced Error Messages** - Better guidance when installation fails
|
|
26
|
+
- **Presets not found** (`lib/utils/preset-loader.js:194`): Shows current vs repo root directory
|
|
27
|
+
- **Hook scripts missing** (`templates/pre-commit:76`, `templates/prepare-commit-msg:76`): Early `.claude/` check with remediation steps
|
|
28
|
+
- **npm package issues**: Suggests verifying `npm list -g claude-git-hooks`
|
|
29
|
+
|
|
30
|
+
- **Bash Wrapper Early Validation** - Hooks now check `.claude/` exists before attempting execution
|
|
31
|
+
- **Why**: Fails fast with helpful message if installation incomplete or performed from wrong directory
|
|
32
|
+
- **Effect**: Users immediately know to `cd` to repo root and reinstall
|
|
33
|
+
|
|
34
|
+
- **Claude Error Diagnostics** - New `lib/utils/claude-diagnostics.js`
|
|
35
|
+
- **Purpose**: Detects and formats Claude CLI errors with actionable solutions
|
|
36
|
+
- **Error types**: Rate limit, authentication, network, invalid response, generic
|
|
37
|
+
- **Exports**: `detectClaudeError()`, `formatClaudeError()`, `ClaudeErrorType`, `isRecoverableError()`
|
|
38
|
+
- **Integration**: `lib/utils/claude-client.js:147` automatically detects and formats errors
|
|
39
|
+
- **Effect**: Users see clear guidance (e.g., "Rate limit resets in 2 hours, switch to haiku model")
|
|
40
|
+
|
|
41
|
+
### 📚 Documentation
|
|
42
|
+
|
|
43
|
+
- **CUSTOMIZATION_GUIDE.md** - Comprehensive preset creation guide in `/templates`
|
|
44
|
+
- Visual flowchart showing prompt assembly (8-step diagram)
|
|
45
|
+
- Step-by-step preset creation tutorial
|
|
46
|
+
- Placeholder system reference with examples
|
|
47
|
+
- Preset kickstart prompt for Claude-assisted generation
|
|
48
|
+
- **Burst limit warning**: Explains why git hooks hit rate limits when manual CLI doesn't
|
|
49
|
+
- Referenced in README.md:333 for discoverability
|
|
50
|
+
|
|
51
|
+
- **Utility Modules Reference** - New section in README.md:596
|
|
52
|
+
- Table of all `lib/utils/` modules with purpose and key exports
|
|
53
|
+
- Usage examples for other Claude instances
|
|
54
|
+
- Promotes code reuse across projects
|
|
55
|
+
|
|
56
|
+
- **README-NPM.md** - Complete rewrite for npm package page
|
|
57
|
+
- **Length**: 266 lines (up from 145 lines, but more focused)
|
|
58
|
+
- **Updated**: v2.3.0 presets, v2.2.0 config centralization, v2.0.0 cross-platform
|
|
59
|
+
- **Added**: Configuration priority explanation, troubleshooting, "What's New" section
|
|
60
|
+
- **Removed**: Outdated v1.x references, environment variable examples
|
|
61
|
+
|
|
62
|
+
### 🎯 User Experience
|
|
63
|
+
|
|
64
|
+
- **Clearer error context**: Errors now show current directory vs repository root
|
|
65
|
+
- **Actionable solutions**: Every error includes specific commands to fix the issue
|
|
66
|
+
- **Installation verification**: Early checks prevent confusing downstream errors
|
|
67
|
+
- **Better documentation**: Users can find utility functions and customization guides easily
|
|
68
|
+
- **Claude error clarity**: Rate limits, auth failures, and network errors now show specific remediation steps
|
|
69
|
+
|
|
8
70
|
## [2.3.0] - 2025-11-11
|
|
9
71
|
|
|
10
72
|
### ✨ Added
|
package/README.md
CHANGED
|
@@ -224,11 +224,13 @@ EOF
|
|
|
224
224
|
```
|
|
225
225
|
defaults (lib/config.js)
|
|
226
226
|
↓
|
|
227
|
-
|
|
227
|
+
user config (.claude/config.json) ← General preferences
|
|
228
228
|
↓
|
|
229
|
-
|
|
229
|
+
preset config (.claude/presets/{name}/config.json) ← MÁXIMA PRIORIDAD (tech-stack specific)
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
+
**Rationale**: User sets general preferences, preset provides tech-stack-specific overrides.
|
|
233
|
+
|
|
232
234
|
**Nota v2.2.0+:** Variables de entorno ya NO son soportadas. Usar `.claude/config.json` en su lugar.
|
|
233
235
|
|
|
234
236
|
### 🎯 Casos de Uso Específicos
|
|
@@ -324,6 +326,16 @@ git commit -m "fix: resolver issues"
|
|
|
324
326
|
- `.claude/CLAUDE_PRE_COMMIT_SONAR.md` - Criterios (backend/frontend/data/db)
|
|
325
327
|
- `.claude/CLAUDE_ANALYSIS_PROMPT_SONAR.md` - Template del prompt
|
|
326
328
|
|
|
329
|
+
**Crear o modificar presets personalizados:**
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
# Ver guía completa de customización
|
|
333
|
+
cat templates/CUSTOMIZATION_GUIDE.md
|
|
334
|
+
|
|
335
|
+
# O en GitHub
|
|
336
|
+
# https://github.com/pablorovito/claude-git-hooks/blob/main/templates/CUSTOMIZATION_GUIDE.md
|
|
337
|
+
```
|
|
338
|
+
|
|
327
339
|
**Ejemplo:**
|
|
328
340
|
|
|
329
341
|
```bash
|
|
@@ -556,16 +568,20 @@ claude-git-hooks/
|
|
|
556
568
|
├── bin/
|
|
557
569
|
│ └── claude-hooks # CLI principal (ES6 modules)
|
|
558
570
|
├── lib/ # 🆕 Código Node.js modular
|
|
571
|
+
│ ├── config.js # Configuración centralizada con merge
|
|
559
572
|
│ ├── hooks/
|
|
560
573
|
│ │ ├── pre-commit.js # Hook de análisis (Node.js)
|
|
561
574
|
│ │ └── prepare-commit-msg.js # Hook de mensajes (Node.js)
|
|
562
575
|
│ └── utils/
|
|
563
576
|
│ ├── logger.js # Sistema de logging centralizado
|
|
564
577
|
│ ├── git-operations.js # Operaciones git abstractas
|
|
565
|
-
│ ├── file-
|
|
578
|
+
│ ├── file-utils.js # Utilidades de sistema de archivos
|
|
566
579
|
│ ├── claude-client.js # Cliente Claude CLI
|
|
567
580
|
│ ├── prompt-builder.js # Constructor de prompts
|
|
568
|
-
│
|
|
581
|
+
│ ├── resolution-prompt.js # Generador de resolution prompts
|
|
582
|
+
│ ├── preset-loader.js # Cargador de presets
|
|
583
|
+
│ ├── installation-diagnostics.js # Diagnósticos de instalación
|
|
584
|
+
│ └── claude-diagnostics.js # Diagnósticos de errores Claude CLI
|
|
569
585
|
├── templates/
|
|
570
586
|
│ ├── pre-commit # Bash wrapper (llama a lib/hooks/pre-commit.js)
|
|
571
587
|
│ ├── prepare-commit-msg # Bash wrapper (llama a lib/hooks/prepare-commit-msg.js)
|
|
@@ -588,6 +604,68 @@ claude-git-hooks/
|
|
|
588
604
|
└── .gitignore # Archivos ignorados por git
|
|
589
605
|
```
|
|
590
606
|
|
|
607
|
+
### 🔌 Utility Modules Reference
|
|
608
|
+
|
|
609
|
+
**Purpose**: Reusable modules for extending claude-hooks or building similar tools
|
|
610
|
+
|
|
611
|
+
#### Core Utilities
|
|
612
|
+
|
|
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 |
|
|
625
|
+
|
|
626
|
+
#### Using Utilities in Other Claude Instances
|
|
627
|
+
|
|
628
|
+
**Example: Check installation health**
|
|
629
|
+
```javascript
|
|
630
|
+
import { formatError } from './lib/utils/installation-diagnostics.js';
|
|
631
|
+
|
|
632
|
+
try {
|
|
633
|
+
// ... operation that may fail
|
|
634
|
+
} catch (error) {
|
|
635
|
+
console.error(formatError('Operation failed', ['Additional context line']));
|
|
636
|
+
process.exit(1);
|
|
637
|
+
}
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
**Example: Load configuration**
|
|
641
|
+
```javascript
|
|
642
|
+
import { getConfig } from './lib/config.js';
|
|
643
|
+
|
|
644
|
+
const config = await getConfig();
|
|
645
|
+
const maxFiles = config.analysis.maxFiles;
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**Example: Execute git operations**
|
|
649
|
+
```javascript
|
|
650
|
+
import { getRepoRoot, getStagedFiles } from './lib/utils/git-operations.js';
|
|
651
|
+
|
|
652
|
+
const repoRoot = getRepoRoot();
|
|
653
|
+
const files = getStagedFiles({ extensions: ['.js', '.ts'] });
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
**Example: Build custom prompts**
|
|
657
|
+
```javascript
|
|
658
|
+
import { buildAnalysisPrompt } from './lib/utils/prompt-builder.js';
|
|
659
|
+
|
|
660
|
+
const prompt = await buildAnalysisPrompt({
|
|
661
|
+
templateName: 'CUSTOM_PROMPT.md',
|
|
662
|
+
files: filesData,
|
|
663
|
+
metadata: { REPO_NAME: 'my-repo' }
|
|
664
|
+
});
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
**Note**: All utilities follow single-responsibility principle and include JSDoc documentation inline.
|
|
668
|
+
|
|
591
669
|
### Configuración del Entorno de Desarrollo
|
|
592
670
|
|
|
593
671
|
```bash
|
package/lib/config.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
* File: config.js
|
|
3
3
|
* Purpose: Centralized configuration management
|
|
4
4
|
*
|
|
5
|
-
* Priority: .claude/config.json > defaults
|
|
5
|
+
* Priority: preset config > .claude/config.json > defaults
|
|
6
6
|
*
|
|
7
7
|
* Key features:
|
|
8
8
|
* - Single source of truth for all configurable values
|
|
9
9
|
* - No environment variables (except OS for platform detection)
|
|
10
10
|
* - Preset-aware (allowedExtensions come from preset templates)
|
|
11
|
-
* -
|
|
11
|
+
* - User config (.claude/config.json) provides general preferences per project
|
|
12
|
+
* - Preset config provides tech-stack-specific overrides (highest priority)
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
import fs from 'fs';
|
|
@@ -79,9 +80,9 @@ const defaults = {
|
|
|
79
80
|
|
|
80
81
|
/**
|
|
81
82
|
* Loads user configuration from .claude/config.json
|
|
82
|
-
* Merges with defaults and preset config (preset
|
|
83
|
+
* Merges with defaults and preset config (preset takes highest priority)
|
|
83
84
|
*
|
|
84
|
-
* Priority: defaults <
|
|
85
|
+
* Priority: defaults < user config < preset config
|
|
85
86
|
*
|
|
86
87
|
* @param {string} baseDir - Base directory to search for config (default: cwd)
|
|
87
88
|
* @returns {Promise<Object>} Merged configuration
|
|
@@ -112,8 +113,8 @@ const loadUserConfig = async (baseDir = process.cwd()) => {
|
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
// Merge: defaults <
|
|
116
|
-
return deepMerge(deepMerge(defaults,
|
|
116
|
+
// Merge: defaults < user < preset
|
|
117
|
+
return deepMerge(deepMerge(defaults, userConfig), presetConfig);
|
|
117
118
|
};
|
|
118
119
|
|
|
119
120
|
/**
|
package/lib/hooks/pre-commit.js
CHANGED
|
@@ -312,7 +312,8 @@ const main = async () => {
|
|
|
312
312
|
|
|
313
313
|
// Step 5: Analyze with Claude (parallel or single)
|
|
314
314
|
let result;
|
|
315
|
-
|
|
315
|
+
// TODO: This can be refactored so no conditional is needed.
|
|
316
|
+
// Lists can have 0...N items, e.g. iterating a list of 1 element is akin to single execution.
|
|
316
317
|
if (subagentsEnabled && filesData.length >= 3) {
|
|
317
318
|
// Parallel execution: split files into batches
|
|
318
319
|
logger.info(`Using parallel execution with batch size ${batchSize}`);
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* - child_process: For executing Claude CLI
|
|
13
13
|
* - fs/promises: For debug file writing
|
|
14
14
|
* - logger: Debug and error logging
|
|
15
|
+
* - claude-diagnostics: Error detection and formatting
|
|
15
16
|
*/
|
|
16
17
|
|
|
17
18
|
import { spawn, execSync } from 'child_process';
|
|
@@ -20,6 +21,7 @@ import path from 'path';
|
|
|
20
21
|
import os from 'os';
|
|
21
22
|
import logger from './logger.js';
|
|
22
23
|
import config from '../config.js';
|
|
24
|
+
import { detectClaudeError, formatClaudeError, ClaudeErrorType } from './claude-diagnostics.js';
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
* Custom error for Claude client failures
|
|
@@ -141,18 +143,25 @@ const executeClaude = (prompt, { timeout = 120000 } = {}) => {
|
|
|
141
143
|
);
|
|
142
144
|
resolve(stdout);
|
|
143
145
|
} else {
|
|
146
|
+
// Detect specific error type
|
|
147
|
+
const errorInfo = detectClaudeError(stdout, stderr, code);
|
|
148
|
+
|
|
144
149
|
logger.error(
|
|
145
150
|
'claude-client - executeClaude',
|
|
146
|
-
`Claude CLI failed
|
|
147
|
-
new ClaudeClientError(
|
|
151
|
+
`Claude CLI failed: ${errorInfo.type}`,
|
|
152
|
+
new ClaudeClientError(`Claude CLI error: ${errorInfo.type}`, {
|
|
148
153
|
output: { stdout, stderr },
|
|
149
|
-
context: { exitCode: code, duration }
|
|
154
|
+
context: { exitCode: code, duration, errorType: errorInfo.type }
|
|
150
155
|
})
|
|
151
156
|
);
|
|
152
157
|
|
|
153
|
-
|
|
158
|
+
// Show formatted error to user
|
|
159
|
+
const formattedError = formatClaudeError(errorInfo);
|
|
160
|
+
console.error('\n' + formattedError + '\n');
|
|
161
|
+
|
|
162
|
+
reject(new ClaudeClientError(`Claude CLI error: ${errorInfo.type}`, {
|
|
154
163
|
output: { stdout, stderr },
|
|
155
|
-
context: { exitCode: code, duration }
|
|
164
|
+
context: { exitCode: code, duration, errorInfo }
|
|
156
165
|
}));
|
|
157
166
|
}
|
|
158
167
|
});
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: claude-diagnostics.js
|
|
3
|
+
* Purpose: Reusable Claude CLI error diagnostics and formatting
|
|
4
|
+
*
|
|
5
|
+
* Key features:
|
|
6
|
+
* - Detects common Claude CLI error patterns
|
|
7
|
+
* - Provides actionable remediation steps
|
|
8
|
+
* - Extensible for future error types
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* import { detectClaudeError, formatClaudeError } from './claude-diagnostics.js';
|
|
12
|
+
*
|
|
13
|
+
* const errorInfo = detectClaudeError(stdout, stderr, exitCode);
|
|
14
|
+
* if (errorInfo) {
|
|
15
|
+
* console.error(formatClaudeError(errorInfo));
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Error types that can be detected
|
|
21
|
+
*/
|
|
22
|
+
export const ClaudeErrorType = {
|
|
23
|
+
RATE_LIMIT: 'RATE_LIMIT',
|
|
24
|
+
AUTH_FAILED: 'AUTH_FAILED',
|
|
25
|
+
TIMEOUT: 'TIMEOUT',
|
|
26
|
+
NETWORK: 'NETWORK',
|
|
27
|
+
INVALID_RESPONSE: 'INVALID_RESPONSE',
|
|
28
|
+
GENERIC: 'GENERIC'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Detects Claude CLI error type and extracts relevant information
|
|
33
|
+
* Why: Centralized error detection for consistent handling
|
|
34
|
+
*
|
|
35
|
+
* Future enhancements:
|
|
36
|
+
* - Network connectivity errors
|
|
37
|
+
* - Authentication expiration
|
|
38
|
+
* - Model availability errors
|
|
39
|
+
* - Token limit exceeded errors
|
|
40
|
+
*
|
|
41
|
+
* @param {string} stdout - Claude CLI stdout
|
|
42
|
+
* @param {string} stderr - Claude CLI stderr
|
|
43
|
+
* @param {number} exitCode - Process exit code
|
|
44
|
+
* @returns {Object|null} Error information or null if no specific error detected
|
|
45
|
+
*/
|
|
46
|
+
export const detectClaudeError = (stdout = '', stderr = '', exitCode = 1) => {
|
|
47
|
+
// 1. Rate limit detection
|
|
48
|
+
const rateLimitMatch = stdout.match(/Claude AI usage limit reached\|(\d+)/);
|
|
49
|
+
if (rateLimitMatch) {
|
|
50
|
+
const resetTimestamp = parseInt(rateLimitMatch[1], 10);
|
|
51
|
+
const resetDate = new Date(resetTimestamp * 1000);
|
|
52
|
+
const now = new Date();
|
|
53
|
+
const minutesUntilReset = Math.ceil((resetDate - now) / 60000);
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
type: ClaudeErrorType.RATE_LIMIT,
|
|
57
|
+
exitCode,
|
|
58
|
+
resetTimestamp,
|
|
59
|
+
resetDate,
|
|
60
|
+
minutesUntilReset
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 2. Authentication failure detection
|
|
65
|
+
if (stdout.includes('not authenticated') || stderr.includes('not authenticated') ||
|
|
66
|
+
stdout.includes('authentication failed') || stderr.includes('authentication failed')) {
|
|
67
|
+
return {
|
|
68
|
+
type: ClaudeErrorType.AUTH_FAILED,
|
|
69
|
+
exitCode
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 3. Network errors
|
|
74
|
+
if (stderr.includes('ENOTFOUND') || stderr.includes('ECONNREFUSED') ||
|
|
75
|
+
stderr.includes('network error') || stderr.includes('connection refused')) {
|
|
76
|
+
return {
|
|
77
|
+
type: ClaudeErrorType.NETWORK,
|
|
78
|
+
exitCode
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 4. Invalid response (JSON parsing errors)
|
|
83
|
+
if (stdout.includes('SyntaxError') || stdout.includes('Unexpected token')) {
|
|
84
|
+
return {
|
|
85
|
+
type: ClaudeErrorType.INVALID_RESPONSE,
|
|
86
|
+
exitCode
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 5. Generic error
|
|
91
|
+
return {
|
|
92
|
+
type: ClaudeErrorType.GENERIC,
|
|
93
|
+
exitCode,
|
|
94
|
+
stdout: stdout.substring(0, 200), // First 200 chars
|
|
95
|
+
stderr: stderr.substring(0, 200)
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Formats Claude error message with diagnostics and remediation steps
|
|
101
|
+
* Why: Provides consistent, actionable error messages
|
|
102
|
+
*
|
|
103
|
+
* @param {Object} errorInfo - Output from detectClaudeError()
|
|
104
|
+
* @returns {string} Formatted error message
|
|
105
|
+
*/
|
|
106
|
+
export const formatClaudeError = (errorInfo) => {
|
|
107
|
+
const lines = [];
|
|
108
|
+
|
|
109
|
+
switch (errorInfo.type) {
|
|
110
|
+
case ClaudeErrorType.RATE_LIMIT:
|
|
111
|
+
return formatRateLimitError(errorInfo);
|
|
112
|
+
|
|
113
|
+
case ClaudeErrorType.AUTH_FAILED:
|
|
114
|
+
return formatAuthError(errorInfo);
|
|
115
|
+
|
|
116
|
+
case ClaudeErrorType.NETWORK:
|
|
117
|
+
return formatNetworkError(errorInfo);
|
|
118
|
+
|
|
119
|
+
case ClaudeErrorType.INVALID_RESPONSE:
|
|
120
|
+
return formatInvalidResponseError(errorInfo);
|
|
121
|
+
|
|
122
|
+
case ClaudeErrorType.GENERIC:
|
|
123
|
+
default:
|
|
124
|
+
return formatGenericError(errorInfo);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Format rate limit error
|
|
130
|
+
*/
|
|
131
|
+
const formatRateLimitError = ({ resetDate, minutesUntilReset }) => {
|
|
132
|
+
const lines = [];
|
|
133
|
+
|
|
134
|
+
lines.push('❌ Claude API usage limit reached');
|
|
135
|
+
lines.push('');
|
|
136
|
+
lines.push('Rate limit details:');
|
|
137
|
+
lines.push(` Reset time: ${resetDate.toLocaleString()}`);
|
|
138
|
+
|
|
139
|
+
if (minutesUntilReset > 60) {
|
|
140
|
+
const hours = Math.ceil(minutesUntilReset / 60);
|
|
141
|
+
lines.push(` Time until reset: ~${hours} hour${hours > 1 ? 's' : ''}`);
|
|
142
|
+
} else if (minutesUntilReset > 0) {
|
|
143
|
+
lines.push(` Time until reset: ~${minutesUntilReset} minute${minutesUntilReset !== 1 ? 's' : ''}`);
|
|
144
|
+
} else {
|
|
145
|
+
lines.push(' Limit should be reset now');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
lines.push('');
|
|
149
|
+
lines.push('Options:');
|
|
150
|
+
lines.push(' 1. Wait for rate limit to reset');
|
|
151
|
+
lines.push(' 2. Skip analysis for now:');
|
|
152
|
+
lines.push(' git commit --no-verify -m "your message"');
|
|
153
|
+
lines.push(' 3. Reduce API usage by switching to haiku model:');
|
|
154
|
+
lines.push(' Edit .claude/config.json:');
|
|
155
|
+
lines.push(' { "subagents": { "model": "haiku" } }');
|
|
156
|
+
|
|
157
|
+
return lines.join('\n');
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Format authentication error
|
|
162
|
+
*/
|
|
163
|
+
const formatAuthError = ({ exitCode }) => {
|
|
164
|
+
const lines = [];
|
|
165
|
+
|
|
166
|
+
lines.push('❌ Claude CLI authentication failed');
|
|
167
|
+
lines.push('');
|
|
168
|
+
lines.push('Possible causes:');
|
|
169
|
+
lines.push(' 1. Not logged in to Claude CLI');
|
|
170
|
+
lines.push(' 2. Authentication token expired');
|
|
171
|
+
lines.push(' 3. Invalid API credentials');
|
|
172
|
+
lines.push('');
|
|
173
|
+
lines.push('Solution:');
|
|
174
|
+
lines.push(' claude auth login');
|
|
175
|
+
lines.push('');
|
|
176
|
+
lines.push('Then try your commit again.');
|
|
177
|
+
|
|
178
|
+
return lines.join('\n');
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Format network error
|
|
183
|
+
*/
|
|
184
|
+
const formatNetworkError = ({ exitCode }) => {
|
|
185
|
+
const lines = [];
|
|
186
|
+
|
|
187
|
+
lines.push('❌ Network error connecting to Claude API');
|
|
188
|
+
lines.push('');
|
|
189
|
+
lines.push('Possible causes:');
|
|
190
|
+
lines.push(' 1. No internet connection');
|
|
191
|
+
lines.push(' 2. Firewall blocking Claude API');
|
|
192
|
+
lines.push(' 3. Claude API temporarily unavailable');
|
|
193
|
+
lines.push('');
|
|
194
|
+
lines.push('Solutions:');
|
|
195
|
+
lines.push(' 1. Check your internet connection');
|
|
196
|
+
lines.push(' 2. Verify firewall settings');
|
|
197
|
+
lines.push(' 3. Try again in a few moments');
|
|
198
|
+
lines.push(' 4. Skip analysis: git commit --no-verify -m "message"');
|
|
199
|
+
|
|
200
|
+
return lines.join('\n');
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Format invalid response error
|
|
205
|
+
*/
|
|
206
|
+
const formatInvalidResponseError = ({ exitCode }) => {
|
|
207
|
+
const lines = [];
|
|
208
|
+
|
|
209
|
+
lines.push('❌ Claude returned invalid response');
|
|
210
|
+
lines.push('');
|
|
211
|
+
lines.push('This usually means:');
|
|
212
|
+
lines.push(' - Claude did not return valid JSON');
|
|
213
|
+
lines.push(' - Response format does not match expected schema');
|
|
214
|
+
lines.push('');
|
|
215
|
+
lines.push('Solutions:');
|
|
216
|
+
lines.push(' 1. Check debug output: .claude/out/debug-claude-response.json');
|
|
217
|
+
lines.push(' 2. Try again (may be temporary issue)');
|
|
218
|
+
lines.push(' 3. Skip analysis: git commit --no-verify -m "message"');
|
|
219
|
+
|
|
220
|
+
return lines.join('\n');
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Format generic error
|
|
225
|
+
*/
|
|
226
|
+
const formatGenericError = ({ exitCode, stdout, stderr }) => {
|
|
227
|
+
const lines = [];
|
|
228
|
+
|
|
229
|
+
lines.push('❌ Claude CLI execution failed');
|
|
230
|
+
lines.push('');
|
|
231
|
+
lines.push(`Exit code: ${exitCode}`);
|
|
232
|
+
|
|
233
|
+
if (stdout && stdout.trim()) {
|
|
234
|
+
lines.push('');
|
|
235
|
+
lines.push('Output:');
|
|
236
|
+
lines.push(` ${stdout.trim()}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (stderr && stderr.trim()) {
|
|
240
|
+
lines.push('');
|
|
241
|
+
lines.push('Error:');
|
|
242
|
+
lines.push(` ${stderr.trim()}`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
lines.push('');
|
|
246
|
+
lines.push('Solutions:');
|
|
247
|
+
lines.push(' 1. Verify Claude CLI is installed: claude --version');
|
|
248
|
+
lines.push(' 2. Check authentication: claude auth login');
|
|
249
|
+
lines.push(' 3. Enable debug mode in .claude/config.json:');
|
|
250
|
+
lines.push(' { "system": { "debug": true } }');
|
|
251
|
+
lines.push(' 4. Skip analysis: git commit --no-verify -m "message"');
|
|
252
|
+
|
|
253
|
+
return lines.join('\n');
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Checks if Claude CLI error is recoverable
|
|
258
|
+
* Why: Some errors (rate limit) should wait, others (auth) should fail immediately
|
|
259
|
+
*
|
|
260
|
+
* @param {Object} errorInfo - Output from detectClaudeError()
|
|
261
|
+
* @returns {boolean} True if error might resolve with retry
|
|
262
|
+
*/
|
|
263
|
+
export const isRecoverableError = (errorInfo) => {
|
|
264
|
+
return errorInfo.type === ClaudeErrorType.RATE_LIMIT ||
|
|
265
|
+
errorInfo.type === ClaudeErrorType.NETWORK;
|
|
266
|
+
};
|