skillwiki 0.2.1-beta.27 → 0.2.1-beta.29

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 CHANGED
@@ -949,6 +949,7 @@ import { dirname as dirname3, resolve as resolve2, join as join5 } from "path";
949
949
  var FENCE2 = /```[\s\S]*?```/g;
950
950
  var INLINE_CODE = /``[^`\n]+``|`[^`\n]+`/g;
951
951
  var MARKER_RE = /\^\[(raw\/[^\]]+)\]/g;
952
+ var FRONTMATTER = /^---\n[\s\S]*?\n---\n?/;
952
953
  function stripFences(body) {
953
954
  return body.replace(FENCE2, "").replace(INLINE_CODE, "");
954
955
  }
@@ -971,7 +972,7 @@ function isLegacyCitationStyle(body) {
971
972
  const markers = extractCitationMarkers(body);
972
973
  if (markers.length === 0) return false;
973
974
  if (!hasSourcesFooter(body)) return true;
974
- const lines = stripFences(body).split("\n");
975
+ const lines = stripFences(body.replace(FRONTMATTER, "")).split("\n");
975
976
  let inSources = false;
976
977
  let lastNonBlankWasTable = false;
977
978
  for (const line of lines) {
@@ -992,12 +993,12 @@ function isLegacyCitationStyle(body) {
992
993
  const afterLast = line.slice(lastMatch.index + lastMatch[0].length).replace(MARKER_RE, "").trim();
993
994
  if (afterLast.length > 0) return true;
994
995
  const beforeFirst = line.slice(0, matches[0].index).trim();
995
- if (beforeFirst.length > 0 && !/[.!?]\s*$/.test(beforeFirst)) return true;
996
+ if (beforeFirst.length > 0 && !/[.!?]["'"]*\s*$/.test(beforeFirst)) return true;
996
997
  }
997
998
  return false;
998
999
  }
999
1000
  function hasOrphanedCitations(body) {
1000
- const stripped = stripFences(body);
1001
+ const stripped = stripFences(body.replace(FRONTMATTER, ""));
1001
1002
  const lines = stripped.split("\n");
1002
1003
  let inSources = false;
1003
1004
  let sourcesEnded = false;
@@ -1030,7 +1031,8 @@ function hasOrphanedCitations(body) {
1030
1031
  }
1031
1032
  if (sourcesStartLine === -1) return false;
1032
1033
  if (sourcesEnded) {
1033
- for (let i = lastNonBlankInSources + 1; i < lines.length; i++) {
1034
+ const scanStart = Math.max(lastNonBlankInSources + 1, sourcesStartLine + 1);
1035
+ for (let i = scanStart; i < lines.length; i++) {
1034
1036
  if (/\^\[raw\//.test(lines[i])) {
1035
1037
  return true;
1036
1038
  }
@@ -2432,7 +2434,6 @@ async function runLint(input) {
2432
2434
  const bodyLines = body.split("\n");
2433
2435
  let inSrc = false;
2434
2436
  const newBodyLines = [];
2435
- const seen = /* @__PURE__ */ new Set();
2436
2437
  for (const line of bodyLines) {
2437
2438
  if (/^## Sources\b/.test(line.trim())) {
2438
2439
  inSrc = true;
@@ -2443,23 +2444,22 @@ async function runLint(input) {
2443
2444
  newBodyLines.push(line);
2444
2445
  continue;
2445
2446
  }
2447
+ INLINE_MARKER.lastIndex = 0;
2446
2448
  const lineWithoutMarkers = line.replace(INLINE_MARKER, "").trim();
2449
+ INLINE_MARKER.lastIndex = 0;
2447
2450
  if (lineWithoutMarkers.length === 0 && INLINE_MARKER.test(line)) {
2448
2451
  continue;
2449
2452
  }
2450
2453
  let cleaned = line;
2451
2454
  for (const marker of inlineMarkers) {
2452
- if (seen.has(marker)) continue;
2453
2455
  const escapedMarker = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2454
2456
  const trailingRe = new RegExp(`([.!?]\\s*)${escapedMarker}`);
2455
2457
  if (trailingRe.test(cleaned)) {
2456
2458
  cleaned = cleaned.replace(trailingRe, "$1");
2457
- seen.add(marker);
2458
2459
  }
2459
2460
  const midRe = new RegExp(`${escapedMarker}\\s*`);
2460
- if (!seen.has(marker) && midRe.test(cleaned)) {
2461
+ if (midRe.test(cleaned)) {
2461
2462
  cleaned = cleaned.replace(midRe, "");
2462
- seen.add(marker);
2463
2463
  }
2464
2464
  }
2465
2465
  newBodyLines.push(cleaned);
@@ -3233,7 +3233,7 @@ async function runArchive(input) {
3233
3233
  indexUpdated = true;
3234
3234
  }
3235
3235
  } catch (e) {
3236
- if (e?.code !== "ENOENT") throw e;
3236
+ if (e instanceof Error && "code" in e && e.code !== "ENOENT") throw e;
3237
3237
  }
3238
3238
  }
3239
3239
  await rename4(join22(input.vault, relPath), join22(input.vault, archivePath));
@@ -3263,7 +3263,7 @@ async function controlledFetch(url, opts) {
3263
3263
  res = await fetch(current, { redirect: "manual", signal: ctrl.signal });
3264
3264
  } catch (e) {
3265
3265
  clearTimeout(timer);
3266
- if (e?.name === "AbortError") return err("FETCH_TIMEOUT", { url: current });
3266
+ if (e instanceof Error && e.name === "AbortError") return err("FETCH_TIMEOUT", { url: current });
3267
3267
  return err("FETCH_FAILED", { message: String(e) });
3268
3268
  }
3269
3269
  clearTimeout(timer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.2.1-beta.27",
3
+ "version": "0.2.1-beta.29",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "skillwiki": "dist/cli.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.2.1-beta.27",
3
+ "version": "0.2.1-beta.29",
4
4
  "skills": "./",
5
5
  "description": "Project-aware Karpathy-style knowledge base for Claude Code: 19 prompt-only skills (wiki-*, proj-*, dev-loop-research, using-skillwiki) backed by the deterministic `skillwiki` CLI.",
6
6
  "author": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillwiki/skills",
3
- "version": "0.2.1-beta.27",
3
+ "version": "0.2.1-beta.29",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",
@@ -13,7 +13,7 @@ description: Write an Architectural Decision Record (ADR). If the decision gener
13
13
  Standard four + project context.
14
14
 
15
15
  ## Steps
16
- 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
+ 1. Compose the ADR in `projects/{slug}/architecture/YYYY-MM-DD-{adr-slug}.md`. Frontmatter: kind=decision, status=in-progress or completed, project link. If no project context exists, default to `playground`.
17
17
  2. `skillwiki validate <adr>`. If non-zero, STOP.
18
18
  3. **Generalization check.** If the decision applies beyond this project, create a `concepts/` page with `provenance: project` (or `mixed` if research-informed).
19
19
  4. Apply writes: ADR → (optional) concept page → vault `index.md` → vault `log.md` and project `log.md`.
@@ -16,7 +16,7 @@ Standard four + project context.
16
16
 
17
17
  ### Source selection
18
18
 
19
- Check `projects/{slug}/compound/` first. If empty, fall back to retro
19
+ Check `projects/{slug}/compound/` first. If no project context exists, default to `playground`. If empty, fall back to retro
20
20
  entries in vault `log.md` (lines matching `## [YYYY-MM-DD] retro`).
21
21
 
22
22
  When reading retros as source material:
@@ -9,6 +9,7 @@ description: Open or run a work item under projects/{slug}/work/YYYY-MM-DD-{slug
9
9
  ## When to invoke
10
10
  - User starts a feature, issue, refactor, or decision inside an existing project.
11
11
  - Brainstorming or writing-plans skills would otherwise default-write outside the project tree.
12
+ - If no project context can be determined, default to the `playground` slug so redirect paths always emit and the PRD bridge chain works.
12
13
 
13
14
  ## Pre-orientation reads
14
15
  Standard four + project context (project README, last ~5 work logs).
@@ -139,6 +139,6 @@ When skillwiki is installed, **all spec and plan documents must land in the vaul
139
139
 
140
140
  Both skills say "User preferences for spec location override this default" — the vault work-item path IS the override.
141
141
 
142
- **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`.
142
+ **If no project context exists** (standalone vault, not inside a project), default to the `playground` project slug. Invoke `proj-work` with `playground` as the slug so redirect paths are emitted normally and the PRD bridge chain works. The `playground` project is a pre-initialized catch-all workspace at `projects/playground/` for exploratory work, experiments, and unclassified features. Work items that mature can be moved to a real project later.
143
143
 
144
144
  **Never create `docs/superpowers/` in any repo.**
@@ -26,7 +26,8 @@ Standard four reads (SCHEMA, index, log, project context if applicable).
26
26
  2. Run `skillwiki archive <page> [vault]`. Read the JSON output.
27
27
  3. Verify with `skillwiki index-check [vault]` — confirm no ghost entries remain.
28
28
  4. Run `skillwiki lint [vault]` — check for broken wikilinks from other pages that still reference the archived page. If found, update those pages to point to the replacement or remove the stale link.
29
- 5. Append a `log.md` entry: `## [{date}] archive | {relPath} _archive/{subdir}/`.
29
+ 5. **Raw file archiving (N9 Reingest Protocol only):** When archiving a `raw/` file due to content drift, update ALL `^[raw/...]` citation markers and `sources:` frontmatter entries that reference the old path. Change `raw/articles/foo.md` to `_archive/raw/articles/foo.md` in every referencing page. Verify with `skillwiki audit` that no broken markers remain.
30
+ 6. Append a `log.md` entry: `## [{date}] archive | {relPath} → _archive/{subdir}/`.
30
31
 
31
32
  ## Reversibility
32
33
 
@@ -39,6 +40,7 @@ Archiving is reversible: move the file back from `_archive/` to its original dir
39
40
 
40
41
  ## Forbidden
41
42
 
42
- - Archiving `raw/` files (N9 raw is immutable).
43
+ - Archiving `raw/` files outside the N9 Reingest Protocol (raw is immutable except during content-drift reingestion).
44
+ - Archiving raw files without updating all `^[raw/...]` citation markers that reference them.
43
45
  - Archiving without user confirmation.
44
46
  - Deleting files (archive moves, never deletes).
@@ -33,3 +33,4 @@ Standard four reads. If cwd is inside `projects/{slug}/`, also read project READ
33
33
  ## Forbidden
34
34
  - Filing without explicit `provenance:`.
35
35
  - Updating `index.md` before `validate` passes.
36
+ - Writing `[[wikilinks]]` to pages that don't exist in the vault. Before linking, verify the target exists: check `index.md` or `ls` the target directory. If the target doesn't exist yet, use plain text instead of a wikilink.
@@ -46,6 +46,7 @@ Run `skillwiki lang` at the start. Generate page-body prose, narrative sections,
46
46
  - Skipping `fetch-guard`.
47
47
  - Updating `index.md` or `log.md` before all pages validate.
48
48
  - Modifying any existing file in `raw/`.
49
+ - Writing `[[wikilinks]]` to pages that don't exist in the vault. Before linking, verify the target exists: check `index.md` or `ls` the target directory. If the target doesn't exist yet, use plain text instead of a wikilink.
49
50
 
50
51
  ## Batch Mode
51
52