skillwiki 0.2.0-beta.20 → 0.2.0-beta.22
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 +193 -47
- package/package.json +3 -2
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/package.json +1 -1
- package/skills/using-skillwiki/SKILL.md +12 -0
package/dist/cli.js
CHANGED
|
@@ -71,7 +71,8 @@ var ExitCode = {
|
|
|
71
71
|
ARCHIVE_ALREADY_ARCHIVED: 31,
|
|
72
72
|
DRIFT_DETECTED: 32,
|
|
73
73
|
RAW_DEDUP_DETECTED: 33,
|
|
74
|
-
MIGRATION_APPLIED: 34
|
|
74
|
+
MIGRATION_APPLIED: 34,
|
|
75
|
+
UNKNOWN_WIKI_PROFILE: 35
|
|
75
76
|
};
|
|
76
77
|
|
|
77
78
|
// ../shared/src/json-output.ts
|
|
@@ -504,6 +505,16 @@ import { readFile as readFile4, writeFile as writeFile2, mkdir as mkdir2 } from
|
|
|
504
505
|
import { dirname as dirname2 } from "path";
|
|
505
506
|
var CONFIG_KEYS = ["WIKI_PATH", "WIKI_LANG"];
|
|
506
507
|
var _whitelist = new Set(CONFIG_KEYS);
|
|
508
|
+
var PROFILE_PATH_RE = /^WIKI_([A-Z][A-Z0-9_]{0,31})_PATH$/;
|
|
509
|
+
var PROFILE_LANG_RE = /^WIKI_([A-Z][A-Z0-9_]{0,31})_LANG$/;
|
|
510
|
+
var PROFILE_DEFAULT_RE = /^WIKI_DEFAULT$/;
|
|
511
|
+
function isValidWikiProfileKey(key) {
|
|
512
|
+
if (key === "WIKI_PATH" || key === "WIKI_LANG") return false;
|
|
513
|
+
return PROFILE_PATH_RE.test(key) || PROFILE_LANG_RE.test(key) || PROFILE_DEFAULT_RE.test(key);
|
|
514
|
+
}
|
|
515
|
+
function profileKey(name, suffix) {
|
|
516
|
+
return `WIKI_${name.toUpperCase().replace(/-/g, "_").replace(/[^A-Z0-9_]/g, "")}_${suffix}`;
|
|
517
|
+
}
|
|
507
518
|
function parseDotenvText(text) {
|
|
508
519
|
const out = {};
|
|
509
520
|
for (const rawLine of text.split(/\r?\n/)) {
|
|
@@ -513,7 +524,7 @@ function parseDotenvText(text) {
|
|
|
513
524
|
if (eq <= 0) continue;
|
|
514
525
|
const key = line.slice(0, eq).trim();
|
|
515
526
|
const value = line.slice(eq + 1).trim();
|
|
516
|
-
if (!_whitelist.has(key)) continue;
|
|
527
|
+
if (!_whitelist.has(key) && !isValidWikiProfileKey(key)) continue;
|
|
517
528
|
if (value.length === 0) continue;
|
|
518
529
|
out[key] = value;
|
|
519
530
|
}
|
|
@@ -598,6 +609,14 @@ async function resolveInitTimePath(input) {
|
|
|
598
609
|
return { path: hermes.WIKI_PATH, source: "hermes-dotenv", ...input.explain ? { chain } : {} };
|
|
599
610
|
}
|
|
600
611
|
if (input.explain) chain.push({ source: "hermes-dotenv", matched: false });
|
|
612
|
+
if (input.cwd) {
|
|
613
|
+
const projCfg = await parseDotenvFile(join2(input.cwd, ".skillwiki", ".env"));
|
|
614
|
+
if (projCfg.WIKI_PATH !== void 0) {
|
|
615
|
+
if (input.explain) chain.push({ source: "project-dotenv", matched: true, value: projCfg.WIKI_PATH });
|
|
616
|
+
return { path: projCfg.WIKI_PATH, source: "project-dotenv", ...input.explain ? { chain } : {} };
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
if (input.explain) chain.push({ source: "project-dotenv", matched: false });
|
|
601
620
|
const fallback = join2(input.home, "wiki");
|
|
602
621
|
if (input.explain) chain.push({ source: "default", matched: true, value: fallback });
|
|
603
622
|
return { path: fallback, source: "default", ...input.explain ? { chain } : {} };
|
|
@@ -609,15 +628,73 @@ async function resolveRuntimePath(input) {
|
|
|
609
628
|
return ok({ path: input.flag, source: "flag", ...input.explain ? { chain } : {} });
|
|
610
629
|
}
|
|
611
630
|
if (input.explain) chain.push({ source: "flag", matched: false });
|
|
631
|
+
const swGlobal = await parseDotenvFile(join2(input.home, ".skillwiki", ".env"));
|
|
632
|
+
const wikiName = input.wiki;
|
|
633
|
+
if (wikiName !== void 0 && wikiName.length > 0) {
|
|
634
|
+
if (wikiName.toLowerCase() === "default") {
|
|
635
|
+
const path2 = swGlobal.WIKI_PATH;
|
|
636
|
+
if (path2 !== void 0) {
|
|
637
|
+
if (input.explain) chain.push({ source: "wiki-profile", matched: true, value: path2 });
|
|
638
|
+
return ok({ path: path2, source: "skillwiki-dotenv", ...input.explain ? { chain } : {} });
|
|
639
|
+
}
|
|
640
|
+
if (input.explain) chain.push({ source: "wiki-profile", matched: false });
|
|
641
|
+
return err("UNKNOWN_WIKI_PROFILE", {
|
|
642
|
+
message: `Wiki profile "default" not found. Set it with: skillwiki config set wiki.path <dir>`
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
const key = profileKey(wikiName, "PATH");
|
|
646
|
+
const path = swGlobal[key];
|
|
647
|
+
if (path !== void 0) {
|
|
648
|
+
if (input.explain) chain.push({ source: "wiki-profile", matched: true, value: path });
|
|
649
|
+
return ok({ path, source: "wiki-profile", ...input.explain ? { chain } : {} });
|
|
650
|
+
}
|
|
651
|
+
if (input.explain) chain.push({ source: "wiki-profile", matched: false });
|
|
652
|
+
return err("UNKNOWN_WIKI_PROFILE", {
|
|
653
|
+
message: `Wiki profile "${wikiName}" not found. Set it with: skillwiki config set wiki.${wikiName}.path <dir>`
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
if (input.wikiEnv !== void 0 && input.wikiEnv.length > 0) {
|
|
657
|
+
const key = profileKey(input.wikiEnv, "PATH");
|
|
658
|
+
const path = swGlobal[key];
|
|
659
|
+
if (path !== void 0) {
|
|
660
|
+
if (input.explain) chain.push({ source: "wiki-profile", matched: true, value: path });
|
|
661
|
+
return ok({ path, source: "wiki-profile", ...input.explain ? { chain } : {} });
|
|
662
|
+
}
|
|
663
|
+
if (input.explain) chain.push({ source: "wiki-profile", matched: false });
|
|
664
|
+
return err("UNKNOWN_WIKI_PROFILE", {
|
|
665
|
+
message: `Wiki profile "${input.wikiEnv}" not found (from $WIKI env). Set it with: skillwiki config set wiki.${input.wikiEnv}.path <dir>`
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
if (input.explain) chain.push({ source: "wiki-profile", matched: false });
|
|
612
669
|
if (input.envValue !== void 0 && input.envValue.length > 0) {
|
|
613
670
|
if (input.explain) chain.push({ source: "env", matched: true, value: input.envValue });
|
|
614
671
|
return ok({ path: input.envValue, source: "env", ...input.explain ? { chain } : {} });
|
|
615
672
|
}
|
|
616
673
|
if (input.explain) chain.push({ source: "env", matched: false });
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
if (
|
|
620
|
-
|
|
674
|
+
if (input.cwd) {
|
|
675
|
+
const projCfg = await parseDotenvFile(join2(input.cwd, ".skillwiki", ".env"));
|
|
676
|
+
if (projCfg.WIKI_PATH !== void 0) {
|
|
677
|
+
if (input.explain) chain.push({ source: "project-dotenv", matched: true, value: projCfg.WIKI_PATH });
|
|
678
|
+
return ok({ path: projCfg.WIKI_PATH, source: "project-dotenv", ...input.explain ? { chain } : {} });
|
|
679
|
+
}
|
|
680
|
+
if (input.explain) chain.push({ source: "project-dotenv", matched: false });
|
|
681
|
+
}
|
|
682
|
+
const defaultProfile = swGlobal["WIKI_DEFAULT"];
|
|
683
|
+
if (defaultProfile !== void 0) {
|
|
684
|
+
const key = profileKey(defaultProfile, "PATH");
|
|
685
|
+
const path = swGlobal[key];
|
|
686
|
+
if (path !== void 0) {
|
|
687
|
+
if (input.explain) chain.push({ source: "wiki-default", matched: true, value: path });
|
|
688
|
+
return ok({ path, source: "wiki-default", ...input.explain ? { chain } : {} });
|
|
689
|
+
}
|
|
690
|
+
if (input.explain) chain.push({ source: "wiki-default", matched: false });
|
|
691
|
+
return err("UNKNOWN_WIKI_PROFILE", {
|
|
692
|
+
message: `Default wiki profile "${defaultProfile}" not found. Set it with: skillwiki config set wiki.${defaultProfile}.path <dir>`
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
if (swGlobal.WIKI_PATH !== void 0) {
|
|
696
|
+
if (input.explain) chain.push({ source: "skillwiki-dotenv", matched: true, value: swGlobal.WIKI_PATH });
|
|
697
|
+
return ok({ path: swGlobal.WIKI_PATH, source: "skillwiki-dotenv", ...input.explain ? { chain } : {} });
|
|
621
698
|
}
|
|
622
699
|
if (input.explain) chain.push({ source: "skillwiki-dotenv", matched: false });
|
|
623
700
|
return err("NO_VAULT_CONFIGURED", {
|
|
@@ -631,8 +708,11 @@ async function runOrphans(input) {
|
|
|
631
708
|
if (input.vault) {
|
|
632
709
|
vault = input.vault;
|
|
633
710
|
} else {
|
|
634
|
-
const r = await resolveRuntimePath({ flag: void 0, envValue: input.envValue, home: input.home ?? "" });
|
|
635
|
-
if (!r.ok)
|
|
711
|
+
const r = await resolveRuntimePath({ flag: void 0, envValue: input.envValue, home: input.home ?? "", wiki: input.wiki });
|
|
712
|
+
if (!r.ok) {
|
|
713
|
+
const exitCode = r.error === "UNKNOWN_WIKI_PROFILE" ? ExitCode.UNKNOWN_WIKI_PROFILE : ExitCode.NO_VAULT_CONFIGURED;
|
|
714
|
+
return { exitCode, result: r };
|
|
715
|
+
}
|
|
636
716
|
vault = r.data.path;
|
|
637
717
|
}
|
|
638
718
|
const scan = await scanVault(vault);
|
|
@@ -953,9 +1033,13 @@ async function runPath(input) {
|
|
|
953
1033
|
flag: input.flag,
|
|
954
1034
|
envValue: input.envValue,
|
|
955
1035
|
home: input.home,
|
|
1036
|
+
wiki: input.wiki,
|
|
956
1037
|
explain: input.explain
|
|
957
1038
|
});
|
|
958
|
-
if (!r.ok)
|
|
1039
|
+
if (!r.ok) {
|
|
1040
|
+
const exitCode = r.error === "UNKNOWN_WIKI_PROFILE" ? ExitCode.UNKNOWN_WIKI_PROFILE : ExitCode.NO_VAULT_CONFIGURED;
|
|
1041
|
+
return { exitCode, result: r };
|
|
1042
|
+
}
|
|
959
1043
|
return { exitCode: ExitCode.OK, result: ok({ path: r.data.path, source: r.data.source, ...r.data.chain ? { chain: r.data.chain } : {}, humanHint: `${r.data.path} (via ${r.data.source})` }) };
|
|
960
1044
|
}
|
|
961
1045
|
|
|
@@ -1124,13 +1208,13 @@ async function runInit(input) {
|
|
|
1124
1208
|
}
|
|
1125
1209
|
const existingEnv = parseDotenvText(existingEnvRaw);
|
|
1126
1210
|
const swDotenvHadPath = existingEnv.WIKI_PATH !== void 0;
|
|
1127
|
-
if (existingEnv.WIKI_PATH !== void 0 && existingEnv.WIKI_PATH !== target && !input.force) {
|
|
1211
|
+
if (!input.profile && existingEnv.WIKI_PATH !== void 0 && existingEnv.WIKI_PATH !== target && !input.force) {
|
|
1128
1212
|
return {
|
|
1129
1213
|
exitCode: ExitCode.ENV_WRITE_CONFLICT,
|
|
1130
1214
|
result: err("ENV_WRITE_CONFLICT", { key: "WIKI_PATH", existing: existingEnv.WIKI_PATH, attempted: target })
|
|
1131
1215
|
};
|
|
1132
1216
|
}
|
|
1133
|
-
if (existingEnv.WIKI_LANG !== void 0 && existingEnv.WIKI_LANG !== canonicalLang && !input.force) {
|
|
1217
|
+
if (!input.profile && existingEnv.WIKI_LANG !== void 0 && existingEnv.WIKI_LANG !== canonicalLang && !input.force) {
|
|
1134
1218
|
return {
|
|
1135
1219
|
exitCode: ExitCode.ENV_WRITE_CONFLICT,
|
|
1136
1220
|
result: err("ENV_WRITE_CONFLICT", { key: "WIKI_LANG", existing: existingEnv.WIKI_LANG, attempted: canonicalLang })
|
|
@@ -1209,7 +1293,16 @@ async function runInit(input) {
|
|
|
1209
1293
|
let envWritten = "";
|
|
1210
1294
|
if (!skipEnv) {
|
|
1211
1295
|
try {
|
|
1212
|
-
|
|
1296
|
+
const envEntries = {};
|
|
1297
|
+
if (input.profile) {
|
|
1298
|
+
envEntries[profileKey(input.profile, "PATH")] = target;
|
|
1299
|
+
envEntries[profileKey(input.profile, "LANG")] = canonicalLang;
|
|
1300
|
+
envEntries["WIKI_DEFAULT"] = input.profile;
|
|
1301
|
+
} else {
|
|
1302
|
+
envEntries["WIKI_PATH"] = target;
|
|
1303
|
+
envEntries["WIKI_LANG"] = canonicalLang;
|
|
1304
|
+
}
|
|
1305
|
+
await writeDotenv(envPath, envEntries, existingEnvRaw);
|
|
1213
1306
|
envWritten = envPath;
|
|
1214
1307
|
} catch (e) {
|
|
1215
1308
|
return { exitCode: ExitCode.WRITE_FAILED, result: err("WRITE_FAILED", { file: envPath, message: String(e) }) };
|
|
@@ -1636,7 +1729,7 @@ import { readFile as readFile12 } from "fs/promises";
|
|
|
1636
1729
|
import { existsSync } from "fs";
|
|
1637
1730
|
import { join as join13 } from "path";
|
|
1638
1731
|
function validateKey(key) {
|
|
1639
|
-
return CONFIG_KEYS.includes(key);
|
|
1732
|
+
return CONFIG_KEYS.includes(key) || isValidWikiProfileKey(key);
|
|
1640
1733
|
}
|
|
1641
1734
|
function configPath(home) {
|
|
1642
1735
|
return join13(home, ".skillwiki", ".env");
|
|
@@ -1671,7 +1764,21 @@ async function runConfigSet(input) {
|
|
|
1671
1764
|
async function runConfigList(input) {
|
|
1672
1765
|
const map = await parseDotenvFile(configPath(input.home));
|
|
1673
1766
|
const entries = Object.entries(map).map(([key, value]) => ({ key, value: value ?? "" }));
|
|
1674
|
-
|
|
1767
|
+
let profiles;
|
|
1768
|
+
if (input.profiles) {
|
|
1769
|
+
const defaultProfile = map["WIKI_DEFAULT"];
|
|
1770
|
+
profiles = [];
|
|
1771
|
+
for (const key of Object.keys(map)) {
|
|
1772
|
+
const m = key.match(/^WIKI_([A-Z][A-Z0-9_]{0,31})_PATH$/);
|
|
1773
|
+
if (m && key !== "WIKI_PATH") {
|
|
1774
|
+
const name = m[1].toLowerCase().replace(/_/g, "-");
|
|
1775
|
+
profiles.push({ name, path: map[key] ?? "", isDefault: name === defaultProfile });
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
profiles.sort((a, b) => a.name.localeCompare(b.name));
|
|
1779
|
+
}
|
|
1780
|
+
const hint = profiles ? profiles.map((p) => `${p.isDefault ? "* " : " "}${p.name} \u2192 ${p.path}`).join("\n") || "(no profiles)" : entries.map((e) => `${e.key}=${e.value}`).join("\n");
|
|
1781
|
+
return { exitCode: ExitCode.OK, result: ok({ entries, profiles, humanHint: hint }) };
|
|
1675
1782
|
}
|
|
1676
1783
|
async function runConfigPath(input) {
|
|
1677
1784
|
const filePath = configPath(input.home);
|
|
@@ -1855,6 +1962,34 @@ function checkPluginVersionDrift(home, currentVersion) {
|
|
|
1855
1962
|
return check("pass", "plugin_version_drift", "Plugin/CLI version", "Could not read plugin cache");
|
|
1856
1963
|
}
|
|
1857
1964
|
}
|
|
1965
|
+
async function checkProfiles(home) {
|
|
1966
|
+
const map = await parseDotenvFile(configPath(home));
|
|
1967
|
+
const profiles = [];
|
|
1968
|
+
for (const key of Object.keys(map)) {
|
|
1969
|
+
if (key.startsWith("WIKI_") && key.endsWith("_PATH") && key !== "WIKI_PATH") {
|
|
1970
|
+
const name = key.slice(5, -5).toLowerCase().replace(/_/g, "-");
|
|
1971
|
+
profiles.push(name);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
if (profiles.length === 0) {
|
|
1975
|
+
return check("pass", "wiki_profiles", "Wiki profiles", "No named profiles configured");
|
|
1976
|
+
}
|
|
1977
|
+
const defaultProfile = map["WIKI_DEFAULT"] ?? "(none)";
|
|
1978
|
+
return check(
|
|
1979
|
+
"pass",
|
|
1980
|
+
"wiki_profiles",
|
|
1981
|
+
"Wiki profiles",
|
|
1982
|
+
`${profiles.length} profile(s): ${profiles.join(", ")}; default: ${defaultProfile}`
|
|
1983
|
+
);
|
|
1984
|
+
}
|
|
1985
|
+
async function checkProjectLocalOverride(cwd) {
|
|
1986
|
+
const dir = cwd ?? process.cwd();
|
|
1987
|
+
const envPath = join15(dir, ".skillwiki", ".env");
|
|
1988
|
+
if (existsSync3(envPath)) {
|
|
1989
|
+
return check("pass", "project_local", "Project-local config", `Found: ${envPath}`);
|
|
1990
|
+
}
|
|
1991
|
+
return check("pass", "project_local", "Project-local config", "None");
|
|
1992
|
+
}
|
|
1858
1993
|
function findSkillMd(dir) {
|
|
1859
1994
|
const results = [];
|
|
1860
1995
|
let entries;
|
|
@@ -1877,6 +2012,8 @@ async function runDoctor(input) {
|
|
|
1877
2012
|
checks.push(checkNodeVersion());
|
|
1878
2013
|
checks.push(checkCliOnPath(input.argv));
|
|
1879
2014
|
checks.push(await checkConfigFile(input.home));
|
|
2015
|
+
checks.push(await checkProfiles(input.home));
|
|
2016
|
+
checks.push(await checkProjectLocalOverride(input.cwd));
|
|
1880
2017
|
const resolved = await resolveRuntimePath({ flag: void 0, envValue: input.envValue, home: input.home });
|
|
1881
2018
|
if (resolved.ok) {
|
|
1882
2019
|
checks.push(check("pass", "wiki_path_set", "WIKI_PATH configured", `Resolved via ${resolved.data.source}: ${resolved.data.path}`));
|
|
@@ -2243,19 +2380,20 @@ function emit(r) {
|
|
|
2243
2380
|
program.command("hash <file>").action(async (file) => emit(await runHash({ file })));
|
|
2244
2381
|
program.command("fetch-guard <url>").action(async (url) => emit(await runFetchGuard({ url })));
|
|
2245
2382
|
program.command("validate <file>").action(async (file) => emit(await runValidate({ file })));
|
|
2246
|
-
program.command("graph").description("graph subcommands").command("build <vault>").option("--out <path>", "graph output path", ".skillwiki/graph.json").action(async (vault, opts) => emit(await runGraphBuild({ vault, out: opts.out })));
|
|
2383
|
+
program.command("graph").description("graph subcommands").command("build <vault>").option("--out <path>", "graph output path", ".skillwiki/graph.json").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => emit(await runGraphBuild({ vault, out: opts.out })));
|
|
2247
2384
|
program.command("overlap <vault>").action(async (vault) => emit(await runOverlap({ vault })));
|
|
2248
|
-
program.command("orphans [vault]").action(async (vault) => emit(await runOrphans({
|
|
2385
|
+
program.command("orphans [vault]").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => emit(await runOrphans({
|
|
2249
2386
|
vault,
|
|
2250
2387
|
envValue: process.env.WIKI_PATH,
|
|
2251
|
-
home: process.env.HOME ?? ""
|
|
2388
|
+
home: process.env.HOME ?? "",
|
|
2389
|
+
wiki: opts.wiki
|
|
2252
2390
|
})));
|
|
2253
2391
|
program.command("audit <file>").action(async (file) => emit(await runAudit({ file })));
|
|
2254
2392
|
program.command("install").option("--target <dir>", "target install directory", `${process.env.HOME ?? ""}/.claude/skills/`).option("--dry-run", "preview only", false).option("--skills-root <dir>", "source skills directory (defaults to packaged)").action(async (opts) => {
|
|
2255
2393
|
const skillsRoot = opts.skillsRoot ?? new URL("../skills/", import.meta.url).pathname;
|
|
2256
2394
|
emit(await runInstall({ skillsRoot, target: opts.target, dryRun: !!opts.dryRun }));
|
|
2257
2395
|
});
|
|
2258
|
-
program.command("path").option("--vault <dir>", "explicit vault override (runtime)").option("--target <dir>", "explicit target override (init-time)").option("--init-time", "use init-time chain instead of runtime", false).option("--explain", "include resolution chain in output", false).action(async (opts) => {
|
|
2396
|
+
program.command("path").option("--vault <dir>", "explicit vault override (runtime)").option("--target <dir>", "explicit target override (init-time)").option("--wiki <name>", "wiki profile name").option("--init-time", "use init-time chain instead of runtime", false).option("--explain", "include resolution chain in output", false).action(async (opts) => {
|
|
2259
2397
|
const initTime = !!opts.initTime;
|
|
2260
2398
|
const flag = initTime ? opts.target : opts.vault;
|
|
2261
2399
|
emit(await runPath({
|
|
@@ -2263,6 +2401,7 @@ program.command("path").option("--vault <dir>", "explicit vault override (runtim
|
|
|
2263
2401
|
envValue: process.env.WIKI_PATH,
|
|
2264
2402
|
home: process.env.HOME ?? "",
|
|
2265
2403
|
initTime,
|
|
2404
|
+
wiki: opts.wiki,
|
|
2266
2405
|
explain: !!opts.explain
|
|
2267
2406
|
}));
|
|
2268
2407
|
});
|
|
@@ -2274,7 +2413,7 @@ program.command("lang").option("--lang <code>", "explicit language override").op
|
|
|
2274
2413
|
explain: !!opts.explain
|
|
2275
2414
|
}));
|
|
2276
2415
|
});
|
|
2277
|
-
program.command("init").option("--target <dir>", "explicit target directory").requiredOption("--domain <text>", "knowledge domain seed").option("--taxonomy <csv>", "comma-separated tag list").option("--lang <code>", "output language (BCP 47 or alias)").option("--force", "override existing target / env conflict", false).option("--no-env", "skip writing ~/.skillwiki/.env").action(async (opts) => {
|
|
2416
|
+
program.command("init").option("--target <dir>", "explicit target directory").requiredOption("--domain <text>", "knowledge domain seed").option("--taxonomy <csv>", "comma-separated tag list").option("--lang <code>", "output language (BCP 47 or alias)").option("--force", "override existing target / env conflict", false).option("--no-env", "skip writing ~/.skillwiki/.env").option("--profile <name>", "write as named wiki profile instead of WIKI_PATH").action(async (opts) => {
|
|
2278
2417
|
const templates = new URL("../templates/", import.meta.url).pathname;
|
|
2279
2418
|
const taxonomy = typeof opts.taxonomy === "string" ? opts.taxonomy.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : void 0;
|
|
2280
2419
|
emit(await runInit({
|
|
@@ -2286,51 +2425,57 @@ program.command("init").option("--target <dir>", "explicit target directory").re
|
|
|
2286
2425
|
taxonomy,
|
|
2287
2426
|
lang: opts.lang,
|
|
2288
2427
|
force: !!opts.force,
|
|
2289
|
-
noEnv: opts.env === false
|
|
2428
|
+
noEnv: opts.env === false,
|
|
2429
|
+
profile: opts.profile
|
|
2290
2430
|
}));
|
|
2291
2431
|
});
|
|
2292
|
-
async function resolveVaultArg(arg) {
|
|
2432
|
+
async function resolveVaultArg(arg, wiki) {
|
|
2293
2433
|
if (arg) return { ok: true, vault: arg };
|
|
2294
2434
|
const r = await resolveRuntimePath({
|
|
2295
2435
|
flag: void 0,
|
|
2296
2436
|
envValue: process.env.WIKI_PATH,
|
|
2297
|
-
|
|
2437
|
+
wikiEnv: process.env.WIKI,
|
|
2438
|
+
home: process.env.HOME ?? "",
|
|
2439
|
+
wiki
|
|
2298
2440
|
});
|
|
2299
|
-
if (!r.ok)
|
|
2441
|
+
if (!r.ok) {
|
|
2442
|
+
const exitCode = r.error === "UNKNOWN_WIKI_PROFILE" ? 35 : 25;
|
|
2443
|
+
return { ok: false, exitCode, payload: r };
|
|
2444
|
+
}
|
|
2300
2445
|
return { ok: true, vault: r.data.path };
|
|
2301
2446
|
}
|
|
2302
|
-
program.command("links [vault]").action(async (vault) => {
|
|
2303
|
-
const v = await resolveVaultArg(vault);
|
|
2447
|
+
program.command("links [vault]").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2448
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2304
2449
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2305
2450
|
else emit(await runLinks({ vault: v.vault }));
|
|
2306
2451
|
});
|
|
2307
|
-
program.command("tag-audit [vault]").action(async (vault) => {
|
|
2308
|
-
const v = await resolveVaultArg(vault);
|
|
2452
|
+
program.command("tag-audit [vault]").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2453
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2309
2454
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2310
2455
|
else emit(await runTagAudit({ vault: v.vault }));
|
|
2311
2456
|
});
|
|
2312
|
-
program.command("index-check [vault]").action(async (vault) => {
|
|
2313
|
-
const v = await resolveVaultArg(vault);
|
|
2457
|
+
program.command("index-check [vault]").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2458
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2314
2459
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2315
2460
|
else emit(await runIndexCheck({ vault: v.vault }));
|
|
2316
2461
|
});
|
|
2317
|
-
program.command("stale [vault]").option("--days <n>", "staleness threshold in days", (s) => parseInt(s, 10), 90).action(async (vault, opts) => {
|
|
2318
|
-
const v = await resolveVaultArg(vault);
|
|
2462
|
+
program.command("stale [vault]").option("--days <n>", "staleness threshold in days", (s) => parseInt(s, 10), 90).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2463
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2319
2464
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2320
2465
|
else emit(await runStale({ vault: v.vault, days: opts.days }));
|
|
2321
2466
|
});
|
|
2322
|
-
program.command("pagesize [vault]").option("--lines <n>", "max body lines", (s) => parseInt(s, 10), 200).action(async (vault, opts) => {
|
|
2323
|
-
const v = await resolveVaultArg(vault);
|
|
2467
|
+
program.command("pagesize [vault]").option("--lines <n>", "max body lines", (s) => parseInt(s, 10), 200).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2468
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2324
2469
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2325
2470
|
else emit(await runPagesize({ vault: v.vault, lines: opts.lines }));
|
|
2326
2471
|
});
|
|
2327
|
-
program.command("log-rotate [vault]").option("--threshold <n>", "entry count threshold", (s) => parseInt(s, 10), 500).option("--apply", "actually rotate", false).action(async (vault, opts) => {
|
|
2328
|
-
const v = await resolveVaultArg(vault);
|
|
2472
|
+
program.command("log-rotate [vault]").option("--threshold <n>", "entry count threshold", (s) => parseInt(s, 10), 500).option("--apply", "actually rotate", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2473
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2329
2474
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2330
2475
|
else emit(await runLogRotate({ vault: v.vault, threshold: opts.threshold, apply: !!opts.apply }));
|
|
2331
2476
|
});
|
|
2332
|
-
program.command("lint [vault]").option("--days <n>", "stale threshold", (s) => parseInt(s, 10), 90).option("--lines <n>", "pagesize threshold", (s) => parseInt(s, 10), 200).option("--log-threshold <n>", "log rotation threshold", (s) => parseInt(s, 10), 500).action(async (vault, opts) => {
|
|
2333
|
-
const v = await resolveVaultArg(vault);
|
|
2477
|
+
program.command("lint [vault]").option("--days <n>", "stale threshold", (s) => parseInt(s, 10), 90).option("--lines <n>", "pagesize threshold", (s) => parseInt(s, 10), 200).option("--log-threshold <n>", "log rotation threshold", (s) => parseInt(s, 10), 500).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2478
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2334
2479
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2335
2480
|
else emit(await runLint({
|
|
2336
2481
|
vault: v.vault,
|
|
@@ -2343,31 +2488,32 @@ program.command("lint [vault]").option("--days <n>", "stale threshold", (s) => p
|
|
|
2343
2488
|
var configCmd = program.command("config").description("manage skillwiki configuration");
|
|
2344
2489
|
configCmd.command("get <key>").description("print the value of a config key").action(async (key) => emit(await runConfigGet({ key, home: process.env.HOME ?? "" })));
|
|
2345
2490
|
configCmd.command("set <key> <value>").description("set a config key value").action(async (key, value) => emit(await runConfigSet({ key, value, home: process.env.HOME ?? "" })));
|
|
2346
|
-
configCmd.command("list").description("list all config key=value pairs").action(async () => emit(await runConfigList({ home: process.env.HOME ?? "" })));
|
|
2491
|
+
configCmd.command("list").option("--profiles", "show wiki profiles summary", false).description("list all config key=value pairs").action(async (opts) => emit(await runConfigList({ home: process.env.HOME ?? "", profiles: !!opts.profiles })));
|
|
2347
2492
|
configCmd.command("path").description("print the config file path").action(async () => emit(await runConfigPath({ home: process.env.HOME ?? "" })));
|
|
2348
2493
|
program.command("doctor").description("diagnose skillwiki setup issues").action(async () => emit(await runDoctor({
|
|
2349
2494
|
home: process.env.HOME ?? "",
|
|
2350
2495
|
envValue: process.env.WIKI_PATH,
|
|
2351
2496
|
argv: process.argv,
|
|
2352
|
-
currentVersion: pkg.version
|
|
2497
|
+
currentVersion: pkg.version,
|
|
2498
|
+
cwd: process.cwd()
|
|
2353
2499
|
})));
|
|
2354
|
-
program.command("archive <page> [vault]").description("archive a typed-knowledge page").action(async (page, vault) => {
|
|
2355
|
-
const v = await resolveVaultArg(vault);
|
|
2500
|
+
program.command("archive <page> [vault]").description("archive a typed-knowledge page").option("--wiki <name>", "wiki profile name").action(async (page, vault, opts) => {
|
|
2501
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2356
2502
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2357
2503
|
else emit(await runArchive({ vault: v.vault, page }));
|
|
2358
2504
|
});
|
|
2359
|
-
program.command("drift [vault]").description("detect content drift in raw sources").action(async (vault) => {
|
|
2360
|
-
const v = await resolveVaultArg(vault);
|
|
2505
|
+
program.command("drift [vault]").description("detect content drift in raw sources").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2506
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2361
2507
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2362
2508
|
else emit(await runDrift({ vault: v.vault }));
|
|
2363
2509
|
});
|
|
2364
|
-
program.command("dedup [vault]").description("detect duplicate raw sources by sha256").action(async (vault) => {
|
|
2365
|
-
const v = await resolveVaultArg(vault);
|
|
2510
|
+
program.command("dedup [vault]").description("detect duplicate raw sources by sha256").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2511
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2366
2512
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2367
2513
|
else emit(await runDedup({ vault: v.vault }));
|
|
2368
2514
|
});
|
|
2369
|
-
program.command("migrate-citations [vault]").description("migrate ^[raw/...] markers to paragraph-end citations").option("--dry-run", "preview changes without writing", false).action(async (vault, opts) => {
|
|
2370
|
-
const v = await resolveVaultArg(vault);
|
|
2515
|
+
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) => {
|
|
2516
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2371
2517
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2372
2518
|
else emit(await runMigrateCitations({ vault: v.vault, dryRun: !!opts.dryRun }));
|
|
2373
2519
|
});
|
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.22",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"skillwiki": "dist/cli.js"
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"build": "tsup && rm -rf ./skills && cp -r ../skills ./skills",
|
|
16
16
|
"test": "vitest run",
|
|
17
17
|
"test:watch": "vitest",
|
|
18
|
-
"typecheck": "tsc --noEmit"
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
19
20
|
},
|
|
20
21
|
"dependencies": {
|
|
21
22
|
"commander": "^12.1.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.22",
|
|
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
|
@@ -88,3 +88,15 @@ Run `skillwiki doctor` to diagnose setup issues. Run `skillwiki config list` to
|
|
|
88
88
|
For longer-running project work, use `proj-init` → `proj-work` → `proj-distill` / `proj-decide`.
|
|
89
89
|
|
|
90
90
|
Maintenance: **Archive** (`wiki-archive`) superseded pages, **Drift** (`wiki-reingest`) to detect stale sources, **Adapter** (`wiki-adapter-prd`) for foreign PRD format ingestion.
|
|
91
|
+
|
|
92
|
+
## Multi-Wiki Profiles
|
|
93
|
+
|
|
94
|
+
skillwiki supports named wiki profiles for working with multiple vaults. Set `WIKI_DEFAULT` to control which wiki all skills target by default.
|
|
95
|
+
|
|
96
|
+
**Manage profiles:**
|
|
97
|
+
- `skillwiki config set wiki.<name>.path <dir>` — register a profile
|
|
98
|
+
- `skillwiki config set default <name>` — set active profile
|
|
99
|
+
- `skillwiki config list --profiles` — list all profiles
|
|
100
|
+
- `skillwiki --wiki <name> lint` — override per-command
|
|
101
|
+
|
|
102
|
+
**Project-local override:** Place a `./skillwiki/.env` in a project root to bind that project to a specific wiki. Skills will use it automatically when running from that directory.
|