claude-git-hooks 2.66.1 → 2.68.0

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,112 @@ 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.68.0] - 2026-06-12
9
+
10
+ ### ✨ Added
11
+ - Silent, throttled pre-command auto-update guard that checks for newer versions before running commands and self-updates automatically (#196)
12
+ - New `autoUpdate` configuration section with `enabled` (default: true) and `intervalHours` (default: 24) settings to control automatic update behavior
13
+ - Centralized `lib/utils/auto-update.js` module providing shared update logic (`getUpdateStatus`, `performUpdate`, `shouldAutoCheck`, `maybeAutoUpdate`) for all update paths
14
+
15
+ ### 🔧 Changed
16
+ - Refactored `update` command into a thin wrapper over the shared auto-update module, eliminating duplicated version-check and npm-install logic
17
+ - Refactored install-time update prompt to use shared `getUpdateStatus()` and `performUpdate()` instead of inline implementation
18
+ - Auto-update is fully fail-open and skipped in `--headless` mode — never blocks the real command on failure
19
+ - Excluded fast/offline commands (`update`, `install`, `uninstall`, `help`, `version`, `migrate-config`) from the pre-command auto-update check to avoid recursion and unnecessary latency
20
+
21
+ ### 🐛 Fixed
22
+ - Fixed install-time update prompt incorrectly offering to "update" dev builds that are ahead of the latest published npm version
23
+
24
+ ### 🗑️ Removed
25
+ - Removed `check-version.sh` template installation from the install command (replaced by the integrated auto-update guard)
26
+ - Removed inline `npm install -g` and `runInstall(['--force'])` calls from `update.js` and `install.js` in favor of centralized `performUpdate()`
27
+
28
+
29
+ ## [2.67.3] - 2026-06-12
30
+
31
+ ### ✨ Added
32
+ - Upfront CLI availability probe in gotcha solicitation — checks once per run instead of discovering failures per-book (#195)
33
+ - New `llm.js` shared CLI wrapper for the librarian pipeline, using the developer's `claude` login session
34
+
35
+ ### 🔧 Changed
36
+ - Replaced Anthropic SDK (`@anthropic-ai/sdk`) with CLI wrapper (`llm.js`) in the librarian's candidate-text-generator (#195)
37
+ - Default model identifier simplified from `claude-sonnet-4-6` to `sonnet` shorthand
38
+ - Gotcha solicitation skips per-book candidate generation entirely when CLI is unavailable, showing a single message instead of one warning per book
39
+ - Tests updated to mock the CLI wrapper instead of the Anthropic SDK
40
+
41
+ ### 🐛 Fixed
42
+ - Resolved library pipeline resolver issues when Anthropic API key is unavailable — librarian now works with just a `claude` CLI login (#195)
43
+
44
+ ### 🗑️ Removed
45
+ - Removed `_classifyError()` helper and all SDK-specific error classification logic from candidate-text-generator
46
+ - Removed direct dependency on `@anthropic-ai/sdk` in the librarian pipeline
47
+
48
+
49
+ ## [2.67.2] - 2026-06-11
50
+
51
+ ### 🔧 Changed
52
+ - 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
53
+ - 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
54
+
55
+ ### 🐛 Fixed
56
+ - Commands no longer produce misleading warnings or errors when the tool is installed as a dependency in repos that have no `.library/` (#194)
57
+ - Sanitized version output at source (#194)
58
+
59
+
60
+ ## [2.67.1] - 2026-06-11
61
+
62
+ ### 🐛 Fixed
63
+ - Sanitized non-semver versions at discovery source in version-manager, preventing invalid version strings from propagating through the bump-version pipeline
64
+
65
+ ### 🗑️ Removed
66
+ - Removed unused `test:full` npm script from package.json
67
+
68
+
69
+ ## [2.67.0] - 2026-06-10
70
+
71
+ ### ✨ Added
72
+
73
+ - 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)
74
+ - 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)
75
+ - 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)
76
+ - `skillRegistry` configuration section (`enabled`, `blockOn`, `resumeOnCreatePr`) registered in package defaults, overridable remotely and per-repo, documented in `config.advanced.example.json`
77
+ - Unit tests for the skill-registry: parser, runner, catalogue, feedback-writer, facade, and resume modules
78
+
79
+ ### 🔧 Changed
80
+
81
+ - 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
82
+ - `analyze` command injects the same rule catalogue into its analysis prompt for parity with pre-commit
83
+ - `CLAUDE_ANALYSIS_PROMPT.md` now instructs Claude to classify each finding against the injected catalogue via `details[].rule`
84
+ - 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
85
+
86
+ ### 🐛 Fixed
87
+
88
+ - 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
89
+ - 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
90
+ - Repaired skill-registry text injections that were being corrupted by suggestion-click commits
91
+ - Skill-gap writer failures during pre-commit are now logged as warnings instead of silently discarded (the commit is never blocked either way)
92
+
93
+ ### 🗑️ Removed
94
+
95
+ - Removed the legacy `mscope-automation--claude-skills` sibling skill-repo name from registry resolution, leaving only the current `automation-skills` name
96
+
8
97
  ## [2.66.1] - 2026-06-10
9
98
 
10
99
  ### 🐛 Fixed
11
- - Normalized path separators to forward slashes in staleness checker for cross-platform compatibility
12
100
 
101
+ - Normalized path separators to forward slashes in staleness checker for cross-platform compatibility
13
102
 
14
103
  ## [2.66.0] - 2026-06-10
15
104
 
16
105
  ### ✨ Added
106
+
17
107
  - Multi-language extractor registry with pluggable per-language architecture [AUT-3742]
18
108
  - End-to-end SDLC stability check test suite
19
109
  - Version alignment validation now scoped to base branch tags (#185)
20
110
  - Extractor notes template for documenting per-language extractors
21
111
 
22
112
  ### 🔧 Changed
113
+
23
114
  - Moved arrow-function extraction from monolithic extractor to pluggable extractor module [AUT-3742]
24
115
  - Decoupled `lib/` from `.library/` static imports with ESLint enforcement rule [AUT-3742]
25
116
  - Library maintenance pipeline now runs before tag push in `create-pr`, ensuring library books are included in tagged commits
@@ -27,6 +118,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
27
118
  - Tags are force-repointed to HEAD after library commit so tagged version includes regenerated books
28
119
 
29
120
  ### 🐛 Fixed
121
+
30
122
  - Fixed `create-pr` gotcha solicitation receiving empty file paths instead of actual book content (#190)
31
123
  - Fixed `create-pr` tag comparison using global tag list instead of base branch scope
32
124
  - Fixed `create-pr` library pipeline leaking host-repo paths into foreign repositories (#186)
@@ -35,12 +127,13 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
35
127
  - Fixed stale git worktree leftovers causing integration test failures
36
128
 
37
129
  ### 🗑️ Removed
38
- - Removed per-file custom version entry option (`promptEditField`) from `bump-version` interactive selection
39
130
 
131
+ - Removed per-file custom version entry option (`promptEditField`) from `bump-version` interactive selection
40
132
 
41
133
  ## [2.65.0] - 2026-06-08
42
134
 
43
135
  ### ✨ Added
136
+
44
137
  - Multi-language extractor registry with pluggable per-language extractors (AUT-3742)
45
138
  - Extractor interface contract and runtime validator for language extractor plugins (AUT-3742)
46
139
  - JS extractor notes template for documenting new extractors (AUT-3742)
@@ -48,6 +141,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
48
141
  - Version alignment now scoped to base branch tags instead of global tag lookup
49
142
 
50
143
  ### 🔧 Changed
144
+
51
145
  - Arrow-function extraction moved from monolithic extract.js to pluggable JS extractor module (AUT-3742)
52
146
  - Decoupled lib/ from .library/ static imports with ESLint enforcement — lib/ must use dynamic import() for Library integration (AUT-3742)
53
147
  - Library maintenance pipeline in create-pr now runs before tag push so tags include regenerated books
@@ -56,6 +150,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
56
150
  - bump-version interactive file selection simplified — goes directly to toggle list, non-semver files pre-deselected
57
151
 
58
152
  ### 🐛 Fixed
153
+
59
154
  - Fixed create-pr library pipeline running incorrectly in foreign repos by deriving paths from resolver config (#186)
60
155
  - Fixed bump-version crash when non-semver files (e.g., Maven `${revision}`) reached version parser (#187)
61
156
  - Fixed create-pr comparing tags against global scope instead of base branch (#185, #189)
@@ -63,13 +158,14 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
63
158
  - Fixed local tag lookup not scoped to HEAD branch, causing cross-branch version mismatches
64
159
 
65
160
  ### 🗑️ Removed
161
+
66
162
  - Removed per-file custom version editing (option `e`) from bump-version interactive selection
67
163
  - Removed `promptMenu` and `promptEditField` usage from bump-version flow
68
164
 
69
-
70
165
  ## [2.64.4] - 2026-06-08
71
166
 
72
167
  ### ✨ Added
168
+
73
169
  - Added multi-language extractor registry with pluggable architecture and runtime interface validation (AUT-3742, #184)
74
170
  - Added JS extractor as first pluggable extractor with dedicated test harness and fixtures (AUT-3742)
75
171
  - Added extractor notes template for documenting per-language extractors (AUT-3742)
@@ -77,6 +173,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
77
173
  - Added branch-scoped version alignment validation in `create-pr` (#185)
78
174
 
79
175
  ### 🔧 Changed
176
+
80
177
  - Decoupled `lib/` from `.library/` static imports with ESLint restricted-imports guard (AUT-3742)
81
178
  - Moved arrow-function extraction from monolithic extractor into pluggable JS extractor module (AUT-3742)
82
179
  - Simplified `bump-version` interactive file selection — removed menu, goes directly to toggle list with non-semver files pre-deselected (#187)
@@ -84,18 +181,20 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
84
181
  - Reordered `create-pr` steps so library pipeline runs before tag push, then re-points unpushed tags to HEAD to include library commits
85
182
 
86
183
  ### 🐛 Fixed
184
+
87
185
  - Fixed `bump-version` crash when non-semver files (e.g., Maven `${revision}`) were included in version resolution (#187)
88
186
  - Fixed `create-pr` library pipeline using hardcoded paths that broke in foreign repositories (#186)
89
187
  - Fixed version alignment and tag lookup returning results from unrelated branches instead of scoping to base branch (#185)
90
188
  - Fixed `create-pr` tag becoming stale after library book regeneration by running the pipeline before tag push and re-pointing tags
91
189
 
92
190
  ### 🗑️ Removed
93
- - Removed `promptMenu` and `promptEditField` options from `bump-version` interactive file selection (#187)
94
191
 
192
+ - Removed `promptMenu` and `promptEditField` options from `bump-version` interactive file selection (#187)
95
193
 
96
194
  ## [2.64.3] - 2026-06-08
97
195
 
98
196
  ### ✨ Added
197
+
99
198
  - Added multi-language extractor registry with pluggable interface, including JS extractor and notes template (AUT-3742)
100
199
  - Added library maintenance pipeline step in create-pr that regenerates books before tag push
101
200
  - Added branch-scoped tag lookup functions (`getLatestLocalTagOnBranch`, `getLatestRemoteTagOnBranch`) to git-tag-manager
@@ -103,6 +202,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
103
202
  - Added extractor test harness with JS fixtures (AUT-3742)
104
203
 
105
204
  ### 🔧 Changed
205
+
106
206
  - Moved arrow-function extraction from monolithic `extract.js` into pluggable extractor under `librarian/extractors/registered/js/` (AUT-3742)
107
207
  - Scoped version alignment validation to base branch tags instead of global tag lookup
108
208
  - Simplified bump-version interactive file selection — goes directly to toggle list, non-semver files pre-deselected
@@ -110,19 +210,21 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
110
210
  - Unpushed tags are force-repointed to HEAD after library commit so tags include regenerated books
111
211
 
112
212
  ### 🐛 Fixed
213
+
113
214
  - Fixed create-pr using stale tag for comparison after library regeneration created a new commit
114
215
  - Fixed create-pr running library pipeline in foreign repos where `.library/` paths were invalid (#186)
115
216
  - Fixed bump-version crashing on non-semver version files (e.g., Maven `${revision}`) by excluding them from version resolution (#187)
116
217
  - Fixed local tag lookup scanning tags from all branches instead of only the current HEAD branch (#185)
117
218
 
118
219
  ### 🗑️ Removed
220
+
119
221
  - Removed per-file custom version editing (`promptEditField` option) from bump-version interactive selection
120
222
  - Removed `promptMenu` four-option flow from bump-version in favor of direct toggle list
121
223
 
122
-
123
224
  ## [2.64.2] - 2026-06-08
124
225
 
125
226
  ### ✨ Added
227
+
126
228
  - Multi-language extractor registry with pluggable extractor interface and JS extractor (AUT-3742, #184)
127
229
  - Extractor notes template and per-extractor documentation standard (AUT-3742)
128
230
  - Test harness for extractors with JS fixtures (AUT-3742)
@@ -131,6 +233,7 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
131
233
  - Library maintenance pipeline step in create-pr to regenerate books before tagging (#187)
132
234
 
133
235
  ### 🔧 Changed
236
+
134
237
  - Moved arrow-function extraction from monolithic extractor to pluggable JS extractor module (AUT-3742)
135
238
  - Decoupled lib/ from .library/ imports — library integration now uses dynamic import with graceful degradation (AUT-3742)
136
239
  - Library pipeline in create-pr derives paths from resolver.yaml config instead of hardcoded values (#186)
@@ -138,42 +241,47 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
138
241
  - Tags are re-pointed to HEAD after library commit so tagged releases include regenerated books (#187)
139
242
 
140
243
  ### 🐛 Fixed
244
+
141
245
  - Fixed bump-version crashing on non-semver version files (e.g., Maven `${revision}`) by excluding them from version resolution (#187)
142
246
  - Fixed create-pr library pipeline leaking git-hooks paths into foreign repos (#186)
143
247
  - Fixed local tag lookup scanning all branches instead of scoping to HEAD branch (#185)
144
248
  - Fixed stale tags in create-pr when library pipeline generates a new commit after tag creation (#187)
145
249
 
146
250
  ### 🗑️ Removed
147
- - Removed per-file custom version editing (option `e`) from bump-version interactive selection (#187)
148
251
 
252
+ - Removed per-file custom version editing (option `e`) from bump-version interactive selection (#187)
149
253
 
150
254
  ## [2.64.1] - 2026-06-08
151
255
 
152
256
  ### ✨ Added
257
+
153
258
  - Multi-language extractor registry with pluggable architecture for Library book generation [AUT-3742] (#184)
154
259
  - JS extractor as first pluggable extractor with Tree-sitter parsing, extractor notes template, and test harness [AUT-3742] (#184)
155
260
  - ESLint rule preventing `lib/` from statically importing `.library/` modules [AUT-3742] (#184)
156
261
  - Branch-scoped tag lookup functions `getLatestLocalTagOnBranch()` and `getLatestRemoteTagOnBranch()` in git-tag-manager (#185)
157
262
 
158
263
  ### 🔧 Changed
264
+
159
265
  - Library pipeline (`createPrPipeline`) now derives `booksDir`/`sourceDir` from overridden `repoRoot`, preventing git-hooks paths from leaking into foreign repos (#186)
160
266
  - Version alignment scoped to base branch tags instead of global tag list (#185)
161
267
  - Bump-version interactive file selection simplified to direct toggle list with non-semver files pre-deselected
162
268
  - Moved arrow-function extraction from monolithic `extract.js` to pluggable extractor module [AUT-3742]
163
269
 
164
270
  ### 🐛 Fixed
271
+
165
272
  - Excluded non-semver files (e.g., Maven `${revision}`) from version resolution in bump-version command, preventing `parseVersion()` failures
166
273
  - Fixed library pipeline using hardcoded git-hooks paths when running in foreign repos (#186)
167
274
  - Scoped local tag lookup to HEAD branch to avoid cross-branch version pollution (#185)
168
275
 
169
276
  ### 🗑️ Removed
277
+
170
278
  - Removed menu-based file selection (all/select/edit/cancel) from bump-version in favor of direct toggle list
171
279
  - Removed per-file custom version entry (`targetVersion`) from interactive file selection
172
280
 
173
-
174
281
  ## [2.64.0] - 2026-06-08
175
282
 
176
283
  ### ✨ Added
284
+
177
285
  - Multi-language extractor registry with pluggable interface and JS extractor (AUT-3742)
178
286
  - Extractor notes template for documenting per-language extractors (AUT-3742)
179
287
  - Test harness with JS fixtures for extractor validation (AUT-3742)
@@ -181,15 +289,16 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
181
289
  - ESLint `no-restricted-imports` rule preventing `lib/` from statically importing `.library/` modules (AUT-3742)
182
290
 
183
291
  ### 🔧 Changed
292
+
184
293
  - Moved arrow-function extraction from monolithic `extract.js` to pluggable extractor module under `librarian/extractors/registered/js/` (AUT-3742)
185
294
  - `validateVersionAlignment()` now accepts a `baseBranch` parameter, scoping version checks to the relevant branch tags instead of all tags
186
295
  - Library pipeline (`createPrPipeline`) now derives `booksDir`/`sourceDir` from resolver config when `repoRoot` is overridden, preventing path leakage into foreign repos
187
296
 
188
297
  ### 🐛 Fixed
298
+
189
299
  - Fixed local tag lookup returning tags from unrelated branches instead of scoping to HEAD branch
190
300
  - Fixed library pipeline leaking git-hooks internal paths into foreign repos during PR creation (#185)
191
301
 
192
-
193
302
  ## [2.63.1] - 2026-06-03
194
303
 
195
304
  ### ✨ 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
 
package/bin/claude-hooks CHANGED
@@ -131,6 +131,25 @@ async function main() {
131
131
  logger.debug('bin - main', 'Authorization guard bypassed (--headless)', { command: entry.name });
132
132
  }
133
133
 
134
+ // --- Pre-command auto-update guard (silent, throttled) ---
135
+ // Single choke-point: every command flows through here, so auto-update is added
136
+ // once instead of in each command file. Mirrors the authorization guard above.
137
+ // Fully fail-open — never blocks the real command.
138
+ if (!isHeadless) {
139
+ try {
140
+ const { maybeAutoUpdate } = await import('../lib/utils/auto-update.js');
141
+ const updated = await maybeAutoUpdate(entry.name);
142
+ if (updated) {
143
+ // The running binary was just replaced; user must re-run their command.
144
+ process.exit(0);
145
+ }
146
+ } catch (err) {
147
+ logger.debug('bin - main', 'Pre-command auto-update skipped (non-fatal)', {
148
+ error: err.message
149
+ });
150
+ }
151
+ }
152
+
134
153
  // --- Commands with special argument handling ---
135
154
 
136
155
  // analyze: translate flags to options object
@@ -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
  }