skillwiki 0.9.1-beta.1 → 0.9.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/dist/cli.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-TPS5XD2J.js";
15
15
 
16
16
  // src/cli.ts
17
- import { join as join47 } from "path";
17
+ import { join as join48 } from "path";
18
18
  import { Command as Command2 } from "commander";
19
19
 
20
20
  // ../shared/src/exit-codes.ts
@@ -1159,8 +1159,8 @@ function simulateRemoval(adj, removed) {
1159
1159
  }
1160
1160
 
1161
1161
  // src/commands/audit.ts
1162
- import { readFile as readFile5, stat as stat2 } from "fs/promises";
1163
- import { dirname as dirname3, resolve as resolve2, join as join5 } from "path";
1162
+ import { readFile as readFile5, stat as stat3 } from "fs/promises";
1163
+ import { dirname as dirname3, resolve as resolve2, join as join6 } from "path";
1164
1164
 
1165
1165
  // src/parsers/citations.ts
1166
1166
  var FENCE2 = /```[\s\S]*?```/g;
@@ -1178,6 +1178,7 @@ function extractCitationMarkers(body) {
1178
1178
  const out = [];
1179
1179
  let m;
1180
1180
  while ((m = MARKER_RE.exec(stripped)) !== null) {
1181
+ if (m[1] === "raw/...") continue;
1181
1182
  out.push({ marker: m[0], target: m[1] });
1182
1183
  }
1183
1184
  return out;
@@ -1267,6 +1268,41 @@ function hasWikilinkCitations(body) {
1267
1268
  return /\[\[raw\/[^\]]+\]\]/.test(stripped);
1268
1269
  }
1269
1270
 
1271
+ // src/utils/raw-source.ts
1272
+ import { existsSync } from "fs";
1273
+ import { stat as stat2 } from "fs/promises";
1274
+ import { join as join5 } from "path";
1275
+ function normalizeRawSourceTarget(entry) {
1276
+ let target = entry.trim().replace(/^"/, "").replace(/"$/, "").replace(/^'/, "").replace(/'$/, "");
1277
+ target = target.replace(/^\^\[/, "").replace(/\]$/, "");
1278
+ if (!target.startsWith("raw/") && !target.startsWith("_archive/raw/")) return null;
1279
+ return target;
1280
+ }
1281
+ function rawSourceTargetCandidates(vault, target) {
1282
+ const normalized = normalizeRawSourceTarget(target);
1283
+ if (!normalized) return [];
1284
+ const candidates = [join5(vault, normalized)];
1285
+ if (!normalized.endsWith(".md")) candidates.push(join5(vault, `${normalized}.md`));
1286
+ if (normalized.startsWith("raw/")) {
1287
+ candidates.push(join5(vault, "_archive", normalized));
1288
+ if (!normalized.endsWith(".md")) candidates.push(join5(vault, "_archive", `${normalized}.md`));
1289
+ }
1290
+ return [...new Set(candidates)];
1291
+ }
1292
+ function rawSourceTargetExistsSync(vault, target) {
1293
+ return rawSourceTargetCandidates(vault, target).some((candidate) => existsSync(candidate));
1294
+ }
1295
+ async function rawSourceTargetExists(vault, target) {
1296
+ for (const candidate of rawSourceTargetCandidates(vault, target)) {
1297
+ try {
1298
+ await stat2(candidate);
1299
+ return true;
1300
+ } catch {
1301
+ }
1302
+ }
1303
+ return false;
1304
+ }
1305
+
1270
1306
  // src/commands/audit.ts
