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 +15 -0
- package/CLAUDE.md +9 -4
- package/lib/config.js +1 -1
- package/lib/utils/judge.js +1 -1
- package/lib/utils/linter-runner.js +29 -4
- package/lib/utils/tool-runner.js +4 -3
- package/package.json +1 -1
- package/templates/CUSTOMIZATION_GUIDE.md +2 -2
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 |
|
|
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 |
|
|
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:
|
|
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:
|
|
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
|
},
|
package/lib/utils/judge.js
CHANGED
|
@@ -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 =
|
|
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:
|
|
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
|
-
|
|
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
|
|
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)
|
package/lib/utils/tool-runner.js
CHANGED
|
@@ -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
|
@@ -284,7 +284,7 @@ cd python-django
|
|
|
284
284
|
"analysis": {
|
|
285
285
|
"maxFileSize": 1000000,
|
|
286
286
|
"maxFiles": 12,
|
|
287
|
-
"timeout":
|
|
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:
|
|
311
|
+
timeout: 360000 // 6 minutes
|
|
312
312
|
},
|
|
313
313
|
subagents: {
|
|
314
314
|
enabled: true,
|