skillwiki 0.10.1 → 0.10.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/{chunk-IZABIE44.js → chunk-U34B2XQJ.js} +126 -88
- package/dist/{chunk-XSTXPA34.js → chunk-Z3WS45PL.js} +15 -14
- package/dist/cli.js +4 -4
- package/dist/{index-projection-ERFX76U5.js → index-projection-VNJ3TLEK.js} +1 -1
- package/dist/skillwiki-mcp.js +2 -2
- 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
|
@@ -9,8 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-C5OLZRRM.js";
|
|
10
10
|
|
|
11
11
|
// src/utils/index-projection.ts
|
|
12
|
-
import {
|
|
13
|
-
import { readFile as readFile3 } from "fs/promises";
|
|
12
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
14
13
|
import { join as join3 } from "path";
|
|
15
14
|
|
|
16
15
|
// src/utils/atomic-write.ts
|
|
@@ -59,6 +58,9 @@ async function atomicWriteText(path, text) {
|
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
|
|
61
|
+
// src/utils/index-universe.ts
|
|
62
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
63
|
+
|
|
62
64
|
// src/utils/typed-page.ts
|
|
63
65
|
import { lstatSync, realpathSync } from "fs";
|
|
64
66
|
import { dirname as dirname2, posix, relative, resolve, sep } from "path";
|
|
@@ -440,8 +442,15 @@ async function readPageCached(p, cache) {
|
|
|
440
442
|
return pending;
|
|
441
443
|
}
|
|
442
444
|
|
|
443
|
-
// src/utils/index-
|
|
444
|
-
var
|
|
445
|
+
// src/utils/index-universe.ts
|
|
446
|
+
var ROOT_INDEX_SECTION_ORDER = [
|
|
447
|
+
"Entities",
|
|
448
|
+
"Concepts",
|
|
449
|
+
"Comparisons",
|
|
450
|
+
"Queries",
|
|
451
|
+
"Meta",
|
|
452
|
+
"Projects"
|
|
453
|
+
];
|
|
445
454
|
var TYPE_SECTION = {
|
|
446
455
|
entity: "Entities",
|
|
447
456
|
concept: "Concepts",
|
|
@@ -450,6 +459,106 @@ var TYPE_SECTION = {
|
|
|
450
459
|
meta: "Meta"
|
|
451
460
|
};
|
|
452
461
|
var compareText = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
462
|
+
function projectTitleFromReadme(text, slug) {
|
|
463
|
+
const match = text.match(/^#\s+Project:\s+(.+)$/m);
|
|
464
|
+
return match?.[1]?.trim() || slug;
|
|
465
|
+
}
|
|
466
|
+
async function buildRootIndexUniverse(input) {
|
|
467
|
+
const scanned = input.scan ? ok(input.scan) : await scanVault(input.vault);
|
|
468
|
+
if (!scanned.ok) return scanned;
|
|
469
|
+
const required = [];
|
|
470
|
+
const rejectedTyped = [];
|
|
471
|
+
const seen = /* @__PURE__ */ new Map();
|
|
472
|
+
let duplicatesRemoved = 0;
|
|
473
|
+
const typedPages = [...scanned.data.typedKnowledge].sort((a, b) => compareText(a.relPath, b.relPath));
|
|
474
|
+
for (const page of typedPages) {
|
|
475
|
+
let text;
|
|
476
|
+
try {
|
|
477
|
+
text = await readFile3(page.absPath, "utf8");
|
|
478
|
+
} catch {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
const prepared = prepareTypedPage(text, page.relPath);
|
|
482
|
+
if (!prepared.ok) {
|
|
483
|
+
rejectedTyped.push({
|
|
484
|
+
relPath: page.relPath,
|
|
485
|
+
error: prepared.error,
|
|
486
|
+
detail: prepared.detail
|
|
487
|
+
});
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
const section = TYPE_SECTION[prepared.data.type];
|
|
491
|
+
if (!section) {
|
|
492
|
+
rejectedTyped.push({
|
|
493
|
+
relPath: page.relPath,
|
|
494
|
+
error: "SCHEME_REJECTED",
|
|
495
|
+
detail: { type: prepared.data.type }
|
|
496
|
+
});
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
const target = prepared.data.target.replace(/\.md$/, "");
|
|
500
|
+
const previousTitle = seen.get(target);
|
|
501
|
+
if (previousTitle !== void 0) {
|
|
502
|
+
if (previousTitle !== prepared.data.title) {
|
|
503
|
+
return err("SCHEME_REJECTED", {
|
|
504
|
+
message: `duplicate index target ${target} with differing titles`,
|
|
505
|
+
titles: [previousTitle, prepared.data.title]
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
duplicatesRemoved += 1;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
seen.set(target, prepared.data.title);
|
|
512
|
+
required.push({
|
|
513
|
+
section,
|
|
514
|
+
target,
|
|
515
|
+
title: prepared.data.title,
|
|
516
|
+
source: "typed"
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
const projectReadmes = scanned.data.allMarkdown.filter((page) => /^projects\/[^/]+\/README\.md$/.test(page.relPath)).sort((a, b) => compareText(a.relPath, b.relPath));
|
|
520
|
+
for (const readme of projectReadmes) {
|
|
521
|
+
let text;
|
|
522
|
+
try {
|
|
523
|
+
text = await readFile3(readme.absPath, "utf8");
|
|
524
|
+
} catch {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
const projectSlug = readme.relPath.split("/")[1];
|
|
528
|
+
const target = `projects/${projectSlug}/README`;
|
|
529
|
+
const title = projectTitleFromReadme(text, projectSlug);
|
|
530
|
+
const previousTitle = seen.get(target);
|
|
531
|
+
if (previousTitle !== void 0) {
|
|
532
|
+
if (previousTitle !== title) {
|
|
533
|
+
return err("SCHEME_REJECTED", {
|
|
534
|
+
message: `duplicate index target ${target} with differing titles`
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
duplicatesRemoved += 1;
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
seen.set(target, title);
|
|
541
|
+
required.push({ section: "Projects", target, title, source: "project" });
|
|
542
|
+
}
|
|
543
|
+
required.sort((a, b) => {
|
|
544
|
+
const sectionA = ROOT_INDEX_SECTION_ORDER.indexOf(a.section);
|
|
545
|
+
const sectionB = ROOT_INDEX_SECTION_ORDER.indexOf(b.section);
|
|
546
|
+
if (sectionA !== sectionB) return sectionA - sectionB;
|
|
547
|
+
return compareText(a.target, b.target);
|
|
548
|
+
});
|
|
549
|
+
const knownTargets = new Set(required.map((entry) => entry.target));
|
|
550
|
+
for (const page of [...scanned.data.compound].sort((a, b) => compareText(a.relPath, b.relPath))) {
|
|
551
|
+
knownTargets.add(page.relPath.replace(/\.md$/, ""));
|
|
552
|
+
}
|
|
553
|
+
return ok({
|
|
554
|
+
required,
|
|
555
|
+
knownTargets,
|
|
556
|
+
rejectedTyped,
|
|
557
|
+
duplicatesRemoved
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// src/utils/index-projection.ts
|
|
453
562
|
var UNMANAGED_START = "<!-- skillwiki:index-unmanaged:start -->";
|
|
454
563
|
var UNMANAGED_END = "<!-- skillwiki:index-unmanaged:end -->";
|
|
455
564
|
function extractUnmanaged(currentText) {
|
|
@@ -480,94 +589,27 @@ function priorWikilinkTargets(text) {
|
|
|
480
589
|
}
|
|
481
590
|
return out;
|
|
482
591
|
}
|
|
483
|
-
function projectTitleFromReadme(text, slug) {
|
|
484
|
-
const m = text.match(/^#\s+Project:\s+(.+)$/m);
|
|
485
|
-
return m?.[1]?.trim() || slug;
|
|
486
|
-
}
|
|
487
592
|
async function renderRootIndex(input) {
|
|
488
593
|
const vault = input.vault;
|
|
489
594
|
let currentText = input.currentText;
|
|
490
595
|
if (currentText === void 0) {
|
|
491
596
|
try {
|
|
492
|
-
currentText = await
|
|
597
|
+
currentText = await readFile4(join3(vault, "index.md"), "utf8");
|
|
493
598
|
} catch {
|
|
494
599
|
currentText = "";
|
|
495
600
|
}
|
|
496
601
|
}
|
|
497
602
|
const unmanaged = extractUnmanaged(currentText);
|
|
498
603
|
if (!unmanaged.ok) return unmanaged;
|
|
499
|
-
const
|
|
500
|
-
if (!
|
|
501
|
-
const entries =
|
|
502
|
-
|
|
503
|
-
let duplicatesRemoved = 0;
|
|
504
|
-
for (const page of scan.data.typedKnowledge) {
|
|
505
|
-
let text;
|
|
506
|
-
try {
|
|
507
|
-
text = await readFile3(join3(vault, page.relPath), "utf8");
|
|
508
|
-
} catch {
|
|
509
|
-
continue;
|
|
510
|
-
}
|
|
511
|
-
const prepared = prepareTypedPage(text, page.relPath);
|
|
512
|
-
if (!prepared.ok) continue;
|
|
513
|
-
const section = TYPE_SECTION[prepared.data.type];
|
|
514
|
-
if (!section) continue;
|
|
515
|
-
const target = prepared.data.target.replace(/\.md$/, "");
|
|
516
|
-
const prev = seen.get(target);
|
|
517
|
-
if (prev !== void 0) {
|
|
518
|
-
if (prev !== prepared.data.title) {
|
|
519
|
-
return err("SCHEME_REJECTED", {
|
|
520
|
-
message: `duplicate index target ${target} with differing titles`,
|
|
521
|
-
titles: [prev, prepared.data.title]
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
duplicatesRemoved += 1;
|
|
525
|
-
continue;
|
|
526
|
-
}
|
|
527
|
-
seen.set(target, prepared.data.title);
|
|
528
|
-
entries.push({
|
|
529
|
-
section,
|
|
530
|
-
target,
|
|
531
|
-
title: prepared.data.title,
|
|
532
|
-
source: "typed"
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
try {
|
|
536
|
-
const projectsRoot = join3(vault, "projects");
|
|
537
|
-
for (const slug of readdirSync(projectsRoot, { withFileTypes: true })) {
|
|
538
|
-
if (!slug.isDirectory()) continue;
|
|
539
|
-
const readmePath = join3(projectsRoot, slug.name, "README.md");
|
|
540
|
-
let text;
|
|
541
|
-
try {
|
|
542
|
-
text = readFileSync2(readmePath, "utf8");
|
|
543
|
-
} catch {
|
|
544
|
-
continue;
|
|
545
|
-
}
|
|
546
|
-
const target = `projects/${slug.name}/README`;
|
|
547
|
-
const title = projectTitleFromReadme(text, slug.name);
|
|
548
|
-
const prev = seen.get(target);
|
|
549
|
-
if (prev !== void 0) {
|
|
550
|
-
if (prev !== title) {
|
|
551
|
-
return err("SCHEME_REJECTED", {
|
|
552
|
-
message: `duplicate index target ${target} with differing titles`
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
duplicatesRemoved += 1;
|
|
556
|
-
continue;
|
|
557
|
-
}
|
|
558
|
-
seen.set(target, title);
|
|
559
|
-
entries.push({ section: "Projects", target, title, source: "project" });
|
|
560
|
-
}
|
|
561
|
-
} catch {
|
|
562
|
-
}
|
|
563
|
-
entries.sort((a, b) => {
|
|
564
|
-
const sa = SECTION_ORDER.indexOf(a.section);
|
|
565
|
-
const sb = SECTION_ORDER.indexOf(b.section);
|
|
566
|
-
if (sa !== sb) return sa - sb;
|
|
567
|
-
return compareText(a.target, b.target);
|
|
568
|
-
});
|
|
604
|
+
const universe = await buildRootIndexUniverse({ vault });
|
|
605
|
+
if (!universe.ok) return universe;
|
|
606
|
+
const entries = universe.data.required;
|
|
607
|
+
let duplicatesRemoved = universe.data.duplicatesRemoved;
|
|
569
608
|
const prior = priorWikilinkTargets(currentText);
|
|
570
|
-
const
|
|
609
|
+
const knownTargets = universe.data.knownTargets;
|
|
610
|
+
const knownBasenames = new Set(
|
|
611
|
+
[...knownTargets].map((target) => target.split("/").pop().toLowerCase())
|
|
612
|
+
);
|
|
571
613
|
const priorLower = /* @__PURE__ */ new Map();
|
|
572
614
|
for (const t of prior) {
|
|
573
615
|
const k = t.toLowerCase();
|
|
@@ -585,15 +627,10 @@ async function renderRootIndex(input) {
|
|
|
585
627
|
const ghostsRemoved = [
|
|
586
628
|
...new Set(
|
|
587
629
|
prior.filter((t) => {
|
|
588
|
-
const bare = t.includes("/") ? t : null;
|
|
589
|
-
if (bare && !generatedTargets.has(bare) && !generatedTargets.has(t)) {
|
|
590
|
-
if (!seen.has(t)) return true;
|
|
591
|
-
}
|
|
592
630
|
if (!t.includes("/")) {
|
|
593
|
-
|
|
594
|
-
return matches.length === 0;
|
|
631
|
+
return !knownBasenames.has(t.toLowerCase());
|
|
595
632
|
}
|
|
596
|
-
return !
|
|
633
|
+
return !knownTargets.has(t);
|
|
597
634
|
})
|
|
598
635
|
)
|
|
599
636
|
];
|
|
@@ -603,7 +640,7 @@ async function renderRootIndex(input) {
|
|
|
603
640
|
"Generated by `skillwiki index rebuild`. Generated sections are derived from typed-page frontmatter and project manifests.",
|
|
604
641
|
""
|
|
605
642
|
];
|
|
606
|
-
for (const section of
|
|
643
|
+
for (const section of ROOT_INDEX_SECTION_ORDER) {
|
|
607
644
|
lines.push(`## ${section}`, "");
|
|
608
645
|
const sectionEntries = entries.filter((e) => e.section === section);
|
|
609
646
|
for (const e of sectionEntries) {
|
|
@@ -642,6 +679,7 @@ export {
|
|
|
642
679
|
scanVault,
|
|
643
680
|
readPage,
|
|
644
681
|
readPageCached,
|
|
682
|
+
buildRootIndexUniverse,
|
|
645
683
|
renderRootIndex,
|
|
646
684
|
writeRootIndexProjection
|
|
647
685
|
};
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-7I2TPIV5.js";
|
|
6
6
|
import {
|
|
7
7
|
atomicWriteText,
|
|
8
|
+
buildRootIndexUniverse,
|
|
8
9
|
extractFrontmatter,
|
|
9
10
|
mapWithConcurrency,
|
|
10
11
|
prepareTypedPage,
|
|
@@ -18,7 +19,7 @@ import {
|
|
|
18
19
|
splitFrontmatter,
|
|
19
20
|
vaultIoConcurrency,
|
|
20
21
|
writeRootIndexProjection
|
|
21
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-U34B2XQJ.js";
|
|
22
23
|
import {
|
|
23
24
|
CONFIG_KEYS,
|
|
24
25
|
isValidWikiProfileKey,
|
|
@@ -1561,8 +1562,11 @@ function normalizeIndexTarget(raw) {
|
|
|
1561
1562
|
return raw.replace(/\.md$/, "").replace(/^\.?\//, "");
|
|
1562
1563
|
}
|
|
1563
1564
|
async function runIndexCheck(input) {
|
|
1564
|
-
const
|
|
1565
|
-
if (!
|
|
1565
|
+
const universe = await buildRootIndexUniverse({ vault: input.vault, scan: input.scan });
|
|
1566
|
+
if (!universe.ok) {
|
|
1567
|
+
const exitCode = universe.error === "VAULT_PATH_INVALID" ? ExitCode.VAULT_PATH_INVALID : ExitCode.SCHEME_REJECTED;
|
|
1568
|
+
return { exitCode, result: universe };
|
|
1569
|
+
}
|
|
1566
1570
|
let indexText = "";
|
|
1567
1571
|
try {
|
|
1568
1572
|
indexText = await readFile6(join10(input.vault, "index.md"), "utf8");
|
|
@@ -1579,25 +1583,22 @@ async function runIndexCheck(input) {
|
|
|
1579
1583
|
indexBare.set(bare, list);
|
|
1580
1584
|
}
|
|
1581
1585
|
const required = /* @__PURE__ */ new Map();
|
|
1582
|
-
const
|
|
1583
|
-
|
|
1584
|
-
const target = p.relPath.replace(/\.md$/, "");
|
|
1585
|
-
required.set(target, p.relPath);
|
|
1586
|
-
known.add(target);
|
|
1586
|
+
for (const entry of universe.data.required) {
|
|
1587
|
+
required.set(entry.target, `${entry.target}.md`);
|
|
1587
1588
|
}
|
|
1588
|
-
|
|
1589
|
-
|
|
1589
|
+
const requiredBasenameCounts = /* @__PURE__ */ new Map();
|
|
1590
|
+
for (const target of required.keys()) {
|
|
1591
|
+
const basename3 = target.split("/").pop().toLowerCase();
|
|
1592
|
+
requiredBasenameCounts.set(basename3, (requiredBasenameCounts.get(basename3) ?? 0) + 1);
|
|
1590
1593
|
}
|
|
1594
|
+
const known = universe.data.knownTargets;
|
|
1591
1595
|
const missing_from_index = [];
|
|
1592
1596
|
for (const [target, relPath] of required.entries()) {
|
|
1593
1597
|
if (indexTargets.has(target)) continue;
|
|
1594
1598
|
const bare = target.split("/").pop().toLowerCase();
|
|
1595
1599
|
const bareHits = indexBare.get(bare) ?? [];
|
|
1596
1600
|
const basenameOnly = bareHits.filter((t) => !t.includes("/"));
|
|
1597
|
-
|
|
1598
|
-
(t) => t.split("/").pop().toLowerCase() === bare
|
|
1599
|
-
);
|
|
1600
|
-
if (basenameOnly.length === 1 && sameNameRequired.length === 1) continue;
|
|
1601
|
+
if (basenameOnly.length === 1 && requiredBasenameCounts.get(bare) === 1) continue;
|
|
1601
1602
|
missing_from_index.push(relPath);
|
|
1602
1603
|
}
|
|
1603
1604
|
const ghost_entries = [];
|
package/dist/cli.js
CHANGED
|
@@ -68,7 +68,7 @@ import {
|
|
|
68
68
|
satelliteLatestRunPath,
|
|
69
69
|
taxonomyCommentForPage,
|
|
70
70
|
upsertIndexEntry
|
|
71
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-Z3WS45PL.js";
|
|
72
72
|
import {
|
|
73
73
|
normalizeDistTag,
|
|
74
74
|
readCache,
|
|
@@ -88,7 +88,7 @@ import {
|
|
|
88
88
|
scanVault,
|
|
89
89
|
splitFrontmatter,
|
|
90
90
|
writeRootIndexProjection
|
|
91
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-U34B2XQJ.js";
|
|
92
92
|
import {
|
|
93
93
|
acquireManagedWriteLock,
|
|
94
94
|
releaseManagedWriteLock,
|
|
@@ -2533,7 +2533,7 @@ ${fmRewritten}
|
|
|
2533
2533
|
await rename2(join17(input.vault, relPath), join17(input.vault, archivePath));
|
|
2534
2534
|
let indexUpdated = false;
|
|
2535
2535
|
if (!isRaw) {
|
|
2536
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
2536
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-VNJ3TLEK.js");
|
|
2537
2537
|
const before = await readFile7(join17(input.vault, "index.md"), "utf8").catch(() => "");
|
|
2538
2538
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
2539
2539
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
@@ -2644,7 +2644,7 @@ async function runRemove(input) {
|
|
|
2644
2644
|
if (relPath.endsWith(".md") && !relPath.startsWith("raw/")) {
|
|
2645
2645
|
const { readFile: readFile17 } = await import("fs/promises");
|
|
2646
2646
|
const { join: pathJoin } = await import("path");
|
|
2647
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
2647
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-VNJ3TLEK.js");
|
|
2648
2648
|
const before = await readFile17(pathJoin(input.vault, "index.md"), "utf8").catch(() => "");
|
|
2649
2649
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
2650
2650
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
package/dist/skillwiki-mcp.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runSkillwikiMcpStdio
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-Z3WS45PL.js";
|
|
5
5
|
import "./chunk-7I2TPIV5.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-U34B2XQJ.js";
|
|
7
7
|
import "./chunk-R6BKJWVC.js";
|
|
8
8
|
import "./chunk-C5OLZRRM.js";
|
|
9
9
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"skills": "./",
|
|
5
5
|
"description": "Project-aware Karpathy-style knowledge base for Claude Code: 19 prompt-only skills (wiki-*, proj-*, using-skillwiki) backed by the deterministic `skillwiki` CLI.",
|
|
6
6
|
"author": {
|