skillwiki 0.2.0-beta.31 → 0.2.0-beta.33
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/dist/cli.js +48 -23
- package/package.json +1 -1
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1367,7 +1367,8 @@ function buildSlugMap(pages) {
|
|
|
1367
1367
|
async function runLinks(input) {
|
|
1368
1368
|
const scan = await scanVault(input.vault);
|
|
1369
1369
|
if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
|
|
1370
|
-
const
|
|
1370
|
+
const allPages = [...scan.data.typedKnowledge, ...scan.data.raw, ...scan.data.workItems, ...scan.data.compound];
|
|
1371
|
+
const slugs = buildSlugMap(allPages);
|
|
1371
1372
|
const broken = [];
|
|
1372
1373
|
for (const p of scan.data.typedKnowledge) {
|
|
1373
1374
|
const text = await readPage(p);
|
|
@@ -1375,7 +1376,7 @@ async function runLinks(input) {
|
|
|
1375
1376
|
const body = split.ok ? split.data.body : text;
|
|
1376
1377
|
const lines = body.split("\n");
|
|
1377
1378
|
for (const slug of extractBodyWikilinks(body)) {
|
|
1378
|
-
const tail = slug.split("/").pop();
|
|
1379
|
+
const tail = slug.split("/").pop().replace(/\.md$/, "");
|
|
1379
1380
|
if (!slugs.has(tail.toLowerCase())) {
|
|
1380
1381
|
const line = lines.findIndex((l) => l.includes(`[[${slug}`));
|
|
1381
1382
|
broken.push({ page: p.relPath, slug, line: line >= 0 ? line + 1 : 0 });
|
|
@@ -1741,7 +1742,8 @@ async function runLint(input) {
|
|
|
1741
1742
|
const dedup = await runDedup({ vault: input.vault });
|
|
1742
1743
|
if (dedup.result.ok && dedup.result.data.duplicates.length > 0) buckets.raw_dedup = dedup.result.data.duplicates;
|
|
1743
1744
|
const scan = await scanVault(input.vault);
|
|
1744
|
-
const
|
|
1745
|
+
const allPages = scan.ok ? [...scan.data.typedKnowledge, ...scan.data.raw, ...scan.data.workItems, ...scan.data.compound] : [];
|
|
1746
|
+
const slugs = scan.ok ? buildSlugMap(allPages) : /* @__PURE__ */ new Map();
|
|
1745
1747
|
if (scan.ok) {
|
|
1746
1748
|
const legacyPages = [];
|
|
1747
1749
|
const orphanedPages = [];
|
|
@@ -1761,7 +1763,7 @@ async function runLint(input) {
|
|
|
1761
1763
|
const fmLinks = rawFm.match(/\[\[([^\[\]|]+)(?:\|[^\[\]]*)?\]\]/g) ?? [];
|
|
1762
1764
|
for (const link of fmLinks) {
|
|
1763
1765
|
const target = link.replace(/^\[\[/, "").replace(/(?:\|[^\[\]]*)?\]\]$/, "").trim();
|
|
1764
|
-
const tail = target.split("/").pop();
|
|
1766
|
+
const tail = target.split("/").pop().replace(/\.md$/, "");
|
|
1765
1767
|
if (!slugs.has(tail.toLowerCase())) {
|
|
1766
1768
|
fmWikilinkFlags.push(`${page.relPath}: [[${target}]] does not resolve`);
|
|
1767
1769
|
}
|
|
@@ -2174,6 +2176,7 @@ async function runArchive(input) {
|
|
|
2174
2176
|
|
|
2175
2177
|
// src/commands/drift.ts
|
|
2176
2178
|
import { createHash as createHash2 } from "crypto";
|
|
2179
|
+
import { writeFile as writeFile7 } from "fs/promises";
|
|
2177
2180
|
|
|
2178
2181
|
// src/utils/fetch.ts
|
|
2179
2182
|
async function controlledFetch(url, opts) {
|
|
@@ -2215,11 +2218,15 @@ async function runDrift(input) {
|
|
|
2215
2218
|
if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
|
|
2216
2219
|
const results = [];
|
|
2217
2220
|
for (const raw of scan.data.raw) {
|
|
2218
|
-
const
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
const
|
|
2222
|
-
|
|
2221
|
+
const text = await readPage(raw);
|
|
2222
|
+
const split = splitFrontmatter(text);
|
|
2223
|
+
if (!split.ok) continue;
|
|
2224
|
+
const { rawFrontmatter, body } = split.data;
|
|
2225
|
+
const sourceUrlMatch = rawFrontmatter.match(/^source_url:\s*(.+)$/m);
|
|
2226
|
+
const storedHashMatch = rawFrontmatter.match(/^sha256:\s*([a-f0-9]+)$/m);
|
|
2227
|
+
if (!sourceUrlMatch || !storedHashMatch) continue;
|
|
2228
|
+
const sourceUrl = sourceUrlMatch[1].trim();
|
|
2229
|
+
const storedHash = storedHashMatch[1];
|
|
2223
2230
|
const resp = await doFetch(sourceUrl, FETCH_OPTS);
|
|
2224
2231
|
if (!resp.ok) {
|
|
2225
2232
|
results.push({
|
|
@@ -2234,29 +2241,47 @@ async function runDrift(input) {
|
|
|
2234
2241
|
}
|
|
2235
2242
|
const currentHash = createHash2("sha256").update(Buffer.from(resp.data.body, "utf8")).digest("hex");
|
|
2236
2243
|
const drifted2 = currentHash !== storedHash;
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
+
if (drifted2 && input.apply) {
|
|
2245
|
+
const newFm = rawFrontmatter.replace(/^sha256:\s*[a-f0-9]+$/m, `sha256: ${currentHash}`);
|
|
2246
|
+
const newText = `---
|
|
2247
|
+
${newFm}
|
|
2248
|
+
---
|
|
2249
|
+
${body}`;
|
|
2250
|
+
await writeFile7(raw.absPath, newText, "utf8");
|
|
2251
|
+
results.push({
|
|
2252
|
+
raw_path: raw.relPath,
|
|
2253
|
+
source_url: sourceUrl,
|
|
2254
|
+
stored_sha256: storedHash,
|
|
2255
|
+
current_sha256: currentHash,
|
|
2256
|
+
status: "updated"
|
|
2257
|
+
});
|
|
2258
|
+
} else {
|
|
2259
|
+
results.push({
|
|
2260
|
+
raw_path: raw.relPath,
|
|
2261
|
+
source_url: sourceUrl,
|
|
2262
|
+
stored_sha256: storedHash,
|
|
2263
|
+
current_sha256: currentHash,
|
|
2264
|
+
status: drifted2 ? "drifted" : "unchanged"
|
|
2265
|
+
});
|
|
2266
|
+
}
|
|
2244
2267
|
}
|
|
2245
2268
|
const drifted = results.filter((r) => r.status === "drifted");
|
|
2246
2269
|
const fetchFailed = results.filter((r) => r.status === "fetch_failed");
|
|
2270
|
+
const updated = results.filter((r) => r.status === "updated");
|
|
2247
2271
|
const unchanged = results.filter((r) => r.status === "unchanged").length;
|
|
2248
2272
|
const exitCode = drifted.length > 0 ? ExitCode.DRIFT_DETECTED : ExitCode.OK;
|
|
2249
2273
|
const hintLines = [`scanned: ${results.length}, unchanged: ${unchanged}`];
|
|
2250
2274
|
if (drifted.length > 0) hintLines.push(`drifted: ${drifted.length}`, ...drifted.map((d) => ` ${d.raw_path}`));
|
|
2251
2275
|
if (fetchFailed.length > 0) hintLines.push(`fetch_failed: ${fetchFailed.length}`, ...fetchFailed.map((f) => ` ${f.raw_path}: ${f.fetch_error}`));
|
|
2276
|
+
if (updated.length > 0) hintLines.push(`updated: ${updated.length}`, ...updated.map((u) => ` ${u.raw_path}`));
|
|
2252
2277
|
return {
|
|
2253
2278
|
exitCode,
|
|
2254
|
-
result: ok({ scanned: results.length, drifted, fetch_failed: fetchFailed, unchanged, humanHint: hintLines.join("\n") })
|
|
2279
|
+
result: ok({ scanned: results.length, drifted, fetch_failed: fetchFailed, updated, unchanged, humanHint: hintLines.join("\n") })
|
|
2255
2280
|
};
|
|
2256
2281
|
}
|
|
2257
2282
|
|
|
2258
2283
|
// src/commands/migrate-citations.ts
|
|
2259
|
-
import { writeFile as
|
|
2284
|
+
import { writeFile as writeFile8 } from "fs/promises";
|
|
2260
2285
|
var MARKER_RE2 = /\^\[(raw\/[^\]]+)\]/g;
|
|
2261
2286
|
function moveMarkersToParagraphEnd(body) {
|
|
2262
2287
|
const lines = body.split("\n");
|
|
@@ -2379,7 +2404,7 @@ ${migratedBody}${newFooter}`;
|
|
|
2379
2404
|
continue;
|
|
2380
2405
|
}
|
|
2381
2406
|
if (!input.dryRun) {
|
|
2382
|
-
await
|
|
2407
|
+
await writeFile8(page.absPath, newText, "utf8");
|
|
2383
2408
|
}
|
|
2384
2409
|
migrated.push(page.relPath);
|
|
2385
2410
|
}
|
|
@@ -2401,7 +2426,7 @@ ${migratedBody}${newFooter}`;
|
|
|
2401
2426
|
}
|
|
2402
2427
|
|
|
2403
2428
|
// src/commands/frontmatter-fix.ts
|
|
2404
|
-
import { writeFile as
|
|
2429
|
+
import { writeFile as writeFile9 } from "fs/promises";
|
|
2405
2430
|
function isoToday() {
|
|
2406
2431
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2407
2432
|
}
|
|
@@ -2443,7 +2468,7 @@ ${newBody}`;
|
|
|
2443
2468
|
continue;
|
|
2444
2469
|
}
|
|
2445
2470
|
if (!input.dryRun) {
|
|
2446
|
-
await
|
|
2471
|
+
await writeFile9(page.absPath, newText, "utf8");
|
|
2447
2472
|
}
|
|
2448
2473
|
fixed.push(page.relPath);
|
|
2449
2474
|
}
|
|
@@ -2661,10 +2686,10 @@ program.command("archive <page> [vault]").description("archive a typed-knowledge
|
|
|
2661
2686
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2662
2687
|
else emit(await runArchive({ vault: v.vault, page }));
|
|
2663
2688
|
});
|
|
2664
|
-
program.command("drift [vault]").description("detect content drift in raw sources").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2689
|
+
program.command("drift [vault]").description("detect content drift in raw sources").option("--apply", "update sha256 in drifted sources").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2665
2690
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2666
2691
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2667
|
-
else emit(await runDrift({ vault: v.vault }));
|
|
2692
|
+
else emit(await runDrift({ vault: v.vault, apply: opts.apply }));
|
|
2668
2693
|
});
|
|
2669
2694
|
program.command("dedup [vault]").description("detect duplicate raw sources by sha256").option("--apply", "rewire citations and remove duplicate raw files", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2670
2695
|
const v = await resolveVaultArg(vault, opts.wiki);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.33",
|
|
4
4
|
"skills": "./",
|
|
5
5
|
"description": "Project-aware Karpathy-style knowledge base for Claude Code: 11 prompt-only skills (wiki-*, proj-*, using-skillwiki) backed by the deterministic `skillwiki` CLI (8 subcommands, JSON-by-default).",
|
|
6
6
|
"author": {
|