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
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: installation-diagnostics.js
|
|
3
|
+
* Purpose: Reusable error diagnostics and formatting utilities
|
|
4
|
+
*
|
|
5
|
+
* Key features:
|
|
6
|
+
* - Generic error formatting with installation diagnostics
|
|
7
|
+
* - Detects common installation issues
|
|
8
|
+
* - Provides actionable remediation steps
|
|
9
|
+
* - Extensible for future diagnostic checks
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* import { formatError } from './installation-diagnostics.js';
|
|
13
|
+
*
|
|
14
|
+
* try {
|
|
15
|
+
* // ... operation that might fail
|
|
16
|
+
* } catch (error) {
|
|
17
|
+
* console.error(formatError('Presets not found'));
|
|
18
|
+
* process.exit(1);
|
|
19
|
+
* }
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import fs from 'fs';
|
|
23
|
+
import path from 'path';
|
|
24
|
+
import { getRepoRoot } from './git-operations.js';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Gets installation diagnostics
|
|
28
|
+
* Why: Centralized logic to detect common installation issues
|
|
29
|
+
*
|
|
30
|
+
* Future enhancements:
|
|
31
|
+
* - Check file permissions
|
|
32
|
+
* - Verify Claude CLI installation
|
|
33
|
+
* - Check Node.js version compatibility
|
|
34
|
+
* - Validate .gitignore entries
|
|
35
|
+
* - Check hook file integrity
|
|
36
|
+
* - Verify template files exist
|
|
37
|
+
* - Check config.json validity
|
|
38
|
+
*
|
|
39
|
+
* @returns {Object} Diagnostic information
|
|
40
|
+
*/
|
|
41
|
+
export const getInstallationDiagnostics = () => {
|
|
42
|
+
const diagnostics = {
|
|
43
|
+
currentDir: process.cwd(),
|
|
44
|
+
repoRoot: null,
|
|
45
|
+
isInRepoRoot: false,
|
|
46
|
+
claudeDirExists: false,
|
|
47
|
+
claudeDirPath: null,
|
|
48
|
+
presetsDirExists: false,
|
|
49
|
+
presetsDirPath: null,
|
|
50
|
+
gitHooksExists: false,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
diagnostics.repoRoot = getRepoRoot();
|
|
55
|
+
diagnostics.isInRepoRoot = diagnostics.currentDir === diagnostics.repoRoot;
|
|
56
|
+
|
|
57
|
+
diagnostics.claudeDirPath = path.join(diagnostics.repoRoot, '.claude');
|
|
58
|
+
diagnostics.claudeDirExists = fs.existsSync(diagnostics.claudeDirPath);
|
|
59
|
+
|
|
60
|
+
diagnostics.presetsDirPath = path.join(diagnostics.claudeDirPath, 'presets');
|
|
61
|
+
diagnostics.presetsDirExists = fs.existsSync(diagnostics.presetsDirPath);
|
|
62
|
+
|
|
63
|
+
const gitHooksPath = path.join(diagnostics.repoRoot, '.git', 'hooks');
|
|
64
|
+
diagnostics.gitHooksExists = fs.existsSync(gitHooksPath);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
// Not in a git repository - diagnostics.repoRoot will be null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return diagnostics;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Formats error message with diagnostics and remediation steps
|
|
74
|
+
* Why: Provides consistent, actionable error messages across all errors
|
|
75
|
+
*
|
|
76
|
+
* @param {string} errorMessage - Description of what failed (e.g., "Presets not found", "Template file missing")
|
|
77
|
+
* @param {string[]} additionalContext - Optional additional context lines
|
|
78
|
+
* @returns {string} Formatted error message with diagnostics and remediation steps
|
|
79
|
+
*/
|
|
80
|
+
export const formatError = (errorMessage, additionalContext = []) => {
|
|
81
|
+
const diagnostics = getInstallationDiagnostics();
|
|
82
|
+
const lines = [];
|
|
83
|
+
|
|
84
|
+
lines.push(`⚠️ ${errorMessage}`);
|
|
85
|
+
lines.push('');
|
|
86
|
+
|
|
87
|
+
// Add any additional context first
|
|
88
|
+
if (additionalContext.length > 0) {
|
|
89
|
+
lines.push(...additionalContext);
|
|
90
|
+
lines.push('');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Diagnostic information
|
|
94
|
+
lines.push('Installation diagnostics:');
|
|
95
|
+
lines.push(` Current directory: ${diagnostics.currentDir}`);
|
|
96
|
+
if (diagnostics.repoRoot) {
|
|
97
|
+
lines.push(` Repository root: ${diagnostics.repoRoot}`);
|
|
98
|
+
lines.push(` .claude/ exists: ${diagnostics.claudeDirExists ? '✓' : '✗'}`);
|
|
99
|
+
lines.push(` presets/ exists: ${diagnostics.presetsDirExists ? '✓' : '✗'}`);
|
|
100
|
+
} else {
|
|
101
|
+
lines.push(` Repository root: [Not in a git repository]`);
|
|
102
|
+
}
|
|
103
|
+
lines.push('');
|
|
104
|
+
|
|
105
|
+
// Remediation steps based on detected issues
|
|
106
|
+
lines.push('Recommended solution:');
|
|
107
|
+
if (!diagnostics.repoRoot) {
|
|
108
|
+
lines.push(' Not in a git repository');
|
|
109
|
+
lines.push(' → Navigate to your repository and try again');
|
|
110
|
+
} else if (!diagnostics.claudeDirExists) {
|
|
111
|
+
lines.push(' claude-hooks not installed');
|
|
112
|
+
if (!diagnostics.isInRepoRoot) {
|
|
113
|
+
lines.push(` → cd ${diagnostics.repoRoot}`);
|
|
114
|
+
lines.push(' → claude-hooks install');
|
|
115
|
+
} else {
|
|
116
|
+
lines.push(' → claude-hooks install');
|
|
117
|
+
}
|
|
118
|
+
} else if (!diagnostics.isInRepoRoot) {
|
|
119
|
+
lines.push(' Running from subdirectory (may cause path issues)');
|
|
120
|
+
lines.push(` → cd ${diagnostics.repoRoot}`);
|
|
121
|
+
lines.push(' → claude-hooks uninstall');
|
|
122
|
+
lines.push(' → claude-hooks install');
|
|
123
|
+
} else if (!diagnostics.presetsDirExists) {
|
|
124
|
+
lines.push(' Incomplete installation (presets missing)');
|
|
125
|
+
lines.push(' → claude-hooks install --force');
|
|
126
|
+
} else {
|
|
127
|
+
lines.push(' Unknown issue detected');
|
|
128
|
+
lines.push(' → claude-hooks install --force');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return lines.join('\n');
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Checks if installation appears healthy
|
|
136
|
+
* Why: Quick validation before operations that require full installation
|
|
137
|
+
*
|
|
138
|
+
* @returns {boolean} True if installation looks healthy
|
|
139
|
+
*/
|
|
140
|
+
export const isInstallationHealthy = () => {
|
|
141
|
+
const diagnostics = getInstallationDiagnostics();
|
|
142
|
+
return diagnostics.claudeDirExists &&
|
|
143
|
+
diagnostics.presetsDirExists &&
|
|
144
|
+
diagnostics.gitHooksExists;
|
|
145
|
+
};
|
|
@@ -13,12 +13,14 @@
|
|
|
13
13
|
* - path: Cross-platform path handling
|
|
14
14
|
* - git-operations: For getRepoRoot()
|
|
15
15
|
* - logger: Debug and error logging
|
|
16
|
+
* - installation-diagnostics: Error formatting with remediation steps
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
import fs from 'fs/promises';
|
|
19
20
|
import path from 'path';
|
|
20
21
|
import { getRepoRoot } from './git-operations.js';
|
|
21
22
|
import logger from './logger.js';
|
|
23
|
+
import { formatError } from './installation-diagnostics.js';
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* Custom error for preset loading failures
|
|
@@ -189,7 +191,10 @@ export async function listPresets() {
|
|
|
189
191
|
}
|
|
190
192
|
}
|
|
191
193
|
} catch (error) {
|
|
192
|
-
|
|
194
|
+
const errorMsg = formatError('No presets directory found', [
|
|
195
|
+
`Expected location: ${presetsDir}`
|
|
196
|
+
]);
|
|
197
|
+
logger.warning(errorMsg);
|
|
193
198
|
logger.debug(
|
|
194
199
|
'preset-loader - listPresets',
|
|
195
200
|
'Failed to read presets directory',
|