claude-git-hooks 2.66.1 → 2.67.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,21 +5,91 @@ 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.67.3] - 2026-06-12
9
+
10
+ ### ✨ Added
11
+ - Upfront CLI availability probe in gotcha solicitation — checks once per run instead of discovering failures per-book (#195)
12
+ - New `llm.js` shared CLI wrapper for the librarian pipeline, using the developer's `claude` login session
13
+
14
+ ### 🔧 Changed
15
+ - Replaced Anthropic SDK (`@anthropic-ai/sdk`) with CLI wrapper (`llm.js`) in the librarian's candidate-text-generator (#195)
16
+ - Default model identifier simplified from `claude-sonnet-4-6` to `sonnet` shorthand
17
+ - Gotcha solicitation skips per-book candidate generation entirely when CLI is unavailable, showing a single message instead of one warning per book
18
+ - Tests updated to mock the CLI wrapper instead of the Anthropic SDK
19
+
20
+ ### 🐛 Fixed
21
+ - Resolved library pipeline resolver issues when Anthropic API key is unavailable — librarian now works with just a `claude` CLI login (#195)
22
+
23
+ ### 🗑️ Removed
24
+ - Removed `_classifyError()` helper and all SDK-specific error classification logic from candidate-text-generator
25
+ - Removed direct dependency on `@anthropic-ai/sdk` in the librarian pipeline
26
+
27
+
28
+ ## [2.67.2] - 2026-06-11
29
+
30
+ ### 🔧 Changed
31
+ - Centralized `.library/` resolution into a dedicated `library-resolver.js` module — all commands now resolve Library paths from the repo root via `libraryModuleUrl()` instead of fragile relative imports
32
+ - Library pipeline steps (staleness checks, verification gates, co-change pipeline) now gracefully skip with a debug log when the working repo has no `.library/` directory
33
+
34
+ ### 🐛 Fixed
35
+ - Commands no longer produce misleading warnings or errors when the tool is installed as a dependency in repos that have no `.library/` (#194)
36
+ - Sanitized version output at source (#194)
37
+
38
+
39
+ ## [2.67.1] - 2026-06-11
40
+
41
+ ### 🐛 Fixed
42
+ - Sanitized non-semver versions at discovery source in version-manager, preventing invalid version strings from propagating through the bump-version pipeline
43
+
44
+ ### 🗑️ Removed
45
+ - Removed unused `test:full` npm script from package.json
46
+
47
+
48
+ ## [2.67.0] - 2026-06-10
49
+
50
+ ### ✨ Added
51
+
52
+ - Integrated the `@mscope/automation-skills` rule registry into the pre-commit hook: deterministic JBE/UIK rule checks run against staged files and surface findings alongside lint + AI output, with optional severity gating via `skillRegistry.blockOn` (Options A + G)
53
+ - Injected the mscope rule catalogue into the Claude analysis prompt; findings Claude cannot classify against the catalogue are appended as `[skill-gap]` candidates to the skill repo's `skill-feedback.md`, fingerprint-deduplicated and reviewed via `automation-skills retro` — never auto-merged (Option E2)
54
+ - Lessons-learned capture on `create-pr`: a new knowledge-capture step hands control to `automation-skills resume` before tags are pushed, recording branch lessons to the skill repo's `implementation-history.md` (supersedes the draft `finish-branch` command; gated by `skillRegistry.resumeOnCreatePr`, skipped in headless mode)
55
+ - `skillRegistry` configuration section (`enabled`, `blockOn`, `resumeOnCreatePr`) registered in package defaults, overridable remotely and per-repo, documented in `config.advanced.example.json`
56
+ - Unit tests for the skill-registry: parser, runner, catalogue, feedback-writer, facade, and resume modules
57
+
58
+ ### 🔧 Changed
59
+
60
+ - Skill-registry consumption is decoupled behind a facade (`runSkillChecks`, `getCatalogueSection`, `recordSkillGaps`) with a memoized registry load; the catalogue reaches the analysis prompt as a plain parameter threaded through `analysis-engine` → `prompt-builder`, which have no skill-registry knowledge
61
+ - `analyze` command injects the same rule catalogue into its analysis prompt for parity with pre-commit
62
+ - `CLAUDE_ANALYSIS_PROMPT.md` now instructs Claude to classify each finding against the injected catalogue via `details[].rule`
63
+ - Library extractor cross-references now resolve through books' frontmatter `source_files` instead of source-file basenames, so books not named after their source (e.g. `skill-registry-parser.md`) survive regeneration with correct references
64
+
65
+ ### 🐛 Fixed
66
+
67
+ - Resolved the `automation-skills` sibling skill repo relative to the working repo (env vars → sibling-of-working-repo) instead of guessing under the user's home directory, making registry loading reliable across machines
68
+ - Fixed catalogue injection never activating in the canonical sibling layout — the registry was loaded without the working repo root, so resolution silently failed unless an env var was set
69
+ - Repaired skill-registry text injections that were being corrupted by suggestion-click commits
70
+ - Skill-gap writer failures during pre-commit are now logged as warnings instead of silently discarded (the commit is never blocked either way)
71
+
72
+ ### 🗑️ Removed
73
+
74
+ - Removed the legacy `mscope-automation--claude-skills` sibling skill-repo name from registry resolution, leaving only the current `automation-skills` name
75
+
8
76
  ## [2.66.1] - 2026-06-10
9
77
 
10
78
  ### 🐛 Fixed
11
- - Normalized path separators to forward slashes in staleness checker for cross-platform compatibility
12
79
 
80
+ - Normalized path separators to forward slashes in staleness checker for cross-platform compatibility
13
81
 
14
82
  ## [2.66.0] - 2026-06-10
15
83
 
16
84
  ### ✨ Added
85
+
17
86
  - Multi-language extractor registry with pluggable per-language architecture [AUT-3742]
18
87
  - End-to-end SDLC stability check test suite
19
88
  - Version alignment validation now scoped to base branch tags (#185)
20
89
  - Extractor notes template for documenting per-language extractors
21
90
 
22
91
  ### 🔧 Changed
92
+
23
93
  - Moved arrow-function extraction from monolithic extractor to pluggable extractor module [AUT-3742]
24
94
  - Decoupled `lib/` from `.library/` static imports with ESLint enforcement rule [AUT-3742]
25
95
  - Library maintenance pipeline now runs before tag push in `create-pr`, ensuring library books are included in tagged commits
@@ -27,6 +97,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
27
97
  - Tags are force-repointed to HEAD after library commit so tagged version includes regenerated books
28
98
 
29
99
  ### 🐛 Fixed
100
+
30
101
  - Fixed `create-pr` gotcha solicitation receiving empty file paths instead of actual book content (#190)
31
102
  - Fixed `create-pr` tag comparison using global tag list instead of base branch scope
32
103
  - Fixed `create-pr` library pipeline leaking host-repo paths into foreign repositories (#186)
@@ -35,12 +106,13 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
35
106
  - Fixed stale git worktree leftovers causing integration test failures
36
107
 
37
108
  ### 🗑️ Removed
38
- - Removed per-file custom version entry option (`promptEditField`) from `bump-version` interactive selection
39
109
 
110
+ - Removed per-file custom version entry option (`promptEditField`) from `bump-version` interactive selection
40
111
 
41
112
  ## [2.65.0] - 2026-06-08
42
113
 
43
114
  ### ✨ Added
115
+
44
116
  - Multi-language extractor registry with pluggable per-language extractors (AUT-3742)
45
117
  - Extractor interface contract and runtime validator for language extractor plugins (AUT-3742)
46
118
  - JS extractor notes template for documenting new extractors (AUT-3742)
@@ -48,6 +120,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
48
120
  - Version alignment now scoped to base branch tags instead of global tag lookup
49
121
 
50
122
  ### 🔧 Changed
123
+
51
124
  - Arrow-function extraction moved from monolithic extract.js to pluggable JS extractor module (AUT-3742)
52
125
  - Decoupled lib/ from .library/ static imports with ESLint enforcement — lib/ must use dynamic import() for Library integration (AUT-3742)
53
126
  - Library maintenance pipeline in create-pr now runs before tag push so tags include regenerated books
@@ -56,6 +129,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
56
129
  - bump-version interactive file selection simplified — goes directly to toggle list, non-semver files pre-deselected
57
130
 
58
131
  ### 🐛 Fixed
132
+
59
133
  - Fixed create-pr library pipeline running incorrectly in foreign repos by deriving paths from resolver config (#186)
60
134
  - Fixed bump-version crash when non-semver files (e.g., Maven `${revision}`) reached version parser (#187)
61
135
  - Fixed create-pr comparing tags against global scope instead of base branch (#185, #189)
@@ -63,13 +137,14 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
63
137
  - Fixed local tag lookup not scoped to HEAD branch, causing cross-branch version mismatches
64
138
 
65
139
  ### 🗑️ Removed
140
+
66
141
  - Removed per-file custom version editing (option `e`) from bump-version interactive selection
67
142
  - Removed `promptMenu` and `promptEditField` usage from bump-version flow
68
143
 
69
-
70
144
  ## [2.64.4] - 2026-06-08
71
145
 
72
146
  ### ✨ Added
147
+
73
148
  - Added multi-language extractor registry with pluggable architecture and runtime interface validation (AUT-3742, #184)
74
149
  - Added JS extractor as first pluggable extractor with dedicated test harness and fixtures (AUT-3742)
75
150
  - Added extractor notes template for documenting per-language extractors (AUT-3742)
@@ -77,6 +152,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
77
152
  - Added branch-scoped version alignment validation in `create-pr` (#185)
78
153
 
79
154
  ### 🔧 Changed
155
+
80
156
  - Decoupled `lib/` from `.library/` static imports with ESLint restricted-imports guard (AUT-3742)
81
157
  - Moved arrow-function extraction from monolithic extractor into pluggable JS extractor module (AUT-3742)
82
158
  - Simplified `bump-version` interactive file selection — removed menu, goes directly to toggle list with non-semver files pre-deselected (#187)
@@ -84,18 +160,20 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
84
160
  - Reordered `create-pr` steps so library pipeline runs before tag push, then re-points unpushed tags to HEAD to include library commits
85
161
 
86
162
  ### 🐛 Fixed
163
+
87
164
  - Fixed `bump-version` crash when non-semver files (e.g., Maven `${revision}`) were included in version resolution (#187)
88
165
  - Fixed `create-pr` library pipeline using hardcoded paths that broke in foreign repositories (#186)
89
166
  - Fixed version alignment and tag lookup returning results from unrelated branches instead of scoping to base branch (#185)
90
167
  - Fixed `create-pr` tag becoming stale after library book regeneration by running the pipeline before tag push and re-pointing tags
91
168
 
92
169
  ### 🗑️ Removed
93
- - Removed `promptMenu` and `promptEditField` options from `bump-version` interactive file selection (#187)
94
170
 
171
+ - Removed `promptMenu` and `promptEditField` options from `bump-version` interactive file selection (#187)
95
172
 
96
173
  ## [2.64.3] - 2026-06-08
97
174
 
98
175
  ### ✨ Added
176
+
99
177
  - Added multi-language extractor registry with pluggable interface, including JS extractor and notes template (AUT-3742)
100
178
  - Added library maintenance pipeline step in create-pr that regenerates books before tag push
101
179
  - Added branch-scoped tag lookup functions (`getLatestLocalTagOnBranch`, `getLatestRemoteTagOnBranch`) to git-tag-manager
@@ -103,6 +181,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
103
181
  - Added extractor test harness with JS fixtures (AUT-3742)
104
182
 
105
183
  ### 🔧 Changed
184
+
106
185
  - Moved arrow-function extraction from monolithic `extract.js` into pluggable extractor under `librarian/extractors/registered/js/` (AUT-3742)
107
186
  - Scoped version alignment validation to base branch tags instead of global tag lookup
108
187
  - Simplified bump-version interactive file selection — goes directly to toggle list, non-semver files pre-deselected
@@ -110,19 +189,21 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
110
189
  - Unpushed tags are force-repointed to HEAD after library commit so tags include regenerated books
111
190
 
112
191
  ### 🐛 Fixed
192
+
113
193
  - Fixed create-pr using stale tag for comparison after library regeneration created a new commit
114
194
  - Fixed create-pr running library pipeline in foreign repos where `.library/` paths were invalid (#186)
115
195
  - Fixed bump-version crashing on non-semver version files (e.g., Maven `${revision}`) by excluding them from version resolution (#187)
116
196
  - Fixed local tag lookup scanning tags from all branches instead of only the current HEAD branch (#185)
117
197
 
118
198
  ### 🗑️ Removed
199
+
119
200
  - Removed per-file custom version editing (`promptEditField` option) from bump-version interactive selection
120
201
  - Removed `promptMenu` four-option flow from bump-version in favor of direct toggle list
121
202
 
122
-
123
203
  ## [2.64.2] - 2026-06-08
124
204
 
125
205
  ### ✨ Added
206
+
126
207
  - Multi-language extractor registry with pluggable extractor interface and JS extractor (AUT-3742, #184)
127
208
  - Extractor notes template and per-extractor documentation standard (AUT-3742)
128
209
  - Test harness for extractors with JS fixtures (AUT-3742)
@@ -131,6 +212,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
131
212
  - Library maintenance pipeline step in create-pr to regenerate books before tagging (#187)
132
213
 
133
214
  ### 🔧 Changed
215
+
134
216
  - Moved arrow-function extraction from monolithic extractor to pluggable JS extractor module (AUT-3742)
135
217
  - Decoupled lib/ from .library/ imports — library integration now uses dynamic import with graceful degradation (AUT-3742)
136
218
  - Library pipeline in create-pr derives paths from resolver.yaml config instead of hardcoded values (#186)
@@ -138,42 +220,47 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
138
220
  - Tags are re-pointed to HEAD after library commit so tagged releases include regenerated books (#187)
139
221
 
140
222
  ### 🐛 Fixed
223
+
141
224
  - Fixed bump-version crashing on non-semver version files (e.g., Maven `${revision}`) by excluding them from version resolution (#187)
142
225
  - Fixed create-pr library pipeline leaking git-hooks paths into foreign repos (#186)
143
226
  - Fixed local tag lookup scanning all branches instead of scoping to HEAD branch (#185)
144
227
  - Fixed stale tags in create-pr when library pipeline generates a new commit after tag creation (#187)
145
228
 
146
229
  ### 🗑️ Removed
147
- - Removed per-file custom version editing (option `e`) from bump-version interactive selection (#187)
148
230
 
231
+ - Removed per-file custom version editing (option `e`) from bump-version interactive selection (#187)
149
232
 
150
233
  ## [2.64.1] - 2026-06-08
151
234
 
152
235
  ### ✨ Added
236
+
153
237
  - Multi-language extractor registry with pluggable architecture for Library book generation [AUT-3742] (#184)
154
238
  - JS extractor as first pluggable extractor with Tree-sitter parsing, extractor notes template, and test harness [AUT-3742] (#184)
155
239
  - ESLint rule preventing `lib/` from statically importing `.library/` modules [AUT-3742] (#184)
156
240
  - Branch-scoped tag lookup functions `getLatestLocalTagOnBranch()` and `getLatestRemoteTagOnBranch()` in git-tag-manager (#185)
157
241
 
158
242
  ### 🔧 Changed
243
+
159
244
  - Library pipeline (`createPrPipeline`) now derives `booksDir`/`sourceDir` from overridden `repoRoot`, preventing git-hooks paths from leaking into foreign repos (#186)
160
245
  - Version alignment scoped to base branch tags instead of global tag list (#185)
161
246
  - Bump-version interactive file selection simplified to direct toggle list with non-semver files pre-deselected
162
247
  - Moved arrow-function extraction from monolithic `extract.js` to pluggable extractor module [AUT-3742]
163
248
 
164
249
  ### 🐛 Fixed
250
+
165
251
  - Excluded non-semver files (e.g., Maven `${revision}`) from version resolution in bump-version command, preventing `parseVersion()` failures
166
252
  - Fixed library pipeline using hardcoded git-hooks paths when running in foreign repos (#186)
167
253
  - Scoped local tag lookup to HEAD branch to avoid cross-branch version pollution (#185)
168
254
 
169
255
  ### 🗑️ Removed
256
+
170
257
  - Removed menu-based file selection (all/select/edit/cancel) from bump-version in favor of direct toggle list
171
258
  - Removed per-file custom version entry (`targetVersion`) from interactive file selection
172
259
 
173
-
174
260
  ## [2.64.0] - 2026-06-08
175
261
 
176
262
  ### ✨ Added
263
+
177
264
  - Multi-language extractor registry with pluggable interface and JS extractor (AUT-3742)
178
265
  - Extractor notes template for documenting per-language extractors (AUT-3742)
179
266
  - Test harness with JS fixtures for extractor validation (AUT-3742)
@@ -181,15 +268,16 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
181
268
  - ESLint `no-restricted-imports` rule preventing `lib/` from statically importing `.library/` modules (AUT-3742)
182
269
 
183
270
  ### 🔧 Changed
271
+
184
272
  - Moved arrow-function extraction from monolithic `extract.js` to pluggable extractor module under `librarian/extractors/registered/js/` (AUT-3742)
185
273
  - `validateVersionAlignment()` now accepts a `baseBranch` parameter, scoping version checks to the relevant branch tags instead of all tags
186
274
  - Library pipeline (`createPrPipeline`) now derives `booksDir`/`sourceDir` from resolver config when `repoRoot` is overridden, preventing path leakage into foreign repos
187
275
 
188
276
  ### 🐛 Fixed
277
+
189
278
  - Fixed local tag lookup returning tags from unrelated branches instead of scoping to HEAD branch
190
279
  - Fixed library pipeline leaking git-hooks internal paths into foreign repos during PR creation (#185)
191
280
 
192
-
193
281
  ## [2.63.1] - 2026-06-03
194
282
 
195
283
  ### ✨ Added
package/README.md CHANGED
@@ -308,6 +308,39 @@ claude-hooks batch-info
308
308
  # Shows: per-model average analysis time and orchestration overhead (from telemetry)
309
309
  ```
310
310
 
311
+ ### mscope Skill-Registry Integration (automation-skills)
312
+
313
+ Connects the hooks to the `@mscope/automation-skills` rule registry. No new commands — the integration runs inside `pre-commit` and `create-pr`.
314
+
315
+ ```bash
316
+ # Setup (one of):
317
+ git clone https://github.com/mscope-S-L/automation-skills ../automation-skills # sibling of your repo
318
+ export CLAUDE_HOOKS_SKILL_REPO=/path/to/automation-skills # or explicit path
319
+
320
+ # Optional — enables freshness checks and lessons-learned capture:
321
+ npm install -g github:mscope-S-L/automation-skills
322
+ ```
323
+
324
+ **What it does on every commit:**
325
+
326
+ - Runs the registry's deterministic JBE/UIK rule checks against staged files and shows findings alongside lint + AI output (warn-only by default)
327
+ - Injects the rule catalogue into the Claude analysis prompt so AI findings are classified against rule IDs
328
+ - Findings the AI cannot classify are appended as `[skill-gap]` candidates to the **sibling skill repo's** `skill-feedback.md` (a cross-repo write — uncommitted, fingerprint-deduplicated, reviewed later via `automation-skills retro`, never auto-merged into the registry)
329
+
330
+ **What it does on `create-pr`:**
331
+
332
+ - Hands control to `automation-skills resume` (interactive) to record the branch's lessons-learned before tags are pushed. Skipped in headless mode or when the CLI is not installed.
333
+
334
+ **Configuration** (`.claude/config.json` overrides):
335
+
336
+ | Key | Default | Effect |
337
+ | --- | --- | --- |
338
+ | `skillRegistry.enabled` | `true` | Master switch for the whole integration |
339
+ | `skillRegistry.blockOn` | `"never"` | Block commits at/above a severity: `critical`, `high`, `medium`, `low` |
340
+ | `skillRegistry.resumeOnCreatePr` | `true` | Lessons-learned capture during `create-pr` |
341
+
342
+ **Use case:** team-wide antipattern enforcement with a feedback loop — the registry teaches the hooks, and unrecognized findings feed back into the registry. Everything silently no-ops when the skill repo isn't found; the integration is value-add, never a hard dependency.
343
+
311
344
  ### Other Commands
312
345
 
313
346
  ```bash
@@ -574,6 +607,7 @@ claude-hooks batch-info # Shows config + per-model avg speed from telemetry
574
607
  - Max files per commit: 30
575
608
  - Orchestrator threshold: 3 files
576
609
  - Orchestrator model: opus (internal, not configurable)
610
+ - Skill registry: enabled, `blockOn: never` (warn-only), `resumeOnCreatePr: true` — silently inactive when the automation-skills repo isn't found
577
611
 
578
612
  ---
579
613
 
@@ -7,6 +7,7 @@ import fs from 'fs';
7
7
  import { analyzeBranchForPR } from '../utils/pr-metadata-engine.js';
8
8
  import { getConfig } from '../config.js';
9
9
  import logger from '../utils/logger.js';
10
+ import { libraryModuleUrl, hasLibrary } from '../utils/library-resolver.js';
10
11
  import { colors, error, info, checkGitRepo } from './helpers.js';
11
12
 
12
13
  /**
@@ -93,31 +94,33 @@ export async function runAnalyzeDiff(args) {
93
94
  console.log(result.testingNotes);
94
95
  }
95
96
 
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}`);
97
+ // Library staleness section (only when the working repo has its own .library/)
98
+ if (hasLibrary()) {
99
+ try {
100
+ const { runAll } = await import(libraryModuleUrl('tools/staleness.js'));
101
+ const { getSourceDir, getBooksDir } = await import(libraryModuleUrl('paths.js'));
102
+ const { getRepoRoot } = await import('../utils/git-operations.js');
103
+ const stalenessResult = await runAll(getBooksDir(), getSourceDir(), getRepoRoot(), false);
104
+ const staleCount = stalenessResult.stale.length +
105
+ stalenessResult.orphan_books.length +
106
+ stalenessResult.unbooked_sources.length;
107
+ if (staleCount > 0) {
108
+ console.log('');
109
+ console.log(`📚 ${colors.yellow}Library Staleness:${colors.reset} ${staleCount} book(s) need attention`);
110
+ for (const item of stalenessResult.stale) {
111
+ console.log(` └─ stale: ${item.book}`);
112
+ }
113
+ for (const item of stalenessResult.orphan_books) {
114
+ console.log(` └─ orphan: ${item.book}`);
115
+ }
116
+ for (const src of stalenessResult.unbooked_sources) {
117
+ console.log(` └─ unbooked: ${src}`);
118
+ }
119
+ console.log(' Run: npm run library:regenerate');
110
120
  }
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');
121
+ } catch {
122
+ logger.warning('📚 Library staleness check unavailable — .library/ tools not found');
118
123
  }
119
- } catch {
120
- logger.warning('📚 Library staleness check unavailable — .library/ tools not found');
121
124
  }
122
125
 
123
126
  // Save the results in a file with context
@@ -43,6 +43,7 @@ import { generateResolutionPrompt } from '../utils/resolution-prompt.js';
43
43
  import { getConfig } from '../config.js';
44
44
  import { loadPreset } from '../utils/preset-loader.js';
45
45
  import { CostTracker } from '../utils/cost-tracker.js';
46
+ import { getCatalogueSection } from '../utils/skill-registry/index.js';
46
47
  import { getVersion } from '../utils/package-info.js';
47
48
  import logger from '../utils/logger.js';
48
49
  import { error, success, info } from './helpers.js';
@@ -219,7 +220,8 @@ export const runAnalyze = async (options = {}) => {
219
220
  const result = await runAnalysis(filesData, config, {
220
221
  hook: 'analyze',
221
222
  headless,
222
- costTracker
223
+ costTracker,
224
+ catalogueSection: getCatalogueSection({ repoRoot: getRepoRoot() })
223
225
  });
224
226
 
225
227
  // Write hooks-verified marker when analysis completes without critical/blocker issues.
@@ -58,6 +58,7 @@ import {
58
58
  promptConfirmation
59
59
  } from '../utils/interactive-ui.js';
60
60
  import logger from '../utils/logger.js';
61
+ import { libraryModuleUrl, hasLibrary } from '../utils/library-resolver.js';
61
62
  import { colors, error, checkGitRepo } from './helpers.js';
62
63
 
63
64
  /** Default source branch for back-merge */
@@ -652,50 +653,55 @@ export async function runBackMerge(args) {
652
653
  console.log('');
653
654
 
654
655
  // 14b. Co-change correlation pipeline (AUT-3777)
656
+ // Only runs when the working repo has its own .library/ (the tool ships without one).
655
657
  let coChangeReport = null;
656
- try {
657
- const { coChangePipeline } = await import('../../.library/librarian/index.js');
658
+ if (!hasLibrary()) {
659
+ logger.debug('back-merge', 'No .library/ in current repo — skipping co-change pipeline');
660
+ } else {
661
+ try {
662
+ const { coChangePipeline } = await import(libraryModuleUrl('librarian/index.js'));
658
663
 
659
- showInfo('Running co-change correlation pipeline...');
660
- const summary = coChangePipeline({ repoCtx: {} });
661
- const { modifiedFiles, perStep, report, warnings, mode } = summary;
664
+ showInfo('Running co-change correlation pipeline...');
665
+ const summary = coChangePipeline({ repoCtx: {} });
666
+ const { modifiedFiles, perStep, report, warnings, mode } = summary;
662
667
 
663
- // Surface summary to stdout
664
- showInfo(
665
- `Co-change: mode=${mode}, detected=${perStep.detection.modifications}, ` +
666
- `injected=${perStep.injection.modifications}, warnings=${warnings.length}`
667
- );
668
- for (const w of warnings) {
669
- showWarning(w);
670
- }
668
+ // Surface summary to stdout
669
+ showInfo(
670
+ `Co-change: mode=${mode}, detected=${perStep.detection.modifications}, ` +
671
+ `injected=${perStep.injection.modifications}, warnings=${warnings.length}`
672
+ );
673
+ for (const w of warnings) {
674
+ showWarning(w);
675
+ }
671
676
 
672
- // Save report for PR body attachment after push
673
- coChangeReport = report;
677
+ // Save report for PR body attachment after push
678
+ coChangeReport = report;
674
679
 
675
- if (modifiedFiles.length === 0) {
676
- showInfo('Co-change pipeline produced no Library changes');
677
- } else {
678
- const root = getRepoRoot();
679
- const absFiles = modifiedFiles.map(f => path.isAbsolute(f) ? f : path.join(root, f));
680
- const stageResult = stageFiles(absFiles);
681
-
682
- if (!stageResult.success) {
683
- showWarning(`Failed to stage co-change files: ${stageResult.error}`);
680
+ if (modifiedFiles.length === 0) {
681
+ showInfo('Co-change pipeline produced no Library changes');
684
682
  } else {
685
- const windowDesc = tagName ? `${tagName}..HEAD` : 'full history';
686
- const libCommitMsg = `chore(library): co-change correlations for ${windowDesc}`;
687
- const libCommit = createCommit(libCommitMsg);
683
+ const root = getRepoRoot();
684
+ const absFiles = modifiedFiles.map(f => path.isAbsolute(f) ? f : path.join(root, f));
685
+ const stageResult = stageFiles(absFiles);
688
686
 
689
- if (!libCommit.success) {
690
- showWarning(`Failed to commit co-change files: ${libCommit.error}`);
687
+ if (!stageResult.success) {
688
+ showWarning(`Failed to stage co-change files: ${stageResult.error}`);
691
689
  } else {
692
- showSuccess(`Co-change committed: ${libCommitMsg} (${modifiedFiles.length} file(s))`);
690
+ const windowDesc = tagName ? `${tagName}..HEAD` : 'full history';
691
+ const libCommitMsg = `chore(library): co-change correlations for ${windowDesc}`;
692
+ const libCommit = createCommit(libCommitMsg);
693
+
694
+ if (!libCommit.success) {
695
+ showWarning(`Failed to commit co-change files: ${libCommit.error}`);
696
+ } else {
697
+ showSuccess(`Co-change committed: ${libCommitMsg} (${modifiedFiles.length} file(s))`);
698
+ }
693
699
  }
694
700
  }
701
+ } catch (err) {
702
+ logger.warning(`co-change pipeline skipped: ${err.message}`);
703
+ logger.debug('back-merge', 'Co-change pipeline skipped', { error: err.message });
695
704
  }
696
- } catch (err) {
697
- logger.warning(`co-change pipeline skipped: ${err.message}`);
698
- logger.debug('back-merge', 'Co-change pipeline skipped', { error: err.message });
699
705
  }
700
706
 
701
707
  // 15. Verify sync
@@ -24,8 +24,7 @@ import {
24
24
  discoverVersionFiles,
25
25
  incrementVersion,
26
26
  modifySuffix,
27
- updateVersionFiles,
28
- validateVersionFormat
27
+ updateVersionFiles
29
28
  } from '../utils/version-manager.js';
30
29
  import { createTag, pushTags, tagExists, formatTagName } from '../utils/git-tag-manager.js';
31
30
  import {
@@ -51,6 +50,7 @@ import {
51
50
  promptToggleList
52
51
  } from '../utils/interactive-ui.js';
53
52
  import logger from '../utils/logger.js';
53
+ import { libraryModuleUrl, hasLibrary } from '../utils/library-resolver.js';
54
54
  import { colors, error, checkGitRepo } from './helpers.js';
55
55
  import {
56
56
  CONSOLE_WARNING_TEMPLATE,
@@ -414,20 +414,25 @@ export async function runBumpVersion(args) {
414
414
 
415
415
  showSuccess('Prerequisites validated');
416
416
 
417
- // Library verification gate — silent on clean, loud-warn on stale, never-hard-fail
418
- logger.debug('bump-version', 'Running Library verification gate');
419
- try {
420
- const { verify } = await import('../../.library/librarian/index.js');
421
- const verifyResult = await verify();
417
+ // Library verification gate — silent on clean, loud-warn on stale, never-hard-fail.
418
+ // Only runs when the working repo has its own .library/ (the tool ships without one).
419
+ if (!hasLibrary()) {
420
+ logger.debug('bump-version', 'No .library/ in current repo — skipping Library verification gate');
421
+ } else {
422
+ logger.debug('bump-version', 'Running Library verification gate');
423
+ try {
424
+ const { verify } = await import(libraryModuleUrl('librarian/index.js'));
425
+ const verifyResult = await verify();
422
426
 
423
- if (verifyResult.clean) {
424
- logger.debug('bump-version', 'Library is clean — no warning needed');
425
- } else {
426
- _emitLibraryWarning(verifyResult);
427
+ if (verifyResult.clean) {
428
+ logger.debug('bump-version', 'Library is clean — no warning needed');
429
+ } else {
430
+ _emitLibraryWarning(verifyResult);
431
+ }
432
+ } catch (verifyErr) {
433
+ const msg = `\n${colors.yellow} ${LIBRARY_VERIFY_SKIPPED_WARNING} ${verifyErr.message}${colors.reset}\n\n`;
434
+ process.stderr.write(msg);
427
435
  }
428
- } catch (verifyErr) {
429
- const msg = `\n${colors.yellow} ${LIBRARY_VERIFY_SKIPPED_WARNING} ${verifyErr.message}${colors.reset}\n\n`;
430
- process.stderr.write(msg);
431
436
  }
432
437
 
433
438
  // Step 2: Discover all version files
@@ -478,7 +483,7 @@ export async function runBumpVersion(args) {
478
483
  ? uniqueSelected[0]
479
484
  : discovery.resolvedVersion;
480
485
 
481
- if (!currentVersion || !validateVersionFormat(currentVersion)) {
486
+ if (!currentVersion) {
482
487
  showError('Could not determine a valid semver version from selected files');
483
488
  process.exit(1);
484
489
  }
@@ -35,6 +35,7 @@ import {
35
35
  promptEditField
36
36
  } from '../utils/interactive-ui.js';
37
37
  import logger from '../utils/logger.js';
38
+ import { libraryModuleUrl, hasLibrary } from '../utils/library-resolver.js';
38
39
  import { resolveLabels } from '../utils/label-resolver.js';
39
40
  import { colors, error, checkGitRepo } from './helpers.js';
40
41
 
@@ -356,26 +357,31 @@ export async function runCloseRelease(args) {
356
357
  console.log('');
357
358
 
358
359
  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);
360
+ // Library staleness gate — block release closure if books are stale.
361
+ // Only runs when the working repo has its own .library/ (the tool ships without one).
362
+ if (!hasLibrary()) {
363
+ logger.debug('close-release', 'No .library/ in current repo skipping Library staleness gate');
364
+ } else {
365
+ try {
366
+ showInfo('📚 Checking library staleness...');
367
+ const { runAll, formatHuman } = await import(libraryModuleUrl('tools/staleness.js'));
368
+ const { getSourceDir, getBooksDir } = await import(libraryModuleUrl('paths.js'));
369
+ const { getRepoRoot } = await import('../utils/git-operations.js');
370
+ const stalenessResult = await runAll(getBooksDir(), getSourceDir(), getRepoRoot(), false);
371
+ const hasDrift = stalenessResult.stale.length > 0 ||
372
+ stalenessResult.orphan_books.length > 0 ||
373
+ stalenessResult.unbooked_sources.length > 0;
374
+ if (hasDrift) {
375
+ error('📚 Library staleness detected — cannot close release with stale books');
376
+ process.stdout.write(formatHuman(stalenessResult));
377
+ error('Run: npm run library:regenerate');
378
+ process.exit(1);
379
+ }
380
+ showSuccess('📚 Library books are current');
381
+ } catch (err) {
382
+ showWarning('📚 Library staleness check unavailable — .library/ tools not found');
383
+ logger.debug('close-release', 'Library staleness check skipped', { error: err.message });
374
384
  }
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
385
  }
380
386
 
381
387
  // ── Step 7: git reset --soft origin/main ─────────────────────────────