claude-git-hooks 2.35.2 → 2.35.3

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,21 @@ 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.35.3] - 2026-04-22
9
+
10
+ ### ✨ Added
11
+ - Code Knowledge Library (`.library/`) with 25 reference books covering source modules — structured documentation with call signatures, I/O behavior, cross-references, and gotchas per module (#125-#131)
12
+ - By-code index for navigating from source file paths to their reference books (`by-code/utils.md`, `by-code/commands.md`, `by-code/hooks.md`)
13
+ - By-domain index with curated reading lists for four business workflows: commit pipeline, release management, PR analysis, and GitHub integration (`by-domain/`)
14
+ - By-task-type index with step-by-step reading sequences for development tasks, starting with add-new-command guide (`by-task-type/`)
15
+ - Dependency graph generator tool and path resolver for library infrastructure (`tools/`)
16
+ - Book schema and token measurement infrastructure with calibration notes and category completeness validation
17
+ - Classification report and category completeness report validating all 66 source modules against the 8-category taxonomy
18
+
19
+ ### 🐛 Fixed
20
+ - Spotless linting timeouts and cmd.exe per-file mode on Windows — resolves batch-mode failures when Spotless wrapper is a `.cmd`/`.bat` file (#124, #125)
21
+
22
+
8
23
  ## [2.35.2] - 2026-04-13
9
24
 
10
25
  ### ✨ Added
package/CLAUDE.md CHANGED
@@ -217,18 +217,19 @@ preset config (.claude/presets/{name}/config.json) ← HIGHEST PRIORITY
217
217
  | Orchestrator threshold | 3 files | Commits with ≥3 files use Opus orchestration |
218
218
  | Orchestrator model | opus | Internal constant — not user-configurable |
219
219
  | Orchestrator timeout | 60s | Lightweight call (file overview only) |
220
- | Analysis timeout | 300s | Per-batch timeout |
220
+ | Analysis timeout | 360s | Per-batch timeout |
221
221
  | Commit msg timeout | 300s | Message generation timeout |
222
222
  | PR metadata timeout | 180s | Engine default (reads config) |
223
223
  | Judge model | sonnet | Default, configurable via `config.judge.model` |
224
- | Judge timeout | 120s | Per-judge call timeout |
224
+ | Judge timeout | 360s | Per-judge call timeout |
225
225
  | PR analysis model | sonnet | Default, configurable via `config.prAnalysis.model` |
226
226
  | PR analysis timeout | 300s | Per-analysis Claude call |
227
227
  | Linting enabled | true | Runs linters before Claude analysis |
228
228
  | Linting auto-fix | true | Auto-fix and re-stage files |
229
229
  | Linting fail on error | true | Block commit on linting errors |
230
230
  | Linting fail on warn | false | Do not block on warnings |
231
- | Linting timeout | 30s | Per-linter timeout |
231
+ | Linting timeout | 30s | Per-linter timeout (tool-specific overrides if higher) |
232
+ | Spotless timeout | 120s | Per-invocation; overrides config default |
232
233
 
233
234
  **Judge behavior (v2.20.0):**
234
235
 
@@ -379,6 +380,10 @@ git commit
379
380
  → for each tool (formatters first, then linters):
380
381
  isToolAvailable() → not found? warn + install hint → skip
381
382
  filterFilesByTool() → matching files
383
+ → timeout = max(config.linting.timeout, toolDef.timeout)
384
+ → perFile tools (Spotless): resolve command path
385
+ .cmd/.bat → per-file mode (cmd.exe pipe safety)
386
+ otherwise → batch mode (single JVM startup)
382
387
  runToolWithAutoFix() → check → auto-fix → re-stage → re-check
383
388
  → unfixable issues forwarded to judge
384
389
 
@@ -1350,7 +1355,7 @@ Recurring patterns validated across 15+ automation sessions. Apply these in new
1350
1355
  - Enables centralized output control and debug mode
1351
1356
 
1352
1357
  9. **DO NOT execute Claude CLI without timeout**
1353
- - Always configure timeout (default: 150s analysis, 180s commit msg)
1358
+ - Always configure timeout (default: 360s analysis, 300s commit msg)
1354
1359
  - Timeout configurable in `.claude/config.json`
1355
1360
 
1356
1361
  10. **DO NOT ignore platform-specific issues**
package/lib/config.js CHANGED
@@ -33,7 +33,7 @@ const HARDCODED = {
33
33
  analysis: {
34
34
  maxFileSize: 1000000, // 1MB - sufficient for most files
35
35
  maxFiles: 30, // Reasonable limit per commit
36
- timeout: 300000, // 5 minutes - adequate for Claude API
36
+ timeout: 360000, // 6 minutes - adequate for Claude API
37
37
  contextLines: 3, // Git default
38
38
  ignoreExtensions: [] // Can be set in advanced config only
39
39
  },
@@ -28,7 +28,7 @@ import logger from './logger.js';
28
28
  import { recordMetric } from './metrics.js';
29
29
 
30
30
  const JUDGE_DEFAULT_MODEL = 'sonnet';
31
- const JUDGE_TIMEOUT = 180000;
31
+ const JUDGE_TIMEOUT = 360000;
32
32
 
33
33
  /**
34
34
  * Applies a single search/replace fix to a file and stages it
@@ -25,6 +25,7 @@ import {
25
25
  displayToolResult
26
26
  } from './tool-runner.js';
27
27
  import { getRepoRoot } from './git-operations.js';
28
+ import { which } from './which-command.js';
28
29
  import { fetchRemoteConfig } from './remote-config.js';
29
30
  import logger from './logger.js';
30
31
 
@@ -324,7 +325,7 @@ export const LINTER_TOOLS = {
324
325
  installHint: 'Add spotless-maven-plugin to pom.xml (see https://github.com/diffplug/spotless)',
325
326
  extensions: ['.java'],
326
327
  parseOutput: parseSpotlessOutput,
327
- timeout: 60000,
328
+ timeout: 120000,
328
329
  // Run per-file to avoid | (pipe) in regex on Windows.
329
330
  // filesToSpotlessRegex joins files with | for regex alternation.
330
331
  // cmd.exe interprets | as a pipe at every expansion level —
@@ -474,9 +475,13 @@ export async function runLinters(files, config, presetName = 'default') {
474
475
  }
475
476
  }
476
477
 
478
+ // Use the higher of config timeout and tool-specific timeout.
479
+ // Spotless (120s) should not be silently capped to the config default (30s).
480
+ const effectiveTimeout = Math.max(timeout, effectiveToolDef.timeout || 0);
481
+
477
482
  const toolOpts = {
478
483
  autoFix,
479
- timeout,
484
+ timeout: effectiveTimeout,
480
485
  restage: true,
481
486
  localBin: availability.localBin,
482
487
  toolCwd: availability.configDir
@@ -487,9 +492,29 @@ export async function runLinters(files, config, presetName = 'default') {
487
492
  // ^ escaping is consumed at the first parse, and %VAR% expansion in batch
488
493
  // scripts (mvn.cmd) re-exposes unescaped | to a second parse.
489
494
  // Running per-file ensures each invocation has a single-file regex (no |).
490
- if (effectiveToolDef.perFile && matchingFiles.length > 1) {
495
+ //
496
+ // However, per-file mode is ONLY needed when the command routes through
497
+ // cmd.exe (.cmd/.bat files). Direct executables and bash scripts (e.g.,
498
+ // mvnw) pass args to the process directly — | is never interpreted as a pipe.
499
+ // Batch mode avoids N separate JVM startups, which is critical for Spotless
500
+ // on Windows/WSL where each startup adds significant overhead.
501
+ let needsPerFile = effectiveToolDef.perFile && matchingFiles.length > 1;
502
+ if (needsPerFile) {
503
+ const resolvedCmd = effectiveToolDef.command.includes(path.sep)
504
+ ? effectiveToolDef.command
505
+ : (which(effectiveToolDef.command) || effectiveToolDef.command);
506
+ if (!/\.(cmd|bat)$/i.test(resolvedCmd)) {
507
+ needsPerFile = false;
508
+ logger.debug('linter-runner - runLinters',
509
+ `${effectiveToolDef.name} command bypasses cmd.exe, using batch mode`,
510
+ { command: resolvedCmd });
511
+ }
512
+ }
513
+
514
+ if (needsPerFile) {
491
515
  logger.debug('linter-runner - runLinters',
492
- `Running ${effectiveToolDef.name} per-file`, { fileCount: matchingFiles.length });
516
+ `Running ${effectiveToolDef.name} per-file (cmd.exe path)`,
517
+ { fileCount: matchingFiles.length });
493
518
 
494
519
  const perFileResults = matchingFiles.map((file) =>
495
520
  runToolWithAutoFix(effectiveToolDef, [file], toolOpts)
@@ -461,8 +461,9 @@ export function runTool(toolDef, files, options = {}) {
461
461
  const parsed = toolDef.parseOutput(err.stdout);
462
462
  result.errors = parsed.errors || [];
463
463
  result.warnings = parsed.warnings || [];
464
- } else if (err.killed) {
465
- // Timeout
464
+ } else if (err.killed || err.code === 'ETIMEDOUT') {
465
+ // Timeout — err.killed for Node.js timeout, ETIMEDOUT for OS-level
466
+ // spawn timeout (common on Windows when cmd.exe → JVM startup is slow)
466
467
  logger.warning(`${toolDef.name} timed out after ${timeout}ms`);
467
468
  result.errors.push({
468
469
  file: '',
@@ -543,7 +544,7 @@ export function runToolFix(toolDef, files, options = {}) {
543
544
  try {
544
545
  execFileSync(exec.command, exec.args, execOptions);
545
546
  } catch (err) {
546
- if (err.killed) {
547
+ if (err.killed || err.code === 'ETIMEDOUT') {
547
548
  logger.warning(`${toolDef.name} auto-fix timed out`);
548
549
  return { fixedFiles: [], fixedCount: 0 };
549
550
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-git-hooks",
3
- "version": "2.35.2",
3
+ "version": "2.35.3",
4
4
  "description": "Git hooks with Claude CLI for code analysis and automatic commit messages",
5
5
  "type": "module",
6
6
  "bin": {
@@ -284,7 +284,7 @@ cd python-django
284
284
  "analysis": {
285
285
  "maxFileSize": 1000000,
286
286
  "maxFiles": 12,
287
- "timeout": 180000
287
+ "timeout": 360000
288
288
  },
289
289
  "subagents": {
290
290
  "enabled": true,
@@ -308,7 +308,7 @@ cd python-django
308
308
  analysis: {
309
309
  maxFileSize: 1000000, // 1MB
310
310
  maxFiles: 30,
311
- timeout: 180000 // 3 minutes
311
+ timeout: 360000 // 6 minutes
312
312
  },
313
313
  subagents: {
314
314
  enabled: true,