skillwiki 0.2.0-beta.27 → 0.2.0-beta.28
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
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-XM5IYZX7.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
|
-
import { readFileSync as
|
|
7
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
|
|
10
10
|
// src/utils/output.ts
|
|
@@ -72,7 +72,8 @@ var ExitCode = {
|
|
|
72
72
|
DRIFT_DETECTED: 32,
|
|
73
73
|
RAW_DEDUP_DETECTED: 33,
|
|
74
74
|
MIGRATION_APPLIED: 34,
|
|
75
|
-
UNKNOWN_WIKI_PROFILE: 35
|
|
75
|
+
UNKNOWN_WIKI_PROFILE: 35,
|
|
76
|
+
DEDUP_APPLIED: 36
|
|
76
77
|
};
|
|
77
78
|
|
|
78
79
|
// ../shared/src/json-output.ts
|
|
@@ -901,7 +902,7 @@ async function runAudit(input) {
|
|
|
901
902
|
return { ...m, resolved: false };
|
|
902
903
|
}
|
|
903
904
|
}));
|
|
904
|
-
const sources = fm.data.sources ?? [];
|
|
905
|
+
const sources = (fm.data.sources ?? []).map((s) => s.replace(/^\^\[/, "").replace(/\]$/, ""));
|
|
905
906
|
const referenced = new Set(resolved.map((m) => m.target));
|
|
906
907
|
const unused_sources = sources.filter((s) => !referenced.has(s));
|
|
907
908
|
const missing_from_sources = [...referenced].filter((t) => !sources.includes(t));
|
|
@@ -1306,8 +1307,7 @@ async function runInit(input) {
|
|
|
1306
1307
|
return tpl.replace(/\{\{INIT_DATE\}\}/g, today).replace("{{DOMAIN}}", domain).replace("{{WIKI_LANG}}", canonicalLang);
|
|
1307
1308
|
});
|
|
1308
1309
|
if (err22) return err22;
|
|
1309
|
-
const
|
|
1310
|
-
const skipEnv = !!input.noEnv || isTempPath;
|
|
1310
|
+
const skipEnv = !!input.noEnv;
|
|
1311
1311
|
let envWritten = "";
|
|
1312
1312
|
if (!skipEnv) {
|
|
1313
1313
|
try {
|
|
@@ -1603,6 +1603,8 @@ ${markdown_links.map((l) => ` line ${l.line}: ${l.text}`).join("\n")}`;
|
|
|
1603
1603
|
}
|
|
1604
1604
|
|
|
1605
1605
|
// src/commands/dedup.ts
|
|
1606
|
+
import { readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
1607
|
+
import { join as join13 } from "path";
|
|
1606
1608
|
async function runDedup(input) {
|
|
1607
1609
|
const scan = await scanVault(input.vault);
|
|
1608
1610
|
if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
|
|
@@ -1619,17 +1621,63 @@ async function runDedup(input) {
|
|
|
1619
1621
|
else hashMap.set(sha, [raw.relPath]);
|
|
1620
1622
|
}
|
|
1621
1623
|
const duplicates = [...hashMap.entries()].filter(([, files]) => files.length > 1).map(([sha256, files]) => ({ sha256, files }));
|
|
1622
|
-
const
|
|
1624
|
+
const rewired = [];
|
|
1625
|
+
const removed = [];
|
|
1626
|
+
if (input.apply && duplicates.length > 0) {
|
|
1627
|
+
const replacements = /* @__PURE__ */ new Map();
|
|
1628
|
+
for (const group of duplicates) {
|
|
1629
|
+
const canonical = group.files[0];
|
|
1630
|
+
for (let i = 1; i < group.files.length; i++) {
|
|
1631
|
+
replacements.set(group.files[i], canonical);
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
for (const page of scan.data.typedKnowledge) {
|
|
1635
|
+
const text = readFileSync(join13(input.vault, page.relPath), "utf-8");
|
|
1636
|
+
let updated = text;
|
|
1637
|
+
let changed = false;
|
|
1638
|
+
for (const [oldPath, newPath] of replacements) {
|
|
1639
|
+
const oldMarker = `^[${oldPath}]`;
|
|
1640
|
+
const newMarker = `^[${newPath}]`;
|
|
1641
|
+
if (updated.includes(oldMarker)) {
|
|
1642
|
+
updated = updated.replaceAll(oldMarker, newMarker);
|
|
1643
|
+
changed = true;
|
|
1644
|
+
}
|
|
1645
|
+
const oldFm = `- "^[${oldPath}]"`;
|
|
1646
|
+
const newFm = `- "^[${newPath}]"`;
|
|
1647
|
+
if (updated.includes(oldFm)) {
|
|
1648
|
+
updated = updated.replaceAll(oldFm, newFm);
|
|
1649
|
+
changed = true;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
if (changed) {
|
|
1653
|
+
writeFileSync(join13(input.vault, page.relPath), updated);
|
|
1654
|
+
rewired.push(page.relPath);
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
for (const [oldPath] of replacements) {
|
|
1658
|
+
const fullPath = join13(input.vault, oldPath);
|
|
1659
|
+
try {
|
|
1660
|
+
unlinkSync(fullPath);
|
|
1661
|
+
removed.push(oldPath);
|
|
1662
|
+
} catch {
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
const exitCode = duplicates.length > 0 ? input.apply ? ExitCode.DEDUP_APPLIED : ExitCode.RAW_DEDUP_DETECTED : ExitCode.OK;
|
|
1623
1667
|
const hintLines = [`scanned: ${totalFiles} raw files`];
|
|
1624
1668
|
if (duplicates.length > 0) {
|
|
1625
1669
|
hintLines.push(`duplicates: ${duplicates.length}`);
|
|
1626
1670
|
for (const d of duplicates) hintLines.push(` ${d.sha256.slice(0, 12)}... \u2192 ${d.files.join(", ")}`);
|
|
1671
|
+
if (input.apply) {
|
|
1672
|
+
hintLines.push(`rewired: ${rewired.length} pages`);
|
|
1673
|
+
hintLines.push(`removed: ${removed.length} raw files`);
|
|
1674
|
+
}
|
|
1627
1675
|
} else {
|
|
1628
1676
|
hintLines.push("0 duplicates");
|
|
1629
1677
|
}
|
|
1630
1678
|
return {
|
|
1631
1679
|
exitCode,
|
|
1632
|
-
result: ok({ scanned: totalFiles, duplicates, humanHint: hintLines.join("\n") })
|
|
1680
|
+
result: ok({ scanned: totalFiles, duplicates, rewired, removed, humanHint: hintLines.join("\n") })
|
|
1633
1681
|
};
|
|
1634
1682
|
}
|
|
1635
1683
|
|
|
@@ -1648,8 +1696,8 @@ function hasDuplicateFrontmatter(body) {
|
|
|
1648
1696
|
return false;
|
|
1649
1697
|
}
|
|
1650
1698
|
var ERROR_ORDER = ["broken_wikilinks", "invalid_frontmatter", "raw_dedup", "tag_not_in_taxonomy"];
|
|
1651
|
-
var WARNING_ORDER = ["index_incomplete", "index_link_format", "stale_page", "page_too_large", "log_rotate_needed", "
|
|
1652
|
-
var INFO_ORDER = ["bridges", "
|
|
1699
|
+
var WARNING_ORDER = ["index_incomplete", "index_link_format", "stale_page", "page_too_large", "log_rotate_needed", "orphans", "legacy_citation_style", "orphaned_citations", "duplicate_frontmatter", "missing_overview"];
|
|
1700
|
+
var INFO_ORDER = ["bridges", "page_structure", "topic_map_recommended", "frontmatter_wikilink"];
|
|
1653
1701
|
async function runLint(input) {
|
|
1654
1702
|
const buckets = {};
|
|
1655
1703
|
const links = await runLinks({ vault: input.vault });
|
|
@@ -1693,20 +1741,31 @@ async function runLint(input) {
|
|
|
1693
1741
|
const dedup = await runDedup({ vault: input.vault });
|
|
1694
1742
|
if (dedup.result.ok && dedup.result.data.duplicates.length > 0) buckets.raw_dedup = dedup.result.data.duplicates;
|
|
1695
1743
|
const scan = await scanVault(input.vault);
|
|
1744
|
+
const slugs = scan.ok ? buildSlugMap(scan.data.typedKnowledge) : /* @__PURE__ */ new Map();
|
|
1696
1745
|
if (scan.ok) {
|
|
1697
1746
|
const legacyPages = [];
|
|
1698
1747
|
const orphanedPages = [];
|
|
1699
1748
|
const structFlags = [];
|
|
1700
1749
|
const dupFrontmatter = [];
|
|
1701
1750
|
const noOverview = [];
|
|
1751
|
+
const fmWikilinkFlags = [];
|
|
1702
1752
|
for (const page of scan.data.typedKnowledge) {
|
|
1703
1753
|
const text = await readPage(page);
|
|
1704
1754
|
const split = splitFrontmatter(text);
|
|
1705
1755
|
if (!split.ok) continue;
|
|
1706
1756
|
const body = split.data.body;
|
|
1757
|
+
const rawFm = split.data.rawFrontmatter;
|
|
1707
1758
|
if (hasDuplicateFrontmatter(body)) dupFrontmatter.push(page.relPath);
|
|
1708
1759
|
if (isLegacyCitationStyle(body)) legacyPages.push(page.relPath);
|
|
1709
1760
|
if (hasOrphanedCitations(body)) orphanedPages.push(page.relPath);
|
|
1761
|
+
const fmLinks = rawFm.match(/\[\[([^\[\]|]+)(?:\|[^\[\]]*)?\]\]/g) ?? [];
|
|
1762
|
+
for (const link of fmLinks) {
|
|
1763
|
+
const target = link.replace(/^\[\[/, "").replace(/(?:\|[^\[\]]*)?\]\]$/, "").trim();
|
|
1764
|
+
const tail = target.split("/").pop();
|
|
1765
|
+
if (!slugs.has(tail.toLowerCase())) {
|
|
1766
|
+
fmWikilinkFlags.push(`${page.relPath}: [[${target}]] does not resolve`);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1710
1769
|
const bodyLines = body.split("\n").filter((l) => l.trim().length > 0).length;
|
|
1711
1770
|
const hasOverview = /^## Overview/m.test(body);
|
|
1712
1771
|
if (!hasOverview) noOverview.push(page.relPath);
|
|
@@ -1726,6 +1785,7 @@ async function runLint(input) {
|
|
|
1726
1785
|
if (structFlags.length > 0) buckets.page_structure = structFlags;
|
|
1727
1786
|
if (dupFrontmatter.length > 0) buckets.duplicate_frontmatter = dupFrontmatter;
|
|
1728
1787
|
if (noOverview.length > 0) buckets.missing_overview = noOverview;
|
|
1788
|
+
if (fmWikilinkFlags.length > 0) buckets.frontmatter_wikilink = fmWikilinkFlags;
|
|
1729
1789
|
}
|
|
1730
1790
|
const errorOut = ERROR_ORDER.flatMap((k) => buckets[k] ? [{ kind: k, items: buckets[k] }] : []);
|
|
1731
1791
|
const warningOut = WARNING_ORDER.flatMap((k) => buckets[k] ? [{ kind: k, items: buckets[k] }] : []);
|
|
@@ -1761,12 +1821,12 @@ async function runLint(input) {
|
|
|
1761
1821
|
// src/commands/config.ts
|
|
1762
1822
|
import { readFile as readFile12 } from "fs/promises";
|
|
1763
1823
|
import { existsSync } from "fs";
|
|
1764
|
-
import { join as
|
|
1824
|
+
import { join as join14 } from "path";
|
|
1765
1825
|
function validateKey(key) {
|
|
1766
1826
|
return CONFIG_KEYS.includes(key) || isValidWikiProfileKey(key);
|
|
1767
1827
|
}
|
|
1768
1828
|
function configPath(home) {
|
|
1769
|
-
return
|
|
1829
|
+
return join14(home, ".skillwiki", ".env");
|
|
1770
1830
|
}
|
|
1771
1831
|
async function runConfigGet(input) {
|
|
1772
1832
|
if (!validateKey(input.key)) {
|
|
@@ -1820,13 +1880,13 @@ async function runConfigPath(input) {
|
|
|
1820
1880
|
}
|
|
1821
1881
|
|
|
1822
1882
|
// src/commands/doctor.ts
|
|
1823
|
-
import { existsSync as existsSync3, readdirSync, readFileSync as
|
|
1824
|
-
import { join as
|
|
1883
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, statSync } from "fs";
|
|
1884
|
+
import { join as join16 } from "path";
|
|
1825
1885
|
import { execSync } from "child_process";
|
|
1826
1886
|
|
|
1827
1887
|
// src/utils/auto-update.ts
|
|
1828
|
-
import { readFileSync, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
|
|
1829
|
-
import { join as
|
|
1888
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync } from "fs";
|
|
1889
|
+
import { join as join15, dirname as dirname6 } from "path";
|
|
1830
1890
|
import { spawn } from "child_process";
|
|
1831
1891
|
|
|
1832
1892
|
// src/utils/update-consts.ts
|
|
@@ -1837,11 +1897,11 @@ var CLI_DISABLE_FLAG = "--no-update-notifier";
|
|
|
1837
1897
|
|
|
1838
1898
|
// src/utils/auto-update.ts
|
|
1839
1899
|
function cachePath(home) {
|
|
1840
|
-
return
|
|
1900
|
+
return join15(home, ".skillwiki", CACHE_FILENAME);
|
|
1841
1901
|
}
|
|
1842
1902
|
function readCacheRaw(home) {
|
|
1843
1903
|
try {
|
|
1844
|
-
const raw =
|
|
1904
|
+
const raw = readFileSync2(cachePath(home), "utf8");
|
|
1845
1905
|
return JSON.parse(raw);
|
|
1846
1906
|
} catch {
|
|
1847
1907
|
return null;
|
|
@@ -1857,7 +1917,7 @@ function readCache(home) {
|
|
|
1857
1917
|
function writeCache(home, cache) {
|
|
1858
1918
|
const p = cachePath(home);
|
|
1859
1919
|
mkdirSync(dirname6(p), { recursive: true });
|
|
1860
|
-
|
|
1920
|
+
writeFileSync2(p, JSON.stringify(cache, null, 2));
|
|
1861
1921
|
}
|
|
1862
1922
|
function latestFromCache(home, currentVersion) {
|
|
1863
1923
|
const { cache } = readCache(home);
|
|
@@ -1940,9 +2000,9 @@ function checkVaultStructure(resolvedPath) {
|
|
|
1940
2000
|
return check("error", "vault_structure", "Vault structure valid", "Cannot check \u2014 vault directory does not exist");
|
|
1941
2001
|
}
|
|
1942
2002
|
const missing = [];
|
|
1943
|
-
if (!existsSync3(
|
|
2003
|
+
if (!existsSync3(join16(resolvedPath, "SCHEMA.md"))) missing.push("SCHEMA.md");
|
|
1944
2004
|
for (const dir of ["raw", "entities", "concepts", "meta"]) {
|
|
1945
|
-
if (!existsSync3(
|
|
2005
|
+
if (!existsSync3(join16(resolvedPath, dir))) missing.push(dir + "/");
|
|
1946
2006
|
}
|
|
1947
2007
|
if (missing.length === 0) {
|
|
1948
2008
|
return check("pass", "vault_structure", "Vault structure valid", "All required files and directories present");
|
|
@@ -1950,7 +2010,7 @@ function checkVaultStructure(resolvedPath) {
|
|
|
1950
2010
|
return check("error", "vault_structure", "Vault structure valid", `Missing: ${missing.join(", ")}`);
|
|
1951
2011
|
}
|
|
1952
2012
|
function checkSkillsInstalled(home) {
|
|
1953
|
-
const skillsDir =
|
|
2013
|
+
const skillsDir = join16(home, ".claude", "skills");
|
|
1954
2014
|
if (!existsSync3(skillsDir)) {
|
|
1955
2015
|
return check("warn", "skills_installed", "Skills installed", `${skillsDir} not found`);
|
|
1956
2016
|
}
|
|
@@ -1971,12 +2031,12 @@ function checkNpmUpdate(home, currentVersion) {
|
|
|
1971
2031
|
return check("pass", "npm_update", "npm CLI version", `v${currentVersion} (latest: v${latest})`);
|
|
1972
2032
|
}
|
|
1973
2033
|
function checkPluginVersionDrift(home, currentVersion) {
|
|
1974
|
-
const pluginJsonPath =
|
|
2034
|
+
const pluginJsonPath = join16(home, ".claude", "plugins", "cache", "llm-wiki", "plugin.json");
|
|
1975
2035
|
if (!existsSync3(pluginJsonPath)) {
|
|
1976
2036
|
return check("pass", "plugin_version_drift", "Plugin/CLI version", "Plugin cache not found \u2014 plugin not installed");
|
|
1977
2037
|
}
|
|
1978
2038
|
try {
|
|
1979
|
-
const content =
|
|
2039
|
+
const content = readFileSync3(pluginJsonPath, { encoding: "utf8" });
|
|
1980
2040
|
const pluginData = JSON.parse(content);
|
|
1981
2041
|
const pluginVersion = pluginData.version;
|
|
1982
2042
|
if (!pluginVersion) {
|
|
@@ -2018,7 +2078,7 @@ async function checkProfiles(home) {
|
|
|
2018
2078
|
}
|
|
2019
2079
|
async function checkProjectLocalOverride(cwd) {
|
|
2020
2080
|
const dir = cwd ?? process.cwd();
|
|
2021
|
-
const envPath =
|
|
2081
|
+
const envPath = join16(dir, ".skillwiki", ".env");
|
|
2022
2082
|
if (existsSync3(envPath)) {
|
|
2023
2083
|
return check("pass", "project_local", "Project-local config", `Found: ${envPath}`);
|
|
2024
2084
|
}
|
|
@@ -2034,9 +2094,9 @@ function findSkillMd(dir) {
|
|
|
2034
2094
|
}
|
|
2035
2095
|
for (const entry of entries) {
|
|
2036
2096
|
if (entry.isFile() && entry.name === "SKILL.md") {
|
|
2037
|
-
results.push(
|
|
2097
|
+
results.push(join16(dir, entry.name));
|
|
2038
2098
|
} else if (entry.isDirectory()) {
|
|
2039
|
-
results.push(...findSkillMd(
|
|
2099
|
+
results.push(...findSkillMd(join16(dir, entry.name)));
|
|
2040
2100
|
}
|
|
2041
2101
|
}
|
|
2042
2102
|
return results;
|
|
@@ -2080,7 +2140,7 @@ async function runDoctor(input) {
|
|
|
2080
2140
|
|
|
2081
2141
|
// src/commands/archive.ts
|
|
2082
2142
|
import { rename as rename3, mkdir as mkdir5, readFile as readFile13, writeFile as writeFile6 } from "fs/promises";
|
|
2083
|
-
import { join as
|
|
2143
|
+
import { join as join17, dirname as dirname7 } from "path";
|
|
2084
2144
|
async function runArchive(input) {
|
|
2085
2145
|
const scan = await scanVault(input.vault);
|
|
2086
2146
|
if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
|
|
@@ -2092,10 +2152,10 @@ async function runArchive(input) {
|
|
|
2092
2152
|
}
|
|
2093
2153
|
if (!relPath) return { exitCode: ExitCode.ARCHIVE_TARGET_NOT_FOUND, result: err("ARCHIVE_TARGET_NOT_FOUND", { page: input.page }) };
|
|
2094
2154
|
if (relPath.startsWith("_archive/")) return { exitCode: ExitCode.ARCHIVE_ALREADY_ARCHIVED, result: err("ARCHIVE_ALREADY_ARCHIVED", { page: relPath }) };
|
|
2095
|
-
const archivePath =
|
|
2096
|
-
await mkdir5(dirname7(
|
|
2155
|
+
const archivePath = join17("_archive", relPath);
|
|
2156
|
+
await mkdir5(dirname7(join17(input.vault, archivePath)), { recursive: true });
|
|
2097
2157
|
let indexUpdated = false;
|
|
2098
|
-
const indexPath =
|
|
2158
|
+
const indexPath = join17(input.vault, "index.md");
|
|
2099
2159
|
try {
|
|
2100
2160
|
const idx = await readFile13(indexPath, "utf8");
|
|
2101
2161
|
const slug = relPath.replace(/\.md$/, "").split("/").pop();
|
|
@@ -2108,7 +2168,7 @@ async function runArchive(input) {
|
|
|
2108
2168
|
} catch (e) {
|
|
2109
2169
|
if (e?.code !== "ENOENT") throw e;
|
|
2110
2170
|
}
|
|
2111
|
-
await rename3(
|
|
2171
|
+
await rename3(join17(input.vault, relPath), join17(input.vault, archivePath));
|
|
2112
2172
|
return { exitCode: ExitCode.OK, result: ok({ archived_from: relPath, archived_to: archivePath, index_updated: indexUpdated, humanHint: `${relPath} -> ${archivePath}${indexUpdated ? " (index updated)" : ""}` }) };
|
|
2113
2173
|
}
|
|
2114
2174
|
|
|
@@ -2407,10 +2467,10 @@ ${newBody}`;
|
|
|
2407
2467
|
|
|
2408
2468
|
// src/commands/update.ts
|
|
2409
2469
|
import { execSync as execSync2 } from "child_process";
|
|
2410
|
-
import { readFileSync as
|
|
2470
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
2411
2471
|
async function runUpdate(input) {
|
|
2412
2472
|
const pkg2 = JSON.parse(
|
|
2413
|
-
|
|
2473
|
+
readFileSync4(new URL("../../package.json", import.meta.url), "utf8")
|
|
2414
2474
|
);
|
|
2415
2475
|
const currentVersion = pkg2.version;
|
|
2416
2476
|
const tag = input.distTag ?? "beta";
|
|
@@ -2467,7 +2527,7 @@ async function runUpdate(input) {
|
|
|
2467
2527
|
}
|
|
2468
2528
|
|
|
2469
2529
|
// src/cli.ts
|
|
2470
|
-
var pkg = JSON.parse(
|
|
2530
|
+
var pkg = JSON.parse(readFileSync5(new URL("../package.json", import.meta.url), "utf8"));
|
|
2471
2531
|
var program = new Command();
|
|
2472
2532
|
program.name("skillwiki").description("Deterministic helpers for CodeWiki skills").version(pkg.version);
|
|
2473
2533
|
program.option("--human", "render terminal-readable output instead of JSON");
|
|
@@ -2606,10 +2666,10 @@ program.command("drift [vault]").description("detect content drift in raw source
|
|
|
2606
2666
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2607
2667
|
else emit(await runDrift({ vault: v.vault }));
|
|
2608
2668
|
});
|
|
2609
|
-
program.command("dedup [vault]").description("detect duplicate raw sources by sha256").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2669
|
+
program.command("dedup [vault]").description("detect duplicate raw sources by sha256").option("--apply", "rewire citations and remove duplicate raw files", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2610
2670
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2611
2671
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2612
|
-
else emit(await runDedup({ vault: v.vault }));
|
|
2672
|
+
else emit(await runDedup({ vault: v.vault, apply: opts.apply }));
|
|
2613
2673
|
});
|
|
2614
2674
|
program.command("migrate-citations [vault]").description("migrate ^[raw/...] markers to paragraph-end citations").option("--dry-run", "preview changes without writing", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2615
2675
|
const v = await resolveVaultArg(vault, opts.wiki);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.28",
|
|
4
4
|
"skills": "./",
|
|
5
5
|
"description": "Project-aware Karpathy-style knowledge base for Claude Code: 11 prompt-only skills (wiki-*, proj-*, using-skillwiki) backed by the deterministic `skillwiki` CLI (8 subcommands, JSON-by-default).",
|
|
6
6
|
"author": {
|
package/skills/package.json
CHANGED
|
@@ -24,7 +24,8 @@ Standard four reads (SCHEMA, index, log, project context if applicable).
|
|
|
24
24
|
1. Identify the target page. Confirm with the user which page to archive (show full relPath).
|
|
25
25
|
2. Run `skillwiki archive <page> [vault]`. Read the JSON output.
|
|
26
26
|
3. Verify with `skillwiki index-check [vault]` — confirm no ghost entries remain.
|
|
27
|
-
4.
|
|
27
|
+
4. Run `skillwiki lint [vault]` — check for broken wikilinks from other pages that still reference the archived page. If found, update those pages to point to the replacement or remove the stale link.
|
|
28
|
+
5. Append a `log.md` entry: `## [{date}] archive | {relPath} → _archive/{subdir}/`.
|
|
28
29
|
|
|
29
30
|
## Reversibility
|
|
30
31
|
|
|
@@ -18,7 +18,7 @@ Standard four reads.
|
|
|
18
18
|
|
|
19
19
|
0. Resolve vault: `skillwiki path` (record source for context).
|
|
20
20
|
1. Run `skillwiki lint <vault>`. Read the JSON.
|
|
21
|
-
2. Reason over findings; present grouped by severity with concrete suggested actions per kind.
|
|
21
|
+
2. Reason over findings; present grouped by severity with concrete suggested actions per kind. If the CLI was recently updated with new lint checks, re-running lint on the full vault may flag pre-existing pages that predate the new rule — treat these as legitimate findings, not false positives.
|
|
22
22
|
3. If `log_rotate_needed` is present and the user consents, run `skillwiki log-rotate <vault> --apply`. Otherwise leave alone.
|
|
23
23
|
4. Append one `log.md` entry summarizing the lint counts (errors/warnings/info).
|
|
24
24
|
|