claude-git-hooks 2.45.0 → 2.51.2

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,126 @@ 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.51.2] - 2026-05-26
9
+
10
+ ### 🔧 Changed
11
+ - Made library integration visible in CLI (#164)
12
+
13
+ ### 🐛 Fixed
14
+ - Fixed partial file selection during version bump — `updateVersionFiles` no longer silently skips unselected files; callers now filter before calling, ensuring only user-selected files are bumped (AUT-3733)
15
+
16
+
17
+ ## [2.51.1] - 2026-05-25
18
+
19
+ ### ✨ Added
20
+ - Specification guide (SPEC_GUIDE.md) — a practitioner's guide to building a Code Knowledge Library, covering setup, schema, taxonomy, maintenance, and worked examples (AUT-3722)
21
+ - Overlap-check tool for detecting book content overlap, closing Library milestone M4 (AUT-3722, #162)
22
+ - Maps/ artifacts (dependency graph, co-change seeds) surfaced via librarian module for programmatic access (AUT-3722)
23
+
24
+ ### 🔧 Changed
25
+ - Rewrote Library README as a specification-oriented guide with clearer structure, worked examples, milestone status tracking, and getting-started table (AUT-3722)
26
+ - Rewrote CLAUDE.md Library section to align with specification guide format and reference SPEC_GUIDE.md (AUT-3722)
27
+ - Made Library integration visible in CLI output so users can discover library-powered features (#163)
28
+
29
+
30
+ ## [2.51.0] - 2026-05-25
31
+
32
+ ### ✨ Added
33
+ - Added unified Library CLI at `.library/bin/library` with commands: check, regenerate, extract, tokens, graph, inject, validate, report (AUT-3272)
34
+ - Added centralized path resolution module (`.library/paths.js`) with resolver.yaml parser for repository-agnostic Library adoption
35
+ - Added Library CLI command registry (`.library/cli.js`) following the same pattern as `lib/cli-metadata.js`
36
+ - Added Library staleness checks to workflow commands: non-blocking warnings in `pre-commit`, `analyze-diff`, and `create-pr`; blocking gates in `create-release` and `close-release` (AUT-3272)
37
+ - Added co-change reference injection to `back-merge` command — automatically refreshes Library references after post-deploy merge (AUT-3272)
38
+ - Added `source:` field to `resolver.yaml` for configurable source directory resolution
39
+ - Added M5 validation results to Library README — hypothesis validated with modest effect size (0.7% mean token reduction, 8/8 accuracy parity)
40
+ - Added npm scripts for all Library CLI commands: `library:check`, `library:regenerate`, `library:extract`, `library:validate`, `library:report`
41
+ - Added N-gram overlap-check tool that compares CLAUDE.md against Library files, audits pointers, and categorises retained sections (AUT-3722)
42
+ - Added Specification Guide (SPEC_GUIDE.md) — a self-contained practitioner's guide for building a Code Knowledge Library in any repository (AUT-3722)
43
+ - Added maps/ artifact resolution to librarian — direct access via @maps/ paths and heuristic routing for co-change, dependency graph, and methodology queries (AUT-3722)
44
+ - Added co-change references to books via PR #161 (AUT-3315)
45
+
46
+ ### 🔧 Changed
47
+ - Refactored all Library tools (`staleness.js`, `generate-graph.js`, `inject-co-change.js`, `measure-tokens.js`, `extract.js`, `librarian/index.js`) to use centralized `paths.js` instead of per-tool `__dirname` arithmetic (AUT-3272)
48
+ - Rewrote `.library/README.md` with adoption guide, command reference, book schema documentation, and automated maintenance via git hooks section
49
+ - Replaced legacy npm scripts (`library:tokens`, `library:graph`, `library:extract-poc`, `library:inject-co-change`) with unified CLI-routed equivalents
50
+ - Updated `jest.config.js` to ignore tests inside `.claude/worktrees/` directories
51
+ - Bumped `last_verified` dates to 2026-05-22 across all 70 Library books
52
+ - Rewrote Library README as a specification-oriented guide — restructured around how the Library works (books, indexes, resolver, librarian, auto-generation) rather than operational steps (AUT-3722)
53
+ - Rewrote CLAUDE.md Library section to reference the Specification Guide instead of duplicating Library documentation (AUT-3722)
54
+ - Closed M4 milestone — resolved OPEN items 1–5 in SPEC_GUIDE § 13 with evidence and deferral justifications (AUT-3722)
55
+
56
+
57
+ ## [2.50.0] - 2026-05-20
58
+
59
+ ### ✨ Added
60
+ - Added co-change reference tracking to library books — frontmatter now includes `co_change_references` with commit counts, confidence scores, and trigger descriptions for files that historically change together (AUT-3315)
61
+ - Added `CO_CHANGE_SEEDS.md` co-change seed patterns document with 4 architectural coupling patterns mined from 6 months of git history (AUT-3315)
62
+ - Added `inject-co-change.js` CLI tool to inject co-change references from seed patterns into book frontmatter, with `--dry-run`, `--json`, and `--seeds` options (AUT-3315)
63
+ - Added librarian module for automated library maintenance pipeline (#160)
64
+
65
+ ### 🔧 Changed
66
+ - Moved staleness detection scripts from `.library/maintenance/` to `.library/tools/` directory (AUT-3315)
67
+ - Updated `.library/maps/` directory scope to include co-change seeds and token reports (AUT-3315)
68
+ - Updated `.library/tools/` directory scope to cover all standalone CLI utilities — staleness, graph, tokens, and co-change injection (AUT-3315)
69
+
70
+
71
+ ## [2.49.0] - 2026-05-19
72
+
73
+ ### ✨ Added
74
+ - Librarian module for Library maintenance pipeline with five core functions: fetch, regenerate, checkOverflow, solicitGotchas, and buildReport (AUT-3309)
75
+ - Execution prompt for running full regeneration cycles via Sonnet sessions (AUT-3309)
76
+ - Report template for structured maintenance cycle output (AUT-3309)
77
+ - Staleness detector for tracking book drift via AST hash comparison (#159, AUT-3307)
78
+
79
+ ### 🔧 Changed
80
+ - Renamed librarian `fetch` export to `fetchLibraryContent` for clarity (AUT-3309)
81
+ - Updated Library README with comprehensive documentation covering auto-generation, staleness detection, librarian module, and maintenance workflow
82
+ - Book schema `generated_from` field now supports AST hash format (`ast:sha256:<hex>`) for staleness tracking
83
+ - Library book count updated from 26 to 70 reflecting auto-generated coverage
84
+
85
+
86
+ ## [2.48.0] - 2026-05-19
87
+
88
+ ### ✨ Added
89
+ - Added staleness detector for library books to identify outdated documentation (AUT-3307)
90
+
91
+ ### 🗑️ Removed
92
+ - Removed extractor evaluation artifacts (PARSER_DECISION.md, QUALITY_GAP.md) after library auto-update evaluation completed (#158, AUT-3305)
93
+
94
+
95
+ ## [2.47.1] - 2026-05-19
96
+
97
+ ### 🐛 Fixed
98
+ - Fixed path normalization in AST extractor for Windows compatibility by using `fileURLToPath()` instead of raw URL pathname and normalizing backslashes in relative paths (AUT-3305)
99
+ - Fixed cross-platform book file detection in help catalog by using regex path separator matching instead of literal forward slash
100
+
101
+
102
+ ## [2.47.0] - 2026-05-19
103
+
104
+ ### ✨ Added
105
+ - Quality gap report and batch runner for the AST documentation extractor (AUT-3305)
106
+ - "preserve-if-filled" strategy for the AST extractor to retain manually-written book sections during regeneration (AUT-3305)
107
+
108
+ ### 🔧 Changed
109
+ - Regenerated all library book documentation from AST extractor output, replacing manually-maintained books with accurate cross-references and call signatures (AUT-3305, PR #157)
110
+
111
+
112
+ ## [2.46.0] - 2026-05-18
113
+
114
+ ### ✨ Added
115
+ - Added AST extractor POC with JavaScript and Python language adapters (AUT-3273)
116
+ - Added source-to-book auto-section generator for automated library documentation (AUT-3273)
117
+ - Generated book stubs for 40 source modules in `.library/books/` (AUT-3273)
118
+ - Added centralized configuration registry (`config-registry.js` + `defaults.json`) with remote override support (#156, ISSUE-138)
119
+
120
+ ### 🔧 Changed
121
+ - Configuration merge priority expanded from 4 to 5 layers, adding remote `settings.json` team-policy overrides (#156)
122
+ - Orchestrator model, threshold, and timeout are now configurable via remote `settings.json` instead of hardcoded values (#156)
123
+ - Judge timeout now configurable via remote `settings.json` (#156)
124
+ - Updated library README and shelf indexes to reflect new book count (AUT-3273)
125
+ - ESLint config updated to include `.library/extractor/` files (AUT-3273)
126
+
127
+
8
128
  ## [2.45.0] - 2026-05-13
9
129
 
10
130
  ### ✨ Added
package/CLAUDE.md CHANGED
@@ -1,8 +1,8 @@
1
- # Repository Context
1
+ # claude-git-hooks
2
2
 
3
- `claude-git-hooks` — intelligent Git hooks system integrating Claude CLI for code analysis, commit message generation, PR creation, and release workflow automation.
3
+ Intelligent Git hooks system integrating Claude CLI for code analysis, commit message generation, PR creation, and release workflow automation.
4
4
 
5
- ## Context Acquisition
5
+ ## Library
6
6
 
7
7
  All project knowledge lives in [`.library/`](.library/). Start at [`.library/index.md`](.library/index.md).
8
8
 
@@ -10,15 +10,16 @@ Load context based on your current task:
10
10
 
11
11
  | Task | Load |
12
12
  |------|------|
13
- | Writing or modifying code | [`.library/conventions.md`](.library/conventions.md) — coding standards, testing patterns |
14
- | Understanding a source module | [`.library/by-code/`](.library/by-code/) — find the book for that file |
15
- | Understanding a business workflow | [`.library/by-domain/`](.library/by-domain/) — commit pipeline, release management, PR analysis, GitHub integration |
16
- | Adding a new CLI command | [`.library/by-task-type/add-new-command.md`](.library/by-task-type/add-new-command.md) — 7-book reading sequence |
17
- | Updating the library after code changes | [`.library/README.md`](.library/README.md) — book schema, template, creation steps |
13
+ | Writing or modifying code | `conventions.md` (Library root) — coding standards, testing patterns |
14
+ | Understanding a source module | `@by-code/` — find the book for that file |
15
+ | Understanding a business workflow | `@by-domain/` — commit pipeline, release management, PR analysis, GitHub integration |
16
+ | Adding a new CLI command | `@by-task-type/add-new-command.md` — 7-book reading sequence |
18
17
 
19
- Books follow a standard template at `.library/templates/book-template.md`. After modifying a module, update its book and the relevant shelf index.
18
+ **Programmatic access**: `fetchLibraryContent(taskOrTopic)` in `.library/librarian/index.js` loads CLAUDE.md + index.md + conventions.md as fixed context, then routes the topic to the relevant index.
20
19
 
21
- ## Global Rules
20
+ **Budget-aware loading**: Every index carries `reading_cost_tokens`; task-type sequences split into core vs conditional books. Check token budgets before loading full sequences.
21
+
22
+ ## Rules
22
23
 
23
24
  These behavioral rules apply to all work in this repository:
24
25
 
@@ -31,5 +32,3 @@ These behavioral rules apply to all work in this repository:
31
32
  7. **Do NOT use `console.log`** — always use `logger.js`: `info()`, `warning()`, `error()`, `debug()`
32
33
  8. **Platform-specific care** — use `path.join()` (no hardcoded `/`); test on Windows, Linux, macOS
33
34
  9. **Input sanitization** — use `sanitize.js` for user inputs in shell commands; avoid `shell: true` in `spawn()`
34
-
35
- > See [`CLAUDE-MIGRATION.md`](CLAUDE-MIGRATION.md) for a mapping of where each original CLAUDE.md section moved.
package/README.md CHANGED
@@ -529,6 +529,13 @@ claude-git-hooks/
529
529
  │ ├── diff-analysis-orchestrator.js # Intelligent batch orchestration
530
530
  │ ├── judge.js # Auto-fix judge (v2.20.0)
531
531
  │ └── token-store.js # Token persistence - settings.local.json
532
+ ├── .library/ # Code Knowledge Library - auto-generated module docs
533
+ │ ├── books/ # One book per source module (auto + manual sections)
534
+ │ ├── extractor/ # Tree-sitter AST tooling
535
+ │ │ ├── extract.js # Source → book auto-section generator
536
+ │ │ ├── parser.js # WASM parser init and grammar loading
537
+ │ │ └── adapters/ # Language-specific CST → normalized AST
538
+ │ └── templates/ # Book schema and category reference
532
539
  ├── templates/
533
540
  │ ├── pre-commit # Bash wrapper - invokes Node.js
534
541
  │ ├── prepare-commit-msg # Bash wrapper - invokes Node.js
@@ -93,6 +93,33 @@ export async function runAnalyzeDiff(args) {
93
93
  console.log(result.testingNotes);
94
94
  }
95
95
 
96
+ // Library staleness section
97
+ try {
98
+ const { runAll } = await import('../../.library/tools/staleness.js');
99
+ const { getSourceDir, getBooksDir } = await import('../../.library/paths.js');
100
+ const { getRepoRoot } = await import('../utils/git-operations.js');
101
+ const stalenessResult = await runAll(getBooksDir(), getSourceDir(), getRepoRoot(), false);
102
+ const staleCount = stalenessResult.stale.length +
103
+ stalenessResult.orphan_books.length +
104
+ stalenessResult.unbooked_sources.length;
105
+ if (staleCount > 0) {
106
+ console.log('');
107
+ console.log(`📚 ${colors.yellow}Library Staleness:${colors.reset} ${staleCount} book(s) need attention`);
108
+ for (const item of stalenessResult.stale) {
109
+ console.log(` └─ stale: ${item.book}`);
110
+ }
111
+ for (const item of stalenessResult.orphan_books) {
112
+ console.log(` └─ orphan: ${item.book}`);
113
+ }
114
+ for (const src of stalenessResult.unbooked_sources) {
115
+ console.log(` └─ unbooked: ${src}`);
116
+ }
117
+ console.log(' Run: npm run library:regenerate');
118
+ }
119
+ } catch {
120
+ logger.warning('📚 Library staleness check unavailable — .library/ tools not found');
121
+ }
122
+
96
123
  // Save the results in a file with context
97
124
  const outputData = {
98
125
  prTitle: result.prTitle,
@@ -719,6 +719,20 @@ export async function runBackMerge(args) {
719
719
  await _revertFollowup(rcBranchForLog, repoRoot);
720
720
  }
721
721
 
722
+ // 18b. Co-change injection — refresh library references with newly merged history
723
+ if (pushStatus === 'pushed') {
724
+ try {
725
+ const { main: injectCoChange } = await import('../../.library/tools/inject-co-change.js');
726
+ showInfo('📚 Refreshing library co-change references...');
727
+ await injectCoChange(['node', 'inject-co-change.js']);
728
+ showSuccess('✓ Co-change references updated');
729
+ } catch (err) {
730
+ showWarning('📚 Co-change injection unavailable — .library/ tools not found');
731
+ logger.debug('back-merge', 'Co-change injection skipped', { error: err.message });
732
+ }
733
+ console.log('');
734
+ }
735
+
722
736
  // 19. Summary
723
737
  console.log('');
724
738
  console.log(`${colors.green}═════════════════════════════════════════════════${colors.reset}`);
@@ -356,6 +356,28 @@ export async function runCloseRelease(args) {
356
356
  console.log('');
357
357
 
358
358
  try {
359
+ // Library staleness gate — block release closure if books are stale
360
+ try {
361
+ showInfo('📚 Checking library staleness...');
362
+ const { runAll, formatHuman } = await import('../../.library/tools/staleness.js');
363
+ const { getSourceDir, getBooksDir } = await import('../../.library/paths.js');
364
+ const { getRepoRoot } = await import('../utils/git-operations.js');
365
+ const stalenessResult = await runAll(getBooksDir(), getSourceDir(), getRepoRoot(), false);
366
+ const hasDrift = stalenessResult.stale.length > 0 ||
367
+ stalenessResult.orphan_books.length > 0 ||
368
+ stalenessResult.unbooked_sources.length > 0;
369
+ if (hasDrift) {
370
+ error('📚 Library staleness detected — cannot close release with stale books');
371
+ process.stdout.write(formatHuman(stalenessResult));
372
+ error('Run: npm run library:regenerate');
373
+ process.exit(1);
374
+ }
375
+ showSuccess('📚 Library books are current');
376
+ } catch (err) {
377
+ showWarning('📚 Library staleness check unavailable — .library/ tools not found');
378
+ logger.debug('close-release', 'Library staleness check skipped', { error: err.message });
379
+ }
380
+
359
381
  // ── Step 7: git reset --soft origin/main ─────────────────────────────
360
382
 
361
383
  showInfo('Resetting to origin/main (--soft)...');
@@ -765,6 +765,38 @@ export async function runCreatePr(args) {
765
765
  finalBody = `> ⚠️ This PR must be merged with **merge commit** (not squash)\n\n${prBody}`;
766
766
  }
767
767
 
768
+ // Library staleness section — informational, non-blocking
769
+ try {
770
+ showInfo('📚 Checking library staleness...');
771
+ const { checkBook } = await import('../../.library/tools/staleness.js');
772
+ const { getBooksDir } = await import('../../.library/paths.js');
773
+ const { getRepoRoot } = await import('../utils/git-operations.js');
774
+ const booksDir = getBooksDir();
775
+ const root = getRepoRoot();
776
+ const changedSourceFiles = (filesArray || [])
777
+ .map(f => f.path || f)
778
+ .filter(p => p.startsWith('lib/') && p.endsWith('.js'));
779
+ const staleBooks = [];
780
+ for (const srcPath of changedSourceFiles) {
781
+ const bookName = `${srcPath.replace(/^lib\/.*\//, '').replace(/\.js$/, '')}.md`;
782
+ try {
783
+ const result = await checkBook(path.join(booksDir, bookName), root);
784
+ if (result.status === 'stale') staleBooks.push(bookName);
785
+ } catch {
786
+ // skip
787
+ }
788
+ }
789
+ if (staleBooks.length > 0) {
790
+ const bookList = staleBooks.map(b => `- \`${b}\``).join('\n');
791
+ finalBody += `\n\n---\n\n### 📚 Library Staleness\n\nThe following library books may need regeneration:\n\n${bookList}\n\nRun: \`npm run library:regenerate\``;
792
+ showWarning(`📚 ${staleBooks.length} stale book(s) — section added to PR body`);
793
+ } else if (changedSourceFiles.length > 0) {
794
+ showSuccess('📚 Library books are current');
795
+ }
796
+ } catch {
797
+ showWarning('📚 Library staleness check unavailable — .library/ tools not found');
798
+ }
799
+
768
800
  // Step 10: Get reviewers from team + config fallback
769
801
  logger.debug('create-pr', 'Step 10: Selecting reviewers via team resolution');
770
802
  const reviewers = await selectReviewers({
@@ -388,6 +388,28 @@ export async function runCreateRelease(args) {
388
388
  const config = await getConfig();
389
389
  const selectedFiles = discovery.files.filter((f) => f.selected);
390
390
 
391
+ // Library staleness gate — block release if books are stale
392
+ try {
393
+ showInfo('📚 Checking library staleness...');
394
+ const { runAll, formatHuman } = await import('../../.library/tools/staleness.js');
395
+ const { getSourceDir, getBooksDir } = await import('../../.library/paths.js');
396
+ const { getRepoRoot } = await import('../utils/git-operations.js');
397
+ const stalenessResult = await runAll(getBooksDir(), getSourceDir(), getRepoRoot(), false);
398
+ const hasDrift = stalenessResult.stale.length > 0 ||
399
+ stalenessResult.orphan_books.length > 0 ||
400
+ stalenessResult.unbooked_sources.length > 0;
401
+ if (hasDrift) {
402
+ showError('📚 Library staleness detected — cannot create release with stale books');
403
+ process.stdout.write(formatHuman(stalenessResult));
404
+ showError('Run: npm run library:regenerate');
405
+ process.exit(1);
406
+ }
407
+ showSuccess('📚 Library books are current');
408
+ } catch (err) {
409
+ showWarning('📚 Library staleness check unavailable — .library/ tools not found');
410
+ logger.debug('create-release', 'Library staleness check skipped', { error: err.message });
411
+ }
412
+
391
413
  // Step 6: Create RC branch from develop
392
414
  logger.debug('create-release', 'Step 6: Creating RC branch', { rcBranch });
393
415
  showInfo(`Creating branch ${rcBranch} from ${SOURCE_BRANCH}...`);
@@ -18,6 +18,7 @@ import { fetchFileContent, fetchDirectoryListing, createIssue } from '../utils/g
18
18
  import { promptMenu, promptEditField, promptConfirmation } from '../utils/interactive-ui.js';
19
19
  import logger from '../utils/logger.js';
20
20
  import { commands } from '../cli-metadata.js';
21
+ import { fetchLibraryContent as librarianFetch } from '../../.library/librarian/index.js';
21
22
 
22
23
  /**
23
24
  * Get claude-hooks source repo coordinates from package.json
@@ -170,12 +171,7 @@ const _packageRoot = path.join(__dirname, '..', '..');
170
171
  */
171
172
  const MAX_BOOKS = 5;
172
173
 
173
- /**
174
- * Catalog directories within .library/ to auto-discover
175
- * Why: These contain index and shelf files that form the navigational catalog.
176
- * books/ is excluded — those are fetched on-demand in Pass 2.
177
- */
178
- const _CATALOG_DIRS = ['by-code', 'by-domain', 'by-task-type'];
174
+ // Catalog routing delegated to the librarian module; see .library/librarian/
179
175
 
180
176
  /**
181
177
  * Read a single file from package root, returning null on failure
@@ -194,67 +190,27 @@ const _readPackageFile = async (relativePath) => {
194
190
  /**
195
191
  * Read the project catalog from .library/ and CLAUDE.md
196
192
  * Why: The catalog provides navigational context for the AI librarian (Pass 1).
197
- * Auto-discovers index/shelf files so the catalog stays current as .library/ grows.
198
- *
199
- * Reads:
200
- * - CLAUDE.md (global rules)
201
- * - .library/index.md (repo identity, capabilities)
202
- * - .library/conventions.md (coding standards)
203
- * - .library/by-code/*.md (source-path shelves)
204
- * - .library/by-domain/*.md (workflow reading lists)
205
- * - .library/by-task-type/*.md (task guidance)
193
+ * Delegates to the librarian module for directory discovery and routing.
206
194
  *
207
195
  * @returns {Promise<string|null>} Concatenated catalog or null if nothing could be read
208
196
  */
209
197
  const readLibraryCatalog = async () => {
210
- const sections = [];
211
-
212
- // Fixed files: CLAUDE.md + core library files
213
- const fixedFiles = [
214
- { label: 'CLAUDE.md', path: 'CLAUDE.md' },
215
- { label: '.library/index.md', path: '.library/index.md' },
216
- { label: '.library/conventions.md', path: '.library/conventions.md' }
217
- ];
218
-
219
- for (const file of fixedFiles) {
220
- const content = await _readPackageFile(file.path);
221
- if (content) {
222
- sections.push(`--- ${file.label} ---\n${content}`);
223
- }
224
- }
225
-
226
- // Auto-discover .md files in each catalog directory
227
- for (const dir of _CATALOG_DIRS) {
228
- const dirPath = path.join(_packageRoot, '.library', dir);
229
- let entries;
230
- try {
231
- entries = await fs.readdir(dirPath);
232
- } catch {
233
- logger.debug('help - readLibraryCatalog', `Could not read .library/${dir}/`);
234
- continue;
235
- }
236
-
237
- const mdFiles = entries.filter((f) => f.endsWith('.md')).sort();
238
- for (const file of mdFiles) {
239
- const relativePath = `.library/${dir}/${file}`;
240
- const content = await _readPackageFile(relativePath);
241
- if (content) {
242
- sections.push(`--- ${relativePath} ---\n${content}`);
243
- }
198
+ // Fetching delegated to the librarian module; see .library/librarian/
199
+ try {
200
+ const result = await librarianFetch(null, { repoRoot: _packageRoot, full: true });
201
+ if (result.catalog) {
202
+ logger.debug('help - readLibraryCatalog', 'Catalog loaded via librarian', {
203
+ files: result.readingList.length,
204
+ length: result.catalog.length
205
+ });
244
206
  }
245
- }
246
-
247
- if (sections.length === 0) {
248
- logger.debug('help - readLibraryCatalog', 'No catalog files found');
207
+ return result.catalog;
208
+ } catch (err) {
209
+ logger.debug('help - readLibraryCatalog', 'Librarian fetch failed', {
210
+ error: err.message
211
+ });
249
212
  return null;
250
213
  }
251
-
252
- const catalog = sections.join('\n\n');
253
- logger.debug('help - readLibraryCatalog', 'Catalog loaded', {
254
- sections: sections.length,
255
- length: catalog.length
256
- });
257
- return catalog;
258
214
  };
259
215
 
260
216
  /**
@@ -19,6 +19,7 @@
19
19
  * - resolution-prompt: Issue resolution generation
20
20
  */
21
21
 
22
+ import { join } from 'path';
22
23
  import { getStagedFiles, getRepoRoot, getStagedTreeSha } from '../utils/git-operations.js';
23
24
  import { writeMarker } from '../utils/hooks-verified-marker.js';
24
25
  import { filterFiles } from '../utils/file-operations.js';
@@ -150,6 +151,41 @@ const main = async () => {
150
151
  process.exit(0);
151
152
  }
152
153
 
154
+ // Library staleness check — non-blocking warning
155
+ try {
156
+ const { checkBook } = await import('../../.library/tools/staleness.js');
157
+ const { getBooksDir } = await import('../../.library/paths.js');
158
+ const booksDir = getBooksDir();
159
+ const sourceFiles = validFiles
160
+ .map(f => (typeof f === 'string' ? f : f.path))
161
+ .filter(p => p.startsWith('lib/'));
162
+
163
+ if (sourceFiles.length > 0) {
164
+ const staleBooks = [];
165
+ for (const srcPath of sourceFiles) {
166
+ const bookName = `${srcPath.replace(/^lib\/(?:.*\/)?/, '').replace(/\.js$/, '')}.md`;
167
+ const bookPath = join(booksDir, bookName);
168
+ try {
169
+ const result = await checkBook(bookPath, getRepoRoot());
170
+ if (result.status === 'stale') {
171
+ staleBooks.push(result.book);
172
+ }
173
+ } catch {
174
+ // Book doesn't exist or check failed — skip silently
175
+ }
176
+ }
177
+ if (staleBooks.length > 0) {
178
+ logger.warning(`📚 ${staleBooks.length} library book(s) will become stale after this commit`);
179
+ for (const book of staleBooks) {
180
+ logger.warning(` └─ ${book}`);
181
+ }
182
+ logger.warning(' Run: npm run library:regenerate');
183
+ }
184
+ }
185
+ } catch {
186
+ logger.warning('📚 Library staleness check unavailable — .library/ tools not found');
187
+ }
188
+
153
189
  // Step 3: Run linters (fast, deterministic — before Claude analysis)
154
190
  // Unfixable lint issues are forwarded to the judge for semantic resolution
155
191
  let unfixableLintDetails = [];
@@ -377,11 +377,13 @@ export function writeVersionToFile(filePath, type, newVersion) {
377
377
  }
378
378
 
379
379
  /**
380
- * Updates version in selected files
381
- * Why: Applies version update to specific VersionFileDescriptor[] subset
380
+ * Updates version in the given files (resolved mutations from the selector)
381
+ * Why: Applies version update to the concrete list of files the caller provides.
382
+ * Every item in the array is a mutation to apply — the caller is responsible
383
+ * for filtering before calling this function.
382
384
  *
383
- * @param {Array} files - Array of VersionFileDescriptor objects with selected=true
384
- * @param {string} newVersion - New version string
385
+ * @param {Array} files - Array of VersionFileDescriptor objects to update
386
+ * @param {string} newVersion - New version string (used when file has no targetVersion)
385
387
  */
386
388
  export function updateVersionFiles(files, newVersion) {
387
389
  logger.debug('version-manager - updateVersionFiles', 'Updating version files', {
@@ -402,10 +404,6 @@ export function updateVersionFiles(files, newVersion) {
402
404
  const errors = [];
403
405
 
404
406
  for (const file of files) {
405
- if (!file.selected) {
406
- continue; // Skip unselected files
407
- }
408
-
409
407
  try {
410
408
  // Verify file still exists
411
409
  if (!fs.existsSync(file.path)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-git-hooks",
3
- "version": "2.45.0",
3
+ "version": "2.51.2",
4
4
  "description": "Git hooks with Claude CLI for code analysis and automatic commit messages",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,8 +21,14 @@
21
21
  "format": "prettier --write \"lib/**/*.js\" \"bin/**\" \"test/**/*.js\"",
22
22
  "precommit": "npm run lint && npm run test:smoke",
23
23
  "prepublishOnly": "npm run test:all",
24
- "library:tokens": "node .library/tools/measure-tokens.js",
25
- "library:graph": "node .library/tools/generate-graph.js"
24
+ "library:check": "node .library/bin/library check",
25
+ "library:regenerate": "node .library/bin/library regenerate",
26
+ "library:extract": "node .library/bin/library extract",
27
+ "library:tokens": "node .library/bin/library tokens",
28
+ "library:graph": "node .library/bin/library graph",
29
+ "library:inject": "node .library/bin/library inject",
30
+ "library:validate": "node .library/bin/library validate",
31
+ "library:report": "node .library/bin/library report"
26
32
  },
27
33
  "keywords": [
28
34
  "git",
@@ -70,6 +76,8 @@
70
76
  "jest": "^29.7.0",
71
77
  "js-tiktoken": "^1.0.18",
72
78
  "madge": "^8.0.0",
73
- "prettier": "^3.2.0"
79
+ "prettier": "^3.2.0",
80
+ "tree-sitter-wasms": "^0.1.13",
81
+ "web-tree-sitter": "^0.24.7"
74
82
  }
75
83
  }