claude-git-hooks 2.18.0 → 2.19.0

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/CLAUDE.md +12 -8
  3. package/README.md +2 -1
  4. package/bin/claude-hooks +75 -89
  5. package/lib/cli-metadata.js +301 -0
  6. package/lib/commands/analyze-diff.js +12 -10
  7. package/lib/commands/analyze.js +9 -5
  8. package/lib/commands/bump-version.js +66 -43
  9. package/lib/commands/create-pr.js +71 -34
  10. package/lib/commands/debug.js +4 -7
  11. package/lib/commands/generate-changelog.js +11 -4
  12. package/lib/commands/help.js +47 -27
  13. package/lib/commands/helpers.js +66 -43
  14. package/lib/commands/hooks.js +15 -13
  15. package/lib/commands/install.js +546 -39
  16. package/lib/commands/migrate-config.js +8 -11
  17. package/lib/commands/presets.js +6 -13
  18. package/lib/commands/setup-github.js +12 -3
  19. package/lib/commands/telemetry-cmd.js +8 -6
  20. package/lib/commands/update.js +1 -2
  21. package/lib/config.js +36 -31
  22. package/lib/hooks/pre-commit.js +34 -54
  23. package/lib/hooks/prepare-commit-msg.js +39 -58
  24. package/lib/utils/analysis-engine.js +28 -21
  25. package/lib/utils/changelog-generator.js +162 -34
  26. package/lib/utils/claude-client.js +438 -377
  27. package/lib/utils/claude-diagnostics.js +20 -10
  28. package/lib/utils/file-operations.js +51 -79
  29. package/lib/utils/file-utils.js +46 -9
  30. package/lib/utils/git-operations.js +140 -123
  31. package/lib/utils/git-tag-manager.js +24 -23
  32. package/lib/utils/github-api.js +85 -61
  33. package/lib/utils/github-client.js +12 -14
  34. package/lib/utils/installation-diagnostics.js +4 -4
  35. package/lib/utils/interactive-ui.js +29 -17
  36. package/lib/utils/logger.js +4 -1
  37. package/lib/utils/pr-metadata-engine.js +67 -33
  38. package/lib/utils/preset-loader.js +20 -62
  39. package/lib/utils/prompt-builder.js +50 -55
  40. package/lib/utils/resolution-prompt.js +33 -44
  41. package/lib/utils/sanitize.js +20 -19
  42. package/lib/utils/task-id.js +27 -40
  43. package/lib/utils/telemetry.js +29 -17
  44. package/lib/utils/version-manager.js +173 -126
  45. package/lib/utils/which-command.js +23 -12
  46. package/package.json +69 -69
@@ -35,7 +35,7 @@ import logger from './logger.js';
35
35
  */
36
36
  const getPathDirs = () => {
37
37
  const pathEnv = process.env.PATH || '';
38
- return pathEnv.split(delimiter).filter(dir => dir.length > 0);
38
+ return pathEnv.split(delimiter).filter((dir) => dir.length > 0);
39
39
  };
40
40
 
41
41
  /**
@@ -56,7 +56,10 @@ const isExecutable = (filePath) => {
56
56
  try {
57
57
  return existsSync(filePath);
58
58
  } catch (error) {
59
- logger.debug('which-command - isExecutable', 'File check failed', { filePath, error: error.message });
59
+ logger.debug('which-command - isExecutable', 'File check failed', {
60
+ filePath,
61
+ error: error.message
62
+ });
60
63
  return false;
61
64
  }
62
65
  };
@@ -83,12 +86,14 @@ const findInPath = (command) => {
83
86
  // Windows: Try command as-is, then with extensions
84
87
  const candidates = [
85
88
  join(dir, command),
86
- ...WINDOWS_EXTENSIONS.map(ext => join(dir, command + ext))
89
+ ...WINDOWS_EXTENSIONS.map((ext) => join(dir, command + ext))
87
90
  ];
88
91
 
89
92
  for (const candidate of candidates) {
90
93
  if (isExecutable(candidate)) {
91
- logger.debug('which-command - findInPath', 'Found in PATH', { path: candidate });
94
+ logger.debug('which-command - findInPath', 'Found in PATH', {
95
+ path: candidate
96
+ });
92
97
  return candidate;
93
98
  }
94
99
  }
@@ -133,7 +138,10 @@ const whichViaCommand = (command) => {
133
138
  });
134
139
 
135
140
  // Windows 'where' returns multiple matches
136
- const matches = result.split('\n').map(line => line.trim()).filter(line => line.length > 0);
141
+ const matches = result
142
+ .split('\n')
143
+ .map((line) => line.trim())
144
+ .filter((line) => line.length > 0);
137
145
 
138
146
  // CRITICAL FIX: On Windows, prefer .cmd/.bat over extensionless entries
139
147
  // Why: npm creates both 'claude' and 'claude.cmd', but only .cmd is executable via spawn()
@@ -141,13 +149,17 @@ const whichViaCommand = (command) => {
141
149
  // 1. C:\Users\...\npm\claude (NOT executable)
142
150
  // 2. C:\Users\...\npm\claude.cmd (executable)
143
151
  if (isWin && matches.length > 1) {
144
- const cmdMatch = matches.find(m => m.endsWith('.cmd') || m.endsWith('.bat'));
152
+ const cmdMatch = matches.find((m) => m.endsWith('.cmd') || m.endsWith('.bat'));
145
153
  if (cmdMatch) {
146
- logger.debug('which-command - whichViaCommand', 'Preferring .cmd/.bat over extensionless', {
147
- command,
148
- preferred: cmdMatch,
149
- allMatches: matches
150
- });
154
+ logger.debug(
155
+ 'which-command - whichViaCommand',
156
+ 'Preferring .cmd/.bat over extensionless',
157
+ {
158
+ command,
159
+ preferred: cmdMatch,
160
+ allMatches: matches
161
+ }
162
+ );
151
163
  return cmdMatch;
152
164
  }
153
165
  }
@@ -161,7 +173,6 @@ const whichViaCommand = (command) => {
161
173
  });
162
174
 
163
175
  return firstMatch;
164
-
165
176
  } catch (error) {
166
177
  // Command not found or which/where command failed
167
178
  logger.debug('which-command - whichViaCommand', 'Command failed', {
package/package.json CHANGED
@@ -1,69 +1,69 @@
1
- {
2
- "name": "claude-git-hooks",
3
- "version": "2.18.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.19.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
+ }