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 +147 -0
- package/CLAUDE.md +11 -12
- package/README.md +7 -0
- package/lib/commands/analyze-diff.js +27 -0
- package/lib/commands/analyze-pr.js +9 -17
- package/lib/commands/back-merge.js +14 -0
- package/lib/commands/close-release.js +22 -0
- package/lib/commands/create-pr.js +32 -0
- package/lib/commands/create-release.js +22 -0
- package/lib/commands/help.js +29 -58
- package/lib/config.js +19 -91
- package/lib/defaults.json +130 -0
- package/lib/hooks/pre-commit.js +36 -0
- package/lib/utils/analysis-engine.js +7 -3
- package/lib/utils/claude-client.js +9 -5
- package/lib/utils/config-registry.js +257 -0
- package/lib/utils/diff-analysis-orchestrator.js +13 -8
- package/lib/utils/judge.js +7 -4
- package/lib/utils/linear-connector.js +6 -4
- package/lib/utils/linter-runner.js +16 -1
- package/lib/utils/pr-metadata-engine.js +11 -8
- package/lib/utils/version-manager.js +6 -8
- package/package.json +12 -4
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
|
-
#
|
|
1
|
+
# claude-git-hooks
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Intelligent Git hooks system integrating Claude CLI for code analysis, commit message generation, PR creation, and release workflow automation.
|
|
4
4
|
|
|
5
|
-
##
|
|
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 |
|
|
14
|
-
| Understanding a source module |
|
|
15
|
-
| Understanding a business workflow |
|
|
16
|
-
| Adding a new CLI command |
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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}...`);
|
package/lib/commands/help.js
CHANGED
|
@@ -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
|
-
*
|
|
168
|
-
* Why:
|
|
169
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
|
|
241
|
-
|
|
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
|