skillwiki 0.9.47 → 0.9.49
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/{chunk-MI4BZI7Q.js → chunk-4Q7MANQI.js} +143 -102
- package/dist/cli.js +3 -1
- package/dist/skillwiki-mcp.js +1 -1
- package/package.json +1 -1
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/.codex-plugin/plugin.json +1 -1
- package/skills/package.json +1 -1
- package/skills/skills/using-skillwiki/SKILL.md +3 -1
- package/skills/using-skillwiki/SKILL.md +3 -1
|
@@ -659,6 +659,7 @@ import { writeFile as writeFile2, mkdir } from "fs/promises";
|
|
|
659
659
|
import { dirname } from "path";
|
|
660
660
|
|
|
661
661
|
// src/utils/vault.ts
|
|
662
|
+
import { existsSync, readFileSync } from "fs";
|
|
662
663
|
import { readFile as readFile2, readdir, stat } from "fs/promises";
|
|
663
664
|
import { join as join2, relative as relative2, sep as sep2 } from "path";
|
|
664
665
|
var TYPED_DIRS = ["entities", "concepts", "comparisons", "queries", "meta"];
|
|
@@ -668,6 +669,40 @@ function vaultIoConcurrency() {
|
|
|
668
669
|
const raw = Number.parseInt(process.env.SKILLWIKI_VAULT_IO_CONCURRENCY ?? "", 10);
|
|
669
670
|
return Number.isFinite(raw) && raw > 0 ? Math.min(raw, 64) : DEFAULT_IO_CONCURRENCY;
|
|
670
671
|
}
|
|
672
|
+
function decodeProcMountPath(value) {
|
|
673
|
+
return value.replace(/\\040/g, " ");
|
|
674
|
+
}
|
|
675
|
+
function isRcloneFuseVaultFromMounts(root, mounts) {
|
|
676
|
+
return mounts.split(/\r?\n/).some((line) => {
|
|
677
|
+
const parts = line.split(" ");
|
|
678
|
+
if (parts.length < 3) return false;
|
|
679
|
+
const mountPoint = decodeProcMountPath(parts[1]);
|
|
680
|
+
const fsType = parts[2];
|
|
681
|
+
return fsType === "fuse.rclone" && (root === mountPoint || root.startsWith(`${mountPoint}/`));
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
function resolveReadOnlyVaultRootWithMounts(root, mounts) {
|
|
685
|
+
if (/^(1|true|yes)$/i.test(process.env.SKILLWIKI_DISABLE_VAULT_READ_MIRROR ?? "")) {
|
|
686
|
+
return { root, mirrored: false };
|
|
687
|
+
}
|
|
688
|
+
const explicitMirror = process.env.SKILLWIKI_VAULT_READ_MIRROR;
|
|
689
|
+
if (explicitMirror && existsSync(join2(explicitMirror, "SCHEMA.md"))) {
|
|
690
|
+
return { root: explicitMirror, mirrored: explicitMirror !== root };
|
|
691
|
+
}
|
|
692
|
+
const siblingMirror = `${root}-git`;
|
|
693
|
+
if (isRcloneFuseVaultFromMounts(root, mounts) && existsSync(join2(siblingMirror, "SCHEMA.md"))) {
|
|
694
|
+
return { root: siblingMirror, mirrored: true };
|
|
695
|
+
}
|
|
696
|
+
return { root, mirrored: false };
|
|
697
|
+
}
|
|
698
|
+
function resolveReadOnlyVaultRoot(root) {
|
|
699
|
+
let mounts = "";
|
|
700
|
+
try {
|
|
701
|
+
mounts = readFileSync("/proc/mounts", "utf8");
|
|
702
|
+
} catch {
|
|
703
|
+
}
|
|
704
|
+
return resolveReadOnlyVaultRootWithMounts(root, mounts);
|
|
705
|
+
}
|
|
671
706
|
async function mapWithConcurrency(items, limit, mapper) {
|
|
672
707
|
const out = new Array(items.length);
|
|
673
708
|
let next = 0;
|
|
@@ -1334,7 +1369,7 @@ function hasWikilinkCitations(body) {
|
|
|
1334
1369
|
}
|
|
1335
1370
|
|
|
1336
1371
|
// src/utils/raw-source.ts
|
|
1337
|
-
import { existsSync } from "fs";
|
|
1372
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1338
1373
|
import { stat as stat2 } from "fs/promises";
|
|
1339
1374
|
import { join as join4 } from "path";
|
|
1340
1375
|
function normalizeRawSourceTarget(entry) {
|
|
@@ -1355,7 +1390,7 @@ function rawSourceTargetCandidates(vault, target) {
|
|
|
1355
1390
|
return [...new Set(candidates)];
|
|
1356
1391
|
}
|
|
1357
1392
|
function rawSourceTargetExistsSync(vault, target) {
|
|
1358
|
-
return rawSourceTargetCandidates(vault, target).some((candidate) =>
|
|
1393
|
+
return rawSourceTargetCandidates(vault, target).some((candidate) => existsSync2(candidate));
|
|
1359
1394
|
}
|
|
1360
1395
|
async function rawSourceTargetExists(vault, target) {
|
|
1361
1396
|
for (const candidate of rawSourceTargetCandidates(vault, target)) {
|
|
@@ -1666,7 +1701,7 @@ function parseExpiryAnnotations(content, pagePath) {
|
|
|
1666
1701
|
}
|
|
1667
1702
|
|
|
1668
1703
|
// src/utils/last-op.ts
|
|
1669
|
-
import { readFileSync, writeFileSync, mkdirSync, unlinkSync, existsSync as
|
|
1704
|
+
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, unlinkSync, existsSync as existsSync3 } from "fs";
|
|
1670
1705
|
import { join as join8 } from "path";
|
|
1671
1706
|
var LAST_OP_DIR = ".skillwiki";
|
|
1672
1707
|
var LAST_OP_FILE = "last-op.json";
|
|
@@ -1675,9 +1710,9 @@ function lastOpPath(vault) {
|
|
|
1675
1710
|
}
|
|
1676
1711
|
function readLastOp(vault) {
|
|
1677
1712
|
const p = lastOpPath(vault);
|
|
1678
|
-
if (!
|
|
1713
|
+
if (!existsSync3(p)) return [];
|
|
1679
1714
|
try {
|
|
1680
|
-
const raw =
|
|
1715
|
+
const raw = readFileSync2(p, "utf8");
|
|
1681
1716
|
const parsed = JSON.parse(raw);
|
|
1682
1717
|
if (!Array.isArray(parsed)) {
|
|
1683
1718
|
unlinkSync(p);
|
|
@@ -1696,7 +1731,7 @@ function appendLastOp(vault, entry) {
|
|
|
1696
1731
|
const existing = readLastOp(vault);
|
|
1697
1732
|
existing.push(entry);
|
|
1698
1733
|
const dir = join8(vault, LAST_OP_DIR);
|
|
1699
|
-
if (!
|
|
1734
|
+
if (!existsSync3(dir)) mkdirSync(dir, { recursive: true });
|
|
1700
1735
|
writeFileSync(lastOpPath(vault), JSON.stringify(existing, null, 2), "utf8");
|
|
1701
1736
|
}
|
|
1702
1737
|
function clearLastOp(vault) {
|
|
@@ -2142,7 +2177,7 @@ ${markdown_links.map((l) => ` line ${l.line}: ${l.text}`).join("\n")}`;
|
|
|
2142
2177
|
|
|
2143
2178
|
// src/commands/dedup.ts
|
|
2144
2179
|
import { createHash as createHash2 } from "crypto";
|
|
2145
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
2180
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
|
|
2146
2181
|
import { dirname as dirname4, join as join12, resolve as resolve3 } from "path";
|
|
2147
2182
|
|
|
2148
2183
|
// src/utils/rclone.ts
|
|
@@ -2262,7 +2297,7 @@ async function runDedup(input) {
|
|
|
2262
2297
|
}
|
|
2263
2298
|
}
|
|
2264
2299
|
for (const page of scan.allMarkdown.filter((p) => !p.relPath.startsWith("raw/"))) {
|
|
2265
|
-
const text =
|
|
2300
|
+
const text = readFileSync3(join12(input.vault, page.relPath), "utf-8");
|
|
2266
2301
|
let updated = text;
|
|
2267
2302
|
let changed = false;
|
|
2268
2303
|
for (const [oldPath, newPath] of replacements) {
|
|
@@ -2379,14 +2414,14 @@ function buildSafeEntries(vault, duplicates, unsafe) {
|
|
|
2379
2414
|
return entries;
|
|
2380
2415
|
}
|
|
2381
2416
|
function hashRawBody(vault, relPath) {
|
|
2382
|
-
const text =
|
|
2417
|
+
const text = readFileSync3(join12(vault, relPath), "utf-8");
|
|
2383
2418
|
const split = splitFrontmatter(text);
|
|
2384
2419
|
const body = split.ok ? split.data.body : text;
|
|
2385
2420
|
return createHash2("sha256").update(body).digest("hex");
|
|
2386
2421
|
}
|
|
2387
2422
|
function readManifest(path) {
|
|
2388
2423
|
try {
|
|
2389
|
-
const parsed = JSON.parse(
|
|
2424
|
+
const parsed = JSON.parse(readFileSync3(path, "utf-8"));
|
|
2390
2425
|
if (parsed.version !== 1 || !Array.isArray(parsed.entries)) {
|
|
2391
2426
|
return err("INVALID_FRONTMATTER", { message: "dedup manifest must have version 1 and entries[]" });
|
|
2392
2427
|
}
|
|
@@ -2553,7 +2588,7 @@ ${newBody}`;
|
|
|
2553
2588
|
}
|
|
2554
2589
|
|
|
2555
2590
|
// src/commands/lint.ts
|
|
2556
|
-
import { existsSync as
|
|
2591
|
+
import { existsSync as existsSync5 } from "fs";
|
|
2557
2592
|
import { readFile as readFile12, readdir as readdir3 } from "fs/promises";
|
|
2558
2593
|
import { createHash as createHash4 } from "crypto";
|
|
2559
2594
|
import { join as join15, relative as relative3, sep as sep3 } from "path";
|
|
@@ -2613,7 +2648,7 @@ async function runRawBodyDedup(vault, scan, pageTextCache) {
|
|
|
2613
2648
|
}
|
|
2614
2649
|
|
|
2615
2650
|
// src/commands/path-too-long.ts
|
|
2616
|
-
import { existsSync as
|
|
2651
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2617
2652
|
import { mkdir as mkdir4, readFile as readFile11, rename as rename4, unlink as unlink2 } from "fs/promises";
|
|
2618
2653
|
import { dirname as dirname6, join as join14, posix, resolve as resolve4 } from "path";
|
|
2619
2654
|
var MAX_PATH_LENGTH = 240;
|
|
@@ -2729,7 +2764,7 @@ async function resolveFixTarget(vault, original, preferred, maxLength) {
|
|
|
2729
2764
|
for (const candidate of candidateRelPaths(preferred, maxLength)) {
|
|
2730
2765
|
if (candidate === original || candidate.length > maxLength) continue;
|
|
2731
2766
|
const candidatePath = join14(vault, candidate);
|
|
2732
|
-
if (!
|
|
2767
|
+
if (!existsSync4(candidatePath)) return { relPath: candidate, mode: "rename" };
|
|
2733
2768
|
if (await hasSameContent(join14(vault, original), candidatePath)) {
|
|
2734
2769
|
return { relPath: candidate, mode: "dedupe" };
|
|
2735
2770
|
}
|
|
@@ -3126,6 +3161,9 @@ ${match.length === 0 ? "0 violations" : match.map((b) => ` ${b.kind}: ${b.items
|
|
|
3126
3161
|
result: ok(input.summary ? summarizeLintOutput(output, input.examplesLimit) : output)
|
|
3127
3162
|
};
|
|
3128
3163
|
}
|
|
3164
|
+
function lintReadVault(input) {
|
|
3165
|
+
return input.fix ? input.vault : resolveReadOnlyVaultRoot(input.vault).root;
|
|
3166
|
+
}
|
|
3129
3167
|
function recomputeRawSha256IfPresent(content) {
|
|
3130
3168
|
const split = splitFrontmatter(content);
|
|
3131
3169
|
if (!split.ok) return content;
|
|
@@ -3188,19 +3226,20 @@ async function walkMarkdownFiles(absDir, vaultRoot) {
|
|
|
3188
3226
|
return pages;
|
|
3189
3227
|
}
|
|
3190
3228
|
async function collectCliRefsPages(vault) {
|
|
3191
|
-
if (!
|
|
3229
|
+
if (!existsSync5(join15(vault, "SCHEMA.md"))) {
|
|
3192
3230
|
return err("VAULT_PATH_INVALID", { root: vault, reason: "SCHEMA.md missing" });
|
|
3193
3231
|
}
|
|
3194
3232
|
const pages = [];
|
|
3195
3233
|
for (const dir of CLI_REFS_TYPED_DIRS) {
|
|
3196
3234
|
const absDir = join15(vault, dir);
|
|
3197
|
-
if (!
|
|
3235
|
+
if (!existsSync5(absDir)) continue;
|
|
3198
3236
|
pages.push(...await walkMarkdownFiles(absDir, vault));
|
|
3199
3237
|
}
|
|
3200
3238
|
return ok(pages);
|
|
3201
3239
|
}
|
|
3202
3240
|
async function runCliRefsOnly(input) {
|
|
3203
|
-
const
|
|
3241
|
+
const lintVault = lintReadVault(input);
|
|
3242
|
+
const pages = await collectCliRefsPages(lintVault);
|
|
3204
3243
|
if (!pages.ok) {
|
|
3205
3244
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: pages };
|
|
3206
3245
|
}
|
|
@@ -3358,7 +3397,8 @@ async function applyFileSourceUrlFix(input, scan, fileSourceUrlFlags, fileSource
|
|
|
3358
3397
|
return remaining;
|
|
3359
3398
|
}
|
|
3360
3399
|
async function runFileSourceUrlOnly(input) {
|
|
3361
|
-
const
|
|
3400
|
+
const lintVault = lintReadVault(input);
|
|
3401
|
+
const scanResult = await scanVault(lintVault);
|
|
3362
3402
|
if (!scanResult.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scanResult };
|
|
3363
3403
|
const pageTextCache = /* @__PURE__ */ new Map();
|
|
3364
3404
|
const fixed = [];
|
|
@@ -3389,10 +3429,11 @@ async function runLint(input) {
|
|
|
3389
3429
|
return runFileSourceUrlOnly(input);
|
|
3390
3430
|
}
|
|
3391
3431
|
const shouldFix = (bucket) => !!input.fix && (!input.only || input.only === bucket);
|
|
3432
|
+
const lintVault = lintReadVault(input);
|
|
3392
3433
|
const buckets = {};
|
|
3393
3434
|
const fixed = [];
|
|
3394
3435
|
const unresolved = [];
|
|
3395
|
-
const scanResult = await scanVault(
|
|
3436
|
+
const scanResult = await scanVault(lintVault);
|
|
3396
3437
|
if (!scanResult.ok) {
|
|
3397
3438
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scanResult };
|
|
3398
3439
|
}
|
|
@@ -3406,64 +3447,64 @@ async function runLint(input) {
|
|
|
3406
3447
|
}
|
|
3407
3448
|
});
|
|
3408
3449
|
}
|
|
3409
|
-
const links = await runLinks({ vault:
|
|
3450
|
+
const links = await runLinks({ vault: lintVault, scan, pageTextCache });
|
|
3410
3451
|
if (links.result.ok && links.result.data.broken.length > 0) buckets.broken_wikilinks = links.result.data.broken;
|
|
3411
3452
|
if (!links.result.ok && links.result.error === "INVALID_FRONTMATTER") {
|
|
3412
3453
|
buckets.invalid_frontmatter = [links.result.detail ?? {}];
|
|
3413
3454
|
}
|
|
3414
|
-
const tags = await runTagAudit({ vault:
|
|
3455
|
+
const tags = await runTagAudit({ vault: lintVault, scan, pageTextCache });
|
|
3415
3456
|
if (tags.result.ok && tags.result.data.violations.length > 0) buckets.tag_not_in_taxonomy = tags.result.data.violations;
|
|
3416
3457
|
if (!tags.result.ok && tags.result.error === "INVALID_FRONTMATTER") {
|
|
3417
3458
|
buckets.invalid_frontmatter = [...buckets.invalid_frontmatter ?? [], tags.result.detail ?? {}];
|
|
3418
3459
|
}
|
|
3419
|
-
const idx = await runIndexCheck({ vault:
|
|
3460
|
+
const idx = await runIndexCheck({ vault: lintVault, scan });
|
|
3420
3461
|
if (idx.result.ok && (idx.result.data.missing_from_index.length > 0 || idx.result.data.ghost_entries.length > 0)) {
|
|
3421
3462
|
buckets.index_incomplete = [{
|
|
3422
3463
|
missing_from_index: idx.result.data.missing_from_index,
|
|
3423
3464
|
ghost_entries: idx.result.data.ghost_entries
|
|
3424
3465
|
}];
|
|
3425
3466
|
}
|
|
3426
|
-
const linkFmt = await runIndexLinkFormat({ vault:
|
|
3467
|
+
const linkFmt = await runIndexLinkFormat({ vault: lintVault });
|
|
3427
3468
|
if (linkFmt.result.ok && linkFmt.result.data.markdown_links.length > 0) {
|
|
3428
3469
|
buckets.index_link_format = linkFmt.result.data.markdown_links;
|
|
3429
3470
|
}
|
|
3430
|
-
const staleResult = await runStale({ vault:
|
|
3471
|
+
const staleResult = await runStale({ vault: lintVault, days: input.days, scan, pageTextCache });
|
|
3431
3472
|
if (staleResult.result.ok) {
|
|
3432
3473
|
const st = staleResult.result.data;
|
|
3433
3474
|
const staleList = [...st.stale_transcripts.map((t) => t.path), ...(st.unclaimed_transcripts ?? []).map((t) => t.path), ...st.incomplete_work_items.map((w) => w.path), ...(st.done_work_items ?? []).map((w) => w.path)];
|
|
3434
3475
|
if (staleList.length > 0) buckets.stale_page = staleList;
|
|
3435
3476
|
}
|
|
3436
|
-
const pagesize = await runPagesize({ vault:
|
|
3477
|
+
const pagesize = await runPagesize({ vault: lintVault, lines: input.lines, scan, pageTextCache });
|
|
3437
3478
|
if (pagesize.result.ok && pagesize.result.data.oversized.length > 0) buckets.page_too_large = pagesize.result.data.oversized;
|
|
3438
|
-
const rotate = await runLogRotate({ vault:
|
|
3479
|
+
const rotate = await runLogRotate({ vault: lintVault, threshold: input.logThreshold, apply: false });
|
|
3439
3480
|
if (rotate.result.ok && rotate.exitCode === ExitCode.LOG_ROTATE_NEEDED) {
|
|
3440
3481
|
buckets.log_rotate_needed = [{ entries: rotate.result.data.entries, threshold: rotate.result.data.threshold }];
|
|
3441
3482
|
}
|
|
3442
|
-
const orphans = await runOrphans({ vault:
|
|
3483
|
+
const orphans = await runOrphans({ vault: lintVault, scan, pageTextCache });
|
|
3443
3484
|
if (orphans.result.ok) {
|
|
3444
3485
|
if (orphans.result.data.orphans.length > 0) buckets.orphans = orphans.result.data.orphans;
|
|
3445
3486
|
if (orphans.result.data.bridges.length > 0) buckets.bridges = orphans.result.data.bridges;
|
|
3446
3487
|
}
|
|
3447
|
-
const sparse = await runSparseCommunity({ vault:
|
|
3488
|
+
const sparse = await runSparseCommunity({ vault: lintVault, scan, pageTextCache });
|
|
3448
3489
|
if (sparse.result.ok && sparse.result.data.communities.length > 0) {
|
|
3449
3490
|
buckets.sparse_community = sparse.result.data.communities;
|
|
3450
3491
|
}
|
|
3451
|
-
const topicMap = await runTopicMapCheck({ vault:
|
|
3492
|
+
const topicMap = await runTopicMapCheck({ vault: lintVault, scan });
|
|
3452
3493
|
if (topicMap.result.ok && topicMap.result.data.recommended) {
|
|
3453
3494
|
buckets.topic_map_recommended = [{ page_count: topicMap.result.data.page_count, threshold: topicMap.result.data.threshold }];
|
|
3454
3495
|
}
|
|
3455
|
-
const dedup = await runDedup({ vault:
|
|
3496
|
+
const dedup = await runDedup({ vault: lintVault, scan, pageTextCache });
|
|
3456
3497
|
if (dedup.result.ok && dedup.result.data.duplicates.length > 0) buckets.raw_dedup = dedup.result.data.duplicates;
|
|
3457
|
-
const bodyDedup = await runRawBodyDedup(
|
|
3498
|
+
const bodyDedup = await runRawBodyDedup(lintVault, scan, pageTextCache);
|
|
3458
3499
|
if (bodyDedup.result.ok && bodyDedup.result.data.duplicates.length > 0) {
|
|
3459
3500
|
buckets.raw_body_duplicate = bodyDedup.result.data.duplicates.map((d) => ({
|
|
3460
3501
|
body_hash: d.bodyHash.slice(0, 12),
|
|
3461
3502
|
files: d.files.map((f) => `${f.relPath} (sha256: ${f.sha256 ?? "none"})`)
|
|
3462
3503
|
}));
|
|
3463
3504
|
}
|
|
3464
|
-
const compoundRefs = await validateCompoundReferences(
|
|
3505
|
+
const compoundRefs = await validateCompoundReferences(lintVault, scan, pageTextCache);
|
|
3465
3506
|
if (compoundRefs.ok && compoundRefs.data.length > 0) buckets.compound_refs = compoundRefs.data;
|
|
3466
|
-
const pathCheck = await runPathTooLong({ vault:
|
|
3507
|
+
const pathCheck = await runPathTooLong({ vault: lintVault, scan });
|
|
3467
3508
|
if (pathCheck.result.ok && pathCheck.result.data.violations.length > 0) buckets.path_too_long = pathCheck.result.data.violations;
|
|
3468
3509
|
const allPages = [...scan.typedKnowledge, ...scan.raw, ...scan.workItems, ...scan.compound];
|
|
3469
3510
|
const slugs = buildSlugMap(allPages);
|
|
@@ -3553,12 +3594,12 @@ async function runLint(input) {
|
|
|
3553
3594
|
for (const entry of sourcesEntries) {
|
|
3554
3595
|
const rawPath = normalizeRawSourceTarget(entry);
|
|
3555
3596
|
if (!rawPath) continue;
|
|
3556
|
-
if (!rawSourceTargetExistsSync(
|
|
3597
|
+
if (!rawSourceTargetExistsSync(lintVault, rawPath)) {
|
|
3557
3598
|
result.brokenSourceFlags.push(`${page.relPath}: ${rawPath}`);
|
|
3558
3599
|
}
|
|
3559
3600
|
}
|
|
3560
3601
|
for (const marker of extractCitationMarkers(body)) {
|
|
3561
|
-
if (!rawSourceTargetExistsSync(
|
|
3602
|
+
if (!rawSourceTargetExistsSync(lintVault, marker.target)) {
|
|
3562
3603
|
result.brokenSourceFlags.push(`${page.relPath}: ${marker.target}`);
|
|
3563
3604
|
}
|
|
3564
3605
|
}
|
|
@@ -3661,8 +3702,8 @@ async function runLint(input) {
|
|
|
3661
3702
|
const readKnowledgeContent = (slug) => {
|
|
3662
3703
|
const existing = knowledgeContentCache.get(slug);
|
|
3663
3704
|
if (existing) return existing;
|
|
3664
|
-
const knowledgePath = join15(
|
|
3665
|
-
const pending =
|
|
3705
|
+
const knowledgePath = join15(lintVault, "projects", slug, "knowledge.md");
|
|
3706
|
+
const pending = existsSync5(knowledgePath) ? readFile12(knowledgePath, "utf8").catch(() => null) : Promise.resolve(null);
|
|
3666
3707
|
knowledgeContentCache.set(slug, pending);
|
|
3667
3708
|
return pending;
|
|
3668
3709
|
};
|
|
@@ -4145,7 +4186,7 @@ ${split.data.body}`;
|
|
|
4145
4186
|
|
|
4146
4187
|
// src/commands/config.ts
|
|
4147
4188
|
import { readFile as readFile13 } from "fs/promises";
|
|
4148
|
-
import { existsSync as
|
|
4189
|
+
import { existsSync as existsSync6 } from "fs";
|
|
4149
4190
|
import { join as join16 } from "path";
|
|
4150
4191
|
function validateKey(key) {
|
|
4151
4192
|
return CONFIG_KEYS.includes(key) || isValidWikiProfileKey(key);
|
|
@@ -4201,11 +4242,11 @@ async function runConfigList(input) {
|
|
|
4201
4242
|
}
|
|
4202
4243
|
async function runConfigPath(input) {
|
|
4203
4244
|
const filePath = configPath(input.home);
|
|
4204
|
-
return { exitCode: ExitCode.OK, result: ok({ path: filePath, exists:
|
|
4245
|
+
return { exitCode: ExitCode.OK, result: ok({ path: filePath, exists: existsSync6(filePath), humanHint: filePath }) };
|
|
4205
4246
|
}
|
|
4206
4247
|
|
|
4207
4248
|
// src/utils/auto-update.ts
|
|
4208
|
-
import { readFileSync as
|
|
4249
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
|
|
4209
4250
|
import { join as join17, dirname as dirname7 } from "path";
|
|
4210
4251
|
import { spawn } from "child_process";
|
|
4211
4252
|
function cachePath(home) {
|
|
@@ -4213,7 +4254,7 @@ function cachePath(home) {
|
|
|
4213
4254
|
}
|
|
4214
4255
|
function readCacheRaw(home) {
|
|
4215
4256
|
try {
|
|
4216
|
-
const raw =
|
|
4257
|
+
const raw = readFileSync4(cachePath(home), "utf8");
|
|
4217
4258
|
return JSON.parse(raw);
|
|
4218
4259
|
} catch {
|
|
4219
4260
|
return null;
|
|
@@ -4253,7 +4294,7 @@ function triggerAutoUpdate(home, currentVersion) {
|
|
|
4253
4294
|
if (!isStale) return;
|
|
4254
4295
|
const distTag = distTagFromCache(home);
|
|
4255
4296
|
const bgScript = new URL("../auto-update-bg.js", import.meta.url).pathname;
|
|
4256
|
-
if (!
|
|
4297
|
+
if (!existsSync7(bgScript)) return;
|
|
4257
4298
|
const child = spawn(process.execPath, [bgScript, home, currentVersion, distTag], {
|
|
4258
4299
|
detached: true,
|
|
4259
4300
|
stdio: "ignore"
|
|
@@ -4717,20 +4758,20 @@ function safeUserName() {
|
|
|
4717
4758
|
}
|
|
4718
4759
|
|
|
4719
4760
|
// src/commands/doctor.ts
|
|
4720
|
-
import { existsSync as
|
|
4761
|
+
import { existsSync as existsSync11, lstatSync, readlinkSync, readdirSync as readdirSync2, statSync, readFileSync as readFileSync8 } from "fs";
|
|
4721
4762
|
import { join as join22, resolve as resolve5 } from "path";
|
|
4722
4763
|
import { execSync as execSync2 } from "child_process";
|
|
4723
4764
|
import { platform as platform2 } from "os";
|
|
4724
4765
|
|
|
4725
4766
|
// src/utils/plugin-registry.ts
|
|
4726
|
-
import { existsSync as
|
|
4767
|
+
import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync5 } from "fs";
|
|
4727
4768
|
import { join as join19 } from "path";
|
|
4728
4769
|
var REGISTRY_PATH = join19(".claude", "plugins", "installed_plugins.json");
|
|
4729
4770
|
var CODEX_CONFIG_PATH = join19(".codex", "config.toml");
|
|
4730
4771
|
var PLUGIN_KEY = "skillwiki@llm-wiki";
|
|
4731
4772
|
function readInstalledPlugins(home) {
|
|
4732
4773
|
try {
|
|
4733
|
-
const raw =
|
|
4774
|
+
const raw = readFileSync5(join19(home, REGISTRY_PATH), "utf8");
|
|
4734
4775
|
return JSON.parse(raw);
|
|
4735
4776
|
} catch {
|
|
4736
4777
|
return null;
|
|
@@ -4767,7 +4808,7 @@ function findCodexPlugin(home, key, pluginName, marketplace) {
|
|
|
4767
4808
|
const config = readCodexPluginConfig(home, key, marketplace);
|
|
4768
4809
|
if (!config?.enabled) return null;
|
|
4769
4810
|
const cacheRoot = join19(home, ".codex", "plugins", "cache", marketplace, pluginName);
|
|
4770
|
-
if (!
|
|
4811
|
+
if (!existsSync8(cacheRoot)) return null;
|
|
4771
4812
|
let versions;
|
|
4772
4813
|
try {
|
|
4773
4814
|
versions = readdirSync(cacheRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
@@ -4799,7 +4840,7 @@ function parsePluginKey(key) {
|
|
|
4799
4840
|
function readCodexPluginConfig(home, key, marketplace) {
|
|
4800
4841
|
let raw;
|
|
4801
4842
|
try {
|
|
4802
|
-
raw =
|
|
4843
|
+
raw = readFileSync5(join19(home, CODEX_CONFIG_PATH), "utf8");
|
|
4803
4844
|
} catch {
|
|
4804
4845
|
return null;
|
|
4805
4846
|
}
|
|
@@ -4841,7 +4882,7 @@ function parseTomlScalar(rawValue) {
|
|
|
4841
4882
|
}
|
|
4842
4883
|
|
|
4843
4884
|
// src/utils/satellite-run-health.ts
|
|
4844
|
-
import { existsSync as
|
|
4885
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
4845
4886
|
import { join as join20 } from "path";
|
|
4846
4887
|
var SATELLITE_STALE_MS = 26 * 60 * 60 * 1e3;
|
|
4847
4888
|
function satelliteLatestRunPath(vault) {
|
|
@@ -4867,9 +4908,9 @@ function readSatelliteLatestRunFromText(text) {
|
|
|
4867
4908
|
}
|
|
4868
4909
|
function readSatelliteLatestRun(vault) {
|
|
4869
4910
|
const latestPath = satelliteLatestRunPath(vault);
|
|
4870
|
-
if (!
|
|
4911
|
+
if (!existsSync9(latestPath)) return null;
|
|
4871
4912
|
try {
|
|
4872
|
-
return parseLatestRunFile(
|
|
4913
|
+
return parseLatestRunFile(readFileSync6(latestPath, "utf8"));
|
|
4873
4914
|
} catch {
|
|
4874
4915
|
return null;
|
|
4875
4916
|
}
|
|
@@ -4898,7 +4939,7 @@ function evaluateSatelliteRunHealth(vault, now) {
|
|
|
4898
4939
|
// src/utils/s3-mount-health.ts
|
|
4899
4940
|
import { execSync } from "child_process";
|
|
4900
4941
|
import { platform } from "os";
|
|
4901
|
-
import { readFileSync as
|
|
4942
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, readFileSync as readFile15 } from "fs";
|
|
4902
4943
|
import { join as join21 } from "path";
|
|
4903
4944
|
var OS = platform();
|
|
4904
4945
|
function findRcloneMountPid() {
|
|
@@ -4983,7 +5024,7 @@ function extractRcloneFs(args) {
|
|
|
4983
5024
|
function getRcloneArgs(pid) {
|
|
4984
5025
|
try {
|
|
4985
5026
|
if (OS === "linux") {
|
|
4986
|
-
const raw =
|
|
5027
|
+
const raw = readFileSync7(`/proc/${pid}/cmdline`);
|
|
4987
5028
|
return new TextDecoder().decode(raw).split("\0").filter(Boolean);
|
|
4988
5029
|
} else {
|
|
4989
5030
|
const out = execSync(`ps -o args= -p ${pid}`, {
|
|
@@ -5026,7 +5067,7 @@ function queryRcloneRC(rcAddr, fs) {
|
|
|
5026
5067
|
function detectFuseMount(vaultPath) {
|
|
5027
5068
|
try {
|
|
5028
5069
|
if (OS === "linux") {
|
|
5029
|
-
const mounts =
|
|
5070
|
+
const mounts = readFileSync7("/proc/mounts", "utf8");
|
|
5030
5071
|
let best = null;
|
|
5031
5072
|
for (const line of mounts.split("\n")) {
|
|
5032
5073
|
const parts = line.split(" ");
|
|
@@ -5158,12 +5199,12 @@ function detectCliChannels(argv, home) {
|
|
|
5158
5199
|
const plugin = findPlugin(home);
|
|
5159
5200
|
if (plugin) {
|
|
5160
5201
|
const pluginBin = join22(plugin.installPath, "bin", "skillwiki");
|
|
5161
|
-
if (
|
|
5202
|
+
if (existsSync11(pluginBin)) {
|
|
5162
5203
|
channels.push({ name: "plugin", path: pluginBin, isDevLink: false });
|
|
5163
5204
|
}
|
|
5164
5205
|
}
|
|
5165
5206
|
const installBin = join22(home, ".claude", "skills", "bin", "skillwiki");
|
|
5166
|
-
if (
|
|
5207
|
+
if (existsSync11(installBin)) {
|
|
5167
5208
|
channels.push({ name: "install", path: installBin, isDevLink: false });
|
|
5168
5209
|
}
|
|
5169
5210
|
return channels;
|
|
@@ -5224,7 +5265,7 @@ function isDevSourceRun(argv) {
|
|
|
5224
5265
|
}
|
|
5225
5266
|
async function checkConfigFile(home) {
|
|
5226
5267
|
const cfgPath = configPath(home);
|
|
5227
|
-
if (!
|
|
5268
|
+
if (!existsSync11(cfgPath)) {
|
|
5228
5269
|
return check("warn", "config_file", "Config file exists", `${cfgPath} not found`);
|
|
5229
5270
|
}
|
|
5230
5271
|
try {
|
|
@@ -5239,7 +5280,7 @@ function checkWikiPathExists(resolvedPath) {
|
|
|
5239
5280
|
if (resolvedPath === void 0) {
|
|
5240
5281
|
return check("error", "wiki_path_exists", "Vault directory exists", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5241
5282
|
}
|
|
5242
|
-
if (
|
|
5283
|
+
if (existsSync11(resolvedPath) && statSync(resolvedPath).isDirectory()) {
|
|
5243
5284
|
return check("pass", "wiki_path_exists", "Vault directory exists", resolvedPath);
|
|
5244
5285
|
}
|
|
5245
5286
|
return check("error", "wiki_path_exists", "Vault directory exists", `${resolvedPath} does not exist or is not a directory`);
|
|
@@ -5248,13 +5289,13 @@ function checkVaultStructure(resolvedPath) {
|
|
|
5248
5289
|
if (resolvedPath === void 0) {
|
|
5249
5290
|
return check("error", "vault_structure", "Vault structure valid", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5250
5291
|
}
|
|
5251
|
-
if (!
|
|
5292
|
+
if (!existsSync11(resolvedPath)) {
|
|
5252
5293
|
return check("error", "vault_structure", "Vault structure valid", "Cannot check \u2014 vault directory does not exist");
|
|
5253
5294
|
}
|
|
5254
5295
|
const missing = [];
|
|
5255
|
-
if (!
|
|
5296
|
+
if (!existsSync11(join22(resolvedPath, "SCHEMA.md"))) missing.push("SCHEMA.md");
|
|
5256
5297
|
for (const dir of ["raw", "entities", "concepts", "meta"]) {
|
|
5257
|
-
if (!
|
|
5298
|
+
if (!existsSync11(join22(resolvedPath, dir))) missing.push(dir + "/");
|
|
5258
5299
|
}
|
|
5259
5300
|
if (missing.length === 0) {
|
|
5260
5301
|
return check("pass", "vault_structure", "Vault structure valid", "All required files and directories present");
|
|
@@ -5263,7 +5304,7 @@ function checkVaultStructure(resolvedPath) {
|
|
|
5263
5304
|
}
|
|
5264
5305
|
function checkSkillsInstalled(home, cwd) {
|
|
5265
5306
|
const srcDir = cwd ? join22(cwd, "packages", "skills") : void 0;
|
|
5266
|
-
if (srcDir &&
|
|
5307
|
+
if (srcDir && existsSync11(srcDir)) {
|
|
5267
5308
|
const found = findInstalledSkillMd(srcDir);
|
|
5268
5309
|
if (found.length > 0) {
|
|
5269
5310
|
return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (source)`);
|
|
@@ -5277,7 +5318,7 @@ function checkSkillsInstalled(home, cwd) {
|
|
|
5277
5318
|
}
|
|
5278
5319
|
}
|
|
5279
5320
|
const skillsDir = join22(home, ".claude", "skills");
|
|
5280
|
-
if (
|
|
5321
|
+
if (existsSync11(skillsDir)) {
|
|
5281
5322
|
const found = findInstalledSkillMd(skillsDir);
|
|
5282
5323
|
if (found.length > 0) {
|
|
5283
5324
|
return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (CLI install)`);
|
|
@@ -5394,7 +5435,7 @@ async function checkProfiles(home) {
|
|
|
5394
5435
|
async function checkProjectLocalOverride(cwd) {
|
|
5395
5436
|
const dir = cwd ?? process.cwd();
|
|
5396
5437
|
const envPath = join22(dir, ".skillwiki", ".env");
|
|
5397
|
-
if (
|
|
5438
|
+
if (existsSync11(envPath)) {
|
|
5398
5439
|
return check("pass", "project_local", "Project-local config", `Found: ${envPath}`);
|
|
5399
5440
|
}
|
|
5400
5441
|
return check("pass", "project_local", "Project-local config", "None");
|
|
@@ -5403,7 +5444,7 @@ function checkVaultGitRemote(resolvedPath) {
|
|
|
5403
5444
|
if (resolvedPath === void 0) {
|
|
5404
5445
|
return check("error", "vault_git_remote", "Vault git remote", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5405
5446
|
}
|
|
5406
|
-
if (!
|
|
5447
|
+
if (!existsSync11(join22(resolvedPath, ".git"))) {
|
|
5407
5448
|
return check("warn", "vault_git_remote", "Vault git remote", "Vault is not a git repository \u2014 sync features unavailable");
|
|
5408
5449
|
}
|
|
5409
5450
|
try {
|
|
@@ -5426,9 +5467,9 @@ function checkObsidianTemplates(resolvedPath) {
|
|
|
5426
5467
|
return check("error", "obsidian_templates", "Obsidian templates", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5427
5468
|
}
|
|
5428
5469
|
const missing = [];
|
|
5429
|
-
if (!
|
|
5430
|
-
if (!
|
|
5431
|
-
if (!
|
|
5470
|
+
if (!existsSync11(join22(resolvedPath, "_Templates"))) missing.push("_Templates/");
|
|
5471
|
+
if (!existsSync11(join22(resolvedPath, ".obsidian", "templates.json"))) missing.push(".obsidian/templates.json");
|
|
5472
|
+
if (!existsSync11(join22(resolvedPath, ".obsidian", "app.json"))) missing.push(".obsidian/app.json");
|
|
5432
5473
|
if (missing.length === 0) {
|
|
5433
5474
|
return check("pass", "obsidian_templates", "Obsidian templates", "Template folder and config present");
|
|
5434
5475
|
}
|
|
@@ -5439,7 +5480,7 @@ function checkDotStoreClean(resolvedPath) {
|
|
|
5439
5480
|
return check("error", "dsstore_clean", "No .DS_Store in raw/", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5440
5481
|
}
|
|
5441
5482
|
const rawDir = join22(resolvedPath, "raw");
|
|
5442
|
-
if (!
|
|
5483
|
+
if (!existsSync11(rawDir)) {
|
|
5443
5484
|
return check("pass", "dsstore_clean", "No .DS_Store in raw/", "raw/ directory not found \u2014 check skipped");
|
|
5444
5485
|
}
|
|
5445
5486
|
const found = [];
|
|
@@ -5467,7 +5508,7 @@ function checkSyncLastPush(resolvedPath) {
|
|
|
5467
5508
|
if (resolvedPath === void 0) {
|
|
5468
5509
|
return check("error", "sync_last_push", "Vault sync recency", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5469
5510
|
}
|
|
5470
|
-
if (!
|
|
5511
|
+
if (!existsSync11(join22(resolvedPath, ".git"))) {
|
|
5471
5512
|
return check("pass", "sync_last_push", "Vault sync recency", "No git repo \u2014 sync check skipped");
|
|
5472
5513
|
}
|
|
5473
5514
|
let timestamp;
|
|
@@ -5515,7 +5556,7 @@ function checkVaultGitDirty(resolvedPath) {
|
|
|
5515
5556
|
if (resolvedPath === void 0) {
|
|
5516
5557
|
return check("pass", "vault_git_dirty", "Vault git dirty state", "No vault path \u2014 check skipped");
|
|
5517
5558
|
}
|
|
5518
|
-
if (!
|
|
5559
|
+
if (!existsSync11(join22(resolvedPath, ".git"))) {
|
|
5519
5560
|
return check("pass", "vault_git_dirty", "Vault git dirty state", "No git repo \u2014 check skipped");
|
|
5520
5561
|
}
|
|
5521
5562
|
try {
|
|
@@ -5583,7 +5624,7 @@ function remoteMainHash(resolvedPath) {
|
|
|
5583
5624
|
}
|
|
5584
5625
|
function checkStaleRemoteMain(resolvedPath) {
|
|
5585
5626
|
if (resolvedPath === void 0) return void 0;
|
|
5586
|
-
if (!
|
|
5627
|
+
if (!existsSync11(join22(resolvedPath, ".git"))) return void 0;
|
|
5587
5628
|
const localOrigin = gitRefHash(resolvedPath, "origin/main");
|
|
5588
5629
|
if (!localOrigin) return void 0;
|
|
5589
5630
|
const remoteMain = remoteMainHash(resolvedPath);
|
|
@@ -5599,7 +5640,7 @@ function checkVaultGitComparison(resolvedPath, id, label, range, nonZeroSuffix,
|
|
|
5599
5640
|
if (resolvedPath === void 0) {
|
|
5600
5641
|
return check("pass", id, label, "No vault path \u2014 check skipped");
|
|
5601
5642
|
}
|
|
5602
|
-
if (!
|
|
5643
|
+
if (!existsSync11(join22(resolvedPath, ".git"))) {
|
|
5603
5644
|
return check("pass", id, label, "No git repo \u2014 check skipped");
|
|
5604
5645
|
}
|
|
5605
5646
|
if (!hasOriginMain(resolvedPath)) {
|
|
@@ -5627,7 +5668,7 @@ function checkSatelliteLastRun(vaultPath, satelliteExpected) {
|
|
|
5627
5668
|
return check("pass", "satellite_job_last_run", "Satellite job last run", "No vault path \u2014 check skipped");
|
|
5628
5669
|
}
|
|
5629
5670
|
const latestPath = satelliteLatestRunPath(vaultPath);
|
|
5630
|
-
if (!
|
|
5671
|
+
if (!existsSync11(latestPath)) {
|
|
5631
5672
|
return check("pass", "satellite_job_last_run", "Satellite job last run", "No latest-run.json \u2014 satellite has not run yet");
|
|
5632
5673
|
}
|
|
5633
5674
|
try {
|
|
@@ -5731,12 +5772,12 @@ function isRecentLogLine(line, nowMs) {
|
|
|
5731
5772
|
return nowMs - ts <= 24 * 60 * 60 * 1e3;
|
|
5732
5773
|
}
|
|
5733
5774
|
function checkVaultGitPullFailures(home) {
|
|
5734
|
-
const path = pullLogPaths(home).find((p) =>
|
|
5775
|
+
const path = pullLogPaths(home).find((p) => existsSync11(p));
|
|
5735
5776
|
if (!path) {
|
|
5736
5777
|
return check("pass", "vault_git_pull_failures", "Vault pull failures", "No wiki-pull.log found \u2014 check skipped");
|
|
5737
5778
|
}
|
|
5738
5779
|
try {
|
|
5739
|
-
const lines =
|
|
5780
|
+
const lines = readFileSync8(path, "utf8").split(/\r?\n/).filter(Boolean);
|
|
5740
5781
|
const now = Date.now();
|
|
5741
5782
|
const failures = lines.filter(
|
|
5742
5783
|
(line) => isRecentLogLine(line, now) && /(pre-push pull failed|FAIL .*pull|FAIL .*rebase|cannot pull with rebase|unstaged changes)/i.test(line)
|
|
@@ -5760,7 +5801,7 @@ function checkS3MountPerf(resolvedPath) {
|
|
|
5760
5801
|
}
|
|
5761
5802
|
const mountPoint = fuse.mountPoint;
|
|
5762
5803
|
const conceptsDir = join22(resolvedPath, "concepts");
|
|
5763
|
-
if (!
|
|
5804
|
+
if (!existsSync11(conceptsDir)) {
|
|
5764
5805
|
return check("pass", "s3_mount_perf", "S3 mount performance", `S3 FUSE mount (${mountPoint}), no concepts/ to benchmark`);
|
|
5765
5806
|
}
|
|
5766
5807
|
const start = Date.now();
|
|
@@ -5943,7 +5984,7 @@ function checkWriteTest(resolvedPath) {
|
|
|
5943
5984
|
return check("pass", "s3_write_test", "S3 write test", "local disk \u2014 check skipped");
|
|
5944
5985
|
}
|
|
5945
5986
|
const conceptsDir = join22(resolvedPath, "concepts");
|
|
5946
|
-
if (!
|
|
5987
|
+
if (!existsSync11(conceptsDir)) {
|
|
5947
5988
|
return check("pass", "s3_write_test", "S3 write test", "no concepts/ dir to test \u2014 check skipped");
|
|
5948
5989
|
}
|
|
5949
5990
|
const result = writeTest(conceptsDir);
|
|
@@ -6029,7 +6070,7 @@ function checkVfsCacheHealth(resolvedPath) {
|
|
|
6029
6070
|
}
|
|
6030
6071
|
function readVaultSyncConfig(home) {
|
|
6031
6072
|
try {
|
|
6032
|
-
const content =
|
|
6073
|
+
const content = readFileSync8(join22(home, ".skillwiki", ".env"), "utf8");
|
|
6033
6074
|
let installed = false;
|
|
6034
6075
|
let role;
|
|
6035
6076
|
let serviceScope;
|
|
@@ -6058,7 +6099,7 @@ function readVaultSyncConfig(home) {
|
|
|
6058
6099
|
}
|
|
6059
6100
|
function readKeyFromEnvFile(path, keys) {
|
|
6060
6101
|
try {
|
|
6061
|
-
const content =
|
|
6102
|
+
const content = readFileSync8(path, "utf8");
|
|
6062
6103
|
for (const line of content.split(/\r?\n/)) {
|
|
6063
6104
|
const trimmed = line.trim();
|
|
6064
6105
|
if (trimmed.length === 0 || trimmed.startsWith("#")) continue;
|
|
@@ -6080,7 +6121,7 @@ function resolveSnapshotGitWorktree(config) {
|
|
|
6080
6121
|
if (fromProfile) return fromProfile;
|
|
6081
6122
|
}
|
|
6082
6123
|
const defaultPath = "/root/wiki-git";
|
|
6083
|
-
return
|
|
6124
|
+
return existsSync11(defaultPath) ? defaultPath : void 0;
|
|
6084
6125
|
}
|
|
6085
6126
|
function vaultSyncChecks(input) {
|
|
6086
6127
|
const os = input.os ?? platform2();
|
|
@@ -6102,11 +6143,11 @@ function vaultSyncChecks(input) {
|
|
|
6102
6143
|
const filterPath = input.filterPath ?? join22(home, ".config", "rclone", "wiki-push-filters.txt");
|
|
6103
6144
|
const packagedSnapshotPath = join22(shareDir, "wiki-snapshot.sh");
|
|
6104
6145
|
const legacySnapshotPath = "/root/.hermes/scripts/wiki-snapshot-v3.sh";
|
|
6105
|
-
const snapshotPath = input.snapshotScriptPath ?? (
|
|
6146
|
+
const snapshotPath = input.snapshotScriptPath ?? (existsSync11(packagedSnapshotPath) ? packagedSnapshotPath : legacySnapshotPath);
|
|
6106
6147
|
function snapshotLastStatusCheck() {
|
|
6107
6148
|
const snapshotLog = join22(logDir, "wiki-snapshot.log");
|
|
6108
6149
|
try {
|
|
6109
|
-
const logContent =
|
|
6150
|
+
const logContent = readFileSync8(snapshotLog, "utf8");
|
|
6110
6151
|
const lines = logContent.trim().split("\n").filter(Boolean);
|
|
6111
6152
|
if (lines.length === 0) {
|
|
6112
6153
|
return check(
|
|
@@ -6151,14 +6192,14 @@ function vaultSyncChecks(input) {
|
|
|
6151
6192
|
}
|
|
6152
6193
|
}
|
|
6153
6194
|
if (input.vaultSyncRole === "snapshotter") {
|
|
6154
|
-
const c12 =
|
|
6195
|
+
const c12 = existsSync11(snapshotPath) ? check("pass", "vault_sync_installed", "Vault sync installed", `Found snapshot script: ${snapshotPath}`) : check("error", "vault_sync_installed", "Vault sync installed", `Snapshot script not found at ${snapshotPath}`);
|
|
6155
6196
|
const serviceScope = input.vaultSyncServiceScope ?? "user";
|
|
6156
6197
|
const userTimerPath = join22(home, ".config", "systemd", "user", "wiki-snapshot.timer");
|
|
6157
6198
|
const systemTimerPath = "/etc/systemd/system/wiki-snapshot.timer";
|
|
6158
6199
|
let c22;
|
|
6159
|
-
if (serviceScope === "user" &&
|
|
6200
|
+
if (serviceScope === "user" && existsSync11(userTimerPath)) {
|
|
6160
6201
|
c22 = check("pass", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `Found: ${userTimerPath}`);
|
|
6161
|
-
} else if (serviceScope === "system" &&
|
|
6202
|
+
} else if (serviceScope === "system" && existsSync11(systemTimerPath)) {
|
|
6162
6203
|
c22 = check("pass", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `Found: ${systemTimerPath}`);
|
|
6163
6204
|
} else if (os !== "linux") {
|
|
6164
6205
|
c22 = check("warn", "vault_sync_jobs_enabled", "Vault sync jobs enabled", "Snapshotter scheduler is Linux-only and no wiki-snapshot.timer file was found");
|
|
@@ -6190,7 +6231,7 @@ function vaultSyncChecks(input) {
|
|
|
6190
6231
|
);
|
|
6191
6232
|
let c52;
|
|
6192
6233
|
try {
|
|
6193
|
-
if (!
|
|
6234
|
+
if (!existsSync11(snapshotPath)) {
|
|
6194
6235
|
c52 = check(
|
|
6195
6236
|
"error",
|
|
6196
6237
|
"vault_sync_snapshot_guard",
|
|
@@ -6198,7 +6239,7 @@ function vaultSyncChecks(input) {
|
|
|
6198
6239
|
`Snapshot script not found at ${snapshotPath}`
|
|
6199
6240
|
);
|
|
6200
6241
|
} else {
|
|
6201
|
-
const content =
|
|
6242
|
+
const content = readFileSync8(snapshotPath, "utf8");
|
|
6202
6243
|
if (!content.includes("--max-delete")) {
|
|
6203
6244
|
c52 = check(
|
|
6204
6245
|
"error",
|
|
@@ -6226,7 +6267,7 @@ function vaultSyncChecks(input) {
|
|
|
6226
6267
|
return [c12, c22, c32, cFetch2, c42, c52];
|
|
6227
6268
|
}
|
|
6228
6269
|
const pushScriptPath = join22(shareDir, "wiki-push.sh");
|
|
6229
|
-
const c1 =
|
|
6270
|
+
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`);
|
|
6230
6271
|
let c2;
|
|
6231
6272
|
try {
|
|
6232
6273
|
if (isMac) {
|
|
@@ -6280,7 +6321,7 @@ function vaultSyncChecks(input) {
|
|
|
6280
6321
|
const logFile = join22(logDir, "wiki-push.log");
|
|
6281
6322
|
let c3;
|
|
6282
6323
|
try {
|
|
6283
|
-
const logContent =
|
|
6324
|
+
const logContent = readFileSync8(logFile, "utf8");
|
|
6284
6325
|
const lines = logContent.trim().split("\n").filter(Boolean);
|
|
6285
6326
|
if (lines.length === 0) {
|
|
6286
6327
|
c3 = check(
|
|
@@ -6336,7 +6377,7 @@ function vaultSyncChecks(input) {
|
|
|
6336
6377
|
}
|
|
6337
6378
|
}
|
|
6338
6379
|
} catch {
|
|
6339
|
-
c3 =
|
|
6380
|
+
c3 = existsSync11(logDir) ? check(
|
|
6340
6381
|
"warn",
|
|
6341
6382
|
"vault_sync_last_push_age",
|
|
6342
6383
|
"Vault sync last push recency",
|
|
@@ -6351,7 +6392,7 @@ function vaultSyncChecks(input) {
|
|
|
6351
6392
|
const fetchLogFile = join22(logDir, "wiki-fetch.log");
|
|
6352
6393
|
let cFetch;
|
|
6353
6394
|
try {
|
|
6354
|
-
const logContent =
|
|
6395
|
+
const logContent = readFileSync8(fetchLogFile, "utf8");
|
|
6355
6396
|
const lines = logContent.trim().split("\n").filter(Boolean);
|
|
6356
6397
|
if (lines.length === 0) {
|
|
6357
6398
|
cFetch = check(
|
|
@@ -6395,7 +6436,7 @@ function vaultSyncChecks(input) {
|
|
|
6395
6436
|
}
|
|
6396
6437
|
let c4;
|
|
6397
6438
|
try {
|
|
6398
|
-
if (!
|
|
6439
|
+
if (!existsSync11(filterPath)) {
|
|
6399
6440
|
c4 = check(
|
|
6400
6441
|
"error",
|
|
6401
6442
|
"vault_sync_filter_present",
|
|
@@ -6403,7 +6444,7 @@ function vaultSyncChecks(input) {
|
|
|
6403
6444
|
`Filter file not found at ${filterPath}`
|
|
6404
6445
|
);
|
|
6405
6446
|
} else {
|
|
6406
|
-
const content =
|
|
6447
|
+
const content = readFileSync8(filterPath, "utf8");
|
|
6407
6448
|
const requiredExcludes = [
|
|
6408
6449
|
"remotely-save/data.json",
|
|
6409
6450
|
".skillwiki/sync.lock",
|
|
@@ -6446,7 +6487,7 @@ function vaultSyncChecks(input) {
|
|
|
6446
6487
|
);
|
|
6447
6488
|
} else {
|
|
6448
6489
|
try {
|
|
6449
|
-
if (!
|
|
6490
|
+
if (!existsSync11(snapshotPath)) {
|
|
6450
6491
|
c5 = check(
|
|
6451
6492
|
"error",
|
|
6452
6493
|
"vault_sync_snapshot_guard",
|
|
@@ -6454,7 +6495,7 @@ function vaultSyncChecks(input) {
|
|
|
6454
6495
|
`Snapshot script not found at ${snapshotPath}`
|
|
6455
6496
|
);
|
|
6456
6497
|
} else {
|
|
6457
|
-
const content =
|
|
6498
|
+
const content = readFileSync8(snapshotPath, "utf8");
|
|
6458
6499
|
if (!content.includes("--max-delete")) {
|
|
6459
6500
|
c5 = check(
|
|
6460
6501
|
"error",
|
|
@@ -6512,7 +6553,7 @@ function findSkillNames(dir) {
|
|
|
6512
6553
|
return results;
|
|
6513
6554
|
}
|
|
6514
6555
|
for (const entry of entries) {
|
|
6515
|
-
if (entry.isDirectory() &&
|
|
6556
|
+
if (entry.isDirectory() && existsSync11(join22(dir, entry.name, "SKILL.md"))) {
|
|
6516
6557
|
results.push(entry.name);
|
|
6517
6558
|
}
|
|
6518
6559
|
}
|
|
@@ -6556,7 +6597,7 @@ async function vaultMetrics(resolvedPath) {
|
|
|
6556
6597
|
}
|
|
6557
6598
|
let logLines = 0;
|
|
6558
6599
|
try {
|
|
6559
|
-
logLines =
|
|
6600
|
+
logLines = readFileSync8(join22(resolvedPath, "log.md"), "utf8").split("\n").length;
|
|
6560
6601
|
} catch {
|
|
6561
6602
|
}
|
|
6562
6603
|
return [
|
|
@@ -6658,7 +6699,7 @@ async function runDoctor(input) {
|
|
|
6658
6699
|
}
|
|
6659
6700
|
|
|
6660
6701
|
// src/utils/package-info.ts
|
|
6661
|
-
import { readFileSync as
|
|
6702
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
6662
6703
|
function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
6663
6704
|
return [
|
|
6664
6705
|
new URL("../package.json", baseUrl),
|
|
@@ -6668,7 +6709,7 @@ function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
|
6668
6709
|
function readCliPackageJson(baseUrl = import.meta.url) {
|
|
6669
6710
|
for (const url of packageJsonCandidateUrls(baseUrl)) {
|
|
6670
6711
|
try {
|
|
6671
|
-
const pkg = JSON.parse(
|
|
6712
|
+
const pkg = JSON.parse(readFileSync9(url, "utf8"));
|
|
6672
6713
|
if (typeof pkg.version === "string") {
|
|
6673
6714
|
return { ...pkg, version: pkg.version };
|
|
6674
6715
|
}
|
|
@@ -6824,7 +6865,7 @@ ${entries.map((e) => ` ${e.type}: [[${e.page.replace(/\.md$/, "")}]] \u2014 ${e
|
|
|
6824
6865
|
|
|
6825
6866
|
// src/commands/observe.ts
|
|
6826
6867
|
import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
|
|
6827
|
-
import { existsSync as
|
|
6868
|
+
import { existsSync as existsSync12, statSync as statSync2 } from "fs";
|
|
6828
6869
|
import { join as join24 } from "path";
|
|
6829
6870
|
import { createHash as createHash5 } from "crypto";
|
|
6830
6871
|
var ALLOWED_KINDS = /* @__PURE__ */ new Set(["note", "bug", "task", "idea", "session-log"]);
|
|
@@ -6848,7 +6889,7 @@ async function runObserve(input) {
|
|
|
6848
6889
|
result: err("SCHEME_REJECTED", { message: "Text must not be empty" })
|
|
6849
6890
|
};
|
|
6850
6891
|
}
|
|
6851
|
-
if (!
|
|
6892
|
+
if (!existsSync12(input.vault) || !statSync2(input.vault).isDirectory()) {
|
|
6852
6893
|
return {
|
|
6853
6894
|
exitCode: ExitCode.VAULT_PATH_INVALID,
|
|
6854
6895
|
result: err("VAULT_PATH_INVALID", { path: input.vault })
|
|
@@ -8522,7 +8563,7 @@ async function fetchQueryPreview(input) {
|
|
|
8522
8563
|
// src/mcp/graph-html.ts
|
|
8523
8564
|
import { readFile as readFile19 } from "fs/promises";
|
|
8524
8565
|
import { join as join29 } from "path";
|
|
8525
|
-
import { existsSync as
|
|
8566
|
+
import { existsSync as existsSync13 } from "fs";
|
|
8526
8567
|
var TYPE_COLORS = {
|
|
8527
8568
|
entities: "#e74c3c",
|
|
8528
8569
|
concepts: "#27ae60",
|
|
@@ -8592,7 +8633,7 @@ ${nodeSvg}
|
|
|
8592
8633
|
async function fetchGraphHtmlReport(input) {
|
|
8593
8634
|
const graphPath = input.graphPath ?? join29(input.vault, ".skillwiki", "graph.json");
|
|
8594
8635
|
const maxNodes = Math.min(Math.max(10, input.maxNodes ?? 120), 500);
|
|
8595
|
-
if (!
|
|
8636
|
+
if (!existsSync13(graphPath)) {
|
|
8596
8637
|
return {
|
|
8597
8638
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
8598
8639
|
result: err("GRAPH_MISSING", { path: graphPath, hint: "Run skillwiki.graph_build first." })
|
package/dist/cli.js
CHANGED
|
@@ -75,7 +75,7 @@ import {
|
|
|
75
75
|
triggerAutoUpdate,
|
|
76
76
|
writeCache,
|
|
77
77
|
writeDotenv
|
|
78
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-4Q7MANQI.js";
|
|
79
79
|
import {
|
|
80
80
|
normalizeDistTag
|
|
81
81
|
} from "./chunk-E6UWZ3S3.js";
|
|
@@ -321,6 +321,8 @@ async function runInstall(input) {
|
|
|
321
321
|
const hintLines2 = [
|
|
322
322
|
`deferred to plugin: skillwiki@llm-wiki v${plugin.version}`,
|
|
323
323
|
`plugin provides skills at ${plugin.installPath}`,
|
|
324
|
+
"Plugin-managed skills are not refreshed with `skillwiki install`.",
|
|
325
|
+
"Do not run `skillwiki install` just to refresh plugin-managed skills; update the active plugin channel instead.",
|
|
324
326
|
`use --force to install CLI copies into ${input.target} anyway`
|
|
325
327
|
];
|
|
326
328
|
return {
|
package/dist/skillwiki-mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.49",
|
|
4
4
|
"skills": "./",
|
|
5
5
|
"description": "Project-aware Karpathy-style knowledge base for Claude Code: 18 prompt-only skills (wiki-*, proj-*, using-skillwiki) backed by the deterministic `skillwiki` CLI.",
|
|
6
6
|
"author": {
|
package/skills/package.json
CHANGED
|
@@ -172,11 +172,13 @@ skillwiki has multiple distribution channels that can drift:
|
|
|
172
172
|
| Channel | Location | Update Command |
|
|
173
173
|
|---------|----------|----------------|
|
|
174
174
|
| npm CLI | `/usr/local/bin/skillwiki` | `npm install -g skillwiki@latest` |
|
|
175
|
-
| npm skills | `/usr/local/lib/node_modules/skillwiki/skills/` | `skillwiki install`
|
|
175
|
+
| npm skills | `/usr/local/lib/node_modules/skillwiki/skills/` | `skillwiki install` only for standalone CLI skill copies; defers when the plugin channel is active |
|
|
176
176
|
| Claude plugin | `~/.claude/plugins/cache/llm-wiki/` | `claude plugin update skillwiki@llm-wiki` |
|
|
177
177
|
| Codex plugin | `~/.codex/plugins/cache/llm-wiki/` | `codex plugin marketplace upgrade llm-wiki`, then reinstall or restart Codex as needed |
|
|
178
178
|
| Local git dev | source repo checkout | `npm link ./packages/cli` (from repo root) |
|
|
179
179
|
**Check versions:** `skillwiki doctor` reports Plugin/CLI version mismatch warnings when installed channels disagree.
|
|
180
|
+
**Plugin channel rule:** Plugin-managed skills are not refreshed with `skillwiki install`. When Claude or Codex plugin is installed and enabled, the plugin cache is the skill provider; `skillwiki install` is only a legacy/standalone copier for `~/.claude/skills/`.
|
|
181
|
+
**Agent update rule:** Do not run `skillwiki install` just to refresh plugin-managed skills. If `skillwiki install` reports `deferred_to_plugin: true`, stop there and update the active plugin channel instead: Claude uses `claude plugin update skillwiki@llm-wiki`; Codex uses `codex plugin marketplace upgrade llm-wiki`, then reinstall or restart Codex as needed. Only use `skillwiki install --force` when the user explicitly wants duplicate CLI-managed copies under `~/.claude/skills/` and accepts that `skillwiki doctor` may report overlap.
|
|
180
182
|
**Authoring rule:** `SKILL.md` frontmatter follows the Agent Skills schema: top-level `name` and `description` plus optional schema fields such as `metadata`. Do not put release version fields at the top level of `SKILL.md`; plugin and package release versions live in `plugin.json` and `package.json`.
|
|
181
183
|
**Fix:** If developing locally, use the repo source plus `npm link`. If using released versions, update the relevant plugin or npm channel; do not infer release freshness from `SKILL.md` frontmatter.
|
|
182
184
|
|
|
@@ -172,11 +172,13 @@ skillwiki has multiple distribution channels that can drift:
|
|
|
172
172
|
| Channel | Location | Update Command |
|
|
173
173
|
|---------|----------|----------------|
|
|
174
174
|
| npm CLI | `/usr/local/bin/skillwiki` | `npm install -g skillwiki@latest` |
|
|
175
|
-
| npm skills | `/usr/local/lib/node_modules/skillwiki/skills/` | `skillwiki install`
|
|
175
|
+
| npm skills | `/usr/local/lib/node_modules/skillwiki/skills/` | `skillwiki install` only for standalone CLI skill copies; defers when the plugin channel is active |
|
|
176
176
|
| Claude plugin | `~/.claude/plugins/cache/llm-wiki/` | `claude plugin update skillwiki@llm-wiki` |
|
|
177
177
|
| Codex plugin | `~/.codex/plugins/cache/llm-wiki/` | `codex plugin marketplace upgrade llm-wiki`, then reinstall or restart Codex as needed |
|
|
178
178
|
| Local git dev | source repo checkout | `npm link ./packages/cli` (from repo root) |
|
|
179
179
|
**Check versions:** `skillwiki doctor` reports Plugin/CLI version mismatch warnings when installed channels disagree.
|
|
180
|
+
**Plugin channel rule:** Plugin-managed skills are not refreshed with `skillwiki install`. When Claude or Codex plugin is installed and enabled, the plugin cache is the skill provider; `skillwiki install` is only a legacy/standalone copier for `~/.claude/skills/`.
|
|
181
|
+
**Agent update rule:** Do not run `skillwiki install` just to refresh plugin-managed skills. If `skillwiki install` reports `deferred_to_plugin: true`, stop there and update the active plugin channel instead: Claude uses `claude plugin update skillwiki@llm-wiki`; Codex uses `codex plugin marketplace upgrade llm-wiki`, then reinstall or restart Codex as needed. Only use `skillwiki install --force` when the user explicitly wants duplicate CLI-managed copies under `~/.claude/skills/` and accepts that `skillwiki doctor` may report overlap.
|
|
180
182
|
**Authoring rule:** `SKILL.md` frontmatter follows the Agent Skills schema: top-level `name` and `description` plus optional schema fields such as `metadata`. Do not put release version fields at the top level of `SKILL.md`; plugin and package release versions live in `plugin.json` and `package.json`.
|
|
181
183
|
**Fix:** If developing locally, use the repo source plus `npm link`. If using released versions, update the relevant plugin or npm channel; do not infer release freshness from `SKILL.md` frontmatter.
|
|
182
184
|
|