claude-git-hooks 2.6.0 → 2.6.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 CHANGED
@@ -5,6 +5,27 @@ 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.6.1] - 2025-12-04
9
+
10
+ ### 🐛 Fixed
11
+
12
+ - **Windows spawn ENOENT errors** - Fixed critical issue where Claude CLI failed to execute on Windows with npm-installed tools
13
+ - **What was broken**: `spawn()` cannot execute `.cmd`/`.bat` files directly on Windows, causing `ENOENT` errors
14
+ - **Root cause**: npm on Windows creates both `claude` (non-executable) and `claude.cmd` (executable), and system was selecting the wrong one
15
+ - **Fix 1**: `which-command.js` now prefers `.cmd`/`.bat` extensions over extensionless entries when multiple matches found
16
+ - **Fix 2**: `claude-client.js` wraps `.cmd`/`.bat` commands with `cmd.exe /c` before spawning
17
+ - **Files changed**:
18
+ - `lib/utils/which-command.js:135-163` - Prefer `.cmd`/`.bat` in Windows path resolution
19
+ - `lib/utils/claude-client.js:165-179` - Wrap batch files with cmd.exe
20
+ - **Impact**: Fixes `analyze-diff` and commit hooks for Windows users with npm-installed Claude CLI
21
+ - **Compatibility**: No impact on Linux/macOS or Windows WSL setups, only affects Windows native npm installations
22
+
23
+ ### 🎯 User Experience
24
+
25
+ - **Before**: Windows users with npm-installed Claude CLI got `ENOENT` errors on every command
26
+ - **After**: Commands work seamlessly, same as other platforms
27
+ - **Debug**: Added detailed logging for Windows .cmd file detection and wrapping
28
+
8
29
  ## [2.6.0] - 2025-12-02
9
30
 
10
31
  ### ✨ Added - Node.js 24 Compatibility
@@ -162,7 +162,23 @@ const executeClaude = (prompt, { timeout = 120000, allowedTools = [] } = {}) =>
162
162
  finalArgs.push('--allowedTools', allowedTools.join(','));
163
163
  }
164
164
 
165
- const fullCommand = finalArgs.length > 0 ? `${command} ${finalArgs.join(' ')}` : command;
165
+ // CRITICAL FIX: Windows .cmd/.bat file handling
166
+ // Why: spawn() cannot execute .cmd/.bat files directly on Windows (ENOENT error)
167
+ // Solution: Wrap with cmd.exe /c when command ends with .cmd or .bat
168
+ // Impact: Only affects Windows npm-installed CLI tools, no impact on other platforms
169
+ let spawnCommand = command;
170
+ let spawnArgs = finalArgs;
171
+
172
+ if (isWindows() && (command.endsWith('.cmd') || command.endsWith('.bat'))) {
173
+ logger.debug('claude-client - executeClaude', 'Wrapping .cmd/.bat with cmd.exe', {
174
+ originalCommand: command,
175
+ originalArgs: finalArgs
176
+ });
177
+ spawnCommand = 'cmd.exe';
178
+ spawnArgs = ['/c', command, ...finalArgs];
179
+ }
180
+
181
+ const fullCommand = spawnArgs.length > 0 ? `${spawnCommand} ${spawnArgs.join(' ')}` : spawnCommand;
166
182
 
167
183
  logger.debug(
168
184
  'claude-client - executeClaude',
@@ -176,7 +192,8 @@ const executeClaude = (prompt, { timeout = 120000, allowedTools = [] } = {}) =>
176
192
  // spawn streams data, exec buffers everything in memory
177
193
  // Node 24 Fix: Removed shell: true to avoid DEP0190 deprecation warning
178
194
  // We now use absolute paths from which(), so shell is not needed
179
- const claude = spawn(command, finalArgs, {
195
+ // Windows .cmd/.bat fix: Wrapped with cmd.exe /c (see above)
196
+ const claude = spawn(spawnCommand, spawnArgs, {
180
197
  stdio: ['pipe', 'pipe', 'pipe'] // stdin, stdout, stderr
181
198
  });
182
199
 
@@ -132,12 +132,32 @@ const whichViaCommand = (command) => {
132
132
  timeout: 3000 // Don't wait forever
133
133
  });
134
134
 
135
- // Windows 'where' returns multiple matches, take first
136
- const firstMatch = result.split('\n')[0].trim();
135
+ // Windows 'where' returns multiple matches
136
+ const matches = result.split('\n').map(line => line.trim()).filter(line => line.length > 0);
137
+
138
+ // CRITICAL FIX: On Windows, prefer .cmd/.bat over extensionless entries
139
+ // Why: npm creates both 'claude' and 'claude.cmd', but only .cmd is executable via spawn()
140
+ // Example: where claude returns:
141
+ // 1. C:\Users\...\npm\claude (NOT executable)
142
+ // 2. C:\Users\...\npm\claude.cmd (executable)
143
+ if (isWin && matches.length > 1) {
144
+ const cmdMatch = matches.find(m => m.endsWith('.cmd') || m.endsWith('.bat'));
145
+ if (cmdMatch) {
146
+ logger.debug('which-command - whichViaCommand', 'Preferring .cmd/.bat over extensionless', {
147
+ command,
148
+ preferred: cmdMatch,
149
+ allMatches: matches
150
+ });
151
+ return cmdMatch;
152
+ }
153
+ }
154
+
155
+ const firstMatch = matches[0];
137
156
 
138
157
  logger.debug('which-command - whichViaCommand', 'Found via command', {
139
158
  command,
140
- path: firstMatch
159
+ path: firstMatch,
160
+ totalMatches: matches.length
141
161
  });
142
162
 
143
163
  return firstMatch;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-git-hooks",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "Git hooks with Claude CLI for code analysis and automatic commit messages",
5
5
  "type": "module",
6
6
  "bin": {