claude-git-hooks 2.21.0 → 2.30.2

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.
@@ -22,11 +22,7 @@ import path from 'path';
22
22
  import { execSync } from 'child_process';
23
23
  import { executeClaudeWithRetry, extractJSON } from './claude-client.js';
24
24
  import { loadPrompt } from './prompt-builder.js';
25
- import {
26
- formatBlockingIssues,
27
- getAffectedFiles,
28
- formatFileContents
29
- } from './resolution-prompt.js';
25
+ import { formatBlockingIssues, getAffectedFiles, formatFileContents } from './resolution-prompt.js';
30
26
  import { getRepoRoot, getRepoName, getCurrentBranch } from './git-operations.js';
31
27
  import logger from './logger.js';
32
28
  import { recordEvent } from './telemetry.js';
@@ -55,6 +51,29 @@ const applyFix = async (fix, repoRoot) => {
55
51
  const firstIndex = content.indexOf(search);
56
52
 
57
53
  if (firstIndex === -1) {
54
+ // Debug: diagnose why the search string didn't match
55
+ if (logger.isDebugMode()) {
56
+ const fileCRLF = content.includes('\r\n');
57
+ const searchCRLF = search.includes('\r\n');
58
+ const searchLines = search.split(/\r?\n/);
59
+ const firstLine = searchLines[0].trim();
60
+ // Try to locate the first line loosely in the file
61
+ const looseIndex = content.indexOf(firstLine);
62
+ logger.debug('judge - applyFix', 'Search mismatch diagnosis', {
63
+ file,
64
+ searchLength: search.length,
65
+ searchLines: searchLines.length,
66
+ fileCRLF,
67
+ searchCRLF,
68
+ crlfMismatch: fileCRLF !== searchCRLF,
69
+ firstLineFound: looseIndex !== -1,
70
+ firstLineFoundAt:
71
+ looseIndex !== -1
72
+ ? `char ${looseIndex} (approx line ${content.substring(0, looseIndex).split('\n').length})`
73
+ : null,
74
+ searchFirst200Hex: Buffer.from(search.substring(0, 200)).toString('hex')
75
+ });
76
+ }
58
77
  return { applied: false, reason: 'search string not found in file' };
59
78
  }
60
79
 
@@ -122,6 +141,42 @@ const judgeAndFix = async (analysisResult, filesData, config) => {
122
141
  const parsed = extractJSON(response);
123
142
  const fixes = parsed?.fixes || [];
124
143
 
144
+ // Debug: dump raw LLM response and parsed fixes for diagnosis
145
+ if (logger.isDebugMode()) {
146
+ try {
147
+ const debugDir = path.join(repoRoot, '.claude', 'out');
148
+ await fs.mkdir(debugDir, { recursive: true });
149
+ await fs.writeFile(
150
+ path.join(debugDir, 'judge-debug.json'),
151
+ JSON.stringify(
152
+ {
153
+ timestamp: new Date().toISOString(),
154
+ model,
155
+ issueCount: allIssues.length,
156
+ fixCount: fixes.length,
157
+ rawResponse: response,
158
+ parsedFixes: fixes.map((f) => ({
159
+ file: f.file,
160
+ assessment: f.assessment,
161
+ searchLength: f.search?.length ?? null,
162
+ replaceLength: f.replace?.length ?? null,
163
+ searchHex: f.search
164
+ ? Buffer.from(f.search.substring(0, 300)).toString('hex')
165
+ : null,
166
+ search: f.search,
167
+ replace: f.replace
168
+ }))
169
+ },
170
+ null,
171
+ 2
172
+ )
173
+ );
174
+ logger.debug('judge', 'Debug dump written to .claude/out/judge-debug.json');
175
+ } catch (debugErr) {
176
+ logger.debug('judge', 'Failed to write debug dump', debugErr);
177
+ }
178
+ }
179
+
125
180
  let fixedCount = 0;
126
181
  let falsePositiveCount = 0;
127
182
  const resolvedIndices = new Set();
@@ -173,11 +228,15 @@ const judgeAndFix = async (analysisResult, filesData, config) => {
173
228
  );
174
229
 
175
230
  if (fixedCount > 0) {
176
- logger.info(` ${fixedCount} fix${fixedCount !== 1 ? 'es' : ''} staged for commit — review with: git diff --cached`);
231
+ logger.info(
232
+ ` ${fixedCount} fix${fixedCount !== 1 ? 'es' : ''} staged for commit — review with: git diff --cached`
233
+ );
177
234
  }
178
235
 
179
236
  if (unresolvedCount > 0) {
180
- logger.warning(` ${unresolvedCount} unresolved issue${unresolvedCount !== 1 ? 's' : ''} — commit will be blocked`);
237
+ logger.warning(
238
+ ` ${unresolvedCount} unresolved issue${unresolvedCount !== 1 ? 's' : ''} — commit will be blocked`
239
+ );
181
240
  }
182
241
 
183
242
  // Record telemetry
@@ -268,10 +268,7 @@ export const fetchTicket = async (identifier) => {
268
268
 
269
269
  if (attempt < MAX_RETRIES) {
270
270
  // Steps c/d: Retry with reconnection
271
- logger.debug(
272
- 'linear-connector - fetchTicket',
273
- 'Retrying after connection failure'
274
- );
271
+ logger.debug('linear-connector - fetchTicket', 'Retrying after connection failure');
275
272
  // Small delay before retry
276
273
  await new Promise((resolve) => setTimeout(resolve, 1000));
277
274
  }
@@ -61,4 +61,3 @@ export const getPackageName = async () => {
61
61
  const pkg = await getPackageJson();
62
62
  return pkg.name;
63
63
  };
64
-
@@ -123,7 +123,10 @@ export const saveToken = (settingsKey, token) => {
123
123
  try {
124
124
  settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
125
125
  } catch {
126
- logger.debug('token-store - saveToken', 'Invalid existing settings, starting fresh');
126
+ logger.debug(
127
+ 'token-store - saveToken',
128
+ 'Invalid existing settings, starting fresh'
129
+ );
127
130
  settings = {};
128
131
  }
129
132
  }
@@ -155,5 +158,4 @@ export const saveToken = (settingsKey, token) => {
155
158
  * @param {string[]} envVars - Environment variable names to check
156
159
  * @returns {boolean}
157
160
  */
158
- export const hasToken = (settingsKey, envVars = []) =>
159
- loadToken(settingsKey, envVars) !== null;
161
+ export const hasToken = (settingsKey, envVars = []) => loadToken(settingsKey, envVars) !== null;
package/package.json CHANGED
@@ -1,69 +1,69 @@
1
- {
2
- "name": "claude-git-hooks",
3
- "version": "2.21.0",
4
- "description": "Git hooks with Claude CLI for code analysis and automatic commit messages",
5
- "type": "module",
6
- "bin": {
7
- "claude-hooks": "./bin/claude-hooks"
8
- },
9
- "scripts": {
10
- "test": "npm run test:all",
11
- "test:all": "npm run lint && npm run test:smoke && npm run test:unit && npm run test:integration",
12
- "test:smoke": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/smoke --maxWorkers=1",
13
- "test:unit": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/unit --forceExit",
14
- "test:integration": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/integration --maxWorkers=1 --testTimeout=30000 --forceExit",
15
- "test:integration:ci": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/integration/ci-safe.test.js --maxWorkers=1 --testTimeout=30000 --forceExit",
16
- "test:changed": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/unit --changedSince=main --forceExit",
17
- "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch",
18
- "test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
19
- "lint": "eslint lib/ bin/claude-hooks",
20
- "lint:fix": "eslint lib/ bin/claude-hooks --fix",
21
- "format": "prettier --write \"lib/**/*.js\" \"bin/**\" \"test/**/*.js\"",
22
- "precommit": "npm run lint && npm run test:smoke",
23
- "prepublishOnly": "npm run test:all"
24
- },
25
- "keywords": [
26
- "git",
27
- "hooks",
28
- "claude",
29
- "ai",
30
- "code-review",
31
- "commit-messages",
32
- "pre-commit",
33
- "automation"
34
- ],
35
- "author": "Pablo Rovito",
36
- "license": "MIT",
37
- "repository": {
38
- "type": "git",
39
- "url": "https://github.com/mscope-S-L/git-hooks.git"
40
- },
41
- "engines": {
42
- "node": ">=16.9.0"
43
- },
44
- "engineStrict": false,
45
- "os": [
46
- "darwin",
47
- "linux",
48
- "win32"
49
- ],
50
- "preferGlobal": true,
51
- "files": [
52
- "bin/",
53
- "lib/",
54
- "templates/",
55
- "README.md",
56
- "CHANGELOG.md",
57
- "CLAUDE.md",
58
- "LICENSE"
59
- ],
60
- "dependencies": {
61
- "@octokit/rest": "^21.0.0"
62
- },
63
- "devDependencies": {
64
- "@types/jest": "^29.5.0",
65
- "eslint": "^8.57.0",
66
- "jest": "^29.7.0",
67
- "prettier": "^3.2.0"
68
- }
69
- }
1
+ {
2
+ "name": "claude-git-hooks",
3
+ "version": "2.30.2",
4
+ "description": "Git hooks with Claude CLI for code analysis and automatic commit messages",
5
+ "type": "module",
6
+ "bin": {
7
+ "claude-hooks": "./bin/claude-hooks"
8
+ },
9
+ "scripts": {
10
+ "test": "npm run test:all",
11
+ "test:all": "npm run lint && npm run test:smoke && npm run test:unit && npm run test:integration",
12
+ "test:smoke": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/smoke --maxWorkers=1",
13
+ "test:unit": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/unit --forceExit",
14
+ "test:integration": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/integration --maxWorkers=1 --testTimeout=30000 --forceExit",
15
+ "test:integration:ci": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/integration/ci-safe.test.js --maxWorkers=1 --testTimeout=30000 --forceExit",
16
+ "test:changed": "node --experimental-vm-modules node_modules/jest/bin/jest.js test/unit --changedSince=main --forceExit",
17
+ "test:watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch",
18
+ "test:coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
19
+ "lint": "eslint lib/ bin/claude-hooks",
20
+ "lint:fix": "eslint lib/ bin/claude-hooks --fix",
21
+ "format": "prettier --write \"lib/**/*.js\" \"bin/**\" \"test/**/*.js\"",
22
+ "precommit": "npm run lint && npm run test:smoke",
23
+ "prepublishOnly": "npm run test:all"
24
+ },
25
+ "keywords": [
26
+ "git",
27
+ "hooks",
28
+ "claude",
29
+ "ai",
30
+ "code-review",
31
+ "commit-messages",
32
+ "pre-commit",
33
+ "automation"
34
+ ],
35
+ "author": "Pablo Rovito",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/mscope-S-L/git-hooks.git"
40
+ },
41
+ "engines": {
42
+ "node": ">=16.9.0"
43
+ },
44
+ "engineStrict": false,
45
+ "os": [
46
+ "darwin",
47
+ "linux",
48
+ "win32"
49
+ ],
50
+ "preferGlobal": true,
51
+ "files": [
52
+ "bin/",
53
+ "lib/",
54
+ "templates/",
55
+ "README.md",
56
+ "CHANGELOG.md",
57
+ "CLAUDE.md",
58
+ "LICENSE"
59
+ ],
60
+ "dependencies": {
61
+ "@octokit/rest": "^21.0.0"
62
+ },
63
+ "devDependencies": {
64
+ "@types/jest": "^29.5.0",
65
+ "eslint": "^8.57.0",
66
+ "jest": "^29.7.0",
67
+ "prettier": "^3.2.0"
68
+ }
69
+ }