skillwiki 0.2.1-beta.10 → 0.2.1-beta.11
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 +115 -15
- package/package.json +1 -1
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1596,6 +1596,9 @@ Chronological action log. Newest entries last. Skill writes append entries; lint
|
|
|
1596
1596
|
return { exitCode: ExitCode.OK, result: ok({ entries, threshold: input.threshold, rotated: true, rotated_to: rotatedName, humanHint: `rotated ${entries} entries to ${rotatedName}` }) };
|
|
1597
1597
|
}
|
|
1598
1598
|
|
|
1599
|
+
// src/commands/lint.ts
|
|
1600
|
+
import { readFile as readFile12, writeFile as writeFile6 } from "fs/promises";
|
|
1601
|
+
|
|
1599
1602
|
// src/commands/topic-map-check.ts
|
|
1600
1603
|
var DEFAULT_THRESHOLD = 200;
|
|
1601
1604
|
async function runTopicMapCheck(input) {
|
|
@@ -1732,6 +1735,8 @@ var WARNING_ORDER = ["index_incomplete", "index_link_format", "stale_page", "pag
|
|
|
1732
1735
|
var INFO_ORDER = ["bridges", "page_structure", "topic_map_recommended", "frontmatter_wikilink", "wikilink_citation"];
|
|
1733
1736
|
async function runLint(input) {
|
|
1734
1737
|
const buckets = {};
|
|
1738
|
+
const fixed = [];
|
|
1739
|
+
const unresolved = [];
|
|
1735
1740
|
const links = await runLinks({ vault: input.vault });
|
|
1736
1741
|
if (links.result.ok && links.result.data.broken.length > 0) buckets.broken_wikilinks = links.result.data.broken;
|
|
1737
1742
|
if (!links.result.ok && links.result.error === "INVALID_FRONTMATTER") {
|
|
@@ -1822,6 +1827,98 @@ async function runLint(input) {
|
|
|
1822
1827
|
if (noOverview.length > 0) buckets.missing_overview = noOverview;
|
|
1823
1828
|
if (fmWikilinkFlags.length > 0) buckets.frontmatter_wikilink = fmWikilinkFlags;
|
|
1824
1829
|
if (wikilinkCitationFlags.length > 0) buckets.wikilink_citation = wikilinkCitationFlags;
|
|
1830
|
+
if (input.fix && legacyPages.length > 0) {
|
|
1831
|
+
const FENCE_RE2 = /```[\s\S]*?```/g;
|
|
1832
|
+
const INLINE_MARKER = /\^\[raw\/[^\]]+\]/g;
|
|
1833
|
+
for (const relPath of legacyPages) {
|
|
1834
|
+
try {
|
|
1835
|
+
const absPath = `${input.vault}/${relPath}`;
|
|
1836
|
+
const raw = await readFile12(absPath, "utf8");
|
|
1837
|
+
const split = splitFrontmatter(raw);
|
|
1838
|
+
if (!split.ok) {
|
|
1839
|
+
unresolved.push(relPath);
|
|
1840
|
+
continue;
|
|
1841
|
+
}
|
|
1842
|
+
const body = split.data.body;
|
|
1843
|
+
const rawFm = split.data.rawFrontmatter;
|
|
1844
|
+
const stripped = body.replace(FENCE_RE2, "");
|
|
1845
|
+
const lines = stripped.split("\n");
|
|
1846
|
+
const inlineMarkers = [];
|
|
1847
|
+
let inSources = false;
|
|
1848
|
+
for (const line of lines) {
|
|
1849
|
+
if (/^## Sources\b/.test(line.trim())) {
|
|
1850
|
+
inSources = true;
|
|
1851
|
+
continue;
|
|
1852
|
+
}
|
|
1853
|
+
if (inSources) continue;
|
|
1854
|
+
for (const m of line.matchAll(INLINE_MARKER)) {
|
|
1855
|
+
inlineMarkers.push(m[0]);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
if (inlineMarkers.length === 0) {
|
|
1859
|
+
unresolved.push(relPath);
|
|
1860
|
+
continue;
|
|
1861
|
+
}
|
|
1862
|
+
const bodyLines = body.split("\n");
|
|
1863
|
+
let inSrc = false;
|
|
1864
|
+
const newBodyLines = [];
|
|
1865
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1866
|
+
for (const line of bodyLines) {
|
|
1867
|
+
if (/^## Sources\b/.test(line.trim())) {
|
|
1868
|
+
inSrc = true;
|
|
1869
|
+
newBodyLines.push(line);
|
|
1870
|
+
continue;
|
|
1871
|
+
}
|
|
1872
|
+
if (inSrc) {
|
|
1873
|
+
newBodyLines.push(line);
|
|
1874
|
+
continue;
|
|
1875
|
+
}
|
|
1876
|
+
const lineWithoutMarkers = line.replace(INLINE_MARKER, "").trim();
|
|
1877
|
+
if (lineWithoutMarkers.length === 0 && INLINE_MARKER.test(line)) {
|
|
1878
|
+
continue;
|
|
1879
|
+
}
|
|
1880
|
+
let cleaned = line;
|
|
1881
|
+
for (const marker of inlineMarkers) {
|
|
1882
|
+
if (seen.has(marker)) continue;
|
|
1883
|
+
const escapedMarker = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1884
|
+
const trailingRe = new RegExp(`([.!?]\\s*)${escapedMarker}`);
|
|
1885
|
+
if (trailingRe.test(cleaned)) {
|
|
1886
|
+
cleaned = cleaned.replace(trailingRe, "$1");
|
|
1887
|
+
seen.add(marker);
|
|
1888
|
+
}
|
|
1889
|
+
const midRe = new RegExp(`${escapedMarker}\\s*`);
|
|
1890
|
+
if (!seen.has(marker) && midRe.test(cleaned)) {
|
|
1891
|
+
cleaned = cleaned.replace(midRe, "");
|
|
1892
|
+
seen.add(marker);
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
newBodyLines.push(cleaned);
|
|
1896
|
+
}
|
|
1897
|
+
let newBody = newBodyLines.join("\n");
|
|
1898
|
+
const dedupedMarkers = [...new Set(inlineMarkers)];
|
|
1899
|
+
const sourceLines = dedupedMarkers.map((m) => `- ${m}`);
|
|
1900
|
+
if (inSrc) {
|
|
1901
|
+
newBody = newBody.trimEnd() + "\n" + sourceLines.join("\n") + "\n";
|
|
1902
|
+
} else {
|
|
1903
|
+
newBody = newBody.trimEnd() + "\n\n## Sources\n\n" + sourceLines.join("\n") + "\n";
|
|
1904
|
+
}
|
|
1905
|
+
const newContent = `---
|
|
1906
|
+
${rawFm}
|
|
1907
|
+
---
|
|
1908
|
+
${newBody}`;
|
|
1909
|
+
await writeFile6(absPath, newContent, "utf8");
|
|
1910
|
+
fixed.push(relPath);
|
|
1911
|
+
} catch {
|
|
1912
|
+
unresolved.push(relPath);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
if (fixed.length > 0) {
|
|
1916
|
+
const fixedSet = new Set(fixed);
|
|
1917
|
+
const remaining = legacyPages.filter((p) => !fixedSet.has(p));
|
|
1918
|
+
if (remaining.length > 0) buckets.legacy_citation_style = remaining;
|
|
1919
|
+
else delete buckets.legacy_citation_style;
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1825
1922
|
}
|
|
1826
1923
|
const errorOut = ERROR_ORDER.flatMap((k) => buckets[k] ? [{ kind: k, items: buckets[k] }] : []);
|
|
1827
1924
|
const warningOut = WARNING_ORDER.flatMap((k) => buckets[k] ? [{ kind: k, items: buckets[k] }] : []);
|
|
@@ -1849,13 +1946,15 @@ async function runLint(input) {
|
|
|
1849
1946
|
vault: { path: input.vault, source: input.source ?? "resolved" },
|
|
1850
1947
|
summary,
|
|
1851
1948
|
by_severity: { error: errorOut, warning: warningOut, info: infoOut },
|
|
1949
|
+
fixed,
|
|
1950
|
+
unresolved,
|
|
1852
1951
|
humanHint: hintLines.join("\n")
|
|
1853
1952
|
})
|
|
1854
1953
|
};
|
|
1855
1954
|
}
|
|
1856
1955
|
|
|
1857
1956
|
// src/commands/config.ts
|
|
1858
|
-
import { readFile as
|
|
1957
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
1859
1958
|
import { existsSync } from "fs";
|
|
1860
1959
|
import { join as join14 } from "path";
|
|
1861
1960
|
function validateKey(key) {
|
|
@@ -1880,7 +1979,7 @@ async function runConfigSet(input) {
|
|
|
1880
1979
|
try {
|
|
1881
1980
|
let originalContent;
|
|
1882
1981
|
try {
|
|
1883
|
-
originalContent = await
|
|
1982
|
+
originalContent = await readFile13(filePath, "utf8");
|
|
1884
1983
|
} catch {
|
|
1885
1984
|
}
|
|
1886
1985
|
const existing = originalContent !== void 0 ? parseDotenvText(originalContent) : {};
|
|
@@ -2193,7 +2292,7 @@ async function runDoctor(input) {
|
|
|
2193
2292
|
}
|
|
2194
2293
|
|
|
2195
2294
|
// src/commands/archive.ts
|
|
2196
|
-
import { rename as rename3, mkdir as mkdir5, readFile as
|
|
2295
|
+
import { rename as rename3, mkdir as mkdir5, readFile as readFile14, writeFile as writeFile7 } from "fs/promises";
|
|
2197
2296
|
import { join as join18, dirname as dirname7 } from "path";
|
|
2198
2297
|
async function runArchive(input) {
|
|
2199
2298
|
const scan = await scanVault(input.vault);
|
|
@@ -2216,12 +2315,12 @@ async function runArchive(input) {
|
|
|
2216
2315
|
if (!isRaw) {
|
|
2217
2316
|
const indexPath = join18(input.vault, "index.md");
|
|
2218
2317
|
try {
|
|
2219
|
-
const idx = await
|
|
2318
|
+
const idx = await readFile14(indexPath, "utf8");
|
|
2220
2319
|
const slug = relPath.replace(/\.md$/, "").split("/").pop();
|
|
2221
2320
|
const originalLines = idx.split("\n");
|
|
2222
2321
|
const filtered = originalLines.filter((l) => !l.includes(`[[${slug}]]`));
|
|
2223
2322
|
if (filtered.length !== originalLines.length) {
|
|
2224
|
-
await
|
|
2323
|
+
await writeFile7(indexPath, filtered.join("\n"), "utf8");
|
|
2225
2324
|
indexUpdated = true;
|
|
2226
2325
|
}
|
|
2227
2326
|
} catch (e) {
|
|
@@ -2234,7 +2333,7 @@ async function runArchive(input) {
|
|
|
2234
2333
|
|
|
2235
2334
|
// src/commands/drift.ts
|
|
2236
2335
|
import { createHash as createHash2 } from "crypto";
|
|
2237
|
-
import { writeFile as
|
|
2336
|
+
import { writeFile as writeFile8 } from "fs/promises";
|
|
2238
2337
|
|
|
2239
2338
|
// src/utils/fetch.ts
|
|
2240
2339
|
async function controlledFetch(url, opts) {
|
|
@@ -2320,7 +2419,7 @@ async function runDrift(input) {
|
|
|
2320
2419
|
${newFm}
|
|
2321
2420
|
---
|
|
2322
2421
|
${body}`;
|
|
2323
|
-
await
|
|
2422
|
+
await writeFile8(raw.absPath, newText, "utf8");
|
|
2324
2423
|
results.push({
|
|
2325
2424
|
raw_path: raw.relPath,
|
|
2326
2425
|
source_url: sourceUrl,
|
|
@@ -2355,7 +2454,7 @@ ${body}`;
|
|
|
2355
2454
|
}
|
|
2356
2455
|
|
|
2357
2456
|
// src/commands/migrate-citations.ts
|
|
2358
|
-
import { writeFile as
|
|
2457
|
+
import { writeFile as writeFile9 } from "fs/promises";
|
|
2359
2458
|
var MARKER_RE2 = /\^\[(raw\/[^\]]+)\]/g;
|
|
2360
2459
|
function moveMarkersToParagraphEnd(body) {
|
|
2361
2460
|
const lines = body.split("\n");
|
|
@@ -2478,7 +2577,7 @@ ${migratedBody}${newFooter}`;
|
|
|
2478
2577
|
continue;
|
|
2479
2578
|
}
|
|
2480
2579
|
if (!input.dryRun) {
|
|
2481
|
-
await
|
|
2580
|
+
await writeFile9(page.absPath, newText, "utf8");
|
|
2482
2581
|
}
|
|
2483
2582
|
migrated.push(page.relPath);
|
|
2484
2583
|
}
|
|
@@ -2500,7 +2599,7 @@ ${migratedBody}${newFooter}`;
|
|
|
2500
2599
|
}
|
|
2501
2600
|
|
|
2502
2601
|
// src/commands/frontmatter-fix.ts
|
|
2503
|
-
import { writeFile as
|
|
2602
|
+
import { writeFile as writeFile10 } from "fs/promises";
|
|
2504
2603
|
function isoToday() {
|
|
2505
2604
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2506
2605
|
}
|
|
@@ -2542,7 +2641,7 @@ ${newBody}`;
|
|
|
2542
2641
|
continue;
|
|
2543
2642
|
}
|
|
2544
2643
|
if (!input.dryRun) {
|
|
2545
|
-
await
|
|
2644
|
+
await writeFile10(page.absPath, newText, "utf8");
|
|
2546
2645
|
}
|
|
2547
2646
|
fixed.push(page.relPath);
|
|
2548
2647
|
}
|
|
@@ -2626,7 +2725,7 @@ async function runUpdate(input) {
|
|
|
2626
2725
|
}
|
|
2627
2726
|
|
|
2628
2727
|
// src/commands/transcripts.ts
|
|
2629
|
-
import { readdir as readdir4, stat as stat6, readFile as
|
|
2728
|
+
import { readdir as readdir4, stat as stat6, readFile as readFile15 } from "fs/promises";
|
|
2630
2729
|
import { join as join19 } from "path";
|
|
2631
2730
|
async function runTranscripts(input) {
|
|
2632
2731
|
const dir = join19(input.vault, "raw", "transcripts");
|
|
@@ -2640,7 +2739,7 @@ async function runTranscripts(input) {
|
|
|
2640
2739
|
for (const entry of entries) {
|
|
2641
2740
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
2642
2741
|
const filePath = join19(dir, entry.name);
|
|
2643
|
-
const content = await
|
|
2742
|
+
const content = await readFile15(filePath, "utf8");
|
|
2644
2743
|
const fm = extractFrontmatter(content);
|
|
2645
2744
|
if (!fm.ok) continue;
|
|
2646
2745
|
const ingested = typeof fm.data.ingested === "string" ? fm.data.ingested : "";
|
|
@@ -2763,7 +2862,7 @@ program.command("log-rotate [vault]").option("--threshold <n>", "entry count thr
|
|
|
2763
2862
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2764
2863
|
else emit(await runLogRotate({ vault: v.vault, threshold: opts.threshold, apply: !!opts.apply }));
|
|
2765
2864
|
});
|
|
2766
|
-
program.command("lint [vault]").option("--days <n>", "stale threshold", (s) => parseInt(s, 10), 90).option("--lines <n>", "pagesize threshold", (s) => parseInt(s, 10), 200).option("--log-threshold <n>", "log rotation threshold", (s) => parseInt(s, 10), 500).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2865
|
+
program.command("lint [vault]").option("--days <n>", "stale threshold", (s) => parseInt(s, 10), 90).option("--lines <n>", "pagesize threshold", (s) => parseInt(s, 10), 200).option("--log-threshold <n>", "log rotation threshold", (s) => parseInt(s, 10), 500).option("--fix", "auto-fix legacy_citation_style violations").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2767
2866
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2768
2867
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2769
2868
|
else emit(await runLint({
|
|
@@ -2771,7 +2870,8 @@ program.command("lint [vault]").option("--days <n>", "stale threshold", (s) => p
|
|
|
2771
2870
|
source: vault ? "flag" : void 0,
|
|
2772
2871
|
days: opts.days,
|
|
2773
2872
|
lines: opts.lines,
|
|
2774
|
-
logThreshold: opts.logThreshold
|
|
2873
|
+
logThreshold: opts.logThreshold,
|
|
2874
|
+
fix: opts.fix ?? false
|
|
2775
2875
|
}));
|
|
2776
2876
|
});
|
|
2777
2877
|
var configCmd = program.command("config").description("manage skillwiki configuration");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.2.1-beta.
|
|
3
|
+
"version": "0.2.1-beta.11",
|
|
4
4
|
"skills": "./",
|
|
5
5
|
"description": "Project-aware Karpathy-style knowledge base for Claude Code: 15 prompt-only skills (wiki-*, proj-*, using-skillwiki) backed by the deterministic `skillwiki` CLI.",
|
|
6
6
|
"author": {
|