1271
1307
  async function runAudit(input) {
1272
1308
  let text;
@@ -1283,12 +1319,7 @@ async function runAudit(input) {
1283
1319
  if (!vault) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID") };
1284
1320
  const markers = extractCitationMarkers(body);
1285
1321
  const resolved = await Promise.all(markers.map(async (m) => {
1286
- try {
1287
- await stat2(join5(vault, m.target));
1288
- return { ...m, resolved: true };
1289
- } catch {
1290
- return { ...m, resolved: false };
1291
- }
1322
+ return { ...m, resolved: await rawSourceTargetExists(vault, m.target) };
1292
1323
  }));
1293
1324
  const sources = (fm.data.sources ?? []).map((s) => s.replace(/^\^\[/, "").replace(/\]$/, ""));
1294
1325
  const referenced = new Set(resolved.map((m) => m.target));
@@ -1329,7 +1360,7 @@ async function findVaultRoot(start) {
1329
1360
  let cur = start;
1330
1361
  for (let i = 0; i < 20; i++) {
1331
1362
  try {
1332
- await stat2(join5(cur, "SCHEMA.md"));
1363
+ await stat3(join6(cur, "SCHEMA.md"));
1333
1364
  return cur;
1334
1365
  } catch {
1335
1366
  }
@@ -1381,17 +1412,17 @@ async function validateCompoundReferences(vault) {
1381
1412
  }
1382
1413
 
1383
1414
  // src/commands/install.ts
1384
- import { readdir as readdir2, stat as stat4, symlink, unlink, mkdir as mkdir4, readFile as readFile6 } from "fs/promises";
1385
- import { join as join6, resolve as resolve3, dirname as dirname5 } from "path";
1415
+ import { readdir as readdir2, stat as stat5, symlink, unlink, mkdir as mkdir4, readFile as readFile6 } from "fs/promises";
1416
+ import { join as join7, resolve as resolve3, dirname as dirname5 } from "path";
1386
1417
 
1387
1418
  // src/utils/install-fs.ts
1388
- import { copyFile, mkdir as mkdir3, rename, writeFile as writeFile4, stat as stat3 } from "fs/promises";
1419
+ import { copyFile, mkdir as mkdir3, rename, writeFile as writeFile4, stat as stat4 } from "fs/promises";
1389
1420
  import { dirname as dirname4 } from "path";
1390
1421
  async function atomicCopyWithBackup(src, dst) {
1391
1422
  await mkdir3(dirname4(dst), { recursive: true });
1392
1423
  let backupPath = null;
1393
1424
  try {
1394
- await stat3(dst);
1425
+ await stat4(dst);
1395
1426
  backupPath = `${dst}.bak`;
1396
1427
  await copyFile(dst, backupPath);
1397
1428
  } catch {
@@ -1445,7 +1476,7 @@ async function runInstall(input) {
1445
1476
  const withSkill = [];
1446
1477
  for (const d of dirs) {
1447
1478
  try {
1448
- await stat4(join6(input.skillsRoot, d.name, "SKILL.md"));
1479
+ await stat5(join7(input.skillsRoot, d.name, "SKILL.md"));
1449
1480
  withSkill.push(d.name);
1450
1481
  } catch {
1451
1482
  }
@@ -1462,10 +1493,10 @@ async function runInstall(input) {
1462
1493
  const version_warnings = [];
1463
1494
  const skillMetas = {};
1464
1495
  for (const name of entries) {
1465
- const src = join6(input.skillsRoot, name, "SKILL.md");
1466
- const dst = join6(input.target, name, "SKILL.md");
1496
+ const src = join7(input.skillsRoot, name, "SKILL.md");
1497
+ const dst = join7(input.target, name, "SKILL.md");
1467
1498
  try {
1468
- await stat4(src);
1499
+ await stat5(src);
1469
1500
  } catch {
1470
1501
  return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { missing: src }) };
1471
1502
  }
@@ -1504,10 +1535,10 @@ async function runInstall(input) {
1504
1535
  if (r.data.backupPath) backed_up.push(r.data.backupPath);
1505
1536
  }
1506
1537
  }
1507
- const binSrc = join6(input.skillsRoot, "bin", "skillwiki");
1538
+ const binSrc = join7(input.skillsRoot, "bin", "skillwiki");
1508
1539
  try {
1509
- await stat4(binSrc);
1510
- const binDst = join6(input.target, "bin", "skillwiki");
1540
+ await stat5(binSrc);
1541
+ const binDst = join7(input.target, "bin", "skillwiki");
1511
1542
  if (!input.dryRun) {
1512
1543
  if (input.symlink) {
1513
1544
  const r = await createSymlink(binSrc, binDst);
@@ -1524,7 +1555,7 @@ async function runInstall(input) {
1524
1555
  }
1525
1556
  } catch {
1526
1557
  }
1527
- const manifest_path = join6(input.target, "wiki-manifest.json");
1558
+ const manifest_path = join7(input.target, "wiki-manifest.json");
1528
1559
  if (!input.dryRun) await writeManifest(manifest_path, { installed, backed_up, symlink: input.symlink || void 0, skills: skillMetas });
1529
1560
  const mode = input.symlink ? "symlink (dev mode)" : "copy";
1530
1561
  const hintLines = [
@@ -1566,7 +1597,7 @@ async function runPath(input) {
1566
1597
  }
1567
1598
 
1568
1599
  // src/utils/lang.ts
1569
- import { join as join7 } from "path";
1600
+ import { join as join8 } from "path";
1570
1601
  var ALIASES = {
1571
1602
  english: "en",
1572
1603
  en: "en",
@@ -1589,7 +1620,7 @@ async function resolveLang(input) {
1589
1620
  if (input.envValue !== void 0 && input.envValue.length > 0) {
1590
1621
  return { value: input.envValue, source: "env", canonical: normalizeLang(input.envValue) };
1591
1622
  }
1592
- const dotenv = await parseDotenvFile(join7(input.home, ".skillwiki", ".env"));
1623
+ const dotenv = await parseDotenvFile(join8(input.home, ".skillwiki", ".env"));
1593
1624
  if (dotenv.WIKI_LANG !== void 0) {
1594
1625
  return { value: dotenv.WIKI_LANG, source: "skillwiki-dotenv", canonical: normalizeLang(dotenv.WIKI_LANG) };
1595
1626
  }
@@ -1597,7 +1628,7 @@ async function resolveLang(input) {
1597
1628
  }
1598
1629
 
1599
1630
  // src/commands/lang.ts
1600
- import { join as join8 } from "path";
1631
+ import { join as join9 } from "path";
1601
1632
  async function runLang(input) {
1602
1633
  const resolved = await resolveLang({ flag: input.flag, envValue: input.envValue, home: input.home });
1603
1634
  let chain;
@@ -1606,7 +1637,7 @@ async function runLang(input) {
1606
1637
  { source: "flag", matched: input.flag !== void 0 && input.flag.length > 0, value: input.flag },
1607
1638
  { source: "env", matched: input.envValue !== void 0 && input.envValue.length > 0, value: input.envValue }
1608
1639
  ];
1609
- const sw = await parseDotenvFile(join8(input.home, ".skillwiki", ".env"));
1640
+ const sw = await parseDotenvFile(join9(input.home, ".skillwiki", ".env"));
1610
1641
  chain.push({ source: "skillwiki-dotenv", matched: sw.WIKI_LANG !== void 0, value: sw.WIKI_LANG });
1611
1642
  chain.push({ source: "default", matched: resolved.source === "default", value: "en" });
1612
1643
  }
@@ -1624,7 +1655,7 @@ async function runLang(input) {
1624
1655
 
1625
1656
  // src/commands/init.ts
1626
1657
  import { mkdir as mkdir5, readFile as readFile7, readdir as readdir3, writeFile as writeFile5 } from "fs/promises";
1627
- import { join as join10 } from "path";
1658
+ import { join as join11 } from "path";
1628
1659
 
1629
1660
  // src/parsers/taxonomy.ts
1630
1661
  import yaml2 from "js-yaml";
@@ -1652,16 +1683,16 @@ function extractTaxonomy(schemaText) {
1652
1683
  }
1653
1684
 
1654
1685
  // src/utils/last-op.ts
1655
- import { readFileSync as readFileSync2, writeFileSync, mkdirSync, unlinkSync, existsSync } from "fs";
1656
- import { join as join9 } from "path";
1686
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync, unlinkSync, existsSync as existsSync2 } from "fs";
1687
+ import { join as join10 } from "path";
1657
1688
  var LAST_OP_DIR = ".skillwiki";
1658
1689
  var LAST_OP_FILE = "last-op.json";
1659
1690
  function lastOpPath(vault) {
1660
- return join9(vault, LAST_OP_DIR, LAST_OP_FILE);
1691
+ return join10(vault, LAST_OP_DIR, LAST_OP_FILE);
1661
1692
  }
1662
1693
  function readLastOp(vault) {
1663
1694
  const p = lastOpPath(vault);
1664
- if (!existsSync(p)) return [];
1695
+ if (!existsSync2(p)) return [];
1665
1696
  try {
1666
1697
  const raw = readFileSync2(p, "utf8");
1667
1698
  const parsed = JSON.parse(raw);
@@ -1681,8 +1712,8 @@ function readLastOp(vault) {
1681
1712
  function appendLastOp(vault, entry) {
1682
1713
  const existing = readLastOp(vault);
1683
1714
  existing.push(entry);
1684
- const dir = join9(vault, LAST_OP_DIR);
1685
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
1715
+ const dir = join10(vault, LAST_OP_DIR);
1716
+ if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
1686
1717
  writeFileSync(lastOpPath(vault), JSON.stringify(existing, null, 2), "utf8");
1687
1718
  }
1688
1719
  function clearLastOp(vault) {
@@ -1735,13 +1766,13 @@ async function discoverTagsFromPages(target, knownSlugs) {
1735
1766
  for (const dir of ["entities", "concepts", "comparisons", "queries"]) {
1736
1767
  let entries;
1737
1768
  try {
1738
- entries = (await readdir3(join10(target, dir), { withFileTypes: true })).filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => e.name);
1769
+ entries = (await readdir3(join11(target, dir), { withFileTypes: true })).filter((e) => e.isFile() && e.name.endsWith(".md")).map((e) => e.name);
1739
1770
  } catch {
1740
1771
  continue;
1741
1772
  }
1742
1773
  for (const file of entries) {
1743
1774
  try {
1744
- const text = await readFile7(join10(target, dir, file), "utf8");
1775
+ const text = await readFile7(join11(target, dir, file), "utf8");
1745
1776
  const fm = extractFrontmatter(text);
1746
1777
  if (!fm.ok || !fm.data.tags || !Array.isArray(fm.data.tags)) continue;
1747
1778
  for (const t of fm.data.tags) {
@@ -1760,7 +1791,7 @@ async function runInit(input) {
1760
1791
  const canonicalLang = langRes.canonical;
1761
1792
  let oldSchemaText;
1762
1793
  try {
1763
- oldSchemaText = await readFile7(join10(target, "SCHEMA.md"), "utf8");
1794
+ oldSchemaText = await readFile7(join11(target, "SCHEMA.md"), "utf8");
1764
1795
  } catch {
1765
1796
  }
1766
1797
  if (oldSchemaText && !input.force) {
@@ -1769,7 +1800,7 @@ async function runInit(input) {
1769
1800
  result: err("INIT_TARGET_NOT_EMPTY", { target })
1770
1801
  };
1771
1802
  }
1772
- const envPath = join10(input.home, ".skillwiki", ".env");
1803
+ const envPath = join11(input.home, ".skillwiki", ".env");
1773
1804
  let existingEnvRaw = "";
1774
1805
  try {
1775
1806
  existingEnvRaw = await readFile7(envPath, "utf8");
@@ -1795,7 +1826,7 @@ async function runInit(input) {
1795
1826
  try {
1796
1827
  await mkdir5(target, { recursive: true });
1797
1828
  for (const d of VAULT_DIRS) {
1798
- await mkdir5(join10(target, d), { recursive: true });
1829
+ await mkdir5(join11(target, d), { recursive: true });
1799
1830
  created.push(d + "/");
1800
1831
  }
1801
1832
  } catch (e) {
@@ -1824,9 +1855,9 @@ async function runInit(input) {
1824
1855
  const discovered_tags = discovered.length;
1825
1856
  const fullTaxonomyYaml = discovered.length > 0 ? taxonomy.map((t) => ` - ${t}`).join("\n") + "\n # --- Discovered from existing pages ---\n" + discovered.map((t) => ` - ${t}`).join("\n") : taxonomy.map((t) => ` - ${t}`).join("\n");
1826
1857
  try {
1827
- const schemaTpl = await readFile7(join10(input.templates, "SCHEMA.md"), "utf8");
1858
+ const schemaTpl = await readFile7(join11(input.templates, "SCHEMA.md"), "utf8");
1828
1859
  const schema = schemaTpl.replace("{{DOMAIN}}", domain).replace("{{WIKI_LANG}}", canonicalLang).replace("{{TAXONOMY_YAML}}", fullTaxonomyYaml);
1829
- await writeFile5(join10(target, "SCHEMA.md"), schema, "utf8");
1860
+ await writeFile5(join11(target, "SCHEMA.md"), schema, "utf8");
1830
1861
  created.push("SCHEMA.md");
1831
1862
  } catch (e) {
1832
1863
  return { exitCode: ExitCode.WRITE_FAILED, result: err("WRITE_FAILED", { file: "SCHEMA.md", message: String(e) }) };
@@ -1834,7 +1865,7 @@ async function runInit(input) {
1834
1865
  const preserved = [];
1835
1866
  async function writeOrPreserve(fileName, render) {
1836
1867
  try {
1837
- const existing = await readFile7(join10(target, fileName), "utf8");
1868
+ const existing = await readFile7(join11(target, fileName), "utf8");
1838
1869
  if (existing.split("\n").length > 10) {
1839
1870
  preserved.push(fileName);
1840
1871
  return void 0;
@@ -1842,7 +1873,7 @@ async function runInit(input) {
1842
1873
  } catch {
1843
1874
  }
1844
1875
  try {
1845
- await writeFile5(join10(target, fileName), await render(), "utf8");
1876
+ await writeFile5(join11(target, fileName), await render(), "utf8");
1846
1877
  created.push(fileName);
1847
1878
  return void 0;
1848
1879
  } catch (e) {
@@ -1850,7 +1881,7 @@ async function runInit(input) {
1850
1881
  }
1851
1882
  }
1852
1883
  const err1 = await writeOrPreserve("index.md", async () => {
1853
- const tpl = await readFile7(join10(input.templates, "index.md"), "utf8");
1884
+ const tpl = await readFile7(join11(input.templates, "index.md"), "utf8");
1854
1885
  return tpl.replace("{{INIT_DATE}}", today);
1855
1886
  });
1856
1887
  if (err1) return err1;
@@ -1877,7 +1908,7 @@ async function runInit(input) {
1877
1908
  });
1878
1909
  if (errTemplate) return errTemplate;
1879
1910
  const err22 = await writeOrPreserve("log.md", async () => {
1880
- const tpl = await readFile7(join10(input.templates, "log.md"), "utf8");
1911
+ const tpl = await readFile7(join11(input.templates, "log.md"), "utf8");
1881
1912
  return tpl.replace(/\{\{INIT_DATE\}\}/g, today).replace("{{DOMAIN}}", domain).replace("{{WIKI_LANG}}", canonicalLang);
1882
1913
  });
1883
1914
  if (err22) return err22;
@@ -1975,11 +2006,11 @@ ${broken.map((b) => ` ${b.page}:[[${b.slug}]] (line ${b.line})`).join("\n")}` }
1975
2006
 
1976
2007
  // src/commands/tag-audit.ts
1977
2008
  import { readFile as readFile8 } from "fs/promises";
1978
- import { join as join11 } from "path";
2009
+ import { join as join12 } from "path";
1979
2010
  async function runTagAudit(input) {
1980
2011
  const scan = await scanVault(input.vault);
1981
2012
  if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
1982
- const schemaText = await readFile8(join11(input.vault, "SCHEMA.md"), "utf8");
2013
+ const schemaText = await readFile8(join12(input.vault, "SCHEMA.md"), "utf8");
1983
2014
  const tax = extractTaxonomy(schemaText);
1984
2015
  if (!tax.ok) return { exitCode: ExitCode.INVALID_FRONTMATTER, result: tax };
1985
2016
  const allowed = new Set(tax.data);
@@ -2004,13 +2035,13 @@ async function runTagAudit(input) {
2004
2035
 
2005
2036
  // src/commands/index-check.ts
2006
2037
  import { readFile as readFile9 } from "fs/promises";
2007
- import { join as join12 } from "path";
2038
+ import { join as join13 } from "path";
2008
2039
  async function runIndexCheck(input) {
2009
2040
  const scan = await scanVault(input.vault);
2010
2041
  if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
2011
2042
  let indexText = "";
2012
2043
  try {
2013
- indexText = await readFile9(join12(input.vault, "index.md"), "utf8");
2044
+ indexText = await readFile9(join13(input.vault, "index.md"), "utf8");
2014
2045
  } catch {
2015
2046
  }
2016
2047
  const indexSlugsLower = /* @__PURE__ */ new Map();
@@ -2050,7 +2081,7 @@ async function runIndexCheck(input) {
2050
2081
 
2051
2082
  // src/commands/stale.ts
2052
2083
  import { readdir as readdir4, rename as rename2, mkdir as mkdir6, readFile as readFile10 } from "fs/promises";
2053
- import { join as join13 } from "path";
2084
+ import { join as join14 } from "path";
2054
2085
 
2055
2086
  // src/parsers/expiry-annotations.ts
2056
2087
  var HEADING_RE = /^#{1,6}\s+(.+)$/;
@@ -2098,7 +2129,7 @@ async function runStale(input) {
2098
2129
  const archived = [];
2099
2130
  const workDirs = /* @__PURE__ */ new Map();
2100
2131
  const workDirsBySlug = /* @__PURE__ */ new Map();
2101
- const projectsDir = join13(input.vault, "projects");
2132
+ const projectsDir = join14(input.vault, "projects");
2102
2133
  let projectSlugs = [];
2103
2134
  try {
2104
2135
  projectSlugs = (await readdir4(projectsDir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name);
@@ -2111,7 +2142,7 @@ async function runStale(input) {
2111
2142
  projectSlugs = [input.project];
2112
2143
  }
2113
2144
  for (const slug of projectSlugs) {
2114
- const workPath = join13(projectsDir, slug, "work");
2145
+ const workPath = join14(projectsDir, slug, "work");
2115
2146
  let entries;
2116
2147
  try {
2117
2148
  entries = await readdir4(workPath, { withFileTypes: true });
@@ -2122,7 +2153,7 @@ async function runStale(input) {
2122
2153
  for (const e of entries) {
2123
2154
  if (!e.isDirectory()) continue;
2124
2155
  const relDir = `projects/${slug}/work/${e.name}`;
2125
- const absDir = join13(workPath, e.name);
2156
+ const absDir = join14(workPath, e.name);
2126
2157
  let status = "";
2127
2158
  let files;
2128
2159
  try {
@@ -2135,7 +2166,7 @@ async function runStale(input) {
2135
2166
  for (const f of files) {
2136
2167
  if (!f.endsWith(".md")) continue;
2137
2168
  try {
2138
- const fm = extractFrontmatter(await readFile10(join13(absDir, f), "utf8"));
2169
+ const fm = extractFrontmatter(await readFile10(join14(absDir, f), "utf8"));
2139
2170
  if (fm.ok && typeof fm.data.status === "string") {
2140
2171
  status = fm.data.status;
2141
2172
  break;
@@ -2159,7 +2190,7 @@ async function runStale(input) {
2159
2190
  const transcriptMeta = /* @__PURE__ */ new Map();
2160
2191
  for (const t of transcripts) {
2161
2192
  try {
2162
- const content = await readFile10(join13(input.vault, t.relPath), "utf8");
2193
+ const content = await readFile10(join14(input.vault, t.relPath), "utf8");
2163
2194
  const fm = extractFrontmatter(content);
2164
2195
  let kind = fm.ok && typeof fm.data.kind === "string" ? fm.data.kind : "";
2165
2196
  let project = fm.ok && typeof fm.data.project === "string" ? fm.data.project : "";
@@ -2227,7 +2258,7 @@ async function runStale(input) {
2227
2258
  }
2228
2259
  }
2229
2260
  for (const [relDir] of workDirs) {
2230
- const specPath = join13(input.vault, relDir, "spec.md");
2261
+ const specPath = join14(input.vault, relDir, "spec.md");
2231
2262
  try {
2232
2263
  const specContent = await readFile10(specPath, "utf8");
2233
2264
  const specFm = extractFrontmatter(specContent);
@@ -2258,7 +2289,7 @@ async function runStale(input) {
2258
2289
  if (daysSince(dateStr) < input.days) continue;
2259
2290
  let files;
2260
2291
  try {
2261
- files = await readdir4(join13(input.vault, relDir));
2292
+ files = await readdir4(join14(input.vault, relDir));
2262
2293
  } catch {
2263
2294
  continue;
2264
2295
  }
@@ -2274,7 +2305,7 @@ async function runStale(input) {
2274
2305
  const stale = [];
2275
2306
  for (const page of scan.data.typedKnowledge) {
2276
2307
  try {
2277
- const text = await readFile10(join13(input.vault, page.relPath), "utf8");
2308
+ const text = await readFile10(join14(input.vault, page.relPath), "utf8");
2278
2309
  const fm = extractFrontmatter(text);
2279
2310
  if (fm.ok && typeof fm.data.updated === "string") {
2280
2311
  if (input.project) {
@@ -2294,7 +2325,7 @@ async function runStale(input) {
2294
2325
  const staleSections = [];
2295
2326
  for (const page of scan.data.typedKnowledge) {
2296
2327
  try {
2297
- const text = await readFile10(join13(input.vault, page.relPath), "utf8");
2328
+ const text = await readFile10(join14(input.vault, page.relPath), "utf8");
2298
2329
  const projectFilter = input.project;
2299
2330
  if (projectFilter) {
2300
2331
  const fm = extractFrontmatter(text);
@@ -2323,11 +2354,11 @@ async function runStale(input) {
2323
2354
  }
2324
2355
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2325
2356
  if (input.archive) {
2326
- const archiveDir = join13(input.vault, "_archive", today);
2357
+ const archiveDir = join14(input.vault, "_archive", today);
2327
2358
  await mkdir6(archiveDir, { recursive: true });
2328
2359
  const citedRawPaths = /* @__PURE__ */ new Set();
2329
2360
  for (const page of scan.data.typedKnowledge) {
2330
- const text = await readFile10(join13(input.vault, page.relPath), "utf8").catch(() => "");
2361
+ const text = await readFile10(join14(input.vault, page.relPath), "utf8").catch(() => "");
2331
2362
  for (const line of text.split("\n")) {
2332
2363
  for (const m of line.matchAll(/\^\[(raw\/[^\]]+)\]/g)) {
2333
2364
  citedRawPaths.add(m[1]);
@@ -2339,9 +2370,9 @@ async function runStale(input) {
2339
2370
  }
2340
2371
  for (const t of staleTranscripts) {
2341
2372
  if (citedRawPaths.has(t.path) || citedRawPaths.has(t.path.replace(/\.md$/, ""))) continue;
2342
- const dest = join13(archiveDir, t.path.split("/").pop());
2373
+ const dest = join14(archiveDir, t.path.split("/").pop());
2343
2374
  try {
2344
- await rename2(join13(input.vault, t.path), dest);
2375
+ await rename2(join14(input.vault, t.path), dest);
2345
2376
  archived.push(t.path);
2346
2377
  } catch {
2347
2378
  }
@@ -2351,18 +2382,18 @@ async function runStale(input) {
2351
2382
  if (parts.length >= 4 && parts[0] === "projects") {
2352
2383
  const slug = parts[1];
2353
2384
  const itemName = parts[3];
2354
- const histDir = join13(input.vault, "projects", slug, "history", "archived-work");
2385
+ const histDir = join14(input.vault, "projects", slug, "history", "archived-work");
2355
2386
  await mkdir6(histDir, { recursive: true });
2356
- const dest = join13(histDir, itemName);
2387
+ const dest = join14(histDir, itemName);
2357
2388
  try {
2358
- await rename2(join13(input.vault, w.path), dest);
2389
+ await rename2(join14(input.vault, w.path), dest);
2359
2390
  archived.push(w.path);
2360
2391
  } catch {
2361
2392
  }
2362
2393
  } else {
2363
- const dest = join13(archiveDir, w.path.replace(/\//g, "_"));
2394
+ const dest = join14(archiveDir, w.path.replace(/\//g, "_"));
2364
2395
  try {
2365
- await rename2(join13(input.vault, w.path), dest);
2396
+ await rename2(join14(input.vault, w.path), dest);
2366
2397
  archived.push(w.path);
2367
2398
  } catch {
2368
2399
  }
@@ -2402,8 +2433,8 @@ async function runStale(input) {
2402
2433
 
2403
2434
  // src/commands/claim.ts
2404
2435
  import { mkdir as mkdir7, writeFile as writeFile6, readFile as readFile11 } from "fs/promises";
2405
- import { existsSync as existsSync2, statSync } from "fs";
2406
- import { join as join14 } from "path";
2436
+ import { existsSync as existsSync3, statSync } from "fs";
2437
+ import { join as join15 } from "path";
2407
2438
  function extractDate(filename) {
2408
2439
  const m = filename.match(/^(\d{4}-\d{2}-\d{2})/);
2409
2440
  return m?.[1] ?? "";
@@ -2415,11 +2446,11 @@ function extractProjectSlug(projectField) {
2415
2446
  return projectField.replace(/^\[\[/, "").replace(/\]\]$/, "").replace(/^"|"$/g, "");
2416
2447
  }
2417
2448
  async function runClaim(input) {
2418
- if (!existsSync2(input.vault) || !statSync(input.vault).isDirectory()) {
2449
+ if (!existsSync3(input.vault) || !statSync(input.vault).isDirectory()) {
2419
2450
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { path: input.vault }) };
2420
2451
  }
2421
- const absTranscript = join14(input.vault, input.transcript);
2422
- if (!existsSync2(absTranscript)) {
2452
+ const absTranscript = join15(input.vault, input.transcript);
2453
+ if (!existsSync3(absTranscript)) {
2423
2454
  return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: input.transcript }) };
2424
2455
  }
2425
2456
  const content = await readFile11(absTranscript, "utf8");
@@ -2434,8 +2465,8 @@ async function runClaim(input) {
2434
2465
  result: err("SCHEME_REJECTED", { message: "No project specified. Use --project or set project in transcript frontmatter." })
2435
2466
  };
2436
2467
  }
2437
- const projectDir = join14(input.vault, "projects", projectSlug);
2438
- if (!existsSync2(projectDir) || !statSync(projectDir).isDirectory()) {
2468
+ const projectDir = join15(input.vault, "projects", projectSlug);
2469
+ if (!existsSync3(projectDir) || !statSync(projectDir).isDirectory()) {
2439
2470
  return {
2440
2471
  exitCode: ExitCode.PROJECT_NOT_FOUND,
2441
2472
  result: err("PROJECT_NOT_FOUND", { project: projectSlug })
@@ -2451,10 +2482,10 @@ async function runClaim(input) {
2451
2482
  }
2452
2483
  const workSlug = input.slug || extractSlugFromFilename(filename);
2453
2484
  const dirName = `${date}-${workSlug}`;
2454
- const workDir = join14(projectDir, "work", dirName);
2485
+ const workDir = join15(projectDir, "work", dirName);
2455
2486
  const relWorkDir = `projects/${projectSlug}/work/${dirName}`;
2456
2487
  const relSpecPath = `${relWorkDir}/spec.md`;
2457
- if (existsSync2(workDir)) {
2488
+ if (existsSync3(workDir)) {
2458
2489
  return {
2459
2490
  exitCode: ExitCode.OK,
2460
2491
  result: ok({
@@ -2480,7 +2511,7 @@ async function runClaim(input) {
2480
2511
  `Claimed from ${input.transcript}`,
2481
2512
  ""
2482
2513
  ];
2483
- await writeFile6(join14(workDir, "spec.md"), specLines.join("\n"), "utf8");
2514
+ await writeFile6(join15(workDir, "spec.md"), specLines.join("\n"), "utf8");
2484
2515
  appendLastOp(input.vault, {
2485
2516
  operation: "claim",
2486
2517
  summary: `claimed ${input.transcript} \u2192 ${relWorkDir}`,
@@ -2515,16 +2546,16 @@ async function runPagesize(input) {
2515
2546
  }
2516
2547
 
2517
2548
  // src/commands/log-rotate.ts
2518
- import { readFile as readFile12, rename as rename3, writeFile as writeFile7, stat as stat5 } from "fs/promises";
2519
- import { join as join15 } from "path";
2549
+ import { readFile as readFile12, rename as rename3, writeFile as writeFile7, stat as stat6 } from "fs/promises";
2550
+ import { join as join16 } from "path";
2520
2551
  var ENTRY_RE = /^## \[(\d{4})-\d{2}-\d{2}\]/gm;
2521
2552
  async function runLogRotate(input) {
2522
2553
  try {
2523
- await stat5(join15(input.vault, "SCHEMA.md"));
2554
+ await stat6(join16(input.vault, "SCHEMA.md"));
2524
2555
  } catch {
2525
2556
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { vault: input.vault }) };
2526
2557
  }
2527
- const logPath = join15(input.vault, "log.md");
2558
+ const logPath = join16(input.vault, "log.md");
2528
2559
  let logText;
2529
2560
  try {
2530
2561
  logText = await readFile12(logPath, "utf8");
@@ -2544,7 +2575,7 @@ async function runLogRotate(input) {
2544
2575
  }
2545
2576
  const newestYear = matches[matches.length - 1][1];
2546
2577
  const rotatedName = `log-${newestYear}.md`;
2547
- const rotatedPath = join15(input.vault, rotatedName);
2578
+ const rotatedPath = join16(input.vault, rotatedName);
2548
2579
  try {
2549
2580
  await rename3(logPath, rotatedPath);
2550
2581
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -2570,14 +2601,14 @@ Chronological action log. Newest entries last. Skill writes append entries; lint
2570
2601
  }
2571
2602
 
2572
2603
  // src/commands/log-append.ts
2573
- import { readFile as readFile13, rename as rename4, writeFile as writeFile8, stat as stat6 } from "fs/promises";
2574
- import { join as join17 } from "path";
2604
+ import { readFile as readFile13, rename as rename4, writeFile as writeFile8, stat as stat7 } from "fs/promises";
2605
+ import { join as join18 } from "path";
2575
2606
 
2576
2607
  // src/utils/log-lock.ts
2577
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, statSync as statSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
2578
- import { join as join16 } from "path";
2608
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, statSync as statSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
2609
+ import { join as join17 } from "path";
2579
2610
  function logLockPath(vault) {
2580
- return join16(vault, ".skillwiki", "log-append.lock");
2611
+ return join17(vault, ".skillwiki", "log-append.lock");
2581
2612
  }
2582
2613
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
2583
2614
  async function acquireLogLock(vault, opts = {}) {
@@ -2585,8 +2616,8 @@ async function acquireLogLock(vault, opts = {}) {
2585
2616
  const pollMs = opts.pollMs ?? 50;
2586
2617
  const staleMs = opts.staleMs ?? 1e4;
2587
2618
  const path = logLockPath(vault);
2588
- const dir = join16(vault, ".skillwiki");
2589
- if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
2619
+ const dir = join17(vault, ".skillwiki");
2620
+ if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
2590
2621
  const deadline = Date.now() + retryMs;
2591
2622
  const content = JSON.stringify({ pid: process.pid, acquired: (/* @__PURE__ */ new Date()).toISOString() }) + "\n";
2592
2623
  for (; ; ) {
@@ -2621,7 +2652,7 @@ function releaseLogLock(vault) {
2621
2652
  var ENTRY_RE2 = /^## \[(\d{4})-\d{2}-\d{2}\]/gm;
2622
2653
  async function runLogAppend(input) {
2623
2654
  try {
2624
- await stat6(join17(input.vault, "SCHEMA.md"));
2655
+ await stat7(join18(input.vault, "SCHEMA.md"));
2625
2656
  } catch {
2626
2657
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { vault: input.vault }) };
2627
2658
  }
@@ -2633,7 +2664,7 @@ async function runLogAppend(input) {
2633
2664
  if (!acquired.ok) {
2634
2665
  return { exitCode: ExitCode.LOG_APPEND_LOCK_HELD, result: err("LOG_APPEND_LOCK_HELD", { vault: input.vault }) };
2635
2666
  }
2636
- const logPath = join17(input.vault, "log.md");
2667
+ const logPath = join18(input.vault, "log.md");
2637
2668
  try {
2638
2669
  let logText;
2639
2670
  try {
@@ -2671,9 +2702,9 @@ ${content}
2671
2702
  }
2672
2703
 
2673
2704
  // src/commands/lint.ts
2674
- import { existsSync as existsSync5 } from "fs";
2705
+ import { existsSync as existsSync6 } from "fs";
2675
2706
  import { readFile as readFile17 } from "fs/promises";
2676
- import { join as join22 } from "path";
2707
+ import { join as join23 } from "path";
2677
2708
 
2678
2709
  // src/commands/sparse-community.ts
2679
2710
  async function runSparseCommunity(input) {
@@ -2709,12 +2740,12 @@ async function runTopicMapCheck(input) {
2709
2740
 
2710
2741
  // src/commands/index-link-format.ts
2711
2742
  import { readFile as readFile14 } from "fs/promises";
2712
- import { join as join18 } from "path";
2743
+ import { join as join19 } from "path";
2713
2744
  var MD_LINK_RE = /\[[^\[\]]+\]\([^)]+\.md\)/;
2714
2745
  async function runIndexLinkFormat(input) {
2715
2746
  let text = "";
2716
2747
  try {
2717
- text = await readFile14(join18(input.vault, "index.md"), "utf8");
2748
+ text = await readFile14(join19(input.vault, "index.md"), "utf8");
2718
2749
  } catch {
2719
2750
  }
2720
2751
  const markdown_links = [];
@@ -2728,7 +2759,7 @@ ${markdown_links.map((l) => ` line ${l.line}: ${l.text}`).join("\n")}`;
2728
2759
 
2729
2760
  // src/commands/dedup.ts
2730
2761
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, unlinkSync as unlinkSync3 } from "fs";
2731
- import { join as join19 } from "path";
2762
+ import { join as join20 } from "path";
2732
2763
  async function runDedup(input) {
2733
2764
  const scan = await scanVault(input.vault);
2734
2765
  if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
@@ -2756,7 +2787,7 @@ async function runDedup(input) {
2756
2787
  }
2757
2788
  }
2758
2789
  for (const page of scan.data.typedKnowledge) {
2759
- const text = readFileSync3(join19(input.vault, page.relPath), "utf-8");
2790
+ const text = readFileSync3(join20(input.vault, page.relPath), "utf-8");
2760
2791
  let updated = text;
2761
2792
  let changed = false;
2762
2793
  for (const [oldPath, newPath] of replacements) {
@@ -2774,12 +2805,12 @@ async function runDedup(input) {
2774
2805
  }
2775
2806
  }
2776
2807
  if (changed) {
2777
- writeFileSync3(join19(input.vault, page.relPath), updated);
2808
+ writeFileSync3(join20(input.vault, page.relPath), updated);
2778
2809
  rewired.push(page.relPath);
2779
2810
  }
2780
2811
  }
2781
2812
  for (const [oldPath] of replacements) {
2782
- const fullPath = join19(input.vault, oldPath);
2813
+ const fullPath = join20(input.vault, oldPath);
2783
2814
  try {
2784
2815
  unlinkSync3(fullPath);
2785
2816
  removed.push(oldPath);
@@ -2816,7 +2847,7 @@ async function runDedup(input) {
2816
2847
  // src/utils/safe-write.ts
2817
2848
  import { open, readFile as readFile15, rename as rename5, unlink as unlink2, writeFile as writeFile9 } from "fs/promises";
2818
2849
  import { randomBytes } from "crypto";
2819
- import { dirname as dirname7, basename, join as join20 } from "path";
2850
+ import { dirname as dirname7, basename, join as join21 } from "path";
2820
2851
  var DEFAULT_MIN_BODY_RATIO = 0.5;
2821
2852
  var DEFAULT_MIN_OLD_BODY_BYTES = 200;
2822
2853
  function bodyBytes(text) {
@@ -2865,7 +2896,7 @@ async function safeWritePage(absPath, newContent, opts = {}) {
2865
2896
  }
2866
2897
  const dir = dirname7(absPath);
2867
2898
  const tmpName = `.${basename(absPath)}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
2868
- const tmpPath = join20(dir, tmpName);
2899
+ const tmpPath = join21(dir, tmpName);
2869
2900
  try {
2870
2901
  const handle = await open(tmpPath, "w");
2871
2902
  try {
@@ -2929,9 +2960,9 @@ async function runRawBodyDedup(vault) {
2929
2960
  }
2930
2961
 
2931
2962
  // src/commands/path-too-long.ts
2932
- import { existsSync as existsSync4 } from "fs";
2963
+ import { existsSync as existsSync5 } from "fs";
2933
2964
  import { mkdir as mkdir8, readFile as readFile16, rename as rename6, unlink as unlink3 } from "fs/promises";
2934
- import { dirname as dirname8, join as join21, posix, resolve as resolve4 } from "path";
2965
+ import { dirname as dirname8, join as join22, posix, resolve as resolve4 } from "path";
2935
2966
  var MAX_PATH_LENGTH = 240;
2936
2967
  var WINDOWS_ABSOLUTE_PATH_LIMIT = 259;
2937
2968
  async function runPathTooLong(input) {
@@ -2964,10 +2995,10 @@ async function fixPathTooLong(input) {
2964
2995
  }
2965
2996
  try {
2966
2997
  if (target.mode === "dedupe") {
2967
- await unlink3(join21(input.vault, violation.relPath));
2998
+ await unlink3(join22(input.vault, violation.relPath));
2968
2999
  } else {
2969
- await mkdir8(dirname8(join21(input.vault, target.relPath)), { recursive: true });
2970
- await rename6(join21(input.vault, violation.relPath), join21(input.vault, target.relPath));
3000
+ await mkdir8(dirname8(join22(input.vault, target.relPath)), { recursive: true });
3001
+ await rename6(join22(input.vault, violation.relPath), join22(input.vault, target.relPath));
2971
3002
  }
2972
3003
  fixed.push({ from: violation.relPath, to: target.relPath });
2973
3004
  } catch {
@@ -3044,9 +3075,9 @@ function truncateFilename(relPath, maxLength = MAX_PATH_LENGTH) {
3044
3075
  async function resolveFixTarget(vault, original, preferred, maxLength) {
3045
3076
  for (const candidate of candidateRelPaths(preferred, maxLength)) {
3046
3077
  if (candidate === original || candidate.length > maxLength) continue;
3047
- const candidatePath = join21(vault, candidate);
3048
- if (!existsSync4(candidatePath)) return { relPath: candidate, mode: "rename" };
3049
- if (await hasSameContent(join21(vault, original), candidatePath)) {
3078
+ const candidatePath = join22(vault, candidate);
3079
+ if (!existsSync5(candidatePath)) return { relPath: candidate, mode: "rename" };
3080
+ if (await hasSameContent(join22(vault, original), candidatePath)) {
3050
3081
  return { relPath: candidate, mode: "dedupe" };
3051
3082
  }
3052
3083
  }
@@ -3543,7 +3574,7 @@ async function runLint(input) {
3543
3574
  const noOverview = [];
3544
3575
  const fmWikilinkFlags = [];
3545
3576
  const wikilinkCitationFlags = [];
3546
- const brokenSourceFlags = [];
3577
+ const brokenSourceFlags = /* @__PURE__ */ new Set();
3547
3578
  const missingTldrFlags = [];
3548
3579
  const missingDiagramFlags = [];
3549
3580
  for (const page of scan.data.typedKnowledge) {
@@ -3558,11 +3589,15 @@ async function runLint(input) {
3558
3589
  if (hasWikilinkCitations(body)) wikilinkCitationFlags.push(page.relPath);
3559
3590
  const sourcesEntries = extractSourceEntries(rawFm);
3560
3591
  for (const entry of sourcesEntries) {
3561
- let rawPath = entry.replace(/^"/, "").replace(/"$/, "").replace(/^'/, "").replace(/'$/, "");
3562
- rawPath = rawPath.replace(/^\^\[/, "").replace(/\]$/, "");
3563
- if (!rawPath.startsWith("raw/") && !rawPath.startsWith("_archive/raw/")) continue;
3564
- if (!existsSync5(join22(input.vault, rawPath)) && !existsSync5(join22(input.vault, rawPath + ".md")) && !rawPath.startsWith("_archive/") && !existsSync5(join22(input.vault, "_archive", rawPath)) && !existsSync5(join22(input.vault, "_archive", rawPath + ".md"))) {
3565
- brokenSourceFlags.push(`${page.relPath}: ${rawPath}`);
3592
+ const rawPath = normalizeRawSourceTarget(entry);
3593
+ if (!rawPath) continue;
3594
+ if (!rawSourceTargetExistsSync(input.vault, rawPath)) {
3595
+ brokenSourceFlags.add(`${page.relPath}: ${rawPath}`);
3596
+ }
3597
+ }
3598
+ for (const marker of extractCitationMarkers(body)) {
3599
+ if (!rawSourceTargetExistsSync(input.vault, marker.target)) {
3600
+ brokenSourceFlags.add(`${page.relPath}: ${marker.target}`);
3566
3601
  }
3567
3602
  }
3568
3603
  const fmLinks = rawFm.match(/\[\[([^\[\]|]+)(?:\|[^\[\]]*)?\]\]/g) ?? [];
@@ -3601,7 +3636,7 @@ async function runLint(input) {
3601
3636
  if (noOverview.length > 0) buckets.missing_overview = noOverview;
3602
3637
  if (fmWikilinkFlags.length > 0) buckets.frontmatter_wikilink = fmWikilinkFlags;
3603
3638
  if (wikilinkCitationFlags.length > 0) buckets.wikilink_citation = wikilinkCitationFlags;
3604
- if (brokenSourceFlags.length > 0) buckets.broken_sources = brokenSourceFlags;
3639
+ if (brokenSourceFlags.size > 0) buckets.broken_sources = [...brokenSourceFlags];
3605
3640
  if (missingTldrFlags.length > 0) buckets.missing_tldr = missingTldrFlags;
3606
3641
  if (missingDiagramFlags.length > 0) buckets.missing_diagram = missingDiagramFlags;
3607
3642
  const workItemHealth = [];
@@ -3652,8 +3687,8 @@ async function runLint(input) {
3652
3687
  const slugMatch = String(entry).match(/\[\[([^\]]+)\]\]/);
3653
3688
  if (!slugMatch) continue;
3654
3689
  const slug = slugMatch[1];
3655
- const knowledgePath = join22(input.vault, "projects", slug, "knowledge.md");
3656
- if (!existsSync5(knowledgePath)) continue;
3690
+ const knowledgePath = join23(input.vault, "projects", slug, "knowledge.md");
3691
+ if (!existsSync6(knowledgePath)) continue;
3657
3692
  const pageRef = page.relPath.replace(/\.md$/, "");
3658
3693
  try {
3659
3694
  const knowledgeContent = await readFile17(knowledgePath, "utf8");
@@ -4098,25 +4133,25 @@ ${match.length === 0 ? "0 violations" : match.map((b) => ` ${b.kind}: ${b.items
4098
4133
  }
4099
4134
 
4100
4135
  // src/commands/health.ts
4101
- import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, writeFileSync as writeFileSync6 } from "fs";
4102
- import { dirname as dirname10, join as join28, resolve as resolve6 } from "path";
4136
+ import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, writeFileSync as writeFileSync6 } from "fs";
4137
+ import { dirname as dirname10, join as join29, resolve as resolve6 } from "path";
4103
4138
  import { platform as platform3 } from "os";
4104
4139
 
4105
4140
  // src/commands/doctor.ts
4106
- import { existsSync as existsSync10, lstatSync, readlinkSync, readdirSync as readdirSync2, statSync as statSync3, readFileSync as readFileSync7 } from "fs";
4107
- import { join as join27, resolve as resolve5 } from "path";
4141
+ import { existsSync as existsSync11, lstatSync, readlinkSync, readdirSync as readdirSync2, statSync as statSync3, readFileSync as readFileSync7 } from "fs";
4142
+ import { join as join28, resolve as resolve5 } from "path";
4108
4143
  import { execSync as execSync2 } from "child_process";
4109
4144
  import { platform as platform2 } from "os";
4110
4145
 
4111
4146
  // src/commands/config.ts
4112
4147
  import { readFile as readFile18 } from "fs/promises";
4113
- import { existsSync as existsSync6 } from "fs";
4114
- import { join as join23 } from "path";
4148
+ import { existsSync as existsSync7 } from "fs";
4149
+ import { join as join24 } from "path";
4115
4150
  function validateKey(key) {
4116
4151
  return CONFIG_KEYS.includes(key) || isValidWikiProfileKey(key);
4117
4152
  }
4118
4153
  function configPath(home) {
4119
- return join23(home, ".skillwiki", ".env");
4154
+ return join24(home, ".skillwiki", ".env");
4120
4155
  }
4121
4156
  async function runConfigGet(input) {
4122
4157
  if (!validateKey(input.key)) {
@@ -4166,15 +4201,15 @@ async function runConfigList(input) {
4166
4201
  }
4167
4202
  async function runConfigPath(input) {
4168
4203
  const filePath = configPath(input.home);
4169
- return { exitCode: ExitCode.OK, result: ok({ path: filePath, exists: existsSync6(filePath), humanHint: filePath }) };
4204
+ return { exitCode: ExitCode.OK, result: ok({ path: filePath, exists: existsSync7(filePath), humanHint: filePath }) };
4170
4205
  }
4171
4206
 
4172
4207
  // src/utils/auto-update.ts
4173
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
4174
- import { join as join24, dirname as dirname9 } from "path";
4208
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
4209
+ import { join as join25, dirname as dirname9 } from "path";
4175
4210
  import { spawn } from "child_process";
4176
4211
  function cachePath(home) {
4177
- return join24(home, ".skillwiki", CACHE_FILENAME);
4212
+ return join25(home, ".skillwiki", CACHE_FILENAME);
4178
4213
  }
4179
4214
  function readCacheRaw(home) {
4180
4215
  try {
@@ -4218,7 +4253,7 @@ function triggerAutoUpdate(home, currentVersion) {
4218
4253
  if (!isStale2) return;
4219
4254
  const distTag = distTagFromCache(home);
4220
4255
  const bgScript = new URL("../auto-update-bg.js", import.meta.url).pathname;
4221
- if (!existsSync7(bgScript)) return;
4256
+ if (!existsSync8(bgScript)) return;
4222
4257
  const child = spawn(process.execPath, [bgScript, home, currentVersion, distTag], {
4223
4258
  detached: true,
4224
4259
  stdio: "ignore"
@@ -4229,14 +4264,14 @@ function triggerAutoUpdate(home, currentVersion) {
4229
4264
  }
4230
4265
 
4231
4266
  // src/utils/plugin-registry.ts
4232
- import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync5 } from "fs";
4233
- import { join as join25 } from "path";
4234
- var REGISTRY_PATH = join25(".claude", "plugins", "installed_plugins.json");
4235
- var CODEX_CONFIG_PATH = join25(".codex", "config.toml");
4267
+ import { existsSync as existsSync9, readdirSync, readFileSync as readFileSync5 } from "fs";
4268
+ import { join as join26 } from "path";
4269
+ var REGISTRY_PATH = join26(".claude", "plugins", "installed_plugins.json");
4270
+ var CODEX_CONFIG_PATH = join26(".codex", "config.toml");
4236
4271
  var PLUGIN_KEY = "skillwiki@llm-wiki";
4237
4272
  function readInstalledPlugins(home) {
4238
4273
  try {
4239
- const raw = readFileSync5(join25(home, REGISTRY_PATH), "utf8");
4274
+ const raw = readFileSync5(join26(home, REGISTRY_PATH), "utf8");
4240
4275
  return JSON.parse(raw);
4241
4276
  } catch {
4242
4277
  return null;
@@ -4272,8 +4307,8 @@ function findPluginInstallations(home, key = PLUGIN_KEY) {
4272
4307
  function findCodexPlugin(home, key, pluginName, marketplace) {
4273
4308
  const config = readCodexPluginConfig(home, key, marketplace);
4274
4309
  if (!config?.enabled) return null;
4275
- const cacheRoot = join25(home, ".codex", "plugins", "cache", marketplace, pluginName);
4276
- if (!existsSync8(cacheRoot)) return null;
4310
+ const cacheRoot = join26(home, ".codex", "plugins", "cache", marketplace, pluginName);
4311
+ if (!existsSync9(cacheRoot)) return null;
4277
4312
  let versions;
4278
4313
  try {
4279
4314
  versions = readdirSync(cacheRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
@@ -4288,7 +4323,7 @@ function findCodexPlugin(home, key, pluginName, marketplace) {
4288
4323
  key,
4289
4324
  pluginName,
4290
4325
  marketplace,
4291
- installPath: join25(cacheRoot, version),
4326
+ installPath: join26(cacheRoot, version),
4292
4327
  version,
4293
4328
  sourceType: config.sourceType,
4294
4329
  source: config.source
@@ -4305,7 +4340,7 @@ function parsePluginKey(key) {
4305
4340
  function readCodexPluginConfig(home, key, marketplace) {
4306
4341
  let raw;
4307
4342
  try {
4308
- raw = readFileSync5(join25(home, CODEX_CONFIG_PATH), "utf8");
4343
+ raw = readFileSync5(join26(home, CODEX_CONFIG_PATH), "utf8");
4309
4344
  } catch {
4310
4345
  return null;
4311
4346
  }
@@ -4350,7 +4385,7 @@ function parseTomlScalar(rawValue) {
4350
4385
  import { execSync } from "child_process";
4351
4386
  import { platform } from "os";
4352
4387
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, unlinkSync as unlinkSync4, readFileSync as readFile19 } from "fs";
4353
- import { join as join26 } from "path";
4388
+ import { join as join27 } from "path";
4354
4389
  var OS = platform();
4355
4390
  function findRcloneMountPid() {
4356
4391
  try {
@@ -4508,7 +4543,7 @@ function detectFuseMount(vaultPath) {
4508
4543
  return null;
4509
4544
  }
4510
4545
  function writeTest(dir) {
4511
- const testFile = join26(dir, `.doctor-write-test-${process.pid}.tmp`);
4546
+ const testFile = join27(dir, `.doctor-write-test-${process.pid}.tmp`);
4512
4547
  const payload = `skillwiki doctor write test \u2014 ${Date.now()} \u2014 ${Math.random().toString(36).slice(2)}`;
4513
4548
  const start = Date.now();
4514
4549
  try {
@@ -4608,13 +4643,13 @@ function detectCliChannels(argv, home) {
4608
4643
  }
4609
4644
  const plugin = findPlugin(home);
4610
4645
  if (plugin) {
4611
- const pluginBin = join27(plugin.installPath, "bin", "skillwiki");
4612
- if (existsSync10(pluginBin)) {
4646
+ const pluginBin = join28(plugin.installPath, "bin", "skillwiki");
4647
+ if (existsSync11(pluginBin)) {
4613
4648
  channels.push({ name: "plugin", path: pluginBin, isDevLink: false });
4614
4649
  }
4615
4650
  }
4616
- const installBin = join27(home, ".claude", "skills", "bin", "skillwiki");
4617
- if (existsSync10(installBin)) {
4651
+ const installBin = join28(home, ".claude", "skills", "bin", "skillwiki");
4652
+ if (existsSync11(installBin)) {
4618
4653
  channels.push({ name: "install", path: installBin, isDevLink: false });
4619
4654
  }
4620
4655
  return channels;
@@ -4666,7 +4701,7 @@ function checkCliChannels(argv, home) {
4666
4701
  }
4667
4702
  async function checkConfigFile(home) {
4668
4703
  const cfgPath = configPath(home);
4669
- if (!existsSync10(cfgPath)) {
4704
+ if (!existsSync11(cfgPath)) {
4670
4705
  return check("warn", "config_file", "Config file exists", `${cfgPath} not found`);
4671
4706
  }
4672
4707
  try {
@@ -4681,7 +4716,7 @@ function checkWikiPathExists(resolvedPath) {
4681
4716
  if (resolvedPath === void 0) {
4682
4717
  return check("error", "wiki_path_exists", "Vault directory exists", "Cannot check \u2014 WIKI_PATH not resolved");
4683
4718
  }
4684
- if (existsSync10(resolvedPath) && statSync3(resolvedPath).isDirectory()) {
4719
+ if (existsSync11(resolvedPath) && statSync3(resolvedPath).isDirectory()) {
4685
4720
  return check("pass", "wiki_path_exists", "Vault directory exists", resolvedPath);
4686
4721
  }
4687
4722
  return check("error", "wiki_path_exists", "Vault directory exists", `${resolvedPath} does not exist or is not a directory`);
@@ -4690,13 +4725,13 @@ function checkVaultStructure(resolvedPath) {
4690
4725
  if (resolvedPath === void 0) {
4691
4726
  return check("error", "vault_structure", "Vault structure valid", "Cannot check \u2014 WIKI_PATH not resolved");
4692
4727
  }
4693
- if (!existsSync10(resolvedPath)) {
4728
+ if (!existsSync11(resolvedPath)) {
4694
4729
  return check("error", "vault_structure", "Vault structure valid", "Cannot check \u2014 vault directory does not exist");
4695
4730
  }
4696
4731
  const missing = [];
4697
- if (!existsSync10(join27(resolvedPath, "SCHEMA.md"))) missing.push("SCHEMA.md");
4732
+ if (!existsSync11(join28(resolvedPath, "SCHEMA.md"))) missing.push("SCHEMA.md");
4698
4733
  for (const dir of ["raw", "entities", "concepts", "meta"]) {
4699
- if (!existsSync10(join27(resolvedPath, dir))) missing.push(dir + "/");
4734
+ if (!existsSync11(join28(resolvedPath, dir))) missing.push(dir + "/");
4700
4735
  }
4701
4736
  if (missing.length === 0) {
4702
4737
  return check("pass", "vault_structure", "Vault structure valid", "All required files and directories present");
@@ -4704,8 +4739,8 @@ function checkVaultStructure(resolvedPath) {
4704
4739
  return check("warn", "vault_structure", "Vault structure valid", `Missing: ${missing.join(", ")} \u2014 run \`skillwiki init\` to add CodeWiki structure`);
4705
4740
  }
4706
4741
  function checkSkillsInstalled(home, cwd) {
4707
- const srcDir = cwd ? join27(cwd, "packages", "skills") : void 0;
4708
- if (srcDir && existsSync10(srcDir)) {
4742
+ const srcDir = cwd ? join28(cwd, "packages", "skills") : void 0;
4743
+ if (srcDir && existsSync11(srcDir)) {
4709
4744
  const found = findInstalledSkillMd(srcDir);
4710
4745
  if (found.length > 0) {
4711
4746
  return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (source)`);
@@ -4718,8 +4753,8 @@ function checkSkillsInstalled(home, cwd) {
4718
4753
  return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (plugin v${plugin.version})`);
4719
4754
  }
4720
4755
  }
4721
- const skillsDir = join27(home, ".claude", "skills");
4722
- if (existsSync10(skillsDir)) {
4756
+ const skillsDir = join28(home, ".claude", "skills");
4757
+ if (existsSync11(skillsDir)) {
4723
4758
  const found = findInstalledSkillMd(skillsDir);
4724
4759
  if (found.length > 0) {
4725
4760
  return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (CLI install)`);
@@ -4729,10 +4764,10 @@ function checkSkillsInstalled(home, cwd) {
4729
4764
  }
4730
4765
  function checkDuplicateSkills(home) {
4731
4766
  const plugin = findPlugin(home);
4732
- const skillsDir = join27(home, ".claude", "skills");
4767
+ const skillsDir = join28(home, ".claude", "skills");
4733
4768
  const agentSkillDirs = [
4734
- { label: "~/.codex/skills/", path: join27(home, ".codex", "skills") },
4735
- { label: "~/.agents/skills/", path: join27(home, ".agents", "skills") }
4769
+ { label: "~/.codex/skills/", path: join28(home, ".codex", "skills") },
4770
+ { label: "~/.agents/skills/", path: join28(home, ".agents", "skills") }
4736
4771
  ];
4737
4772
  if (!plugin) {
4738
4773
  return check("pass", "skills_duplicate", "Skills not duplicated", "Single install channel");
@@ -4831,8 +4866,8 @@ async function checkProfiles(home) {
4831
4866
  }
4832
4867
  async function checkProjectLocalOverride(cwd) {
4833
4868
  const dir = cwd ?? process.cwd();
4834
- const envPath = join27(dir, ".skillwiki", ".env");
4835
- if (existsSync10(envPath)) {
4869
+ const envPath = join28(dir, ".skillwiki", ".env");
4870
+ if (existsSync11(envPath)) {
4836
4871
  return check("pass", "project_local", "Project-local config", `Found: ${envPath}`);
4837
4872
  }
4838
4873
  return check("pass", "project_local", "Project-local config", "None");
@@ -4841,7 +4876,7 @@ function checkVaultGitRemote(resolvedPath) {
4841
4876
  if (resolvedPath === void 0) {
4842
4877
  return check("error", "vault_git_remote", "Vault git remote", "Cannot check \u2014 WIKI_PATH not resolved");
4843
4878
  }
4844
- if (!existsSync10(join27(resolvedPath, ".git"))) {
4879
+ if (!existsSync11(join28(resolvedPath, ".git"))) {
4845
4880
  return check("warn", "vault_git_remote", "Vault git remote", "Vault is not a git repository \u2014 sync features unavailable");
4846
4881
  }
4847
4882
  try {
@@ -4864,9 +4899,9 @@ function checkObsidianTemplates(resolvedPath) {
4864
4899
  return check("error", "obsidian_templates", "Obsidian templates", "Cannot check \u2014 WIKI_PATH not resolved");
4865
4900
  }
4866
4901
  const missing = [];
4867
- if (!existsSync10(join27(resolvedPath, "_Templates"))) missing.push("_Templates/");
4868
- if (!existsSync10(join27(resolvedPath, ".obsidian", "templates.json"))) missing.push(".obsidian/templates.json");
4869
- if (!existsSync10(join27(resolvedPath, ".obsidian", "app.json"))) missing.push(".obsidian/app.json");
4902
+ if (!existsSync11(join28(resolvedPath, "_Templates"))) missing.push("_Templates/");
4903
+ if (!existsSync11(join28(resolvedPath, ".obsidian", "templates.json"))) missing.push(".obsidian/templates.json");
4904
+ if (!existsSync11(join28(resolvedPath, ".obsidian", "app.json"))) missing.push(".obsidian/app.json");
4870
4905
  if (missing.length === 0) {
4871
4906
  return check("pass", "obsidian_templates", "Obsidian templates", "Template folder and config present");
4872
4907
  }
@@ -4876,8 +4911,8 @@ function checkDotStoreClean(resolvedPath) {
4876
4911
  if (resolvedPath === void 0) {
4877
4912
  return check("error", "dsstore_clean", "No .DS_Store in raw/", "Cannot check \u2014 WIKI_PATH not resolved");
4878
4913
  }
4879
- const rawDir = join27(resolvedPath, "raw");
4880
- if (!existsSync10(rawDir)) {
4914
+ const rawDir = join28(resolvedPath, "raw");
4915
+ if (!existsSync11(rawDir)) {
4881
4916
  return check("pass", "dsstore_clean", "No .DS_Store in raw/", "raw/ directory not found \u2014 check skipped");
4882
4917
  }
4883
4918
  const found = [];
@@ -4892,7 +4927,7 @@ function checkDotStoreClean(resolvedPath) {
4892
4927
  if (entry.name === ".DS_Store") {
4893
4928
  found.push(rel ? `${rel}/.DS_Store` : ".DS_Store");
4894
4929
  } else if (entry.isDirectory()) {
4895
- walk2(join27(dir, entry.name), rel ? `${rel}/${entry.name}` : entry.name);
4930
+ walk2(join28(dir, entry.name), rel ? `${rel}/${entry.name}` : entry.name);
4896
4931
  }
4897
4932
  }
4898
4933
  })(rawDir, "");
@@ -4905,7 +4940,7 @@ function checkSyncLastPush(resolvedPath) {
4905
4940
  if (resolvedPath === void 0) {
4906
4941
  return check("error", "sync_last_push", "Vault sync recency", "Cannot check \u2014 WIKI_PATH not resolved");
4907
4942
  }
4908
- if (!existsSync10(join27(resolvedPath, ".git"))) {
4943
+ if (!existsSync11(join28(resolvedPath, ".git"))) {
4909
4944
  return check("pass", "sync_last_push", "Vault sync recency", "No git repo \u2014 sync check skipped");
4910
4945
  }
4911
4946
  let timestamp;
@@ -4953,7 +4988,7 @@ function checkVaultGitDirty(resolvedPath) {
4953
4988
  if (resolvedPath === void 0) {
4954
4989
  return check("pass", "vault_git_dirty", "Vault git dirty state", "No vault path \u2014 check skipped");
4955
4990
  }
4956
- if (!existsSync10(join27(resolvedPath, ".git"))) {
4991
+ if (!existsSync11(join28(resolvedPath, ".git"))) {
4957
4992
  return check("pass", "vault_git_dirty", "Vault git dirty state", "No git repo \u2014 check skipped");
4958
4993
  }
4959
4994
  try {
@@ -4994,7 +5029,7 @@ function checkVaultGitComparison(resolvedPath, id, label, range, nonZeroSuffix,
4994
5029
  if (resolvedPath === void 0) {
4995
5030
  return check("pass", id, label, "No vault path \u2014 check skipped");
4996
5031
  }
4997
- if (!existsSync10(join27(resolvedPath, ".git"))) {
5032
+ if (!existsSync11(join28(resolvedPath, ".git"))) {
4998
5033
  return check("pass", id, label, "No git repo \u2014 check skipped");
4999
5034
  }
5000
5035
  if (!hasOriginMain(resolvedPath)) {
@@ -5016,11 +5051,11 @@ function checkVaultGitComparison(resolvedPath, id, label, range, nonZeroSuffix,
5016
5051
  }
5017
5052
  function pullLogPaths(home) {
5018
5053
  const paths = platform2() === "darwin" ? [
5019
- join27(home, "Library", "Logs", "wiki-pull.log"),
5020
- join27(home, ".local", "state", "vault-sync", "log", "wiki-pull.log")
5054
+ join28(home, "Library", "Logs", "wiki-pull.log"),
5055
+ join28(home, ".local", "state", "vault-sync", "log", "wiki-pull.log")
5021
5056
  ] : [
5022
- join27(home, ".local", "state", "vault-sync", "log", "wiki-pull.log"),
5023
- join27(home, "Library", "Logs", "wiki-pull.log")
5057
+ join28(home, ".local", "state", "vault-sync", "log", "wiki-pull.log"),
5058
+ join28(home, "Library", "Logs", "wiki-pull.log")
5024
5059
  ];
5025
5060
  return [...new Set(paths)];
5026
5061
  }
@@ -5032,7 +5067,7 @@ function isRecentLogLine(line, nowMs) {
5032
5067
  return nowMs - ts <= 24 * 60 * 60 * 1e3;
5033
5068
  }
5034
5069
  function checkVaultGitPullFailures(home) {
5035
- const path = pullLogPaths(home).find((p) => existsSync10(p));
5070
+ const path = pullLogPaths(home).find((p) => existsSync11(p));
5036
5071
  if (!path) {
5037
5072
  return check("pass", "vault_git_pull_failures", "Vault pull failures", "No wiki-pull.log found \u2014 check skipped");
5038
5073
  }
@@ -5060,8 +5095,8 @@ function checkS3MountPerf(resolvedPath) {
5060
5095
  return check("pass", "s3_mount_perf", "S3 mount performance", "local disk");
5061
5096
  }
5062
5097
  const mountPoint = fuse.mountPoint;
5063
- const conceptsDir = join27(resolvedPath, "concepts");
5064
- if (!existsSync10(conceptsDir)) {
5098
+ const conceptsDir = join28(resolvedPath, "concepts");
5099
+ if (!existsSync11(conceptsDir)) {
5065
5100
  return check("pass", "s3_mount_perf", "S3 mount performance", `S3 FUSE mount (${mountPoint}), no concepts/ to benchmark`);
5066
5101
  }
5067
5102
  const start = Date.now();
@@ -5243,8 +5278,8 @@ function checkWriteTest(resolvedPath) {
5243
5278
  if (!fuse) {
5244
5279
  return check("pass", "s3_write_test", "S3 write test", "local disk \u2014 check skipped");
5245
5280
  }
5246
- const conceptsDir = join27(resolvedPath, "concepts");
5247
- if (!existsSync10(conceptsDir)) {
5281
+ const conceptsDir = join28(resolvedPath, "concepts");
5282
+ if (!existsSync11(conceptsDir)) {
5248
5283
  return check("pass", "s3_write_test", "S3 write test", "no concepts/ dir to test \u2014 check skipped");
5249
5284
  }
5250
5285
  const result = writeTest(conceptsDir);
@@ -5330,7 +5365,7 @@ function checkVfsCacheHealth(resolvedPath) {
5330
5365
  }
5331
5366
  function readVaultSyncConfig(home) {
5332
5367
  try {
5333
- const content = readFileSync7(join27(home, ".skillwiki", ".env"), "utf8");
5368
+ const content = readFileSync7(join28(home, ".skillwiki", ".env"), "utf8");
5334
5369
  let installed = false;
5335
5370
  let role;
5336
5371
  for (const line of content.split(/\r?\n/)) {
@@ -5364,12 +5399,12 @@ function vaultSyncChecks(input) {
5364
5399
  ];
5365
5400
  }
5366
5401
  const isMac = os === "darwin";
5367
- const logDir = input.logDir ?? (isMac ? join27(home, "Library", "Logs") : join27(home, ".local", "state", "vault-sync", "log"));
5368
- const shareDir = input.shareDir ?? (isMac ? join27(home, "Library", "Application Support", "vault-sync", "bin") : join27(home, ".local", "share", "vault-sync", "bin"));
5369
- const filterPath = input.filterPath ?? join27(home, ".config", "rclone", "wiki-push-filters.txt");
5402
+ const logDir = input.logDir ?? (isMac ? join28(home, "Library", "Logs") : join28(home, ".local", "state", "vault-sync", "log"));
5403
+ const shareDir = input.shareDir ?? (isMac ? join28(home, "Library", "Application Support", "vault-sync", "bin") : join28(home, ".local", "share", "vault-sync", "bin"));
5404
+ const filterPath = input.filterPath ?? join28(home, ".config", "rclone", "wiki-push-filters.txt");
5370
5405
  const snapshotPath = input.snapshotScriptPath ?? "/root/.hermes/scripts/wiki-snapshot-v3.sh";
5371
- const pushScriptPath = join27(shareDir, "wiki-push.sh");
5372
- const c1 = existsSync10(pushScriptPath) ? check("pass", "vault_sync_installed", "Vault sync installed", `Found: ${pushScriptPath}`) : check("error", "vault_sync_installed", "Vault sync installed", `Script not found at ${pushScriptPath} \u2014 run vault-sync-install`);
5406
+ const pushScriptPath = join28(shareDir, "wiki-push.sh");
5407
+ const c1 = existsSync11(pushScriptPath) ? check("pass", "vault_sync_installed", "Vault sync installed", `Found: ${pushScriptPath}`) : check("error", "vault_sync_installed", "Vault sync installed", `Script not found at ${pushScriptPath} \u2014 run vault-sync-install`);
5373
5408
  let c2;
5374
5409
  try {
5375
5410
  if (isMac) {
@@ -5420,7 +5455,7 @@ function vaultSyncChecks(input) {
5420
5455
  "Scheduler check failed \u2014 run vault-sync-install"
5421
5456
  );
5422
5457
  }
5423
- const logFile = join27(logDir, "wiki-push.log");
5458
+ const logFile = join28(logDir, "wiki-push.log");
5424
5459
  let c3;
5425
5460
  try {
5426
5461
  const logContent = readFileSync7(logFile, "utf8");
@@ -5479,7 +5514,7 @@ function vaultSyncChecks(input) {
5479
5514
  }
5480
5515
  }
5481
5516
  } catch {
5482
- c3 = existsSync10(logDir) ? check(
5517
+ c3 = existsSync11(logDir) ? check(
5483
5518
  "warn",
5484
5519
  "vault_sync_last_push_age",
5485
5520
  "Vault sync last push recency",
@@ -5491,7 +5526,7 @@ function vaultSyncChecks(input) {
5491
5526
  `Log directory not found at ${logDir}`
5492
5527
  );
5493
5528
  }
5494
- const fetchLogFile = join27(logDir, "wiki-fetch.log");
5529
+ const fetchLogFile = join28(logDir, "wiki-fetch.log");
5495
5530
  let cFetch;
5496
5531
  try {
5497
5532
  const logContent = readFileSync7(fetchLogFile, "utf8");
@@ -5538,7 +5573,7 @@ function vaultSyncChecks(input) {
5538
5573
  }
5539
5574
  let c4;
5540
5575
  try {
5541
- if (!existsSync10(filterPath)) {
5576
+ if (!existsSync11(filterPath)) {
5542
5577
  c4 = check(
5543
5578
  "error",
5544
5579
  "vault_sync_filter_present",
@@ -5587,7 +5622,7 @@ function vaultSyncChecks(input) {
5587
5622
  );
5588
5623
  } else {
5589
5624
  try {
5590
- if (!existsSync10(snapshotPath)) {
5625
+ if (!existsSync11(snapshotPath)) {
5591
5626
  c5 = check(
5592
5627
  "error",
5593
5628
  "vault_sync_snapshot_guard",
@@ -5633,15 +5668,15 @@ function findSkillMd(dir) {
5633
5668
  }
5634
5669
  for (const entry of entries) {
5635
5670
  if (entry.isFile() && entry.name === "SKILL.md") {
5636
- results.push(join27(dir, entry.name));
5671
+ results.push(join28(dir, entry.name));
5637
5672
  } else if (entry.isDirectory()) {
5638
- results.push(...findSkillMd(join27(dir, entry.name)));
5673
+ results.push(...findSkillMd(join28(dir, entry.name)));
5639
5674
  }
5640
5675
  }
5641
5676
  return results;
5642
5677
  }
5643
5678
  function findInstalledSkillMd(dir) {
5644
- const directSkills = findSkillNames(dir).map((name) => join27(dir, name, "SKILL.md"));
5679
+ const directSkills = findSkillNames(dir).map((name) => join28(dir, name, "SKILL.md"));
5645
5680
  return directSkills.length > 0 ? directSkills : findSkillMd(dir);
5646
5681
  }
5647
5682
  function findSkillNames(dir) {
@@ -5653,7 +5688,7 @@ function findSkillNames(dir) {
5653
5688
  return results;
5654
5689
  }
5655
5690
  for (const entry of entries) {
5656
- if (entry.isDirectory() && existsSync10(join27(dir, entry.name, "SKILL.md"))) {
5691
+ if (entry.isDirectory() && existsSync11(join28(dir, entry.name, "SKILL.md"))) {
5657
5692
  results.push(entry.name);
5658
5693
  }
5659
5694
  }
@@ -5697,7 +5732,7 @@ async function vaultMetrics(resolvedPath) {
5697
5732
  }
5698
5733
  let logLines = 0;
5699
5734
  try {
5700
- logLines = readFileSync7(join27(resolvedPath, "log.md"), "utf8").split("\n").length;
5735
+ logLines = readFileSync7(join28(resolvedPath, "log.md"), "utf8").split("\n").length;
5701
5736
  } catch {
5702
5737
  }
5703
5738
  return [
@@ -5881,7 +5916,7 @@ function summarizeChecks(checks) {
5881
5916
  };
5882
5917
  }
5883
5918
  function classifyLog(path, id, label, okPattern) {
5884
- if (!existsSync11(path)) return { id, label, status: "warn", detail: `log file missing: ${path}` };
5919
+ if (!existsSync12(path)) return { id, label, status: "warn", detail: `log file missing: ${path}` };
5885
5920
  const lines = readFileSync8(path, "utf8").split(/\r?\n/).filter(Boolean);
5886
5921
  const last = lines[lines.length - 1] ?? "";
5887
5922
  if (!last) return { id, label, status: "warn", detail: `log file empty: ${path}` };
@@ -5900,28 +5935,28 @@ function runVaultSyncHealth(home, syncMode) {
5900
5935
  };
5901
5936
  }
5902
5937
  const isMac = platform3() === "darwin";
5903
- const shareDir = isMac ? join28(home, "Library", "Application Support", "vault-sync", "bin") : join28(home, ".local", "share", "vault-sync", "bin");
5904
- const logDir = isMac ? join28(home, "Library", "Logs") : join28(home, ".local", "state", "vault-sync", "log");
5905
- const filterPath = join28(home, ".config", "rclone", "wiki-push-filters.txt");
5938
+ const shareDir = isMac ? join29(home, "Library", "Application Support", "vault-sync", "bin") : join29(home, ".local", "share", "vault-sync", "bin");
5939
+ const logDir = isMac ? join29(home, "Library", "Logs") : join29(home, ".local", "state", "vault-sync", "log");
5940
+ const filterPath = join29(home, ".config", "rclone", "wiki-push-filters.txt");
5906
5941
  const checks = [];
5907
- const pushScript = join28(shareDir, "wiki-push.sh");
5908
- checks.push(existsSync11(pushScript) ? { id: "vault_sync_installed", label: "Vault sync installed", status: "pass", detail: `Found: ${pushScript}` } : { id: "vault_sync_installed", label: "Vault sync installed", status: "error", detail: `Script missing: ${pushScript}` });
5942
+ const pushScript = join29(shareDir, "wiki-push.sh");
5943
+ checks.push(existsSync12(pushScript) ? { id: "vault_sync_installed", label: "Vault sync installed", status: "pass", detail: `Found: ${pushScript}` } : { id: "vault_sync_installed", label: "Vault sync installed", status: "error", detail: `Script missing: ${pushScript}` });
5909
5944
  if (isMac) {
5910
- const pushPlist = join28(home, "Library", "LaunchAgents", "com.karlchow.wiki-push.plist");
5911
- const fetchPlist = join28(home, "Library", "LaunchAgents", "com.karlchow.wiki-fetch.plist");
5912
- checks.push(existsSync11(pushPlist) && existsSync11(fetchPlist) ? { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "pass", detail: "launchd unit files present (read-only mode)" } : { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "warn", detail: "launchd unit files missing (read-only mode)" });
5945
+ const pushPlist = join29(home, "Library", "LaunchAgents", "com.karlchow.wiki-push.plist");
5946
+ const fetchPlist = join29(home, "Library", "LaunchAgents", "com.karlchow.wiki-fetch.plist");
5947
+ checks.push(existsSync12(pushPlist) && existsSync12(fetchPlist) ? { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "pass", detail: "launchd unit files present (read-only mode)" } : { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "warn", detail: "launchd unit files missing (read-only mode)" });
5913
5948
  checks.push({ id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "pass", detail: "macOS host \u2014 check skipped" });
5914
5949
  } else {
5915
- const pushTimer = join28(home, ".config", "systemd", "user", "wiki-push.timer");
5916
- const fetchTimer = join28(home, ".config", "systemd", "user", "wiki-fetch.timer");
5917
- const fuseTimer = join28(home, ".config", "systemd", "user", "wiki-fuse-refresh.timer");
5918
- const fuseService = join28(home, ".config", "systemd", "user", "wiki-fuse-refresh.service");
5919
- checks.push(existsSync11(pushTimer) && existsSync11(fetchTimer) ? { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "pass", detail: "systemd timer unit files present (read-only mode)" } : { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "warn", detail: "systemd timer unit files missing (read-only mode)" });
5920
- checks.push(existsSync11(fuseTimer) && existsSync11(fuseService) ? { id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "pass", detail: "wiki-fuse-refresh unit files present (read-only mode)" } : { id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "warn", detail: "wiki-fuse-refresh unit files missing (read-only mode)" });
5921
- }
5922
- checks.push(classifyLog(join28(logDir, "wiki-push.log"), "vault_sync_last_push_age", "Vault sync last push recency", /OK push/));
5923
- checks.push(classifyLog(join28(logDir, "wiki-fetch.log"), "vault_sync_last_fetch_status", "Vault sync last fetch status", /NOTIFY|OK behind|OK/));
5924
- if (!existsSync11(filterPath)) {
5950
+ const pushTimer = join29(home, ".config", "systemd", "user", "wiki-push.timer");
5951
+ const fetchTimer = join29(home, ".config", "systemd", "user", "wiki-fetch.timer");
5952
+ const fuseTimer = join29(home, ".config", "systemd", "user", "wiki-fuse-refresh.timer");
5953
+ const fuseService = join29(home, ".config", "systemd", "user", "wiki-fuse-refresh.service");
5954
+ checks.push(existsSync12(pushTimer) && existsSync12(fetchTimer) ? { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "pass", detail: "systemd timer unit files present (read-only mode)" } : { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "warn", detail: "systemd timer unit files missing (read-only mode)" });
5955
+ checks.push(existsSync12(fuseTimer) && existsSync12(fuseService) ? { id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "pass", detail: "wiki-fuse-refresh unit files present (read-only mode)" } : { id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "warn", detail: "wiki-fuse-refresh unit files missing (read-only mode)" });
5956
+ }
5957
+ checks.push(classifyLog(join29(logDir, "wiki-push.log"), "vault_sync_last_push_age", "Vault sync last push recency", /OK push/));
5958
+ checks.push(classifyLog(join29(logDir, "wiki-fetch.log"), "vault_sync_last_fetch_status", "Vault sync last fetch status", /NOTIFY|OK behind|OK/));
5959
+ if (!existsSync12(filterPath)) {
5925
5960
  checks.push({ id: "vault_sync_filter_present", label: "Vault sync filter file present", status: "error", detail: `Filter missing: ${filterPath}` });
5926
5961
  } else {
5927
5962
  const content = readFileSync8(filterPath, "utf8");
@@ -6147,7 +6182,7 @@ async function runHealth(input) {
6147
6182
 
6148
6183
  // src/commands/archive.ts
6149
6184
  import { rename as rename7, mkdir as mkdir9, readFile as readFile20, writeFile as writeFile10 } from "fs/promises";
6150
- import { join as join29, dirname as dirname11 } from "path";
6185
+ import { join as join30, dirname as dirname11 } from "path";
6151
6186
  function countWikilinks(body, slug) {
6152
6187
  const escaped = slug.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6153
6188
  const re = new RegExp(`\\[\\[${escaped}(?:[|#][^\\]]*)?\\]\\]`, "g");
@@ -6175,7 +6210,7 @@ async function runArchive(input) {
6175
6210
  if (!relPath) return { exitCode: ExitCode.ARCHIVE_TARGET_NOT_FOUND, result: err("ARCHIVE_TARGET_NOT_FOUND", { page: input.page }) };
6176
6211
  if (relPath.startsWith("_archive/")) return { exitCode: ExitCode.ARCHIVE_ALREADY_ARCHIVED, result: err("ARCHIVE_ALREADY_ARCHIVED", { page: relPath }) };
6177
6212
  const slug = relPath.replace(/\.md$/, "").split("/").pop();
6178
- const archivePath = join29("_archive", relPath).replace(/\\/g, "/");
6213
+ const archivePath = join30("_archive", relPath).replace(/\\/g, "/");
6179
6214
  let cascade;
6180
6215
  if (input.cascade) {
6181
6216
  const wikilinkRefs = [];
@@ -6199,7 +6234,7 @@ async function runArchive(input) {
6199
6234
  const indexRefs = [];
6200
6235
  if (!isRaw) {
6201
6236
  try {
6202
- const idx = await readFile20(join29(input.vault, "index.md"), "utf8");
6237
+ const idx = await readFile20(join30(input.vault, "index.md"), "utf8");
6203
6238
  idx.split("\n").forEach((line, i) => {
6204
6239
  if (line.includes(`[[${slug}]]`)) indexRefs.push({ line: i + 1, text: line });
6205
6240
  });
@@ -6225,7 +6260,7 @@ async function runArchive(input) {
6225
6260
  }
6226
6261
  if (input.cascade && input.apply && cascade) {
6227
6262
  for (const ref of cascade.source_array_refs) {
6228
- const absPath = join29(input.vault, ref.page);
6263
+ const absPath = join30(input.vault, ref.page);
6229
6264
  const text = await readFile20(absPath, "utf8");
6230
6265
  const split = splitFrontmatter(text);
6231
6266
  if (!split.ok) continue;
@@ -6243,10 +6278,10 @@ ${fmRewritten}
6243
6278
  }
6244
6279
  }
6245
6280
  }
6246
- await mkdir9(dirname11(join29(input.vault, archivePath)), { recursive: true });
6281
+ await mkdir9(dirname11(join30(input.vault, archivePath)), { recursive: true });
6247
6282
  let indexUpdated = false;
6248
6283
  if (!isRaw) {
6249
- const indexPath = join29(input.vault, "index.md");
6284
+ const indexPath = join30(input.vault, "index.md");
6250
6285
  try {
6251
6286
  const idx = await readFile20(indexPath, "utf8");
6252
6287
  const originalLines = idx.split("\n");
@@ -6259,7 +6294,7 @@ ${fmRewritten}
6259
6294
  if (e instanceof Error && "code" in e && e.code !== "ENOENT") throw e;
6260
6295
  }
6261
6296
  }
6262
- await rename7(join29(input.vault, relPath), join29(input.vault, archivePath));
6297
+ await rename7(join30(input.vault, relPath), join30(input.vault, archivePath));
6263
6298
  appendLastOp(input.vault, {
6264
6299
  operation: input.cascade ? "archive-cascade" : "archive",
6265
6300
  summary: `moved ${relPath} to ${archivePath}${input.cascade ? ` (cascade: ${cascade?.source_array_refs.length ?? 0} source arrays updated)` : ""}`,
@@ -6668,7 +6703,7 @@ ${newBody}`;
6668
6703
 
6669
6704
  // src/commands/update.ts
6670
6705
  import { execSync as execSync3 } from "child_process";
6671
- import { join as join30 } from "path";
6706
+ import { join as join31 } from "path";
6672
6707
 
6673
6708
  // src/utils/package-info.ts
6674
6709
  import { readFileSync as readFileSync9 } from "fs";
@@ -6698,7 +6733,7 @@ function resolveGlobalSkillsRoot() {
6698
6733
  encoding: "utf8",
6699
6734
  timeout: 5e3
6700
6735
  }).trim();
6701
- return join30(globalRoot, "skillwiki", "skills");
6736
+ return join31(globalRoot, "skillwiki", "skills");
6702
6737
  } catch {
6703
6738
  return null;
6704
6739
  }
@@ -6722,7 +6757,7 @@ async function runUpdate(input) {
6722
6757
  const pkg2 = readCliPackageJson();
6723
6758
  const currentVersion = pkg2.version;
6724
6759
  const tag = normalizeDistTag(input.distTag);
6725
- const target = join30(input.home, ".claude", "skills");
6760
+ const target = join31(input.home, ".claude", "skills");
6726
6761
  let latest;
6727
6762
  try {
6728
6763
  latest = execSync3(`npm view skillwiki@${tag} version`, {
@@ -6793,15 +6828,15 @@ async function runUpdate(input) {
6793
6828
 
6794
6829
  // src/commands/self-update.ts
6795
6830
  import { execSync as execSync4 } from "child_process";
6796
- import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
6797
- import { join as join31 } from "path";
6831
+ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
6832
+ import { join as join32 } from "path";
6798
6833
  var DEFAULT_SOURCE_ROOT_SUFFIX = "/Desktop/code/llm-wiki";
6799
6834
  async function runSelfUpdate(input) {
6800
6835
  const currentVersion = readCliPackageJson().version;
6801
6836
  const sourceRoot = input.sourceRoot ?? `${input.home}${DEFAULT_SOURCE_ROOT_SUFFIX}`;
6802
6837
  const distTag = normalizeDistTag(input.distTag);
6803
- const localPkgPath = join31(sourceRoot, "packages", "cli", "package.json");
6804
- const hasLocalSource = existsSync12(localPkgPath);
6838
+ const localPkgPath = join32(sourceRoot, "packages", "cli", "package.json");
6839
+ const hasLocalSource = existsSync13(localPkgPath);
6805
6840
  if (input.check) {
6806
6841
  let availableVersion = null;
6807
6842
  let source;
@@ -6932,10 +6967,10 @@ async function runSelfUpdate(input) {
6932
6967
  }
6933
6968
 
6934
6969
  // src/commands/transcripts.ts
6935
- import { readdir as readdir5, stat as stat7, readFile as readFile21 } from "fs/promises";
6936
- import { join as join32 } from "path";
6970
+ import { readdir as readdir5, stat as stat8, readFile as readFile21 } from "fs/promises";
6971
+ import { join as join33 } from "path";
6937
6972
  async function runTranscripts(input) {
6938
- const dir = join32(input.vault, "raw", "transcripts");
6973
+ const dir = join33(input.vault, "raw", "transcripts");
6939
6974
  let entries;
6940
6975
  try {
6941
6976
  entries = await readdir5(dir, { withFileTypes: true });
@@ -6945,13 +6980,13 @@ async function runTranscripts(input) {
6945
6980
  const transcripts = [];
6946
6981
  for (const entry of entries) {
6947
6982
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
6948
- const filePath = join32(dir, entry.name);
6983
+ const filePath = join33(dir, entry.name);
6949
6984
  const content = await readFile21(filePath, "utf8");
6950
6985
  const fm = extractFrontmatter(content);
6951
6986
  if (!fm.ok) continue;
6952
6987
  const ingested = typeof fm.data.ingested === "string" ? fm.data.ingested : "";
6953
6988
  if (input.since && ingested && ingested < input.since) continue;
6954
- const s = await stat7(filePath);
6989
+ const s = await stat8(filePath);
6955
6990
  transcripts.push({
6956
6991
  file: `raw/transcripts/${entry.name}`,
6957
6992
  ingested,
@@ -6964,11 +6999,11 @@ async function runTranscripts(input) {
6964
6999
 
6965
7000
  // src/commands/project-index.ts
6966
7001
  import { readdir as readdir6, readFile as readFile22, writeFile as writeFile11, mkdir as mkdir10 } from "fs/promises";
6967
- import { join as join33, dirname as dirname12 } from "path";
7002
+ import { join as join34, dirname as dirname12 } from "path";
6968
7003
  var LAYER2_DIRS = ["entities", "concepts", "comparisons", "queries", "meta"];
6969
7004
  async function runProjectIndex(input) {
6970
7005
  const slug = input.slug;
6971
- const projectDir = join33(input.vault, "projects", slug);
7006
+ const projectDir = join34(input.vault, "projects", slug);
6972
7007
  try {
6973
7008
  await readdir6(projectDir);
6974
7009
  } catch {
@@ -6979,12 +7014,12 @@ async function runProjectIndex(input) {
6979
7014
  }
6980
7015
  const wikilinkPattern = `[[${slug}]]`;
6981
7016
  const entries = [];
6982
- const compoundDir = join33(input.vault, "projects", slug, "compound");
7017
+ const compoundDir = join34(input.vault, "projects", slug, "compound");
6983
7018
  try {
6984
7019
  const compoundFiles = await readdir6(compoundDir, { withFileTypes: true });
6985
7020
  for (const entry of compoundFiles) {
6986
7021
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
6987
- const filePath = join33(compoundDir, entry.name);
7022
+ const filePath = join34(compoundDir, entry.name);
6988
7023
  let text;
6989
7024
  try {
6990
7025
  text = await readFile22(filePath, "utf8");
@@ -7004,13 +7039,13 @@ async function runProjectIndex(input) {
7004
7039
  for (const dir of LAYER2_DIRS) {
7005
7040
  let files;
7006
7041
  try {
7007
- files = await readdir6(join33(input.vault, dir), { withFileTypes: true });
7042
+ files = await readdir6(join34(input.vault, dir), { withFileTypes: true });
7008
7043
  } catch {
7009
7044
  continue;
7010
7045
  }
7011
7046
  for (const entry of files) {
7012
7047
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
7013
- const filePath = join33(input.vault, dir, entry.name);
7048
+ const filePath = join34(input.vault, dir, entry.name);
7014
7049
  let text;
7015
7050
  try {
7016
7051
  text = await readFile22(filePath, "utf8");
@@ -7034,7 +7069,7 @@ async function runProjectIndex(input) {
7034
7069
  const tb = typeOrder[b.type] ?? 99;
7035
7070
  return ta !== tb ? ta - tb : a.title.localeCompare(b.title);
7036
7071
  });
7037
- const indexPath = join33(projectDir, "knowledge.md");
7072
+ const indexPath = join34(projectDir, "knowledge.md");
7038
7073
  let existing = false;
7039
7074
  let stale = false;
7040
7075
  try {
@@ -7108,8 +7143,8 @@ ${entries.map((e) => ` ${e.type}: [[${e.page.replace(/\.md$/, "")}]] \u2014 ${e
7108
7143
 
7109
7144
  // src/commands/compound.ts
7110
7145
  import { writeFile as writeFile12, mkdir as mkdir11, readdir as readdir7, unlink as unlink4 } from "fs/promises";
7111
- import { join as join34 } from "path";
7112
- import { existsSync as existsSync13 } from "fs";
7146
+ import { join as join35 } from "path";
7147
+ import { existsSync as existsSync14 } from "fs";
7113
7148
  import { readFile as readFile23 } from "fs/promises";
7114
7149
  var RETRO_HEADING_RE = /^## \[(\d{4}-\d{2}-\d{2})(?:\s+[^\]]+)?\] retro \| loop cycle(?: (\d+))?: (.+)$/;
7115
7150
  var FIELD_RE = {
@@ -7208,7 +7243,7 @@ function extractRetroFields(date, cycleName, block) {
7208
7243
  };
7209
7244
  }
7210
7245
  async function runCompound(input) {
7211
- const logPath = join34(input.vault, "log.md");
7246
+ const logPath = join35(input.vault, "log.md");
7212
7247
  let logText;
7213
7248
  try {
7214
7249
  logText = await readFile23(logPath, "utf8");
@@ -7218,7 +7253,7 @@ async function runCompound(input) {
7218
7253
  const entries = parseRetroEntries(logText);
7219
7254
  const promoted = [];
7220
7255
  const skipped = [];
7221
- const compoundDir = join34(input.vault, "projects", input.project, "compound");
7256
+ const compoundDir = join35(input.vault, "projects", input.project, "compound");
7222
7257
  for (const entry of entries) {
7223
7258
  const generalizeValue = entry.generalize.trim();
7224
7259
  if (!/^yes/i.test(generalizeValue)) {
@@ -7226,8 +7261,8 @@ async function runCompound(input) {
7226
7261
  continue;
7227
7262
  }
7228
7263
  const slug = slugify(entry.cycleName);
7229
- const compoundPath = join34(compoundDir, `${slug}.md`);
7230
- if (existsSync13(compoundPath)) {
7264
+ const compoundPath = join35(compoundDir, `${slug}.md`);
7265
+ if (existsSync14(compoundPath)) {
7231
7266
  skipped.push(entry.date);
7232
7267
  continue;
7233
7268
  }
@@ -7265,7 +7300,7 @@ async function runCompound(input) {
7265
7300
  ].join("\n");
7266
7301
  const content = frontmatter + "\n" + body;
7267
7302
  if (!input.dryRun) {
7268
- if (!existsSync13(compoundDir)) {
7303
+ if (!existsSync14(compoundDir)) {
7269
7304
  await mkdir11(compoundDir, { recursive: true });
7270
7305
  }
7271
7306
  await writeFile12(compoundPath, content, "utf8");
@@ -7287,16 +7322,16 @@ async function runCompound(input) {
7287
7322
  };
7288
7323
  }
7289
7324
  async function runCompoundDelete(input) {
7290
- const projectDir = join34(input.vault, "projects", input.project);
7291
- if (!existsSync13(projectDir)) {
7325
+ const projectDir = join35(input.vault, "projects", input.project);
7326
+ if (!existsSync14(projectDir)) {
7292
7327
  return {
7293
7328
  exitCode: ExitCode.PROJECT_NOT_FOUND,
7294
7329
  result: err("PROJECT_NOT_FOUND", { slug: input.project, path: projectDir })
7295
7330
  };
7296
7331
  }
7297
7332
  const entryName = input.entry.replace(/\.md$/, "");
7298
- const compoundPath = join34(projectDir, "compound", `${entryName}.md`);
7299
- if (!existsSync13(compoundPath)) {
7333
+ const compoundPath = join35(projectDir, "compound", `${entryName}.md`);
7334
+ if (!existsSync14(compoundPath)) {
7300
7335
  return {
7301
7336
  exitCode: ExitCode.FILE_NOT_FOUND,
7302
7337
  result: err("FILE_NOT_FOUND", { path: compoundPath })
@@ -7329,8 +7364,8 @@ knowledge.md regenerated`
7329
7364
  };
7330
7365
  }
7331
7366
  async function runCompoundList(input) {
7332
- const compoundDir = join34(input.vault, "projects", input.project, "compound");
7333
- if (!existsSync13(compoundDir)) {
7367
+ const compoundDir = join35(input.vault, "projects", input.project, "compound");
7368
+ if (!existsSync14(compoundDir)) {
7334
7369
  return {
7335
7370
  exitCode: ExitCode.OK,
7336
7371
  result: ok({
@@ -7360,7 +7395,7 @@ could not read compound directory`
7360
7395
  const entries = [];
7361
7396
  for (const dirent of dirents) {
7362
7397
  if (!dirent.isFile() || !dirent.name.endsWith(".md")) continue;
7363
- const filePath = join34(compoundDir, dirent.name);
7398
+ const filePath = join35(compoundDir, dirent.name);
7364
7399
  let text;
7365
7400
  try {
7366
7401
  text = await readFile23(filePath, "utf8");
@@ -7393,8 +7428,8 @@ no compound entries found`;
7393
7428
 
7394
7429
  // src/commands/observe.ts
7395
7430
  import { mkdir as mkdir12, writeFile as writeFile13 } from "fs/promises";
7396
- import { existsSync as existsSync14, statSync as statSync4 } from "fs";
7397
- import { join as join35 } from "path";
7431
+ import { existsSync as existsSync15, statSync as statSync4 } from "fs";
7432
+ import { join as join36 } from "path";
7398
7433
  import { createHash as createHash4 } from "crypto";
7399
7434
  var ALLOWED_KINDS = /* @__PURE__ */ new Set(["note", "bug", "task", "idea", "session-log"]);
7400
7435
  function slugify2(text) {
@@ -7417,13 +7452,13 @@ async function runObserve(input) {
7417
7452
  result: err("SCHEME_REJECTED", { message: "Text must not be empty" })
7418
7453
  };
7419
7454
  }
7420
- if (!existsSync14(input.vault) || !statSync4(input.vault).isDirectory()) {
7455
+ if (!existsSync15(input.vault) || !statSync4(input.vault).isDirectory()) {
7421
7456
  return {
7422
7457
  exitCode: ExitCode.VAULT_PATH_INVALID,
7423
7458
  result: err("VAULT_PATH_INVALID", { path: input.vault })
7424
7459
  };
7425
7460
  }
7426
- const transcriptsDir = join35(input.vault, "raw", "transcripts");
7461
+ const transcriptsDir = join36(input.vault, "raw", "transcripts");
7427
7462
  try {
7428
7463
  await mkdir12(transcriptsDir, { recursive: true });
7429
7464
  } catch {
@@ -7435,7 +7470,7 @@ async function runObserve(input) {
7435
7470
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
7436
7471
  const slug = slugify2(input.text);
7437
7472
  const fileName = `${today}-observation-${slug}.md`;
7438
- const filePath = join35(transcriptsDir, fileName);
7473
+ const filePath = join36(transcriptsDir, fileName);
7439
7474
  const body = `
7440
7475
  ${input.text.trim()}
7441
7476
  `;
@@ -7476,7 +7511,7 @@ ${input.text.trim()}
7476
7511
 
7477
7512
  // src/commands/session-brief.ts
7478
7513
  import { mkdir as mkdir13, readFile as readFile24, writeFile as writeFile14 } from "fs/promises";
7479
- import { join as join36, relative as relative3, sep as sep3 } from "path";
7514
+ import { join as join37, relative as relative3, sep as sep3 } from "path";
7480
7515
  var MAX_WORDS = 900;
7481
7516
  async function runSessionBrief(input) {
7482
7517
  const scan = await scanVault(input.vault);
@@ -7554,7 +7589,7 @@ async function resolveProject(input) {
7554
7589
  const envProject = input.env?.SKILLWIKI_PROJECT;
7555
7590
  if (envProject) return envProject;
7556
7591
  const cwd = input.cwd ?? process.cwd();
7557
- const projectDotenv = await readProjectSlug(join36(cwd, ".skillwiki", ".env"));
7592
+ const projectDotenv = await readProjectSlug(join37(cwd, ".skillwiki", ".env"));
7558
7593
  if (projectDotenv) return projectDotenv;
7559
7594
  const inferred = inferProjectFromPath(input.vault, cwd);
7560
7595
  if (inferred) return inferred;
@@ -7688,7 +7723,7 @@ function appendTextSection(lines, title, items, empty) {
7688
7723
  lines.push("");
7689
7724
  }
7690
7725
  async function loadHealthWarnings(vault) {
7691
- const text = await readIfExists2(join36(vault, ".skillwiki", "health.json"));
7726
+ const text = await readIfExists2(join37(vault, ".skillwiki", "health.json"));
7692
7727
  if (!text) return [];
7693
7728
  try {
7694
7729
  const parsed = JSON.parse(text);
@@ -7701,11 +7736,11 @@ async function loadHealthWarnings(vault) {
7701
7736
  }
7702
7737
  }
7703
7738
  async function writeBriefArtifacts(vault, input) {
7704
- const metaPath = join36(vault, "meta", "latest-session-brief.md");
7705
- const cacheMdPath = join36(vault, ".skillwiki", "session-brief.md");
7706
- const cacheJsonPath = join36(vault, ".skillwiki", "session-brief.json");
7707
- await mkdir13(join36(vault, "meta"), { recursive: true });
7708
- await mkdir13(join36(vault, ".skillwiki"), { recursive: true });
7739
+ const metaPath = join37(vault, "meta", "latest-session-brief.md");
7740
+ const cacheMdPath = join37(vault, ".skillwiki", "session-brief.md");
7741
+ const cacheJsonPath = join37(vault, ".skillwiki", "session-brief.json");
7742
+ await mkdir13(join37(vault, "meta"), { recursive: true });
7743
+ await mkdir13(join37(vault, ".skillwiki"), { recursive: true });
7709
7744
  const committed = renderCommittedBrief(input);
7710
7745
  const previousComparable = comparableBrief(await readIfExists2(metaPath));
7711
7746
  const nextComparable = comparableBrief(committed);
@@ -7765,7 +7800,7 @@ function renderCommittedBrief(input) {
7765
7800
  ].filter((line) => line !== "").join("\n");
7766
7801
  }
7767
7802
  async function ensureIndexEntry(vault) {
7768
- const indexPath = join36(vault, "index.md");
7803
+ const indexPath = join37(vault, "index.md");
7769
7804
  let text = await readIfExists2(indexPath);
7770
7805
  if (!text) return false;
7771
7806
  if (text.includes("[[meta/latest-session-brief]]")) return false;
@@ -7784,7 +7819,7 @@ async function ensureIndexEntry(vault) {
7784
7819
  return true;
7785
7820
  }
7786
7821
  async function appendMaterialLog(vault, today) {
7787
- const logPath = join36(vault, "log.md");
7822
+ const logPath = join37(vault, "log.md");
7788
7823
  const text = await readIfExists2(logPath);
7789
7824
  if (!text) return false;
7790
7825
  const entry = `
@@ -7837,7 +7872,7 @@ function dateFromPath(path) {
7837
7872
 
7838
7873
  // src/commands/ingest.ts
7839
7874
  import { readFile as readFile25, writeFile as writeFile15, mkdir as mkdir14 } from "fs/promises";
7840
- import { join as join37 } from "path";
7875
+ import { join as join38 } from "path";
7841
7876
  import { createHash as createHash5 } from "crypto";
7842
7877
  var ALLOWED_TYPES = /* @__PURE__ */ new Set(["entity", "concept", "comparison", "query"]);
7843
7878
  var TYPE_DIR = {
@@ -8011,8 +8046,8 @@ async function runIngest(input) {
8011
8046
  const rawRelPath = `raw/articles/${slug}.md`;
8012
8047
  const typedDir = TYPE_DIR[input.type] ?? `${input.type}s`;
8013
8048
  const typedRelPath = `${typedDir}/${slug}.md`;
8014
- const rawAbsPath = join37(input.vault, rawRelPath);
8015
- const typedAbsPath = join37(input.vault, typedRelPath);
8049
+ const rawAbsPath = join38(input.vault, rawRelPath);
8050
+ const typedAbsPath = join38(input.vault, typedRelPath);
8016
8051
  const identity = assessSourceIdentity({
8017
8052
  rawPath: rawRelPath,
8018
8053
  sourceUrl: sourceUrl ?? void 0,
@@ -8094,7 +8129,7 @@ async function runIngest(input) {
8094
8129
  };
8095
8130
  }
8096
8131
  try {
8097
- await mkdir14(join37(input.vault, "raw", "articles"), { recursive: true });
8132
+ await mkdir14(join38(input.vault, "raw", "articles"), { recursive: true });
8098
8133
  await writeFile15(rawAbsPath, rawContent, "utf8");
8099
8134
  } catch (e) {
8100
8135
  return {
@@ -8103,7 +8138,7 @@ async function runIngest(input) {
8103
8138
  };
8104
8139
  }
8105
8140
  try {
8106
- await mkdir14(join37(input.vault, typedDir), { recursive: true });
8141
+ await mkdir14(join38(input.vault, typedDir), { recursive: true });
8107
8142
  await writeFile15(typedAbsPath, typedContent, "utf8");
8108
8143
  } catch (e) {
8109
8144
  return {
@@ -8282,12 +8317,12 @@ ${body}`;
8282
8317
  }
8283
8318
 
8284
8319
  // src/commands/sync.ts
8285
- import { existsSync as existsSync16 } from "fs";
8286
- import { join as join39 } from "path";
8320
+ import { existsSync as existsSync17 } from "fs";
8321
+ import { join as join40 } from "path";
8287
8322
 
8288
8323
  // src/utils/sync-lock.ts
8289
- import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync11, renameSync as renameSync2, unlinkSync as unlinkSync5, writeFileSync as writeFileSync7 } from "fs";
8290
- import { join as join38 } from "path";
8324
+ import { existsSync as existsSync16, mkdirSync as mkdirSync5, readFileSync as readFileSync11, renameSync as renameSync2, unlinkSync as unlinkSync5, writeFileSync as writeFileSync7 } from "fs";
8325
+ import { join as join39 } from "path";
8291
8326
  import { createHash as createHash6 } from "crypto";
8292
8327
  function getSessionId() {
8293
8328
  if (process.env.CLAUDE_SESSION_ID) return process.env.CLAUDE_SESSION_ID;
@@ -8295,11 +8330,11 @@ function getSessionId() {
8295
8330
  return process.pid.toString();
8296
8331
  }
8297
8332
  function lockPath(vault) {
8298
- return join38(vault, ".skillwiki", "sync.lock");
8333
+ return join39(vault, ".skillwiki", "sync.lock");
8299
8334
  }
8300
8335
  function readLock(vault) {
8301
8336
  const path = lockPath(vault);
8302
- if (!existsSync15(path)) return null;
8337
+ if (!existsSync16(path)) return null;
8303
8338
  try {
8304
8339
  const raw = readFileSync11(path, "utf8");
8305
8340
  return JSON.parse(raw);
@@ -8314,8 +8349,8 @@ function isStale(lock, now) {
8314
8349
  }
8315
8350
  function acquireLock(vault, opts = {}) {
8316
8351
  const path = lockPath(vault);
8317
- const dir = join38(vault, ".skillwiki");
8318
- if (!existsSync15(dir)) {
8352
+ const dir = join39(vault, ".skillwiki");
8353
+ if (!existsSync16(dir)) {
8319
8354
  mkdirSync5(dir, { recursive: true });
8320
8355
  }
8321
8356
  const sessionId = opts.sessionId ?? getSessionId();
@@ -8360,7 +8395,7 @@ function writeLockedFile(path, lock) {
8360
8395
  }
8361
8396
  function releaseLock(vault, opts = {}) {
8362
8397
  const path = lockPath(vault);
8363
- if (!existsSync15(path)) {
8398
+ if (!existsSync16(path)) {
8364
8399
  return { released: false };
8365
8400
  }
8366
8401
  const sessionId = opts.sessionId ?? getSessionId();
@@ -8389,7 +8424,7 @@ function releaseLock(vault, opts = {}) {
8389
8424
  function runSyncStatus(input) {
8390
8425
  const vault = input.vault;
8391
8426
  const includeStashes = input.includeStashes ?? false;
8392
- if (!existsSync16(join39(vault, ".git"))) {
8427
+ if (!existsSync17(join40(vault, ".git"))) {
8393
8428
  return {
8394
8429
  exitCode: ExitCode.VAULT_PATH_INVALID,
8395
8430
  result: ok({
@@ -8467,7 +8502,7 @@ function runSyncStatus(input) {
8467
8502
  }
8468
8503
  async function runSyncPush(input) {
8469
8504
  const vault = input.vault;
8470
- if (!existsSync16(join39(vault, ".git"))) {
8505
+ if (!existsSync17(join40(vault, ".git"))) {
8471
8506
  return {
8472
8507
  exitCode: ExitCode.VAULT_PATH_INVALID,
8473
8508
  result: err("NOT_A_GIT_REPO", { path: vault })
@@ -8590,7 +8625,7 @@ function enableGitLongPathsOnWindows(vault) {
8590
8625
  }
8591
8626
  async function runSyncPull(input) {
8592
8627
  const vault = input.vault;
8593
- if (!existsSync16(join39(vault, ".git"))) {
8628
+ if (!existsSync17(join40(vault, ".git"))) {
8594
8629
  return {
8595
8630
  exitCode: ExitCode.VAULT_PATH_INVALID,
8596
8631
  result: err("NOT_A_GIT_REPO", { path: vault })
@@ -8762,7 +8797,7 @@ function runSyncPeers(input) {
8762
8797
  }
8763
8798
  function runSyncLock(input) {
8764
8799
  const vault = input.vault;
8765
- if (!existsSync16(vault)) {
8800
+ if (!existsSync17(vault)) {
8766
8801
  return {
8767
8802
  exitCode: ExitCode.VAULT_PATH_INVALID,
8768
8803
  result: err("VAULT_PATH_INVALID", { path: vault })
@@ -8797,7 +8832,7 @@ function runSyncLock(input) {
8797
8832
  }
8798
8833
  function runSyncUnlock(input) {
8799
8834
  const vault = input.vault;
8800
- if (!existsSync16(vault)) {
8835
+ if (!existsSync17(vault)) {
8801
8836
  return {
8802
8837
  exitCode: ExitCode.VAULT_PATH_INVALID,
8803
8838
  result: err("VAULT_PATH_INVALID", { path: vault })
@@ -8831,7 +8866,7 @@ function runSyncUnlock(input) {
8831
8866
 
8832
8867
  // src/commands/backup.ts
8833
8868
  import { statSync as statSync5, readdirSync as readdirSync3, readFileSync as readFileSync12, mkdirSync as mkdirSync6, writeFileSync as writeFileSync8 } from "fs";
8834
- import { join as join40, relative as relative4, dirname as dirname13 } from "path";
8869
+ import { join as join41, relative as relative4, dirname as dirname13 } from "path";
8835
8870
  import { PutObjectCommand, HeadObjectCommand, ListObjectsV2Command, GetObjectCommand, DeleteObjectsCommand } from "@aws-sdk/client-s3";
8836
8871
 
8837
8872
  // src/utils/s3-client.ts
@@ -8855,7 +8890,7 @@ var SKIP_DIRS2 = /* @__PURE__ */ new Set([".git", ".obsidian", "_archive", "node
8855
8890
  function* walkMarkdown(dir, base) {
8856
8891
  for (const entry of readdirSync3(dir, { withFileTypes: true })) {
8857
8892
  if (SKIP_DIRS2.has(entry.name)) continue;
8858
- const full = join40(dir, entry.name);
8893
+ const full = join41(dir, entry.name);
8859
8894
  if (entry.isDirectory()) {
8860
8895
  yield* walkMarkdown(full, base);
8861
8896
  } else if (entry.name.endsWith(".md")) {
@@ -8878,7 +8913,7 @@ async function runBackupSync(input) {
8878
8913
  let failed = 0;
8879
8914
  const files = [...walkMarkdown(input.vault, input.vault)];
8880
8915
  for (const relPath of files) {
8881
- const absPath = join40(input.vault, relPath);
8916
+ const absPath = join41(input.vault, relPath);
8882
8917
  const localStat = statSync5(absPath);
8883
8918
  let needsUpload = true;
8884
8919
  try {
@@ -8954,7 +8989,7 @@ async function runBackupRestore(input) {
8954
8989
  const objects = list.Contents ?? [];
8955
8990
  for (const obj of objects) {
8956
8991
  if (!obj.Key) continue;
8957
- const localPath = join40(target, obj.Key);
8992
+ const localPath = join41(target, obj.Key);
8958
8993
  try {
8959
8994
  const localStat = statSync5(localPath);
8960
8995
  if (obj.LastModified && localStat.mtime > obj.LastModified) {
@@ -9000,11 +9035,11 @@ async function runBackupRestore(input) {
9000
9035
  }
9001
9036
 
9002
9037
  // src/commands/status.ts
9003
- import { existsSync as existsSync17, statSync as statSync6 } from "fs";
9038
+ import { existsSync as existsSync18, statSync as statSync6 } from "fs";
9004
9039
  import { readFile as readFile26 } from "fs/promises";
9005
- import { join as join41 } from "path";
9040
+ import { join as join42 } from "path";
9006
9041
  async function runStatus(input) {
9007
- if (!existsSync17(input.vault)) {
9042
+ if (!existsSync18(input.vault)) {
9008
9043
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { vault: input.vault }) };
9009
9044
  }
9010
9045
  const scan = await scanVault(input.vault);
@@ -9029,7 +9064,7 @@ async function runStatus(input) {
9029
9064
  const compound = scan.data.compound.length;
9030
9065
  let schemaVersion = "v1";
9031
9066
  try {
9032
- const schemaContent = await readFile26(join41(input.vault, "SCHEMA.md"), "utf8");
9067
+ const schemaContent = await readFile26(join42(input.vault, "SCHEMA.md"), "utf8");
9033
9068
  const versionMatch = schemaContent.match(/version:\s*["']?([^"'\s\n]+)/i);
9034
9069
  if (versionMatch) schemaVersion = versionMatch[1];
9035
9070
  } catch {
@@ -9089,8 +9124,8 @@ async function runStatus(input) {
9089
9124
  }
9090
9125
 
9091
9126
  // src/commands/seed.ts
9092
- import { mkdir as mkdir15, writeFile as writeFile16, stat as stat8 } from "fs/promises";
9093
- import { join as join42 } from "path";
9127
+ import { mkdir as mkdir15, writeFile as writeFile16, stat as stat9 } from "fs/promises";
9128
+ import { join as join43 } from "path";
9094
9129
  var TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
9095
9130
  var EXAMPLE_PAGES = {
9096
9131
  "entities/example-project.md": `---
@@ -9159,29 +9194,29 @@ Real sources are immutable after ingestion \u2014 never edit them.
9159
9194
  `;
9160
9195
  async function runSeed(input) {
9161
9196
  try {
9162
- await stat8(join42(input.vault, "SCHEMA.md"));
9197
+ await stat9(join43(input.vault, "SCHEMA.md"));
9163
9198
  } catch {
9164
9199
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { root: input.vault, reason: "SCHEMA.md missing \u2014 run `skillwiki init` first" }) };
9165
9200
  }
9166
9201
  const created = [];
9167
9202
  const skipped = [];
9168
9203
  for (const [relPath, content] of Object.entries(EXAMPLE_PAGES)) {
9169
- const absPath = join42(input.vault, relPath);
9204
+ const absPath = join43(input.vault, relPath);
9170
9205
  try {
9171
- await stat8(absPath);
9206
+ await stat9(absPath);
9172
9207
  skipped.push(relPath);
9173
9208
  } catch {
9174
- await mkdir15(join42(absPath, ".."), { recursive: true });
9209
+ await mkdir15(join43(absPath, ".."), { recursive: true });
9175
9210
  await writeFile16(absPath, content, "utf8");
9176
9211
  created.push(relPath);
9177
9212
  }
9178
9213
  }
9179
- const rawPath = join42(input.vault, "raw", "articles", "example-source.md");
9214
+ const rawPath = join43(input.vault, "raw", "articles", "example-source.md");
9180
9215
  try {
9181
- await stat8(rawPath);
9216
+ await stat9(rawPath);
9182
9217
  skipped.push("raw/articles/example-source.md");
9183
9218
  } catch {
9184
- await mkdir15(join42(rawPath, ".."), { recursive: true });
9219
+ await mkdir15(join43(rawPath, ".."), { recursive: true });
9185
9220
  await writeFile16(rawPath, EXAMPLE_RAW, "utf8");
9186
9221
  created.push("raw/articles/example-source.md");
9187
9222
  }
@@ -9205,8 +9240,8 @@ async function runSeed(input) {
9205
9240
 
9206
9241
  // src/commands/canvas.ts
9207
9242
  import { readFile as readFile27, writeFile as writeFile17 } from "fs/promises";
9208
- import { existsSync as existsSync18 } from "fs";
9209
- import { join as join43 } from "path";
9243
+ import { existsSync as existsSync19 } from "fs";
9244
+ import { join as join44 } from "path";
9210
9245
  var NODE_WIDTH = 240;
9211
9246
  var NODE_HEIGHT = 60;
9212
9247
  var COLUMN_SPACING = 400;
@@ -9284,8 +9319,8 @@ function buildCanvasEdges(adjacency) {
9284
9319
  return edges;
9285
9320
  }
9286
9321
  async function runCanvasGenerate(input) {
9287
- const graphPath = input.graphPath ?? join43(input.vault, ".skillwiki", "graph.json");
9288
- if (!existsSync18(graphPath)) {
9322
+ const graphPath = input.graphPath ?? join44(input.vault, ".skillwiki", "graph.json");
9323
+ if (!existsSync19(graphPath)) {
9289
9324
  return {
9290
9325
  exitCode: ExitCode.FILE_NOT_FOUND,
9291
9326
  result: err("FILE_NOT_FOUND", {
@@ -9322,7 +9357,7 @@ async function runCanvasGenerate(input) {
9322
9357
  const nodes = buildCanvasNodes(paths);
9323
9358
  const edges = buildCanvasEdges(graph.adjacency);
9324
9359
  const canvas = { nodes, edges };
9325
- const outPath = join43(input.vault, "vault-graph.canvas");
9360
+ const outPath = join44(input.vault, "vault-graph.canvas");
9326
9361
  try {
9327
9362
  await writeFile17(outPath, JSON.stringify(canvas, null, 2));
9328
9363
  } catch (e) {
@@ -9344,8 +9379,8 @@ written: ${outPath}`
9344
9379
  }
9345
9380
 
9346
9381
  // src/commands/query.ts
9347
- import { readFile as readFile28, stat as stat9 } from "fs/promises";
9348
- import { join as join44 } from "path";
9382
+ import { readFile as readFile28, stat as stat10 } from "fs/promises";
9383
+ import { join as join45 } from "path";
9349
9384
  var W_KEYWORD = 2;
9350
9385
  var W_SOURCE_OVERLAP = 4;
9351
9386
  var W_WIKILINK = 3;
@@ -9466,10 +9501,10 @@ function computeKeywordScore(terms, title, tags, body) {
9466
9501
  return score;
9467
9502
  }
9468
9503
  async function loadOrBuildGraph(vault) {
9469
- const graphPath = join44(vault, ".skillwiki", "graph.json");
9504
+ const graphPath = join45(vault, ".skillwiki", "graph.json");
9470
9505
  let needsBuild = false;
9471
9506
  try {
9472
- const fileStat = await stat9(graphPath);
9507
+ const fileStat = await stat10(graphPath);
9473
9508
  const ageHours = (Date.now() - fileStat.mtimeMs) / (1e3 * 60 * 60);
9474
9509
  if (ageHours > 24) needsBuild = true;
9475
9510
  } catch {
@@ -9490,9 +9525,9 @@ async function loadOrBuildGraph(vault) {
9490
9525
  // src/commands/fleet.ts
9491
9526
  import { readFile as readFile29 } from "fs/promises";
9492
9527
  import { hostname as nodeHostname, userInfo } from "os";
9493
- import { join as join45 } from "path";
9528
+ import { join as join46 } from "path";
9494
9529
  import yaml3 from "js-yaml";
9495
- var FLEET_REL_PATH = join45("projects", "llm-wiki", "architecture", "fleet.yaml");
9530
+ var FLEET_REL_PATH = join46("projects", "llm-wiki", "architecture", "fleet.yaml");
9496
9531
  async function runFleetValidate(input) {
9497
9532
  const loaded = await loadFleetManifest(input.file);
9498
9533
  if (!loaded.ok) {
@@ -9523,7 +9558,7 @@ async function runFleetContext(input) {
9523
9558
  const osHostname = input.osHostname ?? safeEnvValue(env.HOSTNAME) ?? nodeHostname();
9524
9559
  const user = input.user ?? safeEnvValue(env.USER) ?? safeUserName();
9525
9560
  const vault = input.vault ?? safeEnvValue(env.WIKI_PATH);
9526
- const file = input.file ?? (vault ? join45(vault, FLEET_REL_PATH) : void 0);
9561
+ const file = input.file ?? (vault ? join46(vault, FLEET_REL_PATH) : void 0);
9527
9562
  const loaded = file ? await loadFleetManifest(file) : { ok: false, error: "FILE_NOT_FOUND" };
9528
9563
  if (!loaded.ok) {
9529
9564
  const markdown2 = formatUnknownContext({ osHostname, user, cwd, vault, reason: "fleet manifest unavailable or invalid" });
@@ -9630,7 +9665,7 @@ async function resolveHostId(input) {
9630
9665
  if (input.env.SKILLWIKI_HOST_ID) return { hostId: input.env.SKILLWIKI_HOST_ID, source: "SKILLWIKI_HOST_ID" };
9631
9666
  if (input.env.AGENT_HOST_ID) return { hostId: input.env.AGENT_HOST_ID, source: "AGENT_HOST_ID" };
9632
9667
  if (input.home) {
9633
- const dotenv = await parseDotenvFile(join45(input.home, ".skillwiki", ".env"));
9668
+ const dotenv = await parseDotenvFile(join46(input.home, ".skillwiki", ".env"));
9634
9669
  if (dotenv.SKILLWIKI_HOST_ID) {
9635
9670
  return { hostId: dotenv.SKILLWIKI_HOST_ID, source: "~/.skillwiki/.env:SKILLWIKI_HOST_ID" };
9636
9671
  }
@@ -9740,14 +9775,14 @@ function safeUserName() {
9740
9775
  }
9741
9776
 
9742
9777
  // src/utils/auto-commit.ts
9743
- import { existsSync as existsSync19 } from "fs";
9744
- import { join as join46 } from "path";
9778
+ import { existsSync as existsSync20 } from "fs";
9779
+ import { join as join47 } from "path";
9745
9780
  async function postCommit(vault, exitCode) {
9746
9781
  if (exitCode !== 0) return;
9747
9782
  const home = process.env.HOME ?? "";
9748
9783
  const dotenv = await parseDotenvFile(configPath(home));
9749
9784
  if (dotenv["AUTO_COMMIT"] === "false") return;
9750
- if (!existsSync19(join46(vault, ".git"))) return;
9785
+ if (!existsSync20(join47(vault, ".git"))) return;
9751
9786
  const lastOps = readLastOp(vault);
9752
9787
  if (lastOps.length === 0) return;
9753
9788
  const porcelain = git(vault, ["status", "--porcelain"]);
@@ -9798,7 +9833,7 @@ program.command("validate <file>").description("validate vault page frontmatter
9798
9833
  emit(await runValidate({ file, apply: !!opts.apply, vault }), vault);
9799
9834
  });
9800
9835
  program.command("graph").description("graph subcommands").command("build <vault>").option("--out <path>", "graph output path (default: <vault>/.skillwiki/graph.json)").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
9801
- const out = opts.out ?? join47(vault, ".skillwiki", "graph.json");
9836
+ const out = opts.out ?? join48(vault, ".skillwiki", "graph.json");
9802
9837
  emit(await runGraphBuild({ vault, out }), vault);
9803
9838
  });
9804
9839
  var canvasCmd = program.command("canvas").description("manage Obsidian canvas files");