skillwiki 0.2.0-beta.24 → 0.2.0-beta.26
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 +90 -4
- package/package.json +1 -1
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/bin/skillwiki +5 -0
- package/skills/package.json +1 -1
- package/skills/proj-decide/SKILL.md +1 -1
- package/skills/proj-distill/SKILL.md +1 -1
- package/skills/proj-work/SKILL.md +1 -1
- package/skills/using-skillwiki/SKILL.md +20 -0
- package/skills/wiki-audit/SKILL.md +1 -1
- package/skills/wiki-crystallize/SKILL.md +1 -1
- package/skills/wiki-ingest/SKILL.md +3 -3
- package/skills/wiki-query/SKILL.md +2 -2
package/dist/cli.js
CHANGED
|
@@ -1009,6 +1009,20 @@ async function runInstall(input) {
|
|
|
1009
1009
|
installed.push(dst);
|
|
1010
1010
|
if (r.data.backupPath) backed_up.push(r.data.backupPath);
|
|
1011
1011
|
}
|
|
1012
|
+
const binSrc = join4(input.skillsRoot, "bin", "skillwiki");
|
|
1013
|
+
try {
|
|
1014
|
+
await stat4(binSrc);
|
|
1015
|
+
const binDst = join4(input.target, "bin", "skillwiki");
|
|
1016
|
+
if (!input.dryRun) {
|
|
1017
|
+
const r = await atomicCopyWithBackup(binSrc, binDst);
|
|
1018
|
+
if (!r.ok) return { exitCode: ExitCode.ATOMIC_COPY_FAILED, result: r };
|
|
1019
|
+
installed.push(binDst);
|
|
1020
|
+
if (r.data.backupPath) backed_up.push(r.data.backupPath);
|
|
1021
|
+
} else {
|
|
1022
|
+
installed.push(binDst);
|
|
1023
|
+
}
|
|
1024
|
+
} catch {
|
|
1025
|
+
}
|
|
1012
1026
|
const manifest_path = join4(input.target, "wiki-manifest.json");
|
|
1013
1027
|
if (!input.dryRun) await writeManifest(manifest_path, { installed, backed_up });
|
|
1014
1028
|
const hintLines = [
|
|
@@ -1631,7 +1645,7 @@ function hasDuplicateFrontmatter(body) {
|
|
|
1631
1645
|
return false;
|
|
1632
1646
|
}
|
|
1633
1647
|
var ERROR_ORDER = ["broken_wikilinks", "invalid_frontmatter", "raw_dedup", "tag_not_in_taxonomy"];
|
|
1634
|
-
var WARNING_ORDER = ["index_incomplete", "index_link_format", "stale_page", "page_too_large", "log_rotate_needed", "contested", "orphans", "legacy_citation_style", "orphaned_citations", "duplicate_frontmatter"];
|
|
1648
|
+
var WARNING_ORDER = ["index_incomplete", "index_link_format", "stale_page", "page_too_large", "log_rotate_needed", "contested", "orphans", "legacy_citation_style", "orphaned_citations", "duplicate_frontmatter", "missing_overview"];
|
|
1635
1649
|
var INFO_ORDER = ["bridges", "low_confidence_single_source", "page_structure", "topic_map_recommended"];
|
|
1636
1650
|
async function runLint(input) {
|
|
1637
1651
|
const buckets = {};
|
|
@@ -1681,6 +1695,7 @@ async function runLint(input) {
|
|
|
1681
1695
|
const orphanedPages = [];
|
|
1682
1696
|
const structFlags = [];
|
|
1683
1697
|
const dupFrontmatter = [];
|
|
1698
|
+
const noOverview = [];
|
|
1684
1699
|
for (const page of scan.data.typedKnowledge) {
|
|
1685
1700
|
const text = await readPage(page);
|
|
1686
1701
|
const split = splitFrontmatter(text);
|
|
@@ -1690,13 +1705,13 @@ async function runLint(input) {
|
|
|
1690
1705
|
if (isLegacyCitationStyle(body)) legacyPages.push(page.relPath);
|
|
1691
1706
|
if (hasOrphanedCitations(body)) orphanedPages.push(page.relPath);
|
|
1692
1707
|
const bodyLines = body.split("\n").filter((l) => l.trim().length > 0).length;
|
|
1708
|
+
const hasOverview = /^## Overview/m.test(body);
|
|
1709
|
+
if (!hasOverview) noOverview.push(page.relPath);
|
|
1693
1710
|
if (bodyLines < STRUCT_MIN_BODY_LINES) {
|
|
1694
|
-
const hasOverview = /^## Overview/m.test(body);
|
|
1695
1711
|
const hasRelated = /^## (Related|Relationships)/m.test(body);
|
|
1696
1712
|
const sectionCount = (body.match(/^## /gm) ?? []).length;
|
|
1697
|
-
if (!
|
|
1713
|
+
if (!hasRelated || sectionCount < STRUCT_MIN_SECTIONS) {
|
|
1698
1714
|
const reasons = [];
|
|
1699
|
-
if (!hasOverview) reasons.push("no Overview");
|
|
1700
1715
|
if (!hasRelated) reasons.push("no Related or Relationships");
|
|
1701
1716
|
if (sectionCount < STRUCT_MIN_SECTIONS) reasons.push(`only ${sectionCount} sections`);
|
|
1702
1717
|
structFlags.push(`${page.relPath}: ${bodyLines} lines, ${reasons.join(", ")}`);
|
|
@@ -1707,6 +1722,7 @@ async function runLint(input) {
|
|
|
1707
1722
|
if (orphanedPages.length > 0) buckets.orphaned_citations = orphanedPages;
|
|
1708
1723
|
if (structFlags.length > 0) buckets.page_structure = structFlags;
|
|
1709
1724
|
if (dupFrontmatter.length > 0) buckets.duplicate_frontmatter = dupFrontmatter;
|
|
1725
|
+
if (noOverview.length > 0) buckets.missing_overview = noOverview;
|
|
1710
1726
|
}
|
|
1711
1727
|
const errorOut = ERROR_ORDER.flatMap((k) => buckets[k] ? [{ kind: k, items: buckets[k] }] : []);
|
|
1712
1728
|
const warningOut = WARNING_ORDER.flatMap((k) => buckets[k] ? [{ kind: k, items: buckets[k] }] : []);
|
|
@@ -2321,6 +2337,71 @@ ${migratedBody}${newFooter}`;
|
|
|
2321
2337
|
};
|
|
2322
2338
|
}
|
|
2323
2339
|
|
|
2340
|
+
// src/commands/frontmatter-fix.ts
|
|
2341
|
+
import { writeFile as writeFile8 } from "fs/promises";
|
|
2342
|
+
function isoToday() {
|
|
2343
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2344
|
+
}
|
|
2345
|
+
function fixFrontmatter(rawFm) {
|
|
2346
|
+
const additions = [];
|
|
2347
|
+
if (!/^created:/m.test(rawFm)) additions.push(`created: ${isoToday()}`);
|
|
2348
|
+
if (!/^updated:/m.test(rawFm)) additions.push(`updated: ${isoToday()}`);
|
|
2349
|
+
if (!/^tags:/m.test(rawFm)) additions.push("tags: []");
|
|
2350
|
+
if (!/^sources:/m.test(rawFm)) additions.push("sources: []");
|
|
2351
|
+
if (!/^provenance:/m.test(rawFm)) additions.push("provenance: research");
|
|
2352
|
+
if (additions.length === 0) return rawFm;
|
|
2353
|
+
return rawFm.trimEnd() + "\n" + additions.join("\n") + "\n";
|
|
2354
|
+
}
|
|
2355
|
+
function removeOrphanTagsLines(body) {
|
|
2356
|
+
return body.split("\n").filter((line) => !/^tags:\s*\[/.test(line.trim())).join("\n");
|
|
2357
|
+
}
|
|
2358
|
+
async function runFrontmatterFix(input) {
|
|
2359
|
+
const scan = await scanVault(input.vault);
|
|
2360
|
+
if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
|
|
2361
|
+
const fixed = [];
|
|
2362
|
+
const skipped = [];
|
|
2363
|
+
let unchanged = 0;
|
|
2364
|
+
for (const page of scan.data.typedKnowledge) {
|
|
2365
|
+
const text = await readPage(page);
|
|
2366
|
+
const split = splitFrontmatter(text);
|
|
2367
|
+
if (!split.ok) {
|
|
2368
|
+
skipped.push(page.relPath);
|
|
2369
|
+
continue;
|
|
2370
|
+
}
|
|
2371
|
+
const { rawFrontmatter, body } = split.data;
|
|
2372
|
+
const newFm = fixFrontmatter(rawFrontmatter);
|
|
2373
|
+
const newBody = removeOrphanTagsLines(body);
|
|
2374
|
+
const newText = `---
|
|
2375
|
+
${newFm}
|
|
2376
|
+
---
|
|
2377
|
+
${newBody}`;
|
|
2378
|
+
if (newText === text) {
|
|
2379
|
+
unchanged++;
|
|
2380
|
+
continue;
|
|
2381
|
+
}
|
|
2382
|
+
if (!input.dryRun) {
|
|
2383
|
+
await writeFile8(page.absPath, newText, "utf8");
|
|
2384
|
+
}
|
|
2385
|
+
fixed.push(page.relPath);
|
|
2386
|
+
}
|
|
2387
|
+
const exitCode = fixed.length > 0 ? ExitCode.MIGRATION_APPLIED : ExitCode.OK;
|
|
2388
|
+
const hintLines = [`scanned: ${fixed.length + skipped.length + unchanged}`];
|
|
2389
|
+
if (fixed.length > 0) hintLines.push(`fixed: ${fixed.length}`);
|
|
2390
|
+
if (skipped.length > 0) hintLines.push(`skipped (parse error): ${skipped.length}`);
|
|
2391
|
+
if (unchanged > 0) hintLines.push(`unchanged: ${unchanged}`);
|
|
2392
|
+
if (input.dryRun && fixed.length > 0) hintLines.push("(dry run \u2014 no files written)");
|
|
2393
|
+
return {
|
|
2394
|
+
exitCode,
|
|
2395
|
+
result: ok({
|
|
2396
|
+
scanned: fixed.length + skipped.length + unchanged,
|
|
2397
|
+
fixed,
|
|
2398
|
+
skipped,
|
|
2399
|
+
unchanged,
|
|
2400
|
+
humanHint: hintLines.join("\n")
|
|
2401
|
+
})
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2324
2405
|
// src/commands/update.ts
|
|
2325
2406
|
import { execSync as execSync2 } from "child_process";
|
|
2326
2407
|
import { readFileSync as readFileSync3 } from "fs";
|
|
@@ -2532,6 +2613,11 @@ program.command("migrate-citations [vault]").description("migrate ^[raw/...] mar
|
|
|
2532
2613
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2533
2614
|
else emit(await runMigrateCitations({ vault: v.vault, dryRun: !!opts.dryRun }));
|
|
2534
2615
|
});
|
|
2616
|
+
program.command("frontmatter-fix [vault]").description("fix common frontmatter issues on typed-knowledge pages").option("--dry-run", "preview changes without writing", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
2617
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
2618
|
+
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
2619
|
+
else emit(await runFrontmatterFix({ vault: v.vault, dryRun: !!opts.dryRun }));
|
|
2620
|
+
});
|
|
2535
2621
|
program.command("update").description("update skillwiki CLI to the latest version").option("--tag <tag>", "npm dist-tag", "beta").action(async (opts) => emit(await runUpdate({
|
|
2536
2622
|
home: process.env.HOME ?? "",
|
|
2537
2623
|
distTag: opts.tag
|
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.26",
|
|
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
|
@@ -13,7 +13,7 @@ Standard four + project context.
|
|
|
13
13
|
|
|
14
14
|
## Steps
|
|
15
15
|
1. Compose the ADR in `projects/{slug}/architecture/YYYY-MM-DD-{adr-slug}.md`. Frontmatter: kind=decision, status=in-progress or completed, project link.
|
|
16
|
-
2. `
|
|
16
|
+
2. `skillwiki validate <adr>`. If non-zero, STOP.
|
|
17
17
|
3. **Generalization check.** If the decision applies beyond this project, create a `concepts/` page with `provenance: project` (or `mixed` if research-informed).
|
|
18
18
|
4. Apply writes: ADR → (optional) concept page → vault `index.md` → vault `log.md` and project `log.md`.
|
|
19
19
|
|
|
@@ -31,7 +31,7 @@ When reading retros as source material:
|
|
|
31
31
|
2. **Step 2 — Generate.** Compose the vault concept page with
|
|
32
32
|
`provenance: project` and
|
|
33
33
|
`provenance_projects: ["[[slug]]"]`. Validate with
|
|
34
|
-
`
|
|
34
|
+
`skillwiki validate`.
|
|
35
35
|
3. **Backlink.** Set `promoted_to: "[[concept-slug]]"` on the source
|
|
36
36
|
compound entry. For retro-sourced distillation, skip backlink (log.md
|
|
37
37
|
entries are append-only) and instead add `sources:` citing the vault
|
|
@@ -16,7 +16,7 @@ Standard four + project context (project README, last ~5 work logs).
|
|
|
16
16
|
1. Determine `kind:` (feature | issue | refactor | decision) and slug.
|
|
17
17
|
2. Create folder `projects/{slug}/work/YYYY-MM-DD-{work-slug}/`.
|
|
18
18
|
3. Override default output paths for any nested skill: `spec.md`, `plan.md`, and `log.md` are written here, not at vault root.
|
|
19
|
-
4. Validate work-item frontmatter via `
|
|
19
|
+
4. Validate work-item frontmatter via `skillwiki validate <spec.md>`. If non-zero, STOP.
|
|
20
20
|
5. Manage status transitions: `planned` → `in-progress` → `completed` (set `completed:` date) or `abandoned`.
|
|
21
21
|
6. Append vault `log.md` entry on creation and on each status transition.
|
|
22
22
|
|
|
@@ -100,3 +100,23 @@ skillwiki supports named wiki profiles for working with multiple vaults. Set `WI
|
|
|
100
100
|
- `skillwiki --wiki <name> lint` — override per-command
|
|
101
101
|
|
|
102
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.
|
|
103
|
+
|
|
104
|
+
## PRD Bridge — Redirect Spec/Plan Output to Vault
|
|
105
|
+
|
|
106
|
+
When skillwiki is installed, **all spec and plan documents must land in the vault**, not in repo-local directories like `docs/superpowers/`. This applies to any PRD/design skill (superpowers:brainstorming, superpowers:writing-plans, CodeStable, AIDE, Hermes, etc.).
|
|
107
|
+
|
|
108
|
+
**Rule:** Before a PRD skill writes a spec or plan file, redirect its save path:
|
|
109
|
+
1. Resolve the vault path: `skillwiki path`
|
|
110
|
+
2. If the cwd is inside a project (check for `projects/{slug}/` via `skillwiki path --init-time` or look for `./skillwiki/.env`), use that project's work directory
|
|
111
|
+
3. Create or locate the work item via `proj-work`, which emits redirect paths for `spec.md` and `plan.md`
|
|
112
|
+
4. Pass those vault paths to the PRD skill as its save location
|
|
113
|
+
|
|
114
|
+
**Concrete overrides for superpowers:**
|
|
115
|
+
- `superpowers:brainstorming` step 6: override `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` → vault work-item `spec.md` path from `proj-work`
|
|
116
|
+
- `superpowers:writing-plans` header: override `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md` → vault work-item `plan.md` path from `proj-work`
|
|
117
|
+
|
|
118
|
+
Both skills say "User preferences for spec location override this default" — the vault work-item path IS the override.
|
|
119
|
+
|
|
120
|
+
**If no project context exists** (standalone vault, not inside a project), save specs/plans directly under the vault root with the PRD skill's default naming, e.g. `<vault>/specs/YYYY-MM-DD-<slug>.md`.
|
|
121
|
+
|
|
122
|
+
**Never create `docs/superpowers/` in any repo.**
|
|
@@ -19,7 +19,7 @@ Standard four reads.
|
|
|
19
19
|
|
|
20
20
|
## Steps
|
|
21
21
|
0. **Resolve vault and language.** Run `skillwiki path` (fail if NO_VAULT_CONFIGURED) and `skillwiki lang`.
|
|
22
|
-
1. `
|
|
22
|
+
1. `skillwiki audit <page>`. Read the JSON report.
|
|
23
23
|
2. Reason over the report:
|
|
24
24
|
- For each unresolved marker: suggest ingesting the missing source or correcting the path.
|
|
25
25
|
- For each `unused_sources` entry: suggest adding a body marker or removing from `sources:`.
|
|
@@ -22,7 +22,7 @@ Standard four reads. If cwd is inside `projects/{slug}/`, also read project READ
|
|
|
22
22
|
1. Identify type: entity / concept / comparison / query / summary.
|
|
23
23
|
2. Set `provenance:`. Default `research`. If in project context: `project` with `provenance_projects: ["[[slug]]"]`.
|
|
24
24
|
3. Compose the page with citations pre-attached. Reuse existing `raw/` sources where possible.
|
|
25
|
-
4. `
|
|
25
|
+
4. `skillwiki validate <page>`. If non-zero, STOP.
|
|
26
26
|
5. Apply writes: page → `index.md` → `log.md`.
|
|
27
27
|
|
|
28
28
|
## Stop conditions
|
|
@@ -23,11 +23,11 @@ Run `skillwiki lang` at the start. Generate page-body prose, narrative sections,
|
|
|
23
23
|
|
|
24
24
|
## Steps (in order — N6, N7, N8)
|
|
25
25
|
0. **Resolve vault and language.** Run `skillwiki path` (fail if NO_VAULT_CONFIGURED) and `skillwiki lang`. Use the resolved vault path for all writes; use the canonical language for all generated prose.
|
|
26
|
-
1. **Guard.** For each URL: run `
|
|
26
|
+
1. **Guard.** For each URL: run `skillwiki fetch-guard <url>`. If exit ≠ 0, STOP and surface the error. Do not retry.
|
|
27
27
|
2. **Fetch.** Use `web_fetch` (or read local file) under Layer 2 controls (the CLI Layer 2 fetcher applies in tests; in skill runtime use `web_fetch` directly and treat any error as STOP).
|
|
28
|
-
3. **Hash.** Write the raw file (frontmatter + body). Run `
|
|
28
|
+
3. **Hash.** Write the raw file (frontmatter + body). Run `skillwiki hash <raw-file>` and embed the result in raw frontmatter `sha256:`.
|
|
29
29
|
4. **Generate page(s).** Compose typed-knowledge page(s) with citations pre-attached (`^[raw/...]` markers).
|
|
30
|
-
5. **Validate.** For each generated page: run `
|
|
30
|
+
5. **Validate.** For each generated page: run `skillwiki validate <page>`. If exit ≠ 0, STOP — do not write index/log.
|
|
31
31
|
6. **Apply writes in order.** raw → page(s) → `index.md` → `log.md`.
|
|
32
32
|
7. **Confidence flag.** If only one source is cited, set `confidence: low`.
|
|
33
33
|
|
|
@@ -20,8 +20,8 @@ Standard four reads (SCHEMA, index, log, project context if applicable).
|
|
|
20
20
|
## Steps
|
|
21
21
|
0. **Resolve vault and language.** Run `skillwiki path` (fail if NO_VAULT_CONFIGURED) and `skillwiki lang`.
|
|
22
22
|
1. **Determine scope.** Ask the user once if ambiguous: vault | current project | project+concepts.
|
|
23
|
-
2. **Refresh graph.** If `.skillwiki/graph.json` is missing or older than 24h: `
|
|
24
|
-
3. **Compute overlap.** `
|
|
23
|
+
2. **Refresh graph.** If `.skillwiki/graph.json` is missing or older than 24h: `skillwiki graph build <vault>`.
|
|
24
|
+
3. **Compute overlap.** `skillwiki overlap <vault>`.
|
|
25
25
|
4. **Score candidates** in prompt using the 4 signals:
|
|
26
26
|
- Direct wikilink: 3.0×
|
|
27
27
|
- Source overlap: 4.0× (read from overlap output)
|