claude-git-hooks 2.17.0 → 2.17.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 +25 -6
- package/lib/commands/helpers.js +20 -0
- package/lib/commands/hooks.js +12 -8
- package/lib/commands/install.js +2 -1
- package/lib/utils/installation-diagnostics.js +2 -1
- package/package.json +68 -68
package/CHANGELOG.md
CHANGED
|
@@ -5,23 +5,37 @@ 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.17.1] - 2026-03-02
|
|
9
|
+
|
|
10
|
+
### 🐛 Fixed
|
|
11
|
+
|
|
12
|
+
- Installer no longer crashes with `ENOTDIR` when running inside a Git worktree where `.git` is a file pointer instead of a directory
|
|
13
|
+
- Hook management commands (`enable`, `disable`, `status`, `uninstall`) now correctly resolve the hooks path in worktree repos
|
|
14
|
+
|
|
15
|
+
### 🔧 Changed
|
|
16
|
+
|
|
17
|
+
- Extracted `getGitHooksPath()` to `helpers.js` — uses `git rev-parse --git-common-dir` to find the shared hooks directory in both regular repos and worktrees
|
|
18
|
+
|
|
8
19
|
## [2.17.0] - 2026-02-16
|
|
9
20
|
|
|
10
21
|
### ✨ Added
|
|
22
|
+
|
|
11
23
|
- Automatic GitHub token setup now runs after installation
|
|
12
24
|
|
|
13
25
|
### 🔧 Changed
|
|
26
|
+
|
|
14
27
|
- Simplified CLI help output to show concise command reference instead of verbose documentation
|
|
15
28
|
- Commands in help output are now listed in alphabetical order for easier navigation
|
|
16
29
|
- Installation success message now shows single help reference instead of detailed usage examples
|
|
17
30
|
|
|
18
31
|
### 🗑️ Removed
|
|
19
|
-
- Removed extensive inline documentation from help output (use README for detailed docs)
|
|
20
32
|
|
|
33
|
+
- Removed extensive inline documentation from help output (use README for detailed docs)
|
|
21
34
|
|
|
22
35
|
## [2.16.0] - 2026-02-15
|
|
23
36
|
|
|
24
37
|
### ✨ Added
|
|
38
|
+
|
|
25
39
|
- Multi-file version discovery with recursive scanning up to 3 levels deep
|
|
26
40
|
- Per-file version editing with `--interactive` flag for advanced control
|
|
27
41
|
- Support for additional project types: build.gradle, build.gradle.kts, pyproject.toml, Cargo.toml, version.sbt
|
|
@@ -32,22 +46,25 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
|
|
|
32
46
|
- New UI components: `promptToggleList()` and `promptEditField()` in interactive-ui.js
|
|
33
47
|
|
|
34
48
|
### 🔧 Changed
|
|
49
|
+
|
|
35
50
|
- Refactored version-manager.js to use new discovery-based API with `discoverVersionFiles()`, `updateVersionFiles()`, and `modifySuffix()`
|
|
36
51
|
- Bump-version workflow now supports selecting specific files to update
|
|
37
52
|
- Each file can have an independent target version when using per-file editing mode
|
|
38
53
|
- Updated CLAUDE.md documentation with new version bump flow and API changes
|
|
39
54
|
|
|
40
55
|
### ⚠️ Deprecated
|
|
41
|
-
- Legacy version-manager functions `detectProjectType()`, `getCurrentVersion()`, `updateVersion()`, and `getDiscoveredPaths()` replaced by new discovery API
|
|
42
56
|
|
|
57
|
+
- Legacy version-manager functions `detectProjectType()`, `getCurrentVersion()`, `updateVersion()`, and `getDiscoveredPaths()` replaced by new discovery API
|
|
43
58
|
|
|
44
59
|
## [2.15.5] - 2026-02-12
|
|
45
60
|
|
|
46
61
|
### ✨ Added
|
|
62
|
+
|
|
47
63
|
- Added comprehensive CI-safe integration test suite that runs without Claude CLI dependency
|
|
48
64
|
- Added new test scripts: `test:integration:ci` for CI environments and `test:changed` for testing only modified files
|
|
49
65
|
|
|
50
66
|
### 🔧 Changed
|
|
67
|
+
|
|
51
68
|
- Optimized CI matrix to run full OS/Node.js combinations only on push events, reducing PR build times
|
|
52
69
|
- Refactored integration tests to verify installation workflow, hook lifecycle, config persistence, and CLI routing
|
|
53
70
|
- Improved timeout handling in Claude CLI client by clearing timeouts consistently on all exit paths
|
|
@@ -55,35 +72,37 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
|
|
|
55
72
|
- Reduced Jest verbosity and coverage reporters for cleaner CI output
|
|
56
73
|
|
|
57
74
|
### 🐛 Fixed
|
|
75
|
+
|
|
58
76
|
- Fixed potential timeout leak in claude-client.js where timeouts were not cleared on error or stdin failures
|
|
59
77
|
|
|
60
78
|
### 🗑️ Removed
|
|
61
|
-
- Removed unused variables and parameters across multiple modules (analyze-diff, create-pr, install, config, changelog-generator, claude-client, claude-diagnostics, file-utils, git-operations, prompt-builder)
|
|
62
79
|
|
|
80
|
+
- Removed unused variables and parameters across multiple modules (analyze-diff, create-pr, install, config, changelog-generator, claude-client, claude-diagnostics, file-utils, git-operations, prompt-builder)
|
|
63
81
|
|
|
64
82
|
## [2.15.4] - 2026-02-11
|
|
65
83
|
|
|
66
84
|
### ✨ Added
|
|
85
|
+
|
|
67
86
|
- Added comprehensive unit tests for claude-diagnostics.js covering error detection, formatting, and recovery classification
|
|
68
87
|
- Added unit tests for file-utils.js covering directory creation and file writing operations
|
|
69
88
|
|
|
70
|
-
|
|
71
89
|
## [2.15.3] - 2026-02-10
|
|
72
90
|
|
|
73
91
|
### ✨ Added
|
|
92
|
+
|
|
74
93
|
- Unit tests for `generate-changelog.js` command covering CHANGELOG generation, version detection, and error handling
|
|
75
94
|
- Unit tests for `github-client.js` covering CODEOWNERS parsing, reviewer detection, and GitHub repo parsing
|
|
76
95
|
- Unit tests for `hooks.js` command covering enable, disable, status, and uninstall operations
|
|
77
96
|
|
|
78
|
-
|
|
79
97
|
## [2.15.2] - 2026-02-10
|
|
80
98
|
|
|
81
99
|
### 🔧 Changed
|
|
100
|
+
|
|
82
101
|
- The bump-version command now uses the configured default branch (from github.pr.defaultBase) in the 'Next steps' output instead of hardcoded 'main'
|
|
83
102
|
|
|
84
103
|
### 🐛 Fixed
|
|
85
|
-
- Fixed cross-platform path assertions in unit tests to use partial matching instead of exact paths, improving Windows compatibility
|
|
86
104
|
|
|
105
|
+
- Fixed cross-platform path assertions in unit tests to use partial matching instead of exact paths, improving Windows compatibility
|
|
87
106
|
|
|
88
107
|
## [2.15.1] - 2026-02-10
|
|
89
108
|
|
package/lib/commands/helpers.js
CHANGED
|
@@ -95,6 +95,26 @@ export function getTemplatesPath() {
|
|
|
95
95
|
return path.join(__dirname, '..', '..', 'templates');
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Get the git hooks directory, correctly handling worktrees.
|
|
100
|
+
* In a worktree, hooks live in the main repo's .git/hooks, not the worktree's .git file.
|
|
101
|
+
* Uses `git rev-parse --git-common-dir` to find the shared git directory.
|
|
102
|
+
* @returns {string} Path to the git hooks directory
|
|
103
|
+
*/
|
|
104
|
+
export function getGitHooksPath() {
|
|
105
|
+
try {
|
|
106
|
+
let gitCommonDir = execSync('git rev-parse --git-common-dir', { encoding: 'utf8' }).trim();
|
|
107
|
+
// Handle Windows paths when running under WSL (e.g. C:\... -> /mnt/c/...)
|
|
108
|
+
if (/^[A-Za-z]:/.test(gitCommonDir)) {
|
|
109
|
+
gitCommonDir = gitCommonDir.replace(/^([A-Za-z]):/, (_, drive) => `/mnt/${drive.toLowerCase()}`);
|
|
110
|
+
gitCommonDir = gitCommonDir.replace(/\\/g, '/');
|
|
111
|
+
}
|
|
112
|
+
return path.join(gitCommonDir, 'hooks');
|
|
113
|
+
} catch (e) {
|
|
114
|
+
return path.join('.git', 'hooks');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
98
118
|
/**
|
|
99
119
|
* Detect if running on Windows
|
|
100
120
|
* Why: Need to use 'wsl claude' instead of 'claude' on Windows
|
package/lib/commands/hooks.js
CHANGED
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
success,
|
|
11
11
|
info,
|
|
12
12
|
warning,
|
|
13
|
-
checkGitRepo
|
|
13
|
+
checkGitRepo,
|
|
14
|
+
getGitHooksPath
|
|
14
15
|
} from './helpers.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -22,11 +23,12 @@ export function runEnable(hookName) {
|
|
|
22
23
|
error('You are not in a Git repository.');
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
const hooksDir = getGitHooksPath();
|
|
25
27
|
const hooks = hookName ? [hookName] : ['pre-commit', 'prepare-commit-msg'];
|
|
26
28
|
|
|
27
29
|
hooks.forEach(hook => {
|
|
28
|
-
const disabledPath =
|
|
29
|
-
const enabledPath =
|
|
30
|
+
const disabledPath = path.join(hooksDir, `${hook}.disabled`);
|
|
31
|
+
const enabledPath = path.join(hooksDir, hook);
|
|
30
32
|
|
|
31
33
|
if (fs.existsSync(disabledPath)) {
|
|
32
34
|
fs.renameSync(disabledPath, enabledPath);
|
|
@@ -48,11 +50,12 @@ export function runDisable(hookName) {
|
|
|
48
50
|
error('You are not in a Git repository.');
|
|
49
51
|
}
|
|
50
52
|
|
|
53
|
+
const hooksDir = getGitHooksPath();
|
|
51
54
|
const hooks = hookName ? [hookName] : ['pre-commit', 'prepare-commit-msg'];
|
|
52
55
|
|
|
53
56
|
hooks.forEach(hook => {
|
|
54
|
-
const enabledPath =
|
|
55
|
-
const disabledPath =
|
|
57
|
+
const enabledPath = path.join(hooksDir, hook);
|
|
58
|
+
const disabledPath = path.join(hooksDir, `${hook}.disabled`);
|
|
56
59
|
|
|
57
60
|
if (fs.existsSync(enabledPath)) {
|
|
58
61
|
fs.renameSync(enabledPath, disabledPath);
|
|
@@ -75,10 +78,11 @@ export function runStatus() {
|
|
|
75
78
|
|
|
76
79
|
info('Claude Git Hooks status:\n');
|
|
77
80
|
|
|
81
|
+
const hooksDir = getGitHooksPath();
|
|
78
82
|
const hooks = ['pre-commit', 'prepare-commit-msg'];
|
|
79
83
|
hooks.forEach(hook => {
|
|
80
|
-
const enabledPath =
|
|
81
|
-
const disabledPath =
|
|
84
|
+
const enabledPath = path.join(hooksDir, hook);
|
|
85
|
+
const disabledPath = path.join(hooksDir, `${hook}.disabled`);
|
|
82
86
|
|
|
83
87
|
if (fs.existsSync(enabledPath)) {
|
|
84
88
|
success(`${hook}: enabled`);
|
|
@@ -135,7 +139,7 @@ export function runUninstall() {
|
|
|
135
139
|
|
|
136
140
|
info('Uninstalling Claude Git Hooks...');
|
|
137
141
|
|
|
138
|
-
const hooksPath =
|
|
142
|
+
const hooksPath = getGitHooksPath();
|
|
139
143
|
const hooks = ['pre-commit', 'prepare-commit-msg'];
|
|
140
144
|
|
|
141
145
|
hooks.forEach(hook => {
|
package/lib/commands/install.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
warning,
|
|
24
24
|
checkGitRepo,
|
|
25
25
|
getTemplatesPath,
|
|
26
|
+
getGitHooksPath,
|
|
26
27
|
isWindows,
|
|
27
28
|
getClaudeCommand,
|
|
28
29
|
getPackageJson,
|
|
@@ -402,7 +403,7 @@ export async function runInstall(args) {
|
|
|
402
403
|
await checkAndInstallDependencies(skipAuth);
|
|
403
404
|
|
|
404
405
|
const templatesPath = getTemplatesPath();
|
|
405
|
-
const hooksPath =
|
|
406
|
+
const hooksPath = getGitHooksPath();
|
|
406
407
|
|
|
407
408
|
// Create hooks directory if it doesn't exist
|
|
408
409
|
if (!fs.existsSync(hooksPath)) {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
import fs from 'fs';
|
|
23
23
|
import path from 'path';
|
|
24
24
|
import { getRepoRoot } from './git-operations.js';
|
|
25
|
+
import { getGitHooksPath } from '../commands/helpers.js';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* Gets installation diagnostics
|
|
@@ -60,7 +61,7 @@ export const getInstallationDiagnostics = () => {
|
|
|
60
61
|
diagnostics.presetsDirPath = path.join(diagnostics.claudeDirPath, 'presets');
|
|
61
62
|
diagnostics.presetsDirExists = fs.existsSync(diagnostics.presetsDirPath);
|
|
62
63
|
|
|
63
|
-
const gitHooksPath =
|
|
64
|
+
const gitHooksPath = getGitHooksPath();
|
|
64
65
|
diagnostics.gitHooksExists = fs.existsSync(gitHooksPath);
|
|
65
66
|
} catch (error) {
|
|
66
67
|
// Not in a git repository - diagnostics.repoRoot will be null
|
package/package.json
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "claude-git-hooks",
|
|
3
|
-
"version": "2.17.
|
|
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/pablorovito/claude-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
|
-
"LICENSE"
|
|
58
|
-
],
|
|
59
|
-
"dependencies": {
|
|
60
|
-
"@octokit/rest": "^21.0.0"
|
|
61
|
-
},
|
|
62
|
-
"devDependencies": {
|
|
63
|
-
"@types/jest": "^29.5.0",
|
|
64
|
-
"eslint": "^8.57.0",
|
|
65
|
-
"jest": "^29.7.0",
|
|
66
|
-
"prettier": "^3.2.0"
|
|
67
|
-
}
|
|
68
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-git-hooks",
|
|
3
|
+
"version": "2.17.1",
|
|
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/pablorovito/claude-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
|
+
"LICENSE"
|
|
58
|
+
],
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@octokit/rest": "^21.0.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/jest": "^29.5.0",
|
|
64
|
+
"eslint": "^8.57.0",
|
|
65
|
+
"jest": "^29.7.0",
|
|
66
|
+
"prettier": "^3.2.0"
|
|
67
|
+
}
|
|
68
|
+
}
|