skillwiki 0.2.0 → 0.2.1-beta.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 +67 -42
- package/package.json +2 -1
- package/skills/.claude-plugin/plugin.json +2 -1
- package/skills/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -878,6 +878,10 @@ function hasOrphanedCitations(body) {
|
|
|
878
878
|
}
|
|
879
879
|
return false;
|
|
880
880
|
}
|
|
881
|
+
function hasWikilinkCitations(body) {
|
|
882
|
+
const stripped = stripFences(body);
|
|
883
|
+
return /\[\[raw\/[^\]]+\]\]/.test(stripped);
|
|
884
|
+
}
|
|
881
885
|
|
|
882
886
|
// src/commands/audit.ts
|
|
883
887
|
async function runAudit(input) {
|
|
@@ -1704,7 +1708,7 @@ function hasDuplicateFrontmatter(body) {
|
|
|
1704
1708
|
}
|
|
1705
1709
|
var ERROR_ORDER = ["broken_wikilinks", "invalid_frontmatter", "raw_dedup", "tag_not_in_taxonomy"];
|
|
1706
1710
|
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"];
|
|
1707
|
-
var INFO_ORDER = ["bridges", "page_structure", "topic_map_recommended", "frontmatter_wikilink"];
|
|
1711
|
+
var INFO_ORDER = ["bridges", "page_structure", "topic_map_recommended", "frontmatter_wikilink", "wikilink_citation"];
|
|
1708
1712
|
async function runLint(input) {
|
|
1709
1713
|
const buckets = {};
|
|
1710
1714
|
const links = await runLinks({ vault: input.vault });
|
|
@@ -1757,6 +1761,7 @@ async function runLint(input) {
|
|
|
1757
1761
|
const dupFrontmatter = [];
|
|
1758
1762
|
const noOverview = [];
|
|
1759
1763
|
const fmWikilinkFlags = [];
|
|
1764
|
+
const wikilinkCitationFlags = [];
|
|
1760
1765
|
for (const page of scan.data.typedKnowledge) {
|
|
1761
1766
|
const text = await readPage(page);
|
|
1762
1767
|
const split = splitFrontmatter(text);
|
|
@@ -1766,6 +1771,7 @@ async function runLint(input) {
|
|
|
1766
1771
|
if (hasDuplicateFrontmatter(body)) dupFrontmatter.push(page.relPath);
|
|
1767
1772
|
if (isLegacyCitationStyle(body)) legacyPages.push(page.relPath);
|
|
1768
1773
|
if (hasOrphanedCitations(body)) orphanedPages.push(page.relPath);
|
|
1774
|
+
if (hasWikilinkCitations(body)) wikilinkCitationFlags.push(page.relPath);
|
|
1769
1775
|
const fmLinks = rawFm.match(/\[\[([^\[\]|]+)(?:\|[^\[\]]*)?\]\]/g) ?? [];
|
|
1770
1776
|
for (const link of fmLinks) {
|
|
1771
1777
|
const target = link.replace(/^\[\[/, "").replace(/(?:\|[^\[\]]*)?\]\]$/, "").trim();
|
|
@@ -1794,6 +1800,7 @@ async function runLint(input) {
|
|
|
1794
1800
|
if (dupFrontmatter.length > 0) buckets.duplicate_frontmatter = dupFrontmatter;
|
|
1795
1801
|
if (noOverview.length > 0) buckets.missing_overview = noOverview;
|
|
1796
1802
|
if (fmWikilinkFlags.length > 0) buckets.frontmatter_wikilink = fmWikilinkFlags;
|
|
1803
|
+
if (wikilinkCitationFlags.length > 0) buckets.wikilink_citation = wikilinkCitationFlags;
|
|
1797
1804
|
}
|
|
1798
1805
|
const errorOut = ERROR_ORDER.flatMap((k) => buckets[k] ? [{ kind: k, items: buckets[k] }] : []);
|
|
1799
1806
|
const warningOut = WARNING_ORDER.flatMap((k) => buckets[k] ? [{ kind: k, items: buckets[k] }] : []);
|
|
@@ -1888,8 +1895,8 @@ async function runConfigPath(input) {
|
|
|
1888
1895
|
}
|
|
1889
1896
|
|
|
1890
1897
|
// src/commands/doctor.ts
|
|
1891
|
-
import { existsSync as existsSync3, readdirSync,
|
|
1892
|
-
import { join as
|
|
1898
|
+
import { existsSync as existsSync3, readdirSync, statSync } from "fs";
|
|
1899
|
+
import { join as join17 } from "path";
|
|
1893
1900
|
import { execSync } from "child_process";
|
|
1894
1901
|
|
|
1895
1902
|
// src/utils/auto-update.ts
|
|
@@ -1953,6 +1960,27 @@ function triggerAutoUpdate(home, currentVersion) {
|
|
|
1953
1960
|
child.unref();
|
|
1954
1961
|
}
|
|
1955
1962
|
|
|
1963
|
+
// src/utils/plugin-registry.ts
|
|
1964
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
1965
|
+
import { join as join16 } from "path";
|
|
1966
|
+
var REGISTRY_PATH = join16(".claude", "plugins", "installed_plugins.json");
|
|
1967
|
+
var PLUGIN_KEY = "skillwiki@llm-wiki";
|
|
1968
|
+
function readInstalledPlugins(home) {
|
|
1969
|
+
try {
|
|
1970
|
+
const raw = readFileSync3(join16(home, REGISTRY_PATH), "utf8");
|
|
1971
|
+
return JSON.parse(raw);
|
|
1972
|
+
} catch {
|
|
1973
|
+
return null;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
function findPlugin(home, key = PLUGIN_KEY) {
|
|
1977
|
+
const registry = readInstalledPlugins(home);
|
|
1978
|
+
if (!registry?.plugins) return null;
|
|
1979
|
+
const entries = registry.plugins[key];
|
|
1980
|
+
if (!entries || entries.length === 0) return null;
|
|
1981
|
+
return entries[0];
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1956
1984
|
// src/commands/doctor.ts
|
|
1957
1985
|
function check(status, id, label, detail) {
|
|
1958
1986
|
return { id, label, status, detail };
|
|
@@ -2008,9 +2036,9 @@ function checkVaultStructure(resolvedPath) {
|
|
|
2008
2036
|
return check("error", "vault_structure", "Vault structure valid", "Cannot check \u2014 vault directory does not exist");
|
|
2009
2037
|
}
|
|
2010
2038
|
const missing = [];
|
|
2011
|
-
if (!existsSync3(
|
|
2039
|
+
if (!existsSync3(join17(resolvedPath, "SCHEMA.md"))) missing.push("SCHEMA.md");
|
|
2012
2040
|
for (const dir of ["raw", "entities", "concepts", "meta"]) {
|
|
2013
|
-
if (!existsSync3(
|
|
2041
|
+
if (!existsSync3(join17(resolvedPath, dir))) missing.push(dir + "/");
|
|
2014
2042
|
}
|
|
2015
2043
|
if (missing.length === 0) {
|
|
2016
2044
|
return check("pass", "vault_structure", "Vault structure valid", "All required files and directories present");
|
|
@@ -2018,15 +2046,21 @@ function checkVaultStructure(resolvedPath) {
|
|
|
2018
2046
|
return check("warn", "vault_structure", "Vault structure valid", `Missing: ${missing.join(", ")} \u2014 run \`skillwiki init\` to add CodeWiki structure`);
|
|
2019
2047
|
}
|
|
2020
2048
|
function checkSkillsInstalled(home) {
|
|
2021
|
-
const
|
|
2022
|
-
if (
|
|
2023
|
-
|
|
2049
|
+
const plugin = findPlugin(home);
|
|
2050
|
+
if (plugin) {
|
|
2051
|
+
const found = findSkillMd(plugin.installPath);
|
|
2052
|
+
if (found.length > 0) {
|
|
2053
|
+
return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (plugin v${plugin.version})`);
|
|
2054
|
+
}
|
|
2024
2055
|
}
|
|
2025
|
-
const
|
|
2026
|
-
if (
|
|
2027
|
-
|
|
2056
|
+
const skillsDir = join17(home, ".claude", "skills");
|
|
2057
|
+
if (existsSync3(skillsDir)) {
|
|
2058
|
+
const found = findSkillMd(skillsDir);
|
|
2059
|
+
if (found.length > 0) {
|
|
2060
|
+
return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (CLI install)`);
|
|
2061
|
+
}
|
|
2028
2062
|
}
|
|
2029
|
-
return check("warn", "skills_installed", "Skills installed", "No SKILL.md files found
|
|
2063
|
+
return check("warn", "skills_installed", "Skills installed", "No SKILL.md files found");
|
|
2030
2064
|
}
|
|
2031
2065
|
function checkNpmUpdate(home, currentVersion) {
|
|
2032
2066
|
const { hasUpdate, latest } = latestFromCache(home, currentVersion);
|
|
@@ -2039,30 +2073,21 @@ function checkNpmUpdate(home, currentVersion) {
|
|
|
2039
2073
|
return check("pass", "npm_update", "npm CLI version", `v${currentVersion} (latest: v${latest})`);
|
|
2040
2074
|
}
|
|
2041
2075
|
function checkPluginVersionDrift(home, currentVersion) {
|
|
2042
|
-
const
|
|
2043
|
-
if (!
|
|
2044
|
-
return check("pass", "plugin_version_drift", "Plugin/CLI version", "Plugin
|
|
2076
|
+
const plugin = findPlugin(home);
|
|
2077
|
+
if (!plugin) {
|
|
2078
|
+
return check("pass", "plugin_version_drift", "Plugin/CLI version", "Plugin not installed \u2014 CLI only");
|
|
2045
2079
|
}
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
const pluginVersion = pluginData.version;
|
|
2050
|
-
if (!pluginVersion) {
|
|
2051
|
-
return check("pass", "plugin_version_drift", "Plugin/CLI version", "Plugin version not found in cache");
|
|
2052
|
-
}
|
|
2053
|
-
if (pluginVersion === currentVersion) {
|
|
2054
|
-
return check("pass", "plugin_version_drift", "Plugin/CLI version", `Both at v${currentVersion}`);
|
|
2055
|
-
}
|
|
2056
|
-
const updateCmd = semverGt(pluginVersion, currentVersion) ? "npm install -g skillwiki@beta" : "claude plugin update skillwiki@llm-wiki";
|
|
2057
|
-
return check(
|
|
2058
|
-
"warn",
|
|
2059
|
-
"plugin_version_drift",
|
|
2060
|
-
"Plugin/CLI version",
|
|
2061
|
-
`Plugin v${pluginVersion} \u2260 CLI v${currentVersion} \u2014 run \`${updateCmd}\``
|
|
2062
|
-
);
|
|
2063
|
-
} catch {
|
|
2064
|
-
return check("pass", "plugin_version_drift", "Plugin/CLI version", "Could not read plugin cache");
|
|
2080
|
+
const pluginVersion = plugin.version;
|
|
2081
|
+
if (pluginVersion === currentVersion) {
|
|
2082
|
+
return check("pass", "plugin_version_drift", "Plugin/CLI version", `Both at v${currentVersion}`);
|
|
2065
2083
|
}
|
|
2084
|
+
const updateCmd = semverGt(pluginVersion, currentVersion) ? "npm install -g skillwiki@beta" : "claude plugin update skillwiki@llm-wiki";
|
|
2085
|
+
return check(
|
|
2086
|
+
"warn",
|
|
2087
|
+
"plugin_version_drift",
|
|
2088
|
+
"Plugin/CLI version",
|
|
2089
|
+
`Plugin v${pluginVersion} \u2260 CLI v${currentVersion} \u2014 run \`${updateCmd}\``
|
|
2090
|
+
);
|
|
2066
2091
|
}
|
|
2067
2092
|
async function checkProfiles(home) {
|
|
2068
2093
|
const map = await parseDotenvFile(configPath(home));
|
|
@@ -2086,7 +2111,7 @@ async function checkProfiles(home) {
|
|
|
2086
2111
|
}
|
|
2087
2112
|
async function checkProjectLocalOverride(cwd) {
|
|
2088
2113
|
const dir = cwd ?? process.cwd();
|
|
2089
|
-
const envPath =
|
|
2114
|
+
const envPath = join17(dir, ".skillwiki", ".env");
|
|
2090
2115
|
if (existsSync3(envPath)) {
|
|
2091
2116
|
return check("pass", "project_local", "Project-local config", `Found: ${envPath}`);
|
|
2092
2117
|
}
|
|
@@ -2102,9 +2127,9 @@ function findSkillMd(dir) {
|
|
|
2102
2127
|
}
|
|
2103
2128
|
for (const entry of entries) {
|
|
2104
2129
|
if (entry.isFile() && entry.name === "SKILL.md") {
|
|
2105
|
-
results.push(
|
|
2130
|
+
results.push(join17(dir, entry.name));
|
|
2106
2131
|
} else if (entry.isDirectory()) {
|
|
2107
|
-
results.push(...findSkillMd(
|
|
2132
|
+
results.push(...findSkillMd(join17(dir, entry.name)));
|
|
2108
2133
|
}
|
|
2109
2134
|
}
|
|
2110
2135
|
return results;
|
|
@@ -2148,7 +2173,7 @@ async function runDoctor(input) {
|
|
|
2148
2173
|
|
|
2149
2174
|
// src/commands/archive.ts
|
|
2150
2175
|
import { rename as rename3, mkdir as mkdir5, readFile as readFile13, writeFile as writeFile6 } from "fs/promises";
|
|
2151
|
-
import { join as
|
|
2176
|
+
import { join as join18, dirname as dirname7 } from "path";
|
|
2152
2177
|
async function runArchive(input) {
|
|
2153
2178
|
const scan = await scanVault(input.vault);
|
|
2154
2179
|
if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
|
|
@@ -2160,10 +2185,10 @@ async function runArchive(input) {
|
|
|
2160
2185
|
}
|
|
2161
2186
|
if (!relPath) return { exitCode: ExitCode.ARCHIVE_TARGET_NOT_FOUND, result: err("ARCHIVE_TARGET_NOT_FOUND", { page: input.page }) };
|
|
2162
2187
|
if (relPath.startsWith("_archive/")) return { exitCode: ExitCode.ARCHIVE_ALREADY_ARCHIVED, result: err("ARCHIVE_ALREADY_ARCHIVED", { page: relPath }) };
|
|
2163
|
-
const archivePath =
|
|
2164
|
-
await mkdir5(dirname7(
|
|
2188
|
+
const archivePath = join18("_archive", relPath);
|
|
2189
|
+
await mkdir5(dirname7(join18(input.vault, archivePath)), { recursive: true });
|
|
2165
2190
|
let indexUpdated = false;
|
|
2166
|
-
const indexPath =
|
|
2191
|
+
const indexPath = join18(input.vault, "index.md");
|
|
2167
2192
|
try {
|
|
2168
2193
|
const idx = await readFile13(indexPath, "utf8");
|
|
2169
2194
|
const slug = relPath.replace(/\.md$/, "").split("/").pop();
|
|
@@ -2176,7 +2201,7 @@ async function runArchive(input) {
|
|
|
2176
2201
|
} catch (e) {
|
|
2177
2202
|
if (e?.code !== "ENOENT") throw e;
|
|
2178
2203
|
}
|
|
2179
|
-
await rename3(
|
|
2204
|
+
await rename3(join18(input.vault, relPath), join18(input.vault, archivePath));
|
|
2180
2205
|
return { exitCode: ExitCode.OK, result: ok({ archived_from: relPath, archived_to: archivePath, index_updated: indexUpdated, humanHint: `${relPath} -> ${archivePath}${indexUpdated ? " (index updated)" : ""}` }) };
|
|
2181
2206
|
}
|
|
2182
2207
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1-beta.2",
|
|
4
|
+
"version": "0.2.1-beta.2",
|
|
4
5
|
"skills": "./",
|
|
5
6
|
"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
7
|
"author": {
|