claude-git-hooks 2.44.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,153 @@ 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
+
128
+ ## [2.45.0] - 2026-05-13
129
+
130
+ ### ✨ Added
131
+ - Added centralized config-registry module with local defaults and remote override support (SUE-138)
132
+ - Added lib/defaults.json as the single source of truth for all package default values (SUE-138)
133
+
134
+ ### 🔧 Changed
135
+ - Replaced inline hardcoded constants across modules with config-registry lookups — judge, orchestrator, Linear connector, model aliases, linter tools, and PR analysis categories now read from defaults.json with remote override capability (SUE-138)
136
+ - Updated config merge priority to HARDCODED < remote settings.json < defaults < preset < user overrides (SUE-138)
137
+ - Added config-registry mocks to unit tests for modules consuming centralized defaults (SUE-138)
138
+
139
+ ### 🐛 Fixed
140
+ - Fixed Linear ticket fetch issue (#155)
141
+
142
+
143
+ ## [2.44.1] - 2026-05-13
144
+
145
+ ### ✨ Added
146
+ - Added unit tests for linear-connector module covering ticket extraction, parsing, token loading, connection testing, and ticket fetching (SUE-154)
147
+
148
+ ### 🐛 Fixed
149
+ - Fixed help command to cap book reads at 5 in Pass 2, preventing oversized prompts when the LLM requests too many library books (SUE-154)
150
+
151
+ ### 🗑️ Removed
152
+ - Removed CLAUDE-MIGRATION.md — migration map no longer needed after library stabilization
153
+
154
+
8
155
  ## [2.44.0] - 2026-05-04
9
156
 
10
157
  ### ✨ 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,
@@ -33,6 +33,7 @@ import { promptConfirmation, promptMenu } from '../utils/interactive-ui.js';
33
33
  import { CostTracker } from '../utils/cost-tracker.js';
34
34
  import { colors, error, fatal, info, warning, checkGitRepo } from './helpers.js';
35
35
  import logger from '../utils/logger.js';
36
+ import { resolveSection } from '../utils/config-registry.js';
36
37
  import path from 'path';
37
38
 
38
39
  // ─── JSON Error Helper ────────────────────────────────────────────────────
@@ -380,23 +381,14 @@ export async function runAnalyzePr(args) {
380
381
  warning(`Could not load preset "${presetName}" guidelines, using defaults`);
381
382
  }
382
383
 
383
- // Step 7: Build category strings from config
384
- const inlineCategories = config.prAnalysis?.inlineCategories || [
385
- 'bug',
386
- 'security',
387
- 'performance',
388
- 'hotspot'
389
- ];
390
- const generalCategories = config.prAnalysis?.generalCategories || [
391
- 'ticket-alignment',
392
- 'scope',
393
- 'style',
394
- 'good-practice',
395
- 'extensibility',
396
- 'observability',
397
- 'documentation',
398
- 'testing'
399
- ];
384
+ // Step 7: Build category strings from config (remote categories.json > local defaults)
385
+ // Categories are guaranteed by defaults.json loaded at import time via config-registry.
386
+ // The || [] fallback guards against unexpected config corruption or a missing section.
387
+ const resolvedPrAnalysis = await resolveSection('prAnalysis');
388
+ const inlineCategories = resolvedPrAnalysis?.inlineCategories ||
389
+ config.prAnalysis?.inlineCategories || [];
390
+ const generalCategories = resolvedPrAnalysis?.generalCategories ||
391
+ config.prAnalysis?.generalCategories || [];
400
392
  const allCategories = [...inlineCategories, ...generalCategories];
401
393
 
402
394
  const inlineCategoriesStr = inlineCategories.map((c) => `- \`${c}\``).join('\n');
@@ -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
@@ -164,11 +165,13 @@ function printAiResponse(response, source) {
164
165
  const _packageRoot = path.join(__dirname, '..', '..');
165
166
 
166
167
  /**
167
- * Catalog directories within .library/ to auto-discover
168
- * Why: These contain index and shelf files that form the navigational catalog.
169
- * books/ is excluded those are fetched on-demand in Pass 2.
168
+ * Maximum number of books to read in Pass 2.
169
+ * Why: Matches the "do not request more than 5" instruction in HELP_NAVIGATE.md.
170
+ * Caps LLM-sourced lists to prevent oversized prompts that would fail the second call.
170
171
  */
171
- const _CATALOG_DIRS = ['by-code', 'by-domain', 'by-task-type'];
172
+ const MAX_BOOKS = 5;
173
+
174
+ // Catalog routing delegated to the librarian module; see .library/librarian/
172
175
 
173
176
  /**
174
177
  * Read a single file from package root, returning null on failure
@@ -187,67 +190,27 @@ const _readPackageFile = async (relativePath) => {
187
190
  /**
188
191
  * Read the project catalog from .library/ and CLAUDE.md
189
192
  * Why: The catalog provides navigational context for the AI librarian (Pass 1).
190
- * Auto-discovers index/shelf files so the catalog stays current as .library/ grows.
191
- *
192
- * Reads:
193
- * - CLAUDE.md (global rules)
194
- * - .library/index.md (repo identity, capabilities)
195
- * - .library/conventions.md (coding standards)
196
- * - .library/by-code/*.md (source-path shelves)
197
- * - .library/by-domain/*.md (workflow reading lists)
198
- * - .library/by-task-type/*.md (task guidance)
193
+ * Delegates to the librarian module for directory discovery and routing.
199
194
  *
200
195
  * @returns {Promise<string|null>} Concatenated catalog or null if nothing could be read
201
196
  */
202
197
  const readLibraryCatalog = async () => {
203
- const sections = [];
204
-
205
- // Fixed files: CLAUDE.md + core library files
206
- const fixedFiles = [
207
- { label: 'CLAUDE.md', path: 'CLAUDE.md' },
208
- { label: '.library/index.md', path: '.library/index.md' },
209
- { label: '.library/conventions.md', path: '.library/conventions.md' }
210
- ];
211
-
212
- for (const file of fixedFiles) {
213
- const content = await _readPackageFile(file.path);
214
- if (content) {
215
- sections.push(`--- ${file.label} ---\n${content}`);
216
- }
217
- }
218
-
219
- // Auto-discover .md files in each catalog directory
220
- for (const dir of _CATALOG_DIRS) {
221
- const dirPath = path.join(_packageRoot, '.library', dir);
222
- let entries;
223
- try {
224
- entries = await fs.readdir(dirPath);
225
- } catch {
226
- logger.debug('help - readLibraryCatalog', `Could not read .library/${dir}/`);
227
- continue;
228
- }
229
-
230
- const mdFiles = entries.filter((f) => f.endsWith('.md')).sort();
231
- for (const file of mdFiles) {
232
- const relativePath = `.library/${dir}/${file}`;
233
- const content = await _readPackageFile(relativePath);
234
- if (content) {
235
- sections.push(`--- ${relativePath} ---\n${content}`);
236
- }
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
+ });
237
206
  }
238
- }
239
-
240
- if (sections.length === 0) {
241
- 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
+ });
242
212
  return null;
243
213
  }
244
-
245
- const catalog = sections.join('\n\n');
246
- logger.debug('help - readLibraryCatalog', 'Catalog loaded', {
247
- sections: sections.length,
248
- length: catalog.length
249
- });
250
- return catalog;
251
214
  };
252
215
 
253
216
  /**
@@ -346,6 +309,14 @@ async function readAndAnswerWithBooks(booksLine, question, catalog) {
346
309
  return null;
347
310
  }
348
311
 
312
+ if (bookPaths.length > MAX_BOOKS) {
313
+ logger.debug('help - readAndAnswerWithBooks', 'Capping book list', {
314
+ requested: bookPaths.length,
315
+ max: MAX_BOOKS
316
+ });
317
+ bookPaths.length = MAX_BOOKS;
318
+ }
319
+
349
320
  logger.debug('help - readAndAnswerWithBooks', 'Reading books from disk', { bookPaths });
350
321
 
351
322
  // Read books from local filesystem in parallel