project-librarian 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +49 -9
- package/README.md +44 -4
- package/dist/agent-surfaces.js +67 -0
- package/dist/args.js +94 -89
- package/dist/code-index/evidence.js +79 -0
- package/dist/code-index/extractors/config.js +58 -0
- package/dist/code-index/extractors/light-languages.js +52 -0
- package/dist/code-index/extractors/registry.js +137 -0
- package/dist/code-index/extractors/shared.js +36 -0
- package/dist/code-index/extractors/tree-sitter.js +319 -0
- package/dist/code-index/extractors/types.js +2 -0
- package/dist/code-index/extractors/typescript.js +211 -0
- package/dist/code-index/incremental.js +16 -0
- package/dist/code-index/index-health.js +164 -0
- package/dist/code-index/modes.js +309 -0
- package/dist/code-index/ownership.js +183 -0
- package/dist/code-index/reports.js +322 -0
- package/dist/code-index/schema.js +196 -0
- package/dist/code-index/search.js +153 -0
- package/dist/code-index-file-policy.js +21 -27
- package/dist/code-index.js +167 -1850
- package/dist/init-project-wiki.js +105 -66
- package/dist/install-skill.js +3 -3
- package/dist/mcp-server.js +60 -6
- package/dist/migration.js +10 -6
- package/dist/modes.js +121 -63
- package/dist/path-ignore-policy.js +30 -0
- package/dist/wiki-corpus.js +25 -0
- package/dist/wiki-diagnostics.js +19 -0
- package/dist/wiki-files.js +2 -1
- package/dist/wiki-graph.js +1 -2
- package/package.json +15 -3
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const args_1 = require("./args");
|
|
5
|
+
const agent_surfaces_1 = require("./agent-surfaces");
|
|
5
6
|
const hooks_1 = require("./hooks");
|
|
6
7
|
const install_skill_1 = require("./install-skill");
|
|
7
8
|
const modes_1 = require("./modes");
|
|
@@ -39,10 +40,12 @@ Options:
|
|
|
39
40
|
--refresh-index Update the managed auto-discovered wiki index block.
|
|
40
41
|
--capture-inbox Append a candidate note with --title, --content, and optional --category.
|
|
41
42
|
--glossary-init Create and route the optional glossary page.
|
|
43
|
+
--agents <list> With init/update, write only selected agent surfaces: codex, claude, cursor, gemini, or all. Existing project skill/setup surfaces are preserved by default.
|
|
42
44
|
--prune-check Report active pages with stale or unresolved signals.
|
|
43
45
|
--review-migration Sync unit coverage and compatible inbox statuses into migration review files.
|
|
44
46
|
--no-git-config Install hook files without changing git core.hooksPath.
|
|
45
47
|
--code-index Build the disposable .project-wiki code evidence index.
|
|
48
|
+
--code-index-health Inspect code evidence cache compatibility and print rebuild guidance without writing.
|
|
46
49
|
--acknowledge-small-repo With --code-index, proceed below the small-repo scale gate after its cost warning.
|
|
47
50
|
--incremental With --code-index, require an existing compatible index and update only changes.
|
|
48
51
|
--code-index-full With --code-index, force a full rebuild even when incremental update is possible.
|
|
@@ -68,6 +71,20 @@ Commands:
|
|
|
68
71
|
function exitAfterStdoutDrain(code) {
|
|
69
72
|
process.stdout.write("", () => process.exit(code));
|
|
70
73
|
}
|
|
74
|
+
function activeCodeEvidenceCliModes() {
|
|
75
|
+
const modes = [
|
|
76
|
+
{ active: args_1.codeQueryMode, drainStdout: true, run: (codeIndexModule) => codeIndexModule.runCodeQueryMode() },
|
|
77
|
+
{ active: args_1.codeReportMode, drainStdout: true, run: (codeIndexModule) => codeIndexModule.runCodeReportMode() },
|
|
78
|
+
{ active: args_1.codeStatusMode, drainStdout: true, run: (codeIndexModule) => codeIndexModule.runCodeStatusMode() },
|
|
79
|
+
{ active: args_1.codeFilesMode, drainStdout: true, run: (codeIndexModule) => codeIndexModule.runCodeFilesMode() },
|
|
80
|
+
{ active: args_1.codeImpactMode, drainStdout: true, run: (codeIndexModule) => codeIndexModule.runCodeImpactMode() },
|
|
81
|
+
{ active: args_1.codeContextPackMode, drainStdout: true, run: (codeIndexModule) => codeIndexModule.runCodeContextPackMode() },
|
|
82
|
+
{ active: args_1.codeSearchSymbolMode, drainStdout: true, run: (codeIndexModule) => codeIndexModule.runCodeSearchSymbolMode() },
|
|
83
|
+
{ active: args_1.codeIndexHealthMode, drainStdout: true, run: (codeIndexModule) => codeIndexModule.runCodeIndexHealthMode() },
|
|
84
|
+
{ active: args_1.codeIndexMode, drainStdout: false, run: (codeIndexModule) => codeIndexModule.runCodeIndexMode() },
|
|
85
|
+
];
|
|
86
|
+
return modes.filter((mode) => mode.active);
|
|
87
|
+
}
|
|
71
88
|
if (args_1.helpMode) {
|
|
72
89
|
printUsage();
|
|
73
90
|
process.exit(0);
|
|
@@ -92,6 +109,11 @@ if (args_1.missingValueOptions.length > 0) {
|
|
|
92
109
|
printUsage();
|
|
93
110
|
process.exit(1);
|
|
94
111
|
}
|
|
112
|
+
if (args_1.invalidAgentTargets.length > 0) {
|
|
113
|
+
console.error(`invalid --agents entr${args_1.invalidAgentTargets.length === 1 ? "y" : "ies"}: ${args_1.invalidAgentTargets.join(", ")}; expected codex, claude, cursor, gemini, or all`);
|
|
114
|
+
printUsage();
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
95
117
|
if (args_1.command === "update" && args_1.migrateMode) {
|
|
96
118
|
console.error("update cannot be combined with --migrate or --adopt-existing; use project-librarian --migrate for migration.");
|
|
97
119
|
process.exit(1);
|
|
@@ -147,50 +169,20 @@ else {
|
|
|
147
169
|
runInitCommand();
|
|
148
170
|
}
|
|
149
171
|
function runInitCommand() {
|
|
150
|
-
const activeCodeModes =
|
|
151
|
-
if (activeCodeModes > 1) {
|
|
152
|
-
console.error("Use one code evidence mode at a time: --code-index, --code-query, --code-report, --code-status, --code-files, --code-impact, --code-context-pack, or --code-search-symbol.");
|
|
172
|
+
const activeCodeModes = activeCodeEvidenceCliModes();
|
|
173
|
+
if (activeCodeModes.length > 1) {
|
|
174
|
+
console.error("Use one code evidence mode at a time: --code-index, --code-index-health, --code-query, --code-report, --code-status, --code-files, --code-impact, --code-context-pack, or --code-search-symbol.");
|
|
153
175
|
process.exit(1);
|
|
154
176
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
exitAfterStdoutDrain(0);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
if (args_1.codeStatusMode) {
|
|
166
|
-
codeIndex().runCodeStatusMode();
|
|
167
|
-
exitAfterStdoutDrain(0);
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
if (args_1.codeFilesMode) {
|
|
171
|
-
codeIndex().runCodeFilesMode();
|
|
172
|
-
exitAfterStdoutDrain(0);
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
if (args_1.codeImpactMode) {
|
|
176
|
-
codeIndex().runCodeImpactMode();
|
|
177
|
-
exitAfterStdoutDrain(0);
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
if (args_1.codeContextPackMode) {
|
|
181
|
-
codeIndex().runCodeContextPackMode();
|
|
182
|
-
exitAfterStdoutDrain(0);
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
if (args_1.codeSearchSymbolMode) {
|
|
186
|
-
codeIndex().runCodeSearchSymbolMode();
|
|
187
|
-
exitAfterStdoutDrain(0);
|
|
177
|
+
const activeCodeMode = activeCodeModes[0];
|
|
178
|
+
if (activeCodeMode) {
|
|
179
|
+
activeCodeMode.run(codeIndex());
|
|
180
|
+
if (activeCodeMode.drainStdout)
|
|
181
|
+
exitAfterStdoutDrain(0);
|
|
182
|
+
else
|
|
183
|
+
process.exit(0);
|
|
188
184
|
return;
|
|
189
185
|
}
|
|
190
|
-
if (args_1.codeIndexMode) {
|
|
191
|
-
codeIndex().runCodeIndexMode();
|
|
192
|
-
process.exit(0);
|
|
193
|
-
}
|
|
194
186
|
if (args_1.wikiImpactMode) {
|
|
195
187
|
(0, modes_1.runWikiImpactMode)();
|
|
196
188
|
exitAfterStdoutDrain(0);
|
|
@@ -258,6 +250,20 @@ function runInitCommand() {
|
|
|
258
250
|
(0, modes_1.runLintMode)();
|
|
259
251
|
process.exit(0);
|
|
260
252
|
}
|
|
253
|
+
if (args_1.refreshIndexMode && !args_1.migrateMode && !args_1.glossaryMode && !args_1.captureInboxMode) {
|
|
254
|
+
runRefreshIndexOnlyMode();
|
|
255
|
+
process.exit(0);
|
|
256
|
+
}
|
|
257
|
+
const selectedAgentSurfaces = args_1.agentTargets.length > 0
|
|
258
|
+
? args_1.agentTargets
|
|
259
|
+
: args_1.migrateMode
|
|
260
|
+
? Array.from(agent_surfaces_1.allAgentSurfaces)
|
|
261
|
+
: (0, agent_surfaces_1.resolveBootstrapAgentSurfaces)(args_1.agentTargets, workspace_1.exists, workspace_1.read);
|
|
262
|
+
const shouldWriteSurface = (surface) => (0, agent_surfaces_1.includesAgentSurface)(selectedAgentSurfaces, surface);
|
|
263
|
+
const writeCodexSurface = shouldWriteSurface("codex");
|
|
264
|
+
const writeClaudeSurface = shouldWriteSurface("claude");
|
|
265
|
+
const writeCursorSurface = shouldWriteSurface("cursor");
|
|
266
|
+
const writeGeminiSurface = shouldWriteSurface("gemini");
|
|
261
267
|
const migrationState = args_1.migrateMode ? (0, migration_1.prepareMigrationMode)() : null;
|
|
262
268
|
const results = [];
|
|
263
269
|
if (migrationState)
|
|
@@ -267,11 +273,16 @@ function runInitCommand() {
|
|
|
267
273
|
(0, workspace_1.mkdirp)("wiki/inbox");
|
|
268
274
|
(0, workspace_1.mkdirp)("wiki/meta");
|
|
269
275
|
(0, workspace_1.mkdirp)("wiki/sources");
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
276
|
+
if (writeCodexSurface)
|
|
277
|
+
(0, workspace_1.mkdirp)(".codex/hooks");
|
|
278
|
+
if (writeClaudeSurface)
|
|
279
|
+
(0, workspace_1.mkdirp)(".claude/hooks");
|
|
280
|
+
if (writeCursorSurface) {
|
|
281
|
+
(0, workspace_1.mkdirp)(".cursor/hooks");
|
|
282
|
+
(0, workspace_1.mkdirp)(".cursor/rules");
|
|
283
|
+
}
|
|
284
|
+
if (writeGeminiSurface)
|
|
285
|
+
(0, workspace_1.mkdirp)(".gemini/hooks");
|
|
275
286
|
(0, workspace_1.mkdirp)(".githooks");
|
|
276
287
|
// B1 fallback: sync the CURRENT startup.md TL;DR into the managed AGENTS.md block
|
|
277
288
|
// so non-interactive `codex exec` (which does not run SessionStart hooks) still
|
|
@@ -282,23 +293,34 @@ function runInitCommand() {
|
|
|
282
293
|
const startupForSync = (0, workspace_1.exists)("wiki/startup.md") ? (0, workspace_1.read)("wiki/startup.md") : templates_1.startup;
|
|
283
294
|
const startupTldrForAgents = (0, templates_1.extractStartupTldr)(startupForSync);
|
|
284
295
|
results.push(["AGENTS.md", (0, workspace_1.upsertMarkedSection)("AGENTS.md", "<!-- PROJECT-WIKI-FIRST:START -->", "<!-- PROJECT-WIKI-FIRST:END -->", (0, templates_1.agentsSection)(startupTldrForAgents))]);
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
296
|
+
if (writeClaudeSurface)
|
|
297
|
+
results.push(["CLAUDE.md", (0, workspace_1.upsertMarkedSection)("CLAUDE.md", "<!-- PROJECT-WIKI-CLAUDE:START -->", "<!-- PROJECT-WIKI-CLAUDE:END -->", templates_1.claudeSection)]);
|
|
298
|
+
if (writeGeminiSurface)
|
|
299
|
+
results.push(["GEMINI.md", (0, workspace_1.upsertMarkedSection)("GEMINI.md", "<!-- PROJECT-WIKI-GEMINI:START -->", "<!-- PROJECT-WIKI-GEMINI:END -->", templates_1.geminiSection)]);
|
|
300
|
+
if (writeCursorSurface)
|
|
301
|
+
results.push([".cursor/rules/project-librarian.mdc", (0, workspace_1.writeManaged)(".cursor/rules/project-librarian.mdc", templates_1.cursorRule)]);
|
|
288
302
|
results.push(["wiki/AGENTS.md", (0, workspace_1.upsertMarkedSection)("wiki/AGENTS.md", "<!-- PROJECT-WIKI-INTERNAL:START -->", "<!-- PROJECT-WIKI-INTERNAL:END -->", templates_1.wikiAgentsSection)]);
|
|
289
303
|
results.push([".githooks/prepare-commit-msg", (0, workspace_1.writeManaged)(".githooks/prepare-commit-msg", hooks_1.gitPrepareCommitMsgHook)]);
|
|
290
304
|
(0, workspace_1.makeExecutable)(".githooks/prepare-commit-msg");
|
|
291
305
|
results.push([".githooks/wiki-commit-trailers.js", (0, workspace_1.writeManaged)(".githooks/wiki-commit-trailers.js", hooks_1.gitWikiCommitTrailersScript)]);
|
|
292
306
|
(0, workspace_1.makeExecutable)(".githooks/wiki-commit-trailers.js");
|
|
293
307
|
results.push(["git core.hooksPath", (0, hooks_1.upsertGitHooksPath)()]);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
308
|
+
if (writeCodexSurface) {
|
|
309
|
+
results.push([".codex/hooks.json", (0, hooks_1.upsertHookConfig)()]);
|
|
310
|
+
results.push([".codex/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".codex/hooks/wiki-session-start.js", hooks_1.hookScript)]);
|
|
311
|
+
}
|
|
312
|
+
if (writeClaudeSurface) {
|
|
313
|
+
results.push([".claude/settings.json", (0, hooks_1.upsertClaudeHookConfig)()]);
|
|
314
|
+
results.push([".claude/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".claude/hooks/wiki-session-start.js", hooks_1.hookScript)]);
|
|
315
|
+
}
|
|
316
|
+
if (writeCursorSurface) {
|
|
317
|
+
results.push([".cursor/hooks.json", (0, hooks_1.upsertCursorHookConfig)()]);
|
|
318
|
+
results.push([".cursor/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".cursor/hooks/wiki-session-start.js", hooks_1.cursorHookScript)]);
|
|
319
|
+
}
|
|
320
|
+
if (writeGeminiSurface) {
|
|
321
|
+
results.push([".gemini/settings.json", (0, hooks_1.upsertGeminiHookConfig)()]);
|
|
322
|
+
results.push([".gemini/hooks/wiki-session-start.js", (0, workspace_1.writeManaged)(".gemini/hooks/wiki-session-start.js", hooks_1.hookScript)]);
|
|
323
|
+
}
|
|
302
324
|
// Bootstrap-managed MCP registration (preservation-first, idempotent). Claude
|
|
303
325
|
// Code reads `.mcp.json`, Cursor reads `.cursor/mcp.json`, and Gemini reads
|
|
304
326
|
// `mcpServers` inside `.gemini/settings.json`. Codex only supports user-level MCP
|
|
@@ -307,16 +329,24 @@ function runInitCommand() {
|
|
|
307
329
|
// Registration is scale-gated (2026-06-12 decision): below the measured
|
|
308
330
|
// file-count threshold with no existing .project-wiki index, the rows report the
|
|
309
331
|
// skip reason instead of writing config; an existing index registers regardless.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
332
|
+
if (writeClaudeSurface || writeCursorSurface || writeGeminiSurface) {
|
|
333
|
+
const mcpGate = (0, hooks_1.mcpRegistrationGate)();
|
|
334
|
+
if (mcpGate.register) {
|
|
335
|
+
if (writeClaudeSurface)
|
|
336
|
+
results.push([".mcp.json", (0, hooks_1.upsertClaudeMcpConfig)()]);
|
|
337
|
+
if (writeCursorSurface)
|
|
338
|
+
results.push([".cursor/mcp.json", (0, hooks_1.upsertCursorMcpConfig)()]);
|
|
339
|
+
if (writeGeminiSurface)
|
|
340
|
+
results.push([".gemini/settings.json mcpServers", (0, hooks_1.upsertGeminiMcpConfig)()]);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
if (writeClaudeSurface)
|
|
344
|
+
results.push([".mcp.json", mcpGate.reason]);
|
|
345
|
+
if (writeCursorSurface)
|
|
346
|
+
results.push([".cursor/mcp.json", mcpGate.reason]);
|
|
347
|
+
if (writeGeminiSurface)
|
|
348
|
+
results.push([".gemini/settings.json mcpServers", mcpGate.reason]);
|
|
349
|
+
}
|
|
320
350
|
}
|
|
321
351
|
// Routers accumulate user-maintained project state after bootstrap, so they are
|
|
322
352
|
// starter files: templates are written only when the file is absent, never rebuilt.
|
|
@@ -366,3 +396,12 @@ function runInitCommand() {
|
|
|
366
396
|
console.log(`${String(status).padEnd(7)} ${relativePath}`);
|
|
367
397
|
}
|
|
368
398
|
}
|
|
399
|
+
function runRefreshIndexOnlyMode() {
|
|
400
|
+
const results = [];
|
|
401
|
+
results.push(["wiki/index.md", (0, workspace_1.writeStarter)("wiki/index.md", templates_1.index)]);
|
|
402
|
+
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)())]);
|
|
403
|
+
console.log("Project Librarian refresh-index complete.");
|
|
404
|
+
for (const [relativePath, status] of results) {
|
|
405
|
+
console.log(`${String(status).padEnd(7)} ${relativePath}`);
|
|
406
|
+
}
|
|
407
|
+
}
|
package/dist/install-skill.js
CHANGED
|
@@ -37,9 +37,9 @@ exports.runInstallSkillMode = runInstallSkillMode;
|
|
|
37
37
|
const fs = __importStar(require("node:fs"));
|
|
38
38
|
const os = __importStar(require("node:os"));
|
|
39
39
|
const path = __importStar(require("node:path"));
|
|
40
|
+
const agent_surfaces_1 = require("./agent-surfaces");
|
|
40
41
|
const args_1 = require("./args");
|
|
41
42
|
const skillName = "project-librarian";
|
|
42
|
-
const allAgentTargets = ["codex", "claude", "cursor", "gemini"];
|
|
43
43
|
const packageFiles = [
|
|
44
44
|
"SKILL.md",
|
|
45
45
|
"dist",
|
|
@@ -65,10 +65,10 @@ function installAgents() {
|
|
|
65
65
|
const agents = new Set();
|
|
66
66
|
for (const part of parts) {
|
|
67
67
|
if (part === "all") {
|
|
68
|
-
for (const agent of
|
|
68
|
+
for (const agent of agent_surfaces_1.allAgentSurfaces)
|
|
69
69
|
agents.add(agent);
|
|
70
70
|
}
|
|
71
|
-
else if (
|
|
71
|
+
else if (agent_surfaces_1.allAgentSurfaces.includes(part)) {
|
|
72
72
|
agents.add(part);
|
|
73
73
|
}
|
|
74
74
|
else {
|
package/dist/mcp-server.js
CHANGED
|
@@ -58,6 +58,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
58
58
|
const path = __importStar(require("node:path"));
|
|
59
59
|
const code_index_1 = require("./code-index");
|
|
60
60
|
const code_index_file_policy_1 = require("./code-index-file-policy");
|
|
61
|
+
const schema_1 = require("./code-index/schema");
|
|
61
62
|
const workspace_1 = require("./workspace");
|
|
62
63
|
// Pinned MCP protocol version. This is the spec revision this server is written
|
|
63
64
|
// against; one constant so the supported version is auditable in a single place.
|
|
@@ -366,8 +367,8 @@ function ownershipAnswer(filePath) {
|
|
|
366
367
|
lines.push(`Workspace owner: ${info.owner} (source: ${info.owner_source})${info.codeowners ? `; codeowners ${info.codeowners}` : ""}.`);
|
|
367
368
|
return lines.join("\n");
|
|
368
369
|
}
|
|
369
|
-
function impactAnswer(database, term) {
|
|
370
|
-
const impact = (0, code_index_1.codeImpact)(database, term);
|
|
370
|
+
function impactAnswer(database, term, context) {
|
|
371
|
+
const impact = (0, code_index_1.codeImpact)(database, term, { staleness: context.staleness });
|
|
371
372
|
const matches = (impact.matches ?? {});
|
|
372
373
|
const edges = (impact.edges ?? {});
|
|
373
374
|
const owners = asRows(impact.impacted_owners);
|
|
@@ -483,7 +484,7 @@ const TOOLS = [
|
|
|
483
484
|
properties: { term: { type: "string", description: "Path, symbol, route, module, or concept to build a compact code context pack for." } },
|
|
484
485
|
required: ["term"],
|
|
485
486
|
},
|
|
486
|
-
run: (database, args) => (0, code_index_1.codeContextPack)(database, requireStringArg(args, "term")),
|
|
487
|
+
run: (database, args, context) => (0, code_index_1.codeContextPack)(database, requireStringArg(args, "term"), { staleness: context.staleness }),
|
|
487
488
|
},
|
|
488
489
|
{
|
|
489
490
|
name: "code_impact",
|
|
@@ -493,7 +494,7 @@ const TOOLS = [
|
|
|
493
494
|
properties: { term: { type: "string", description: "File path, symbol name, route, or module to trace." } },
|
|
494
495
|
required: ["term"],
|
|
495
496
|
},
|
|
496
|
-
run: (database, args) => impactAnswer(database, requireStringArg(args, "term")),
|
|
497
|
+
run: (database, args, context) => impactAnswer(database, requireStringArg(args, "term"), context),
|
|
497
498
|
},
|
|
498
499
|
{
|
|
499
500
|
name: "code_ownership",
|
|
@@ -537,6 +538,59 @@ const TOOLS = [
|
|
|
537
538
|
},
|
|
538
539
|
];
|
|
539
540
|
const TOOLS_BY_NAME = new Map(TOOLS.map((tool) => [tool.name, tool]));
|
|
541
|
+
let cachedStaleness = null;
|
|
542
|
+
function statFingerprint(relativePath) {
|
|
543
|
+
const absolutePath = path.join(workspace_1.root, relativePath);
|
|
544
|
+
try {
|
|
545
|
+
const stat = fs.statSync(absolutePath);
|
|
546
|
+
if (!stat.isFile())
|
|
547
|
+
return `${relativePath}:not-file`;
|
|
548
|
+
return [
|
|
549
|
+
relativePath,
|
|
550
|
+
stat.size,
|
|
551
|
+
stat.mtimeMs,
|
|
552
|
+
stat.ctimeMs,
|
|
553
|
+
].join(":");
|
|
554
|
+
}
|
|
555
|
+
catch {
|
|
556
|
+
return `${relativePath}:missing`;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
function codeEvidenceFreshnessCacheKey(opened) {
|
|
560
|
+
try {
|
|
561
|
+
const database = opened.database;
|
|
562
|
+
const scopes = (0, schema_1.indexedScopes)(database);
|
|
563
|
+
const parserMode = (0, schema_1.indexedParserMode)(database);
|
|
564
|
+
const schemaVersion = (0, schema_1.readMetaValue)(database, "schema_version");
|
|
565
|
+
const updatedAt = (0, schema_1.readMetaValue)(database, "updated_at");
|
|
566
|
+
const currentFiles = (0, code_index_file_policy_1.discoverCodeFiles)(scopes.length > 0 ? scopes : ["."]);
|
|
567
|
+
const currentFingerprint = currentFiles.map(statFingerprint).join("\n");
|
|
568
|
+
const indexedFingerprint = database.prepare("SELECT path, hash, mtime_ms, size FROM files ORDER BY path")
|
|
569
|
+
.all()
|
|
570
|
+
.map((row) => `${String(row.path)}:${String(row.hash)}:${Number(row.mtime_ms)}:${Number(row.size)}`)
|
|
571
|
+
.join("\n");
|
|
572
|
+
return [
|
|
573
|
+
opened.relativePath,
|
|
574
|
+
schemaVersion,
|
|
575
|
+
updatedAt,
|
|
576
|
+
parserMode,
|
|
577
|
+
scopes.join("\0"),
|
|
578
|
+
currentFingerprint,
|
|
579
|
+
indexedFingerprint,
|
|
580
|
+
].join("\n---\n");
|
|
581
|
+
}
|
|
582
|
+
catch {
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
function codeIndexStalenessForToolCall(opened) {
|
|
587
|
+
const cacheKey = codeEvidenceFreshnessCacheKey(opened);
|
|
588
|
+
if (cacheKey && cachedStaleness?.cacheKey === cacheKey)
|
|
589
|
+
return cachedStaleness.staleness;
|
|
590
|
+
const staleness = (0, code_index_1.codeIndexStaleness)(opened.database);
|
|
591
|
+
cachedStaleness = cacheKey ? { cacheKey, staleness } : null;
|
|
592
|
+
return staleness;
|
|
593
|
+
}
|
|
540
594
|
// ---------------------------------------------------------------------------
|
|
541
595
|
// tools/call dispatch
|
|
542
596
|
// ---------------------------------------------------------------------------
|
|
@@ -559,10 +613,10 @@ function callTool(name, rawArgs) {
|
|
|
559
613
|
throw error;
|
|
560
614
|
}
|
|
561
615
|
try {
|
|
562
|
-
const staleness = (
|
|
616
|
+
const staleness = codeIndexStalenessForToolCall(opened);
|
|
563
617
|
const body = name === "code_status"
|
|
564
618
|
? statusAnswer(opened.database, opened.relativePath, staleness)
|
|
565
|
-
: TOOLS_BY_NAME.get(name).run(opened.database, args);
|
|
619
|
+
: TOOLS_BY_NAME.get(name).run(opened.database, args, { staleness });
|
|
566
620
|
return toolResultContent(finalizeAnswer(body, staleness));
|
|
567
621
|
}
|
|
568
622
|
catch (error) {
|
package/dist/migration.js
CHANGED
|
@@ -37,6 +37,7 @@ exports.generatedMigrationInboxFiles = void 0;
|
|
|
37
37
|
exports.classifyMarkdown = classifyMarkdown;
|
|
38
38
|
exports.formOnlyMigrationDocumentReason = formOnlyMigrationDocumentReason;
|
|
39
39
|
exports.extractMigrationUnits = extractMigrationUnits;
|
|
40
|
+
exports.loadMigrationUnitContext = loadMigrationUnitContext;
|
|
40
41
|
exports.collectMigrationCoverageDiagnostics = collectMigrationCoverageDiagnostics;
|
|
41
42
|
exports.collectMigrationUnitMapDiagnostics = collectMigrationUnitMapDiagnostics;
|
|
42
43
|
exports.collectMigrationSplitPlanDiagnostics = collectMigrationSplitPlanDiagnostics;
|
|
@@ -321,6 +322,9 @@ function expectedMigrationUnits() {
|
|
|
321
322
|
.flatMap((legacyRoot) => (0, wiki_files_1.walkMarkdownFiles)((0, workspace_1.abs)(legacyRoot), [], (0, workspace_1.abs)(legacyRoot)))
|
|
322
323
|
.flatMap((file) => extractMigrationUnits(file.basePath, (0, workspace_1.read)(file.path)));
|
|
323
324
|
}
|
|
325
|
+
function loadMigrationUnitContext() {
|
|
326
|
+
return { units: expectedMigrationUnits() };
|
|
327
|
+
}
|
|
324
328
|
function isMigrationConfidence(value) {
|
|
325
329
|
return ["high", "medium", "low"].includes(value);
|
|
326
330
|
}
|
|
@@ -353,8 +357,8 @@ function isReviewedCoverageRetarget(cells) {
|
|
|
353
357
|
return note.includes("reviewed low-confidence content; retargeted")
|
|
354
358
|
|| reason.includes("reviewed source context; taxonomy target assigned");
|
|
355
359
|
}
|
|
356
|
-
function collectMigrationCoverageDiagnostics() {
|
|
357
|
-
const units =
|
|
360
|
+
function collectMigrationCoverageDiagnostics(context = loadMigrationUnitContext()) {
|
|
361
|
+
const units = context.units;
|
|
358
362
|
if (units.length === 0)
|
|
359
363
|
return [];
|
|
360
364
|
if (!(0, workspace_1.exists)("wiki/migration/coverage.md")) {
|
|
@@ -417,8 +421,8 @@ function collectMigrationCoverageDiagnostics() {
|
|
|
417
421
|
}
|
|
418
422
|
return diagnostics.sort((a, b) => a.file.localeCompare(b.file) || a.code.localeCompare(b.code) || a.message.localeCompare(b.message));
|
|
419
423
|
}
|
|
420
|
-
function collectMigrationUnitMapDiagnostics() {
|
|
421
|
-
const units =
|
|
424
|
+
function collectMigrationUnitMapDiagnostics(context = loadMigrationUnitContext()) {
|
|
425
|
+
const units = context.units;
|
|
422
426
|
if (units.length === 0)
|
|
423
427
|
return [];
|
|
424
428
|
const file = "wiki/migration/unit-map.md";
|
|
@@ -485,8 +489,8 @@ function collectMigrationUnitMapDiagnostics() {
|
|
|
485
489
|
}
|
|
486
490
|
return diagnostics.sort((a, b) => a.file.localeCompare(b.file) || a.code.localeCompare(b.code) || a.message.localeCompare(b.message));
|
|
487
491
|
}
|
|
488
|
-
function collectMigrationSplitPlanDiagnostics() {
|
|
489
|
-
const units =
|
|
492
|
+
function collectMigrationSplitPlanDiagnostics(context = loadMigrationUnitContext()) {
|
|
493
|
+
const units = context.units;
|
|
490
494
|
if (units.length === 0)
|
|
491
495
|
return [];
|
|
492
496
|
const file = "wiki/migration/split-plan.md";
|