project-librarian 0.2.0 → 0.3.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.
@@ -8,34 +8,39 @@ const modes_1 = require("./modes");
8
8
  const migration_1 = require("./migration");
9
9
  const templates_1 = require("./templates");
10
10
  const workspace_1 = require("./workspace");
11
- const wiki_files_1 = require("./wiki-files");
12
11
  function codeIndex() {
13
12
  return require("./code-index");
14
13
  }
15
14
  function printUsage() {
16
15
  console.log(`Usage:
17
16
  project-librarian [init] [options]
18
- project-librarian install-skill [--scope user|project] [--agents codex|claude|both]
17
+ project-librarian install-skill [--scope user|project] [--agents codex|claude|cursor|gemini|all]
18
+ project-librarian mcp
19
19
 
20
20
  Options:
21
- --migrate, --adopt-existing Preserve an existing wiki as wiki_legacy and create migration inboxes.
21
+ --migrate, --adopt-existing Preserve an existing wiki as wiki_legacy and create unit-level migration map, split plan, coverage ledger, review files, and inboxes.
22
22
  --lint Validate the generated project wiki setup without editing files.
23
23
  --link-check Report broken wiki links, duplicate routes, and orphan pages.
24
24
  --quality-check Report stale, conflicting, and low-quality wiki document signals.
25
25
  --doctor Run lint, link-check, and quality-check together.
26
26
  --fix With --doctor, safely refresh generated index routing.
27
+ --migration-lint Validate migration review scaffolding separately from normal lint.
28
+ --migration-quality-check Report migration policy/structure signals separately from normal quality-check.
29
+ --migration-doctor Run migration-lint and migration-quality-check together.
27
30
  --issue-create Create a GitHub issue with gh issue create after explicit user approval.
28
31
  --issue-draft Print a problem/side-effect GitHub issue body draft.
29
32
  --issue-body-file <path> With --issue-create, use an existing Markdown body file.
30
33
  --issue-title <title> Override the generated issue draft title.
31
- --query <terms> Search wiki paths, metadata, titles, and bodies.
34
+ --query <terms> Search wiki paths, metadata, titles, and bodies (answer-shaped, capped output).
35
+ --wiki-impact <page-or-term> Show wiki backlinks, decision_ref citations, and router depth for matching pages.
32
36
  --refresh-index Update the managed auto-discovered wiki index block.
33
37
  --capture-inbox Append a candidate note with --title, --content, and optional --category.
34
38
  --glossary-init Create and route the optional glossary page.
35
39
  --prune-check Report active pages with stale or unresolved signals.
36
- --review-migration Sync migration inbox statuses into migration review files.
40
+ --review-migration Sync unit coverage and compatible inbox statuses into migration review files.
37
41
  --no-git-config Install hook files without changing git core.hooksPath.
38
42
  --code-index Build the disposable .project-wiki code evidence index.
43
+ --acknowledge-small-repo With --code-index, proceed below the small-repo scale gate after its cost warning.
39
44
  --incremental With --code-index, require an existing compatible index and update only changes.
40
45
  --code-index-full With --code-index, force a full rebuild even when incremental update is possible.
41
46
  --code-parser <mode> With --code-index, use parser mode default or tree-sitter.
@@ -45,8 +50,19 @@ Options:
45
50
  --code-report-section <section> With --code-report, print one section: coverage, ownership, languages, parsers, workspaces, workspace-graph, routes, hotspots, configs, or edges.
46
51
  --code-impact <term> Show file, symbol, route, import, and edge impact evidence for a term.
47
52
  --code-search-symbol <term> Search indexed symbols.
53
+
54
+ Commands:
55
+ mcp Run the stdio MCP server exposing answer-shaped code-evidence tools (code_impact, code_ownership, code_workspace_graph, code_search, code_status) over the existing .project-wiki index.
56
+
48
57
  --help Show this help.`);
49
58
  }
59
+ // console.log queues asynchronously on pipes; an immediate process.exit() discards
60
+ // anything past the first ~64KB pipe chunk (observed truncating a large
61
+ // --code-report on an 11k-file repo). Exiting from a zero-length write callback
62
+ // guarantees everything queued before it has drained.
63
+ function exitAfterStdoutDrain(code) {
64
+ process.stdout.write("", () => process.exit(code));
65
+ }
50
66
  if (args_1.helpMode) {
51
67
  printUsage();
52
68
  process.exit(0);
@@ -87,6 +103,10 @@ if (args_1.codeIndexIncrementalMode && !args_1.codeIndexMode) {
87
103
  console.error("--incremental is only supported with --code-index.");
88
104
  process.exit(1);
89
105
  }
106
+ if (args_1.acknowledgeSmallRepoMode && !args_1.codeIndexMode) {
107
+ console.error("--acknowledge-small-repo is only supported with --code-index.");
108
+ process.exit(1);
109
+ }
90
110
  if (args_1.codeIndexFullMode && !args_1.codeIndexMode) {
91
111
  console.error("--code-index-full is only supported with --code-index.");
92
112
  process.exit(1);
@@ -103,144 +123,216 @@ if (args_1.command === "install-skill") {
103
123
  (0, install_skill_1.runInstallSkillMode)();
104
124
  process.exit(0);
105
125
  }
106
- const activeCodeModes = [args_1.codeQueryMode, args_1.codeReportMode, args_1.codeStatusMode, args_1.codeFilesMode, args_1.codeImpactMode, args_1.codeSearchSymbolMode, args_1.codeIndexMode].filter(Boolean).length;
107
- if (activeCodeModes > 1) {
108
- console.error("Use one code evidence mode at a time: --code-index, --code-query, --code-report, --code-status, --code-files, --code-impact, or --code-search-symbol.");
109
- process.exit(1);
110
- }
111
- if (args_1.codeQueryMode) {
112
- codeIndex().runCodeQueryMode();
113
- process.exit(0);
114
- }
115
- if (args_1.codeReportMode) {
116
- codeIndex().runCodeReportMode();
117
- process.exit(0);
118
- }
119
- if (args_1.codeStatusMode) {
120
- codeIndex().runCodeStatusMode();
121
- process.exit(0);
122
- }
123
- if (args_1.codeFilesMode) {
124
- codeIndex().runCodeFilesMode();
125
- process.exit(0);
126
- }
127
- if (args_1.codeImpactMode) {
128
- codeIndex().runCodeImpactMode();
129
- process.exit(0);
130
- }
131
- if (args_1.codeSearchSymbolMode) {
132
- codeIndex().runCodeSearchSymbolMode();
133
- process.exit(0);
134
- }
135
- if (args_1.codeIndexMode) {
136
- codeIndex().runCodeIndexMode();
137
- process.exit(0);
138
- }
139
- if (args_1.queryTerm) {
140
- (0, modes_1.runQueryMode)();
141
- process.exit(0);
142
- }
143
- if (args_1.issueCreateMode) {
144
- (0, modes_1.runIssueCreateMode)();
145
- process.exit(0);
146
- }
147
- if (args_1.issueDraftMode) {
148
- (0, modes_1.runIssueDraftMode)();
149
- process.exit(0);
150
- }
151
- if (args_1.pruneCheckMode) {
152
- (0, modes_1.runPruneCheckMode)();
153
- process.exit(0);
154
- }
155
- if (args_1.reviewMigrationMode) {
156
- (0, migration_1.runReviewMigrationMode)();
157
- process.exit(0);
158
- }
159
- if (args_1.doctorMode) {
160
- (0, modes_1.runDoctorMode)(args_1.fixMode);
161
- process.exit(0);
162
- }
163
- if (args_1.linkCheckMode) {
164
- (0, modes_1.runLinkCheckMode)();
165
- process.exit(0);
166
- }
167
- if (args_1.qualityCheckMode) {
168
- (0, modes_1.runQualityCheckMode)();
169
- process.exit(0);
170
- }
171
- if (args_1.lintMode) {
172
- (0, modes_1.runLintMode)();
173
- process.exit(0);
174
- }
175
- const migrationState = args_1.migrateMode ? (0, migration_1.prepareMigrationMode)() : null;
176
- const results = [];
177
- if (migrationState)
178
- results.push(["migration prepare", migrationState.note]);
179
- (0, workspace_1.mkdirp)("wiki/canonical");
180
- (0, workspace_1.mkdirp)("wiki/decisions");
181
- (0, workspace_1.mkdirp)("wiki/inbox");
182
- (0, workspace_1.mkdirp)("wiki/meta");
183
- (0, workspace_1.mkdirp)("wiki/sources");
184
- (0, workspace_1.mkdirp)(".codex/hooks");
185
- (0, workspace_1.mkdirp)(".claude/hooks");
186
- (0, workspace_1.mkdirp)(".githooks");
187
- results.push(["AGENTS.md", (0, workspace_1.upsertMarkedSection)("AGENTS.md", "<!-- PROJECT-WIKI-FIRST:START -->", "<!-- PROJECT-WIKI-FIRST:END -->", templates_1.agentsSection)]);
188
- results.push(["CLAUDE.md", (0, workspace_1.upsertMarkedSection)("CLAUDE.md", "<!-- PROJECT-WIKI-CLAUDE:START -->", "<!-- PROJECT-WIKI-CLAUDE:END -->", templates_1.claudeSection)]);
189
- results.push(["wiki/AGENTS.md", (0, workspace_1.upsertMarkedSection)("wiki/AGENTS.md", "<!-- PROJECT-WIKI-INTERNAL:START -->", "<!-- PROJECT-WIKI-INTERNAL:END -->", templates_1.wikiAgentsSection)]);
190
- results.push([".githooks/prepare-commit-msg", (0, workspace_1.writeManaged)(".githooks/prepare-commit-msg", hooks_1.gitPrepareCommitMsgHook)]);
191
- (0, workspace_1.makeExecutable)(".githooks/prepare-commit-msg");
192
- results.push([".githooks/wiki-commit-trailers.js", (0, workspace_1.writeManaged)(".githooks/wiki-commit-trailers.js", hooks_1.gitWikiCommitTrailersScript)]);
193
- (0, workspace_1.makeExecutable)(".githooks/wiki-commit-trailers.js");
194
- results.push(["git core.hooksPath", (0, hooks_1.upsertGitHooksPath)()]);
195
- results.push([".codex/hooks.json", (0, hooks_1.upsertHookConfig)()]);
196
- results.push([".codex/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".codex/hooks/wiki-session-start.js", hooks_1.hookScript)]);
197
- results.push([".claude/settings.json", (0, hooks_1.upsertClaudeHookConfig)()]);
198
- results.push([".claude/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".claude/hooks/wiki-session-start.js", hooks_1.hookScript)]);
199
- results.push(["wiki/startup.md", (0, workspace_1.writeManaged)("wiki/startup.md", (0, wiki_files_1.withPreservedMarkedSections)("wiki/startup.md", templates_1.startup, [["<!-- PROJECT-WIKI-MIGRATION:START -->", "<!-- PROJECT-WIKI-MIGRATION:END -->"]]))]);
200
- results.push(["wiki/index.md", (0, workspace_1.writeManaged)("wiki/index.md", (0, wiki_files_1.withPreservedMarkedSections)("wiki/index.md", templates_1.index, [
201
- ["<!-- PROJECT-WIKI-MIGRATION:START -->", "<!-- PROJECT-WIKI-MIGRATION:END -->"],
202
- ["<!-- PROJECT-WIKI-GLOSSARY:START -->", "<!-- PROJECT-WIKI-GLOSSARY:END -->"],
203
- ["<!-- PROJECT-WIKI-INBOX:START -->", "<!-- PROJECT-WIKI-INBOX:END -->"],
204
- ["<!-- PROJECT-WIKI-AUTO-INDEX:START -->", "<!-- PROJECT-WIKI-AUTO-INDEX:END -->"],
205
- ]))]);
206
- results.push(["wiki/meta/operating-model.md", (0, workspace_1.writeManaged)("wiki/meta/operating-model.md", templates_1.wikiOperatingModel)]);
207
- results.push(["wiki/meta/decision-policy.md", (0, workspace_1.writeManaged)("wiki/meta/decision-policy.md", templates_1.decisionPolicy)]);
208
- results.push(["wiki/canonical/wiki-operating-model.md", (0, workspace_1.deleteIfGenerated)("wiki/canonical/wiki-operating-model.md", ["# Wiki Operating Model"])]);
209
- results.push(["wiki/canonical/decision-policy.md", (0, workspace_1.deleteIfGenerated)("wiki/canonical/decision-policy.md", ["# Decision Policy"])]);
210
- results.push(["wiki/decisions/wiki-v1-decisions.md", (0, workspace_1.deleteIfGenerated)("wiki/decisions/wiki-v1-decisions.md", ["# Wiki v1 Decisions", "# Wiki Operations v1 Decisions"])]);
211
- for (const [relativePath, content] of Object.entries(templates_1.starterFiles)) {
212
- results.push([relativePath, (0, workspace_1.writeStarter)(relativePath, content)]);
213
- }
214
- results.push(["wiki/meta/wiki-ops-v1-decisions.md", (0, workspace_1.writeManaged)("wiki/meta/wiki-ops-v1-decisions.md", templates_1.starterFiles["wiki/meta/wiki-ops-v1-decisions.md"])]);
215
- if (args_1.glossaryMode) {
216
- results.push(["wiki/canonical/glossary.md", (0, workspace_1.writeStarter)("wiki/canonical/glossary.md", templates_1.glossary)]);
217
- results.push(["wiki/index.md glossary router", (0, workspace_1.upsertMarkedSection)("wiki/index.md", "<!-- PROJECT-WIKI-GLOSSARY:START -->", "<!-- PROJECT-WIKI-GLOSSARY:END -->", templates_1.glossaryIndexBlock)]);
218
- }
219
- if (args_1.captureInboxMode) {
220
- results.push(["wiki/inbox/project-candidates.md", (0, modes_1.appendCaptureInbox)()]);
221
- results.push(["wiki/index.md inbox router", (0, workspace_1.upsertMarkedSection)("wiki/index.md", "<!-- PROJECT-WIKI-INBOX:START -->", "<!-- PROJECT-WIKI-INBOX:END -->", templates_1.inboxIndexBlock)]);
222
- }
223
- if (args_1.refreshIndexMode) {
224
- results.push(["wiki/index.md auto-discovered pages", (0, workspace_1.upsertMarkedSection)("wiki/index.md", "<!-- PROJECT-WIKI-AUTO-INDEX:START -->", "<!-- PROJECT-WIKI-AUTO-INDEX:END -->", (0, modes_1.buildRefreshIndexBlock)())]);
225
- }
226
- if (args_1.migrateMode && migrationState) {
227
- const migration = (0, migration_1.runMigrationMode)(migrationState);
228
- for (const result of migration.results)
229
- results.push(result);
230
- results.push(["migration summary", `${migration.total} files from ${migration.legacyPath || "no legacy"}`]);
231
- }
232
- const modes = [];
233
- if (args_1.migrateMode)
234
- modes.push("migration");
235
- if (args_1.glossaryMode)
236
- modes.push("glossary");
237
- if (args_1.captureInboxMode)
238
- modes.push("capture-inbox");
239
- if (args_1.refreshIndexMode)
240
- modes.push("refresh-index");
241
- if (args_1.noGitConfigMode)
242
- modes.push("no-git-config");
243
- console.log(modes.length > 0 ? `Project Librarian + ${modes.join(" + ")} complete.` : "Project Librarian complete.");
244
- for (const [relativePath, status] of results) {
245
- console.log(`${String(status).padEnd(7)} ${relativePath}`);
126
+ if (args_1.command === "mcp") {
127
+ // Hand-rolled stdio MCP server over the existing code-evidence index. Lazy
128
+ // require keeps the server (and its node:sqlite dependency) out of the normal
129
+ // bootstrap path. The server roots at process.cwd() and runs until stdin ends,
130
+ // exiting from inside runMcpServerMode; the init flow below must not run.
131
+ require("./mcp-server").runMcpServerMode();
132
+ }
133
+ else {
134
+ runInitCommand();
135
+ }
136
+ function runInitCommand() {
137
+ const activeCodeModes = [args_1.codeQueryMode, args_1.codeReportMode, args_1.codeStatusMode, args_1.codeFilesMode, args_1.codeImpactMode, args_1.codeSearchSymbolMode, args_1.codeIndexMode].filter(Boolean).length;
138
+ if (activeCodeModes > 1) {
139
+ console.error("Use one code evidence mode at a time: --code-index, --code-query, --code-report, --code-status, --code-files, --code-impact, or --code-search-symbol.");
140
+ process.exit(1);
141
+ }
142
+ if (args_1.codeQueryMode) {
143
+ codeIndex().runCodeQueryMode();
144
+ exitAfterStdoutDrain(0);
145
+ return;
146
+ }
147
+ if (args_1.codeReportMode) {
148
+ codeIndex().runCodeReportMode();
149
+ exitAfterStdoutDrain(0);
150
+ return;
151
+ }
152
+ if (args_1.codeStatusMode) {
153
+ codeIndex().runCodeStatusMode();
154
+ exitAfterStdoutDrain(0);
155
+ return;
156
+ }
157
+ if (args_1.codeFilesMode) {
158
+ codeIndex().runCodeFilesMode();
159
+ exitAfterStdoutDrain(0);
160
+ return;
161
+ }
162
+ if (args_1.codeImpactMode) {
163
+ codeIndex().runCodeImpactMode();
164
+ exitAfterStdoutDrain(0);
165
+ return;
166
+ }
167
+ if (args_1.codeSearchSymbolMode) {
168
+ codeIndex().runCodeSearchSymbolMode();
169
+ exitAfterStdoutDrain(0);
170
+ return;
171
+ }
172
+ if (args_1.codeIndexMode) {
173
+ codeIndex().runCodeIndexMode();
174
+ process.exit(0);
175
+ }
176
+ if (args_1.wikiImpactMode) {
177
+ (0, modes_1.runWikiImpactMode)();
178
+ exitAfterStdoutDrain(0);
179
+ return;
180
+ }
181
+ if (args_1.queryTerm) {
182
+ (0, modes_1.runQueryMode)();
183
+ exitAfterStdoutDrain(0);
184
+ return;
185
+ }
186
+ if (args_1.issueCreateMode) {
187
+ (0, modes_1.runIssueCreateMode)();
188
+ process.exit(0);
189
+ }
190
+ if (args_1.issueDraftMode) {
191
+ (0, modes_1.runIssueDraftMode)();
192
+ exitAfterStdoutDrain(0);
193
+ return;
194
+ }
195
+ if (args_1.pruneCheckMode) {
196
+ (0, modes_1.runPruneCheckMode)();
197
+ process.exit(0);
198
+ }
199
+ if (args_1.reviewMigrationMode) {
200
+ (0, migration_1.runReviewMigrationMode)();
201
+ process.exit(0);
202
+ }
203
+ if (args_1.migrationDoctorMode) {
204
+ (0, modes_1.runMigrationDoctorMode)();
205
+ process.exit(0);
206
+ }
207
+ if (args_1.migrationQualityCheckMode) {
208
+ (0, modes_1.runMigrationQualityCheckMode)();
209
+ process.exit(0);
210
+ }
211
+ if (args_1.migrationLintMode) {
212
+ (0, modes_1.runMigrationLintMode)();
213
+ process.exit(0);
214
+ }
215
+ if (args_1.doctorMode) {
216
+ (0, modes_1.runDoctorMode)(args_1.fixMode);
217
+ process.exit(0);
218
+ }
219
+ if (args_1.linkCheckMode) {
220
+ (0, modes_1.runLinkCheckMode)();
221
+ process.exit(0);
222
+ }
223
+ if (args_1.qualityCheckMode) {
224
+ (0, modes_1.runQualityCheckMode)();
225
+ process.exit(0);
226
+ }
227
+ if (args_1.lintMode) {
228
+ (0, modes_1.runLintMode)();
229
+ process.exit(0);
230
+ }
231
+ const migrationState = args_1.migrateMode ? (0, migration_1.prepareMigrationMode)() : null;
232
+ const results = [];
233
+ if (migrationState)
234
+ results.push(["migration prepare", migrationState.note]);
235
+ (0, workspace_1.mkdirp)("wiki/canonical");
236
+ (0, workspace_1.mkdirp)("wiki/decisions");
237
+ (0, workspace_1.mkdirp)("wiki/inbox");
238
+ (0, workspace_1.mkdirp)("wiki/meta");
239
+ (0, workspace_1.mkdirp)("wiki/sources");
240
+ (0, workspace_1.mkdirp)(".codex/hooks");
241
+ (0, workspace_1.mkdirp)(".claude/hooks");
242
+ (0, workspace_1.mkdirp)(".cursor/hooks");
243
+ (0, workspace_1.mkdirp)(".cursor/rules");
244
+ (0, workspace_1.mkdirp)(".gemini/hooks");
245
+ (0, workspace_1.mkdirp)(".githooks");
246
+ // B1 fallback: sync the CURRENT startup.md TL;DR into the managed AGENTS.md block
247
+ // so non-interactive `codex exec` (which does not run SessionStart hooks) still
248
+ // gets compact startup context. Routers are starter files written later in this
249
+ // flow, so on a fresh bootstrap startup.md does not exist yet; fall back to the
250
+ // template TL;DR that bootstrap is about to write. A missing "## TL;DR" section in
251
+ // an existing startup.md fails loudly inside extractStartupTldr (no fallback).
252
+ const startupForSync = (0, workspace_1.exists)("wiki/startup.md") ? (0, workspace_1.read)("wiki/startup.md") : templates_1.startup;
253
+ const startupTldrForAgents = (0, templates_1.extractStartupTldr)(startupForSync);
254
+ results.push(["AGENTS.md", (0, workspace_1.upsertMarkedSection)("AGENTS.md", "<!-- PROJECT-WIKI-FIRST:START -->", "<!-- PROJECT-WIKI-FIRST:END -->", (0, templates_1.agentsSection)(startupTldrForAgents))]);
255
+ results.push(["CLAUDE.md", (0, workspace_1.upsertMarkedSection)("CLAUDE.md", "<!-- PROJECT-WIKI-CLAUDE:START -->", "<!-- PROJECT-WIKI-CLAUDE:END -->", templates_1.claudeSection)]);
256
+ results.push(["GEMINI.md", (0, workspace_1.upsertMarkedSection)("GEMINI.md", "<!-- PROJECT-WIKI-GEMINI:START -->", "<!-- PROJECT-WIKI-GEMINI:END -->", templates_1.geminiSection)]);
257
+ results.push([".cursor/rules/project-librarian.mdc", (0, workspace_1.writeManaged)(".cursor/rules/project-librarian.mdc", templates_1.cursorRule)]);
258
+ results.push(["wiki/AGENTS.md", (0, workspace_1.upsertMarkedSection)("wiki/AGENTS.md", "<!-- PROJECT-WIKI-INTERNAL:START -->", "<!-- PROJECT-WIKI-INTERNAL:END -->", templates_1.wikiAgentsSection)]);
259
+ results.push([".githooks/prepare-commit-msg", (0, workspace_1.writeManaged)(".githooks/prepare-commit-msg", hooks_1.gitPrepareCommitMsgHook)]);
260
+ (0, workspace_1.makeExecutable)(".githooks/prepare-commit-msg");
261
+ results.push([".githooks/wiki-commit-trailers.js", (0, workspace_1.writeManaged)(".githooks/wiki-commit-trailers.js", hooks_1.gitWikiCommitTrailersScript)]);
262
+ (0, workspace_1.makeExecutable)(".githooks/wiki-commit-trailers.js");
263
+ results.push(["git core.hooksPath", (0, hooks_1.upsertGitHooksPath)()]);
264
+ results.push([".codex/hooks.json", (0, hooks_1.upsertHookConfig)()]);
265
+ results.push([".codex/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".codex/hooks/wiki-session-start.js", hooks_1.hookScript)]);
266
+ results.push([".claude/settings.json", (0, hooks_1.upsertClaudeHookConfig)()]);
267
+ results.push([".claude/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".claude/hooks/wiki-session-start.js", hooks_1.hookScript)]);
268
+ results.push([".cursor/hooks.json", (0, hooks_1.upsertCursorHookConfig)()]);
269
+ results.push([".cursor/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".cursor/hooks/wiki-session-start.js", hooks_1.cursorHookScript)]);
270
+ results.push([".gemini/settings.json", (0, hooks_1.upsertGeminiHookConfig)()]);
271
+ results.push([".gemini/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".gemini/hooks/wiki-session-start.js", hooks_1.hookScript)]);
272
+ // Bootstrap-managed MCP registration (preservation-first, idempotent). Claude
273
+ // Code reads `.mcp.json`, Cursor reads `.cursor/mcp.json`, and Gemini reads
274
+ // `mcpServers` inside `.gemini/settings.json`. Codex only supports user-level MCP
275
+ // config (`codex mcp add` -> ~/.codex/config.toml), so it is intentionally not
276
+ // registered at project level; the README documents the manual user-level step.
277
+ // Registration is scale-gated (2026-06-12 decision): below the measured
278
+ // file-count threshold with no existing .project-wiki index, the rows report the
279
+ // skip reason instead of writing config; an existing index registers regardless.
280
+ const mcpGate = (0, hooks_1.mcpRegistrationGate)();
281
+ if (mcpGate.register) {
282
+ results.push([".mcp.json", (0, hooks_1.upsertClaudeMcpConfig)()]);
283
+ results.push([".cursor/mcp.json", (0, hooks_1.upsertCursorMcpConfig)()]);
284
+ results.push([".gemini/settings.json mcpServers", (0, hooks_1.upsertGeminiMcpConfig)()]);
285
+ }
286
+ else {
287
+ results.push([".mcp.json", mcpGate.reason]);
288
+ results.push([".cursor/mcp.json", mcpGate.reason]);
289
+ results.push([".gemini/settings.json mcpServers", mcpGate.reason]);
290
+ }
291
+ // Routers accumulate user-maintained project state after bootstrap, so they are
292
+ // starter files: templates are written only when the file is absent, never rebuilt.
293
+ results.push(["wiki/startup.md", (0, workspace_1.writeStarter)("wiki/startup.md", templates_1.startup)]);
294
+ results.push(["wiki/index.md", (0, workspace_1.writeStarter)("wiki/index.md", templates_1.index)]);
295
+ results.push(["wiki/meta/operating-model.md", (0, workspace_1.writeManaged)("wiki/meta/operating-model.md", templates_1.wikiOperatingModel)]);
296
+ results.push(["wiki/meta/decision-policy.md", (0, workspace_1.writeManaged)("wiki/meta/decision-policy.md", templates_1.decisionPolicy)]);
297
+ results.push(["wiki/canonical/wiki-operating-model.md", (0, workspace_1.deleteIfGenerated)("wiki/canonical/wiki-operating-model.md", ["# Wiki Operating Model"])]);
298
+ results.push(["wiki/canonical/decision-policy.md", (0, workspace_1.deleteIfGenerated)("wiki/canonical/decision-policy.md", ["# Decision Policy"])]);
299
+ results.push(["wiki/decisions/wiki-v1-decisions.md", (0, workspace_1.deleteIfGenerated)("wiki/decisions/wiki-v1-decisions.md", ["# Wiki v1 Decisions", "# Wiki Operations v1 Decisions"])]);
300
+ for (const [relativePath, content] of Object.entries(templates_1.starterFiles)) {
301
+ if (!templates_1.defaultStarterFilePaths.has(relativePath))
302
+ continue;
303
+ results.push([relativePath, (0, workspace_1.writeStarter)(relativePath, content)]);
304
+ }
305
+ results.push(["wiki/meta/wiki-ops-v1-decisions.md", (0, workspace_1.writeManaged)("wiki/meta/wiki-ops-v1-decisions.md", templates_1.starterFiles["wiki/meta/wiki-ops-v1-decisions.md"])]);
306
+ if (args_1.glossaryMode) {
307
+ results.push(["wiki/canonical/glossary.md", (0, workspace_1.writeStarter)("wiki/canonical/glossary.md", templates_1.glossary)]);
308
+ results.push(["wiki/index.md glossary router", (0, workspace_1.upsertMarkedSection)("wiki/index.md", "<!-- PROJECT-WIKI-GLOSSARY:START -->", "<!-- PROJECT-WIKI-GLOSSARY:END -->", templates_1.glossaryIndexBlock)]);
309
+ }
310
+ if (args_1.captureInboxMode) {
311
+ results.push(["wiki/inbox/project-candidates.md", (0, modes_1.appendCaptureInbox)()]);
312
+ results.push(["wiki/index.md inbox router", (0, workspace_1.upsertMarkedSection)("wiki/index.md", "<!-- PROJECT-WIKI-INBOX:START -->", "<!-- PROJECT-WIKI-INBOX:END -->", templates_1.inboxIndexBlock)]);
313
+ }
314
+ if (args_1.refreshIndexMode) {
315
+ results.push(["wiki/index.md auto-discovered pages", (0, workspace_1.upsertMarkedSection)("wiki/index.md", "<!-- PROJECT-WIKI-AUTO-INDEX:START -->", "<!-- PROJECT-WIKI-AUTO-INDEX:END -->", (0, modes_1.buildRefreshIndexBlock)())]);
316
+ }
317
+ if (args_1.migrateMode && migrationState) {
318
+ const migration = (0, migration_1.runMigrationMode)(migrationState);
319
+ for (const result of migration.results)
320
+ results.push(result);
321
+ results.push(["migration summary", `${migration.total} files from ${migration.legacyPath || "no legacy"}`]);
322
+ }
323
+ const modes = [];
324
+ if (args_1.migrateMode)
325
+ modes.push("migration");
326
+ if (args_1.glossaryMode)
327
+ modes.push("glossary");
328
+ if (args_1.captureInboxMode)
329
+ modes.push("capture-inbox");
330
+ if (args_1.refreshIndexMode)
331
+ modes.push("refresh-index");
332
+ if (args_1.noGitConfigMode)
333
+ modes.push("no-git-config");
334
+ console.log(modes.length > 0 ? `Project Librarian + ${modes.join(" + ")} complete.` : "Project Librarian complete.");
335
+ for (const [relativePath, status] of results) {
336
+ console.log(`${String(status).padEnd(7)} ${relativePath}`);
337
+ }
246
338
  }
@@ -39,13 +39,12 @@ const os = __importStar(require("node:os"));
39
39
  const path = __importStar(require("node:path"));
40
40
  const args_1 = require("./args");
41
41
  const skillName = "project-librarian";
42
+ const allAgentTargets = ["codex", "claude", "cursor", "gemini"];
42
43
  const packageFiles = [
43
44
  "SKILL.md",
44
45
  "dist",
45
46
  "README.md",
46
47
  "README.ko.md",
47
- "README.ja.md",
48
- "README.zh.md",
49
48
  "LICENSE",
50
49
  "package.json",
51
50
  "agents",
@@ -61,19 +60,19 @@ function installScope() {
61
60
  return fail(`invalid --scope: ${scope}; expected user or project`);
62
61
  }
63
62
  function installAgents() {
64
- const value = (0, args_1.argValue)("--agents") || "both";
63
+ const value = (0, args_1.argValue)("--agents") || "all";
65
64
  const parts = value.split(",").map((item) => item.trim()).filter(Boolean);
66
65
  const agents = new Set();
67
66
  for (const part of parts) {
68
- if (part === "both" || part === "all") {
69
- agents.add("codex");
70
- agents.add("claude");
67
+ if (part === "all") {
68
+ for (const agent of allAgentTargets)
69
+ agents.add(agent);
71
70
  }
72
- else if (part === "codex" || part === "claude") {
71
+ else if (allAgentTargets.includes(part)) {
73
72
  agents.add(part);
74
73
  }
75
74
  else {
76
- return fail(`invalid --agents entry: ${part}; expected codex, claude, or both`);
75
+ return fail(`invalid --agents entry: ${part}; expected codex, claude, cursor, gemini, or all`);
77
76
  }
78
77
  }
79
78
  return Array.from(agents);
@@ -85,10 +84,23 @@ function userAgentRoot(agent) {
85
84
  const home = os.homedir();
86
85
  if (agent === "codex")
87
86
  return process.env.CODEX_HOME || path.join(home, ".codex");
88
- return process.env.CLAUDE_HOME || path.join(home, ".claude");
87
+ if (agent === "claude")
88
+ return process.env.CLAUDE_HOME || path.join(home, ".claude");
89
+ if (agent === "cursor")
90
+ return process.env.CURSOR_HOME || path.join(home, ".cursor");
91
+ return process.env.GEMINI_HOME || path.join(home, ".gemini");
92
+ }
93
+ function projectAgentRoot(agent) {
94
+ if (agent === "codex")
95
+ return ".codex";
96
+ if (agent === "claude")
97
+ return ".claude";
98
+ if (agent === "cursor")
99
+ return ".cursor";
100
+ return ".gemini";
89
101
  }
90
102
  function installTarget(agent, scope) {
91
- const base = scope === "user" ? userAgentRoot(agent) : path.join(process.cwd(), agent === "codex" ? ".codex" : ".claude");
103
+ const base = scope === "user" ? userAgentRoot(agent) : path.join(process.cwd(), projectAgentRoot(agent));
92
104
  return path.join(base, "skills", skillName);
93
105
  }
94
106
  function sameFile(source, target) {
@@ -134,8 +146,8 @@ function runInstallSkillMode() {
134
146
  console.log(`Project Librarian skill ${dryRun ? "install dry-run" : "install"} complete.`);
135
147
  console.log(`scope: ${scope}`);
136
148
  console.log(`agents: ${agents.join(", ")}`);
137
- console.log("note: install-skill only installs the reusable skill files; it does not create or update AGENTS.md, CLAUDE.md, wiki/, .codex/hooks.json, or .claude/settings.json.");
138
- console.log("next: agents should run the installed local project-librarian runner from the target project root; direct shell users can still run `npx project-librarian` when registry access is available.");
149
+ console.log("note: install-skill only installs the reusable skill files; it does not create or update AGENTS.md, CLAUDE.md, GEMINI.md, wiki/, .cursor/rules/, .cursor/hooks.json, .gemini/settings.json, .codex/hooks.json, or .claude/settings.json.");
150
+ console.log("next: ask your agent to use Project Librarian from the target project root; the installed skill resolves the local runner.");
139
151
  for (const [label, status] of rows) {
140
152
  console.log(`${status.padEnd(7)} ${label}`);
141
153
  }