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 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 readFile12 } from "fs/promises";
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 readFile12(filePath, "utf8");
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 readFile13, writeFile as writeFile6 } from "fs/promises";
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 readFile13(indexPath, "utf8");
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 writeFile6(indexPath, filtered.join("\n"), "utf8");
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 writeFile7 } from "fs/promises";
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 writeFile7(raw.absPath, newText, "utf8");
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 writeFile8 } from "fs/promises";
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 writeFile8(page.absPath, newText, "utf8");
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 writeFile9 } from "fs/promises";
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 writeFile9(page.absPath, newText, "utf8");
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 readFile14 } from "fs/promises";
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 readFile14(filePath, "utf8");
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.10",
3
+ "version": "0.2.1-beta.11",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "skillwiki": "dist/cli.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.2.1-beta.10",
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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillwiki/skills",
3
- "version": "0.2.1-beta.10",
3
+ "version": "0.2.1-beta.11",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",