project-librarian 0.2.0 → 0.2.1
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.ja.md +34 -46
- package/README.ko.md +35 -47
- package/README.md +38 -47
- package/README.zh.md +34 -46
- package/SKILL.md +27 -12
- package/dist/args.js +10 -1
- package/dist/code-index-file-policy.js +2 -0
- package/dist/hooks.js +65 -7
- package/dist/init-project-wiki.js +25 -1
- package/dist/install-skill.js +28 -9
- package/dist/migration.js +203 -4
- package/dist/modes.js +129 -100
- package/dist/templates.js +28 -7
- package/dist/wiki-files.js +9 -1
- package/package.json +9 -6
package/dist/install-skill.js
CHANGED
|
@@ -39,6 +39,8 @@ 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"];
|
|
43
|
+
const legacyBothAgentTargets = ["codex", "claude"];
|
|
42
44
|
const packageFiles = [
|
|
43
45
|
"SKILL.md",
|
|
44
46
|
"dist",
|
|
@@ -61,19 +63,23 @@ function installScope() {
|
|
|
61
63
|
return fail(`invalid --scope: ${scope}; expected user or project`);
|
|
62
64
|
}
|
|
63
65
|
function installAgents() {
|
|
64
|
-
const value = (0, args_1.argValue)("--agents") || "
|
|
66
|
+
const value = (0, args_1.argValue)("--agents") || "all";
|
|
65
67
|
const parts = value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
66
68
|
const agents = new Set();
|
|
67
69
|
for (const part of parts) {
|
|
68
|
-
if (part === "
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
if (part === "all") {
|
|
71
|
+
for (const agent of allAgentTargets)
|
|
72
|
+
agents.add(agent);
|
|
71
73
|
}
|
|
72
|
-
else if (part === "
|
|
74
|
+
else if (part === "both") {
|
|
75
|
+
for (const agent of legacyBothAgentTargets)
|
|
76
|
+
agents.add(agent);
|
|
77
|
+
}
|
|
78
|
+
else if (allAgentTargets.includes(part)) {
|
|
73
79
|
agents.add(part);
|
|
74
80
|
}
|
|
75
81
|
else {
|
|
76
|
-
return fail(`invalid --agents entry: ${part}; expected codex, claude, or both`);
|
|
82
|
+
return fail(`invalid --agents entry: ${part}; expected codex, claude, cursor, gemini, all, or legacy both`);
|
|
77
83
|
}
|
|
78
84
|
}
|
|
79
85
|
return Array.from(agents);
|
|
@@ -85,10 +91,23 @@ function userAgentRoot(agent) {
|
|
|
85
91
|
const home = os.homedir();
|
|
86
92
|
if (agent === "codex")
|
|
87
93
|
return process.env.CODEX_HOME || path.join(home, ".codex");
|
|
88
|
-
|
|
94
|
+
if (agent === "claude")
|
|
95
|
+
return process.env.CLAUDE_HOME || path.join(home, ".claude");
|
|
96
|
+
if (agent === "cursor")
|
|
97
|
+
return process.env.CURSOR_HOME || path.join(home, ".cursor");
|
|
98
|
+
return process.env.GEMINI_HOME || path.join(home, ".gemini");
|
|
99
|
+
}
|
|
100
|
+
function projectAgentRoot(agent) {
|
|
101
|
+
if (agent === "codex")
|
|
102
|
+
return ".codex";
|
|
103
|
+
if (agent === "claude")
|
|
104
|
+
return ".claude";
|
|
105
|
+
if (agent === "cursor")
|
|
106
|
+
return ".cursor";
|
|
107
|
+
return ".gemini";
|
|
89
108
|
}
|
|
90
109
|
function installTarget(agent, scope) {
|
|
91
|
-
const base = scope === "user" ? userAgentRoot(agent) : path.join(process.cwd(), agent
|
|
110
|
+
const base = scope === "user" ? userAgentRoot(agent) : path.join(process.cwd(), projectAgentRoot(agent));
|
|
92
111
|
return path.join(base, "skills", skillName);
|
|
93
112
|
}
|
|
94
113
|
function sameFile(source, target) {
|
|
@@ -134,7 +153,7 @@ function runInstallSkillMode() {
|
|
|
134
153
|
console.log(`Project Librarian skill ${dryRun ? "install dry-run" : "install"} complete.`);
|
|
135
154
|
console.log(`scope: ${scope}`);
|
|
136
155
|
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.");
|
|
156
|
+
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.");
|
|
138
157
|
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.");
|
|
139
158
|
for (const [label, status] of rows) {
|
|
140
159
|
console.log(`${status.padEnd(7)} ${label}`);
|
package/dist/migration.js
CHANGED
|
@@ -34,6 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.classifyMarkdown = classifyMarkdown;
|
|
37
|
+
exports.extractMigrationUnits = extractMigrationUnits;
|
|
38
|
+
exports.collectMigrationCoverageDiagnostics = collectMigrationCoverageDiagnostics;
|
|
37
39
|
exports.markdownTableRows = markdownTableRows;
|
|
38
40
|
exports.buildInbox = buildInbox;
|
|
39
41
|
exports.timestampSuffix = timestampSuffix;
|
|
@@ -67,6 +69,157 @@ function classifyMarkdown(relativePath, text) {
|
|
|
67
69
|
function markdownTableCell(value) {
|
|
68
70
|
return String(value).replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
|
|
69
71
|
}
|
|
72
|
+
function slugPart(value) {
|
|
73
|
+
return value.toLowerCase().replace(/[^a-z0-9가-힣ぁ-んァ-ン一-龥]+/g, "-").replace(/^-|-$/g, "").slice(0, 40) || "unit";
|
|
74
|
+
}
|
|
75
|
+
function unitSummary(value) {
|
|
76
|
+
return value.replace(/\s+/g, " ").trim().slice(0, 180);
|
|
77
|
+
}
|
|
78
|
+
function nextUnitId(legacyPath, index, summary) {
|
|
79
|
+
return `${legacyPath}#u${String(index).padStart(3, "0")}-${slugPart(summary)}`;
|
|
80
|
+
}
|
|
81
|
+
function extractMigrationUnits(legacyPath, text) {
|
|
82
|
+
const body = (0, workspace_1.stripMetadataHeader)(text);
|
|
83
|
+
const lines = body.split(/\r?\n/);
|
|
84
|
+
const units = [];
|
|
85
|
+
let heading = "";
|
|
86
|
+
let paragraph = [];
|
|
87
|
+
let inCodeFence = false;
|
|
88
|
+
let codeBlock = [];
|
|
89
|
+
const pushUnit = (type, value) => {
|
|
90
|
+
const summary = unitSummary(value);
|
|
91
|
+
if (!summary)
|
|
92
|
+
return;
|
|
93
|
+
units.push({
|
|
94
|
+
id: nextUnitId(legacyPath, units.length + 1, summary),
|
|
95
|
+
legacyPath,
|
|
96
|
+
type,
|
|
97
|
+
heading,
|
|
98
|
+
summary,
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
const flushParagraph = () => {
|
|
102
|
+
if (paragraph.length === 0)
|
|
103
|
+
return;
|
|
104
|
+
pushUnit("paragraph", paragraph.join(" "));
|
|
105
|
+
paragraph = [];
|
|
106
|
+
};
|
|
107
|
+
for (const line of lines) {
|
|
108
|
+
const trimmed = line.trim();
|
|
109
|
+
if (/^```/.test(trimmed)) {
|
|
110
|
+
if (inCodeFence) {
|
|
111
|
+
codeBlock.push(line);
|
|
112
|
+
pushUnit("code-block", codeBlock.join("\n"));
|
|
113
|
+
codeBlock = [];
|
|
114
|
+
inCodeFence = false;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
flushParagraph();
|
|
118
|
+
inCodeFence = true;
|
|
119
|
+
codeBlock = [line];
|
|
120
|
+
}
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (inCodeFence) {
|
|
124
|
+
codeBlock.push(line);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (!trimmed) {
|
|
128
|
+
flushParagraph();
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const headingMatch = trimmed.match(/^(#{1,6})\s+(.+)$/);
|
|
132
|
+
if (headingMatch?.[2]) {
|
|
133
|
+
flushParagraph();
|
|
134
|
+
heading = headingMatch[2].trim();
|
|
135
|
+
pushUnit("heading", heading);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (/^\|.+\|$/.test(trimmed) && !/^\|\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?$/.test(trimmed)) {
|
|
139
|
+
flushParagraph();
|
|
140
|
+
pushUnit("table-row", trimmed);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (/^([-*+]|\d+[.)])\s+/.test(trimmed)) {
|
|
144
|
+
flushParagraph();
|
|
145
|
+
pushUnit("list-item", trimmed);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
paragraph.push(trimmed);
|
|
149
|
+
}
|
|
150
|
+
if (inCodeFence && codeBlock.length > 0)
|
|
151
|
+
pushUnit("code-block", codeBlock.join("\n"));
|
|
152
|
+
flushParagraph();
|
|
153
|
+
return units;
|
|
154
|
+
}
|
|
155
|
+
function coverageTableRows(units) {
|
|
156
|
+
if (units.length === 0)
|
|
157
|
+
return "| none | - | - | - | - | pending | - | - |\n";
|
|
158
|
+
return units.map((unit) => `| ${markdownTableCell(unit.id)} | ${markdownTableCell(unit.legacyPath)} | ${unit.type} | ${markdownTableCell(unit.heading || "-")} | ${markdownTableCell(unit.summary)} | pending | - | - |`).join("\n") + "\n";
|
|
159
|
+
}
|
|
160
|
+
function isMigrationCoverageStatus(value) {
|
|
161
|
+
return ["adopted", "merged", "superseded", "rejected", "resolved", "needs-human-review", "pending"].includes(value);
|
|
162
|
+
}
|
|
163
|
+
function legacyWikiRoots() {
|
|
164
|
+
if (!fs.existsSync(workspace_1.root))
|
|
165
|
+
return [];
|
|
166
|
+
return fs.readdirSync(workspace_1.root, { withFileTypes: true })
|
|
167
|
+
.filter((entry) => entry.isDirectory() && /^wiki_legacy(?:_|$)/.test(entry.name))
|
|
168
|
+
.map((entry) => entry.name)
|
|
169
|
+
.sort();
|
|
170
|
+
}
|
|
171
|
+
function expectedMigrationUnits() {
|
|
172
|
+
return legacyWikiRoots()
|
|
173
|
+
.flatMap((legacyRoot) => (0, wiki_files_1.walkMarkdownFiles)((0, workspace_1.abs)(legacyRoot), [], (0, workspace_1.abs)(legacyRoot)))
|
|
174
|
+
.flatMap((file) => extractMigrationUnits(file.basePath, (0, workspace_1.read)(file.path)));
|
|
175
|
+
}
|
|
176
|
+
function collectMigrationCoverageDiagnostics() {
|
|
177
|
+
const units = expectedMigrationUnits();
|
|
178
|
+
if (units.length === 0)
|
|
179
|
+
return [];
|
|
180
|
+
if (!(0, workspace_1.exists)("wiki/migration/coverage.md")) {
|
|
181
|
+
return [{
|
|
182
|
+
code: "migration-coverage-missing",
|
|
183
|
+
severity: "error",
|
|
184
|
+
file: "wiki/migration/coverage.md",
|
|
185
|
+
message: "migration unit coverage ledger is missing; run --migrate to account for legacy meaning units",
|
|
186
|
+
}];
|
|
187
|
+
}
|
|
188
|
+
const diagnostics = [];
|
|
189
|
+
const expectedIds = new Set(units.map((unit) => unit.id));
|
|
190
|
+
const seenIds = new Set();
|
|
191
|
+
const rows = (0, wiki_files_1.parseMarkdownTableRows)((0, workspace_1.read)("wiki/migration/coverage.md"), 8).filter((cells) => cells[0] !== "Unit ID");
|
|
192
|
+
for (const cells of rows) {
|
|
193
|
+
const id = cells[0] || "";
|
|
194
|
+
const status = String(cells[5] || "").trim().toLowerCase();
|
|
195
|
+
const target = String(cells[6] || "").trim();
|
|
196
|
+
if (seenIds.has(id)) {
|
|
197
|
+
diagnostics.push({ code: "migration-duplicate-unit", severity: "error", file: "wiki/migration/coverage.md", message: `duplicate migration unit row: ${id}` });
|
|
198
|
+
}
|
|
199
|
+
seenIds.add(id);
|
|
200
|
+
if (!expectedIds.has(id)) {
|
|
201
|
+
diagnostics.push({ code: "migration-stale-unit", severity: "warn", file: "wiki/migration/coverage.md", message: `coverage row does not match current legacy units: ${id}` });
|
|
202
|
+
}
|
|
203
|
+
if (!isMigrationCoverageStatus(status)) {
|
|
204
|
+
diagnostics.push({ code: "migration-invalid-status", severity: "error", file: "wiki/migration/coverage.md", message: `unit ${id} has invalid status: ${status || "(blank)"}` });
|
|
205
|
+
}
|
|
206
|
+
if (["adopted", "merged"].includes(status) && !/^wiki\/(canonical|decisions|sources|meta)\//.test(target)) {
|
|
207
|
+
diagnostics.push({ code: "migration-missing-target", severity: "error", file: "wiki/migration/coverage.md", message: `unit ${id} is ${status} but target is not a new wiki page` });
|
|
208
|
+
}
|
|
209
|
+
if (/\bwiki_legacy(?:_|\b|\/)/.test(target)) {
|
|
210
|
+
diagnostics.push({ code: "migration-legacy-target", severity: "error", file: "wiki/migration/coverage.md", message: `unit ${id} targets wiki_legacy* instead of migrated new-wiki truth` });
|
|
211
|
+
}
|
|
212
|
+
if (status === "pending") {
|
|
213
|
+
diagnostics.push({ code: "migration-pending-unit", severity: "warn", file: "wiki/migration/coverage.md", message: `unit ${id} is still pending migration review` });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
for (const unit of units) {
|
|
217
|
+
if (!seenIds.has(unit.id)) {
|
|
218
|
+
diagnostics.push({ code: "migration-unaccounted-unit", severity: "error", file: unit.legacyPath, message: `legacy meaning unit missing from coverage ledger: ${unit.id}` });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return diagnostics.sort((a, b) => a.file.localeCompare(b.file) || a.code.localeCompare(b.code) || a.message.localeCompare(b.message));
|
|
222
|
+
}
|
|
70
223
|
function markdownTableRows(items) {
|
|
71
224
|
if (items.length === 0)
|
|
72
225
|
return "| none | - | - | - |\n";
|
|
@@ -87,6 +240,22 @@ function buildInbox(title, description, items) {
|
|
|
87
240
|
| --- | --- | --- | --- |
|
|
88
241
|
${markdownTableRows(items)}`;
|
|
89
242
|
}
|
|
243
|
+
function migrationBatchScope(legacyRoot) {
|
|
244
|
+
return `${workspace_1.today} migration batch${legacyRoot && legacyRoot !== "none" ? ` from ${legacyRoot}` : ""}`;
|
|
245
|
+
}
|
|
246
|
+
function semanticCompletionValue(complete, batchScope) {
|
|
247
|
+
if (complete)
|
|
248
|
+
return `yes, for the ${batchScope} only`;
|
|
249
|
+
return `no, the ${batchScope} still has unresolved rows`;
|
|
250
|
+
}
|
|
251
|
+
function completionScopeSection(batchScope) {
|
|
252
|
+
return `## Completion Scope
|
|
253
|
+
|
|
254
|
+
- This page records the ${batchScope} only.
|
|
255
|
+
- It does not mean future requests to build a new wiki from the existing wiki should reuse current \`wiki/\` in place.
|
|
256
|
+
- For a fresh rebuild request, treat current \`wiki/\` as the legacy source unless the user says otherwise: preserve it as \`wiki_legacy*\`, create a fresh standard \`wiki/\`, migrate/adopt content from the preserved legacy source, then refresh routing and diagnostics.
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
90
259
|
function timestampSuffix() {
|
|
91
260
|
return new Date().toISOString().replace(/[-:]/g, "").replace(/\..+$/, "").replace("T", "_");
|
|
92
261
|
}
|
|
@@ -156,6 +325,22 @@ function runMigrationMode(migrationState) {
|
|
|
156
325
|
| Legacy Source | Classification | Title | Size (bytes) | Summary |
|
|
157
326
|
| --- | --- | --- | ---: | --- |
|
|
158
327
|
${inventoryRows}`;
|
|
328
|
+
const units = items.flatMap((item) => extractMigrationUnits(item.legacyPath, (0, workspace_1.read)(item.path)));
|
|
329
|
+
const coverage = `${(0, templates_1.metadata)("migration-coverage", "on-demand", "wiki/meta/wiki-ops-v1-decisions.md", "migration unit coverage statuses change")}
|
|
330
|
+
# Migration Coverage Ledger
|
|
331
|
+
|
|
332
|
+
## TL;DR
|
|
333
|
+
|
|
334
|
+
- Generated: ${workspace_1.today}
|
|
335
|
+
- Legacy root: ${legacyPath || "none"}
|
|
336
|
+
- Legacy meaning units: ${units.length}
|
|
337
|
+
- Every legacy heading, paragraph, list item, table row, and code block should remain accounted for.
|
|
338
|
+
- Status values: pending, adopted, merged, superseded, rejected, resolved, needs-human-review.
|
|
339
|
+
- \`adopted\` and \`merged\` rows require a new-wiki target under \`wiki/canonical/\`, \`wiki/decisions/\`, \`wiki/sources/\`, or \`wiki/meta/\`.
|
|
340
|
+
|
|
341
|
+
| Unit ID | Legacy Source | Type | Heading | Summary | Status | Target | Note |
|
|
342
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
343
|
+
${coverageTableRows(units)}`;
|
|
159
344
|
const plan = `${(0, templates_1.metadata)("migration-plan", "short", "wiki/meta/wiki-ops-v1-decisions.md", "migration procedure or status changes")}
|
|
160
345
|
# Migration Plan
|
|
161
346
|
|
|
@@ -189,6 +374,8 @@ ${inventoryRows}`;
|
|
|
189
374
|
- coverage: ${items.length === markdownFiles.length ? "pass" : "fail"}
|
|
190
375
|
- This verifies file coverage only. Semantic completeness is confirmed after inbox statuses are resolved.
|
|
191
376
|
|
|
377
|
+
${completionScopeSection(migrationBatchScope(legacyPath || "none"))}
|
|
378
|
+
|
|
192
379
|
| Legacy Source | Classification | New Wiki Target | Coverage | Semantic Status |
|
|
193
380
|
| --- | --- | --- | --- | --- |
|
|
194
381
|
${verificationRows}`;
|
|
@@ -198,12 +385,13 @@ ${verificationRows}`;
|
|
|
198
385
|
- ${workspace_1.today}: preserved existing wiki at \`${legacyPath || "no wiki_legacy"}\` and regenerated the standard wiki structure.
|
|
199
386
|
- Scanned ${items.length} legacy markdown files and created migration inventory, plan, verification, and inbox files.
|
|
200
387
|
- Do not delete \`${legacyPath || "wiki_legacy"}\` until all migration inbox items are adopted/rejected/resolved and needs-human-review is 0.
|
|
388
|
+
- Migration completion status is scoped to this batch only. For a future fresh rebuild request, treat current \`wiki/\` as the legacy source unless the user says otherwise.
|
|
201
389
|
<!-- PROJECT-WIKI-MIGRATION:END -->`;
|
|
202
390
|
const migrationIndexBlock = `<!-- PROJECT-WIKI-MIGRATION:START -->
|
|
203
391
|
## Migration
|
|
204
392
|
|
|
205
393
|
- [[migration/plan]]
|
|
206
|
-
- Read when: migration procedure or status matters.
|
|
394
|
+
- Read when: migration procedure, fresh rebuild procedure, or status matters.
|
|
207
395
|
- Update when: migration procedure or state changes.
|
|
208
396
|
- Token budget: short.
|
|
209
397
|
- [[migration/inventory]]
|
|
@@ -214,6 +402,10 @@ ${verificationRows}`;
|
|
|
214
402
|
- Read when: legacy file coverage or semantic migration status matters.
|
|
215
403
|
- Update when: migration inbox statuses change.
|
|
216
404
|
- Token budget: on-demand.
|
|
405
|
+
- [[migration/coverage]]
|
|
406
|
+
- Read when: checking whether legacy meaning units were adopted, merged, superseded, rejected, resolved, or marked for review.
|
|
407
|
+
- Update when: unit-level migration coverage statuses, targets, or notes change.
|
|
408
|
+
- Token budget: on-demand.
|
|
217
409
|
- [[migration/review]]
|
|
218
410
|
- Read when: semantic migration review status matters.
|
|
219
411
|
- Update when: \`--review-migration\` syncs migration state.
|
|
@@ -234,6 +426,7 @@ ${verificationRows}`;
|
|
|
234
426
|
const results = [];
|
|
235
427
|
(0, workspace_1.mkdirp)("wiki/migration");
|
|
236
428
|
results.push(["wiki/migration/inventory.md", (0, workspace_1.writeManaged)("wiki/migration/inventory.md", inventory)]);
|
|
429
|
+
results.push(["wiki/migration/coverage.md", (0, workspace_1.writeManaged)("wiki/migration/coverage.md", coverage)]);
|
|
237
430
|
results.push(["wiki/migration/plan.md", (0, workspace_1.writeManaged)("wiki/migration/plan.md", plan)]);
|
|
238
431
|
results.push(["wiki/migration/verification.md", (0, workspace_1.writeManaged)("wiki/migration/verification.md", verification)]);
|
|
239
432
|
results.push(["wiki/canonical/migration-inbox.md", (0, workspace_1.writeManaged)("wiki/canonical/migration-inbox.md", buildInbox("Canonical Migration Inbox", "Legacy content that may belong in current project truth.", byKind.canonical.concat(byKind.other)))]);
|
|
@@ -305,6 +498,9 @@ function runReviewMigrationMode() {
|
|
|
305
498
|
const pending = counts.pending || 0;
|
|
306
499
|
const needsHuman = counts["needs-human-review"] || 0;
|
|
307
500
|
const complete = pending === 0 && needsHuman === 0;
|
|
501
|
+
const legacyRoot = (verificationText.match(/^- legacy root:\s*(.+)$/m) || [])[1] || "unknown";
|
|
502
|
+
const batchScope = migrationBatchScope(legacyRoot);
|
|
503
|
+
const completionValue = semanticCompletionValue(complete, batchScope);
|
|
308
504
|
const reviewRows = reviewedRows.length === 0
|
|
309
505
|
? "| none | - | - | - | - |\n"
|
|
310
506
|
: reviewedRows.map((row) => `| ${markdownTableCell(row.legacyPath)} | ${row.kind} | ${row.inboxStatus} | ${row.semanticStatus} | ${markdownTableCell(row.note)} |`).join("\n") + "\n";
|
|
@@ -320,7 +516,9 @@ function runReviewMigrationMode() {
|
|
|
320
516
|
- resolved: ${counts.resolved || 0}
|
|
321
517
|
- pending: ${pending}
|
|
322
518
|
- needs-human-review: ${needsHuman}
|
|
323
|
-
- semantic migration complete: ${
|
|
519
|
+
- semantic migration complete: ${completionValue}
|
|
520
|
+
|
|
521
|
+
${completionScopeSection(batchScope)}
|
|
324
522
|
|
|
325
523
|
| Legacy Source | Classification | Inbox Status | Semantic Status | Evidence |
|
|
326
524
|
| --- | --- | --- | --- | --- |
|
|
@@ -328,7 +526,6 @@ ${reviewRows}`;
|
|
|
328
526
|
const verificationRowsText = reviewedRows.length === 0
|
|
329
527
|
? "| none | - | - | pass | - |\n"
|
|
330
528
|
: reviewedRows.map((row) => `| ${markdownTableCell(row.legacyPath)} | ${row.kind} | ${row.target} | ${row.coverage} | ${row.semanticStatus} |`).join("\n") + "\n";
|
|
331
|
-
const legacyRoot = (verificationText.match(/^- legacy root:\s*(.+)$/m) || [])[1] || "unknown";
|
|
332
529
|
const verification = `${(0, templates_1.metadata)("migration-verification", "on-demand", "wiki/meta/wiki-ops-v1-decisions.md", "migration inbox items are adopted, rejected, resolved, or marked needs-human-review")}
|
|
333
530
|
# Migration Verification
|
|
334
531
|
|
|
@@ -338,10 +535,12 @@ ${reviewRows}`;
|
|
|
338
535
|
- legacy markdown files: ${reviewedRows.length}
|
|
339
536
|
- mapped files: ${reviewedRows.filter((row) => row.coverage === "mapped").length}
|
|
340
537
|
- coverage: ${reviewedRows.every((row) => row.coverage === "mapped") ? "pass" : "fail"}
|
|
341
|
-
- semantic migration complete: ${
|
|
538
|
+
- semantic migration complete: ${completionValue}
|
|
342
539
|
- pending: ${pending}
|
|
343
540
|
- needs-human-review: ${needsHuman}
|
|
344
541
|
|
|
542
|
+
${completionScopeSection(batchScope)}
|
|
543
|
+
|
|
345
544
|
| Legacy Source | Classification | New Wiki Target | Coverage | Semantic Status |
|
|
346
545
|
| --- | --- | --- | --- | --- |
|
|
347
546
|
${verificationRowsText}`;
|