skillwiki 0.10.21 → 0.10.23

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.
Files changed (49) hide show
  1. package/dist/chunk-6ZDKTNLA.js +294 -0
  2. package/dist/{chunk-65Q5UGND.js → chunk-BASWDOQB.js} +2 -2
  3. package/dist/{chunk-Y6KRDGI2.js → chunk-C2DKFJFA.js} +6 -1
  4. package/dist/chunk-EQPU2BPM.js +468 -0
  5. package/dist/{chunk-GNS2ZV5P.js → chunk-PQG26AGJ.js} +1 -1
  6. package/dist/{chunk-I5JD3BQZ.js → chunk-QBZYEEBD.js} +13 -296
  7. package/dist/chunk-QNTBNNEL.js +616 -0
  8. package/dist/{chunk-UNPZDCWN.js → chunk-SYKSL3JQ.js} +860 -700
  9. package/dist/cli.js +2334 -273
  10. package/dist/{index-projection-HAXDEM2F.js → index-projection-FRWTZB5Y.js} +3 -2
  11. package/dist/{managed-write-preflight-CTXX2MHQ.js → managed-write-preflight-4LPVMP42.js} +3 -3
  12. package/dist/skillwiki-mcp.js +6 -4
  13. package/dist/sources-L2SQV63E.js +10 -0
  14. package/package.json +1 -1
  15. package/skills/.claude-plugin/plugin.json +1 -1
  16. package/skills/.codex-plugin/plugin.json +1 -1
  17. package/skills/README.md +13 -2
  18. package/skills/agents/wiki-add-task.md +2 -1
  19. package/skills/agents/wiki-archive.md +8 -9
  20. package/skills/agents/wiki-audit.md +2 -1
  21. package/skills/agents/wiki-lint.md +2 -1
  22. package/skills/agents/wiki-query.md +3 -1
  23. package/skills/agents/wiki-reingest.md +9 -8
  24. package/skills/package.json +1 -1
  25. package/skills/proj-decide/SKILL.md +35 -5
  26. package/skills/skills/proj-decide/SKILL.md +35 -5
  27. package/skills/skills/using-skillwiki/SKILL.md +19 -13
  28. package/skills/skills/wiki-add-task/SKILL.md +4 -3
  29. package/skills/skills/wiki-archive/SKILL.md +23 -18
  30. package/skills/skills/wiki-audit/SKILL.md +3 -1
  31. package/skills/skills/wiki-init/SKILL.md +12 -1
  32. package/skills/skills/wiki-lint/SKILL.md +2 -1
  33. package/skills/skills/wiki-query/SKILL.md +7 -0
  34. package/skills/skills/wiki-reingest/SKILL.md +12 -8
  35. package/skills/skills/wiki-remove/SKILL.md +22 -5
  36. package/skills/skills/wiki-sync/SKILL.md +39 -54
  37. package/skills/using-skillwiki/SKILL.md +19 -13
  38. package/skills/wiki-add-task/SKILL.md +4 -3
  39. package/skills/wiki-archive/SKILL.md +23 -18
  40. package/skills/wiki-audit/SKILL.md +3 -1
  41. package/skills/wiki-init/SKILL.md +12 -1
  42. package/skills/wiki-lint/SKILL.md +2 -1
  43. package/skills/wiki-query/SKILL.md +7 -0
  44. package/skills/wiki-reingest/SKILL.md +12 -8
  45. package/skills/wiki-remove/SKILL.md +22 -5
  46. package/skills/wiki-sync/SKILL.md +39 -54
  47. package/templates/SCHEMA.md +8 -5
  48. package/templates/web-clipper/llm-wiki-clippings.json +56 -0
  49. package/templates/web-clipper/readme.txt +16 -0
@@ -1,16 +1,20 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ extractFrontmatter,
4
+ scanSensitiveContent,
5
+ scanVault
6
+ } from "./chunk-6ZDKTNLA.js";
2
7
  import {
3
8
  MetaSchema,
4
9
  TypedKnowledgeSchema,
5
10
  detectSchema,
6
11
  err,
7
- getErrorMessage,
8
12
  ok
9
- } from "./chunk-Y6KRDGI2.js";
13
+ } from "./chunk-C2DKFJFA.js";
10
14
 
11
15
  // src/utils/index-projection.ts
12
- import { readFile as readFile4 } from "fs/promises";
13
- import { join as join3 } from "path";
16
+ import { readFile as readFile3 } from "fs/promises";
17
+ import { join as join2 } from "path";
14
18
 
15
19
  // src/utils/atomic-write.ts
16
20
  import { randomBytes } from "crypto";
@@ -59,186 +63,11 @@ async function atomicWriteText(path, text) {
59
63
  }
60
64
 
61
65
  // src/utils/index-universe.ts
62
- import { readFile as readFile3 } from "fs/promises";
66
+ import { readFile as readFile2 } from "fs/promises";
63
67
 
64
68
  // src/utils/typed-page.ts
65
69
  import { lstatSync, realpathSync } from "fs";
66
70
  import { dirname as dirname2, posix, relative, resolve, sep } from "path";
67
-
68
- // src/parsers/frontmatter.ts
69
- import yaml from "js-yaml";
70
- var FM_OPEN = /^---\r?\n/;
71
- function splitFrontmatter(text) {
72
- if (!FM_OPEN.test(text)) return ok({ rawFrontmatter: "", body: text, bodyStart: 0 });
73
- const afterOpen = text.replace(FM_OPEN, "");
74
- const closeIdx = afterOpen.search(/\r?\n---\r?\n/);
75
- if (closeIdx === -1) return err("MISSING_CLOSING_DELIMITER");
76
- const rawFrontmatter = afterOpen.slice(0, closeIdx);
77
- const closeMatch = afterOpen.slice(closeIdx).match(/\r?\n---\r?\n/);
78
- const bodyStart = text.length - (afterOpen.length - closeIdx - closeMatch[0].length);
79
- const body = text.slice(bodyStart);
80
- return ok({ rawFrontmatter, body, bodyStart });
81
- }
82
- function extractFrontmatter(text) {
83
- const split = splitFrontmatter(text);
84
- if (!split.ok) return split;
85
- if (!split.data.rawFrontmatter) return ok({});
86
- try {
87
- const parsed = yaml.load(split.data.rawFrontmatter, { schema: yaml.JSON_SCHEMA });
88
- if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return ok({});
89
- return ok(parsed);
90
- } catch (e) {
91
- return err("INVALID_FRONTMATTER", { message: getErrorMessage(e) });
92
- }
93
- }
94
-
95
- // src/utils/sensitive-content.ts
96
- import { createHash } from "crypto";
97
- var REDACTED_RE = /\[REDACTED:[^\]]+\]/i;
98
- var SYNTHETIC_RE = /^(?:<[^>]+>|\$\{[^}]+\}|REPLACE_WITH_[A-Z0-9_]+|YOUR_[A-Z0-9_]+|EXAMPLE_[A-Z0-9_]+)$/i;
99
- var MATCHERS = [
100
- {
101
- kind: "private_key",
102
- re: /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/g
103
- },
104
- {
105
- kind: "authorization_header",
106
- re: /\bAuthorization["']?\s*:\s*["']?(Bearer\s+[A-Za-z0-9._~+/-]{20,})["']?/gi,
107
- valueGroup: 1
108
- },
109
- {
110
- kind: "cookie",
111
- re: /\b(?:Cookie|Set-Cookie)\s*:\s*([^\n]{20,})/gi,
112
- valueGroup: 1
113
- },
114
- {
115
- kind: "jwt",
116
- re: /\b([A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{12,}\.[A-Za-z0-9_-]{12,})\b/g,
117
- valueGroup: 1
118
- },
119
- {
120
- kind: "provider_key",
121
- re: /\b(sk-[A-Za-z0-9_-]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}|gh[pousr]_[A-Za-z0-9_=-]{20,})\b/g,
122
- valueGroup: 1
123
- },
124
- {
125
- kind: "access_key",
126
- re: /\b((?:AKIA|ASIA)[A-Z0-9]{16})\b/g,
127
- valueGroup: 1
128
- },
129
- {
130
- kind: "access_key",
131
- re: /\b(?:access[-_ ]?key|credential)["']?\s*[:=]\s*["']?([A-Za-z0-9._~+/-]{20,})["']?/gi,
132
- valueGroup: 1
133
- },
134
- {
135
- kind: "api_key",
136
- re: /\b(?:api[-_ ]?key)["']?\s*[:=]\s*["']?([A-Za-z0-9._~+/-]{20,})["']?/gi,
137
- valueGroup: 1
138
- },
139
- {
140
- kind: "password",
141
- re: /\b(?:pass(?:word|wd)?)["']?\s*[:=]\s*["']?([^\s`"']{8,})["']?/gi,
142
- valueGroup: 1
143
- },
144
- {
145
- kind: "secret",
146
- re: /\b(?:secret|client[-_ ]?secret)["']?\s*[:=]\s*["']?([A-Za-z0-9._~+/-]{16,})["']?/gi,
147
- valueGroup: 1
148
- },
149
- {
150
- kind: "token",
151
- re: /\b(?:token|session)["']?\s*[:=]\s*["']?([A-Za-z0-9._~+/-]{16,})["']?/gi,
152
- valueGroup: 1
153
- }
154
- ];
155
- function fingerprint(value) {
156
- return createHash("sha256").update(value).digest("hex").slice(0, 12);
157
- }
158
- function lineFor(text, offset) {
159
- return text.slice(0, offset).split(/\r?\n/).length;
160
- }
161
- function redactMarker(kind, value) {
162
- return `[REDACTED:${kind}:${fingerprint(value)}]`;
163
- }
164
- function isSyntheticPlaceholder(value) {
165
- return REDACTED_RE.test(value) || SYNTHETIC_RE.test(value.trim());
166
- }
167
- function isNonSecretTokenCapture(value) {
168
- if (value.startsWith("//")) return true;
169
- if (/^[a-z]{2,}(?:-[a-z]{2,})+$/.test(value)) return true;
170
- return false;
171
- }
172
- function collectMatches(text) {
173
- const matches = [];
174
- for (const matcher of MATCHERS) {
175
- matcher.re.lastIndex = 0;
176
- for (const m of text.matchAll(matcher.re)) {
177
- const whole = m[0];
178
- const start = m.index ?? 0;
179
- if (REDACTED_RE.test(whole)) continue;
180
- const value = matcher.valueGroup ? m[matcher.valueGroup] : whole;
181
- if (isSyntheticPlaceholder(value)) continue;
182
- if (matcher.kind === "token" && isNonSecretTokenCapture(value)) continue;
183
- const valueOffset = whole.lastIndexOf(value);
184
- const valueStart = start + Math.max(0, valueOffset);
185
- matches.push({
186
- start,
187
- end: start + whole.length,
188
- valueStart,
189
- valueEnd: valueStart + value.length,
190
- kind: matcher.kind
191
- });
192
- }
193
- }
194
- return matches.sort((a, b) => {
195
- if (a.valueStart !== b.valueStart) return a.valueStart - b.valueStart;
196
- return b.valueEnd - b.valueStart - (a.valueEnd - a.valueStart);
197
- });
198
- }
199
- function collapseOverlaps(matches) {
200
- const kept = [];
201
- for (const match of matches) {
202
- const overlaps = kept.some((k) => match.valueStart < k.valueEnd && match.valueEnd > k.valueStart);
203
- if (!overlaps) kept.push(match);
204
- }
205
- return kept;
206
- }
207
- function scanSensitiveContent(text, opts = {}) {
208
- return collapseOverlaps(collectMatches(text)).map((match) => {
209
- const value = text.slice(match.valueStart, match.valueEnd);
210
- const marker = redactMarker(match.kind, value);
211
- const rawPreview = text.slice(Math.max(0, match.start - 24), Math.min(text.length, match.end + 24));
212
- const preview = rawPreview.replace(value, marker);
213
- return {
214
- file: opts.file,
215
- line: lineFor(text, match.valueStart),
216
- kind: match.kind,
217
- preview,
218
- fingerprint: fingerprint(value)
219
- };
220
- });
221
- }
222
- function redactSensitiveContent(text, opts = {}) {
223
- const matches = collapseOverlaps(collectMatches(text));
224
- if (matches.length === 0) return { text, changed: false, findings: [] };
225
- let out = "";
226
- let cursor = 0;
227
- for (const match of matches) {
228
- const value = text.slice(match.valueStart, match.valueEnd);
229
- out += text.slice(cursor, match.valueStart);
230
- out += redactMarker(match.kind, value);
231
- cursor = match.valueEnd;
232
- }
233
- out += text.slice(cursor);
234
- return {
235
- text: out,
236
- changed: out !== text,
237
- findings: scanSensitiveContent(text, opts)
238
- };
239
- }
240
-
241
- // src/utils/typed-page.ts
242
71
  var TYPE_DIRECTORY = {
243
72
  entity: "entities",
244
73
  concept: "concepts",
@@ -346,108 +175,6 @@ function prepareTypedPage(content, target) {
346
175
  return invalidFrontmatter(target, []);
347
176
  }
348
177
 
349
- // src/utils/vault.ts
350
- import { existsSync, readFileSync } from "fs";
351
- import { readFile as readFile2, readdir, stat } from "fs/promises";
352
- import { join as join2, relative as relative2, sep as sep2 } from "path";
353
- var TYPED_DIRS = ["entities", "concepts", "comparisons", "queries", "meta"];
354
- var SKIP_DIRS = /* @__PURE__ */ new Set([".git", "node_modules"]);
355
- var DEFAULT_IO_CONCURRENCY = 1;
356
- function vaultIoConcurrency() {
357
- const raw = Number.parseInt(process.env.SKILLWIKI_VAULT_IO_CONCURRENCY ?? "", 10);
358
- return Number.isFinite(raw) && raw > 0 ? Math.min(raw, 64) : DEFAULT_IO_CONCURRENCY;
359
- }
360
- function decodeProcMountPath(value) {
361
- return value.replace(/\\040/g, " ");
362
- }
363
- function isRcloneFuseVaultFromMounts(root, mounts) {
364
- return mounts.split(/\r?\n/).some((line) => {
365
- const parts = line.split(" ");
366
- if (parts.length < 3) return false;
367
- const mountPoint = decodeProcMountPath(parts[1]);
368
- const fsType = parts[2];
369
- return fsType === "fuse.rclone" && (root === mountPoint || root.startsWith(`${mountPoint}/`));
370
- });
371
- }
372
- function resolveReadOnlyVaultRootWithMounts(root, mounts) {
373
- if (/^(1|true|yes)$/i.test(process.env.SKILLWIKI_DISABLE_VAULT_READ_MIRROR ?? "")) {
374
- return { root, mirrored: false };
375
- }
376
- const explicitMirror = process.env.SKILLWIKI_VAULT_READ_MIRROR;
377
- if (explicitMirror && existsSync(join2(explicitMirror, "SCHEMA.md"))) {
378
- return { root: explicitMirror, mirrored: explicitMirror !== root };
379
- }
380
- const siblingMirror = `${root}-git`;
381
- if (isRcloneFuseVaultFromMounts(root, mounts) && existsSync(join2(siblingMirror, "SCHEMA.md"))) {
382
- return { root: siblingMirror, mirrored: true };
383
- }
384
- return { root, mirrored: false };
385
- }
386
- function resolveReadOnlyVaultRoot(root) {
387
- let mounts = "";
388
- try {
389
- mounts = readFileSync("/proc/mounts", "utf8");
390
- } catch {
391
- }
392
- return resolveReadOnlyVaultRootWithMounts(root, mounts);
393
- }
394
- async function mapWithConcurrency(items, limit, mapper) {
395
- const out = new Array(items.length);
396
- let next = 0;
397
- const workers = Array.from({ length: Math.min(Math.max(1, limit), items.length) }, async () => {
398
- for (; ; ) {
399
- const index = next++;
400
- if (index >= items.length) return;
401
- out[index] = await mapper(items[index], index);
402
- }
403
- });
404
- await Promise.all(workers);
405
- return out;
406
- }
407
- async function scanVault(root) {
408
- try {
409
- await stat(join2(root, "SCHEMA.md"));
410
- } catch {
411
- return err("VAULT_PATH_INVALID", { root, reason: "SCHEMA.md missing" });
412
- }
413
- const all = await walk(root);
414
- const rels = all.map((p) => ({ absPath: p, relPath: relative2(root, p).split(sep2).join("/") }));
415
- return ok({
416
- root,
417
- allMarkdown: rels,
418
- typedKnowledge: rels.filter((p) => TYPED_DIRS.some((d) => p.relPath.startsWith(d + "/"))),
419
- raw: rels.filter((p) => p.relPath.startsWith("raw/")),
420
- workItems: rels.filter((p) => /^projects\/[^/]+\/work\/[^/]+\/(spec|plan|log)\.md$/.test(p.relPath)),
421
- compound: rels.filter((p) => /^projects\/[^/]+\/compound\//.test(p.relPath))
422
- });
423
- }
424
- async function walk(dir) {
425
- const entries = await readdir(dir, { withFileTypes: true });
426
- const out = [];
427
- const subdirs = [];
428
- for (const e of entries) {
429
- const p = join2(dir, e.name);
430
- if (e.isDirectory()) {
431
- if (SKIP_DIRS.has(e.name)) continue;
432
- subdirs.push(p);
433
- } else if (e.isFile() && e.name.endsWith(".md")) out.push(p);
434
- }
435
- const nested = await mapWithConcurrency(subdirs, Math.min(8, vaultIoConcurrency()), walk);
436
- for (const files of nested) out.push(...files);
437
- return out;
438
- }
439
- async function readPage(p) {
440
- return readFile2(p.absPath, "utf8");
441
- }
442
- async function readPageCached(p, cache) {
443
- if (!cache) return readPage(p);
444
- const existing = cache.get(p.absPath);
445
- if (existing) return existing;
446
- const pending = readPage(p);
447
- cache.set(p.absPath, pending);
448
- return pending;
449
- }
450
-
451
178
  // src/utils/index-universe.ts
452
179
  var ROOT_INDEX_SECTION_ORDER = [
453
180
  "Entities",
@@ -480,7 +207,7 @@ async function buildRootIndexUniverse(input) {
480
207
  for (const page of typedPages) {
481
208
  let text;
482
209
  try {
483
- text = await readFile3(page.absPath, "utf8");
210
+ text = await readFile2(page.absPath, "utf8");
484
211
  } catch {
485
212
  continue;
486
213
  }
@@ -526,7 +253,7 @@ async function buildRootIndexUniverse(input) {
526
253
  for (const readme of projectReadmes) {
527
254
  let text;
528
255
  try {
529
- text = await readFile3(readme.absPath, "utf8");
256
+ text = await readFile2(readme.absPath, "utf8");
530
257
  } catch {
531
258
  continue;
532
259
  }
@@ -600,7 +327,7 @@ async function renderRootIndex(input) {
600
327
  let currentText = input.currentText;
601
328
  if (currentText === void 0) {
602
329
  try {
603
- currentText = await readFile4(join3(vault, "index.md"), "utf8");
330
+ currentText = await readFile3(join2(vault, "index.md"), "utf8");
604
331
  } catch {
605
332
  currentText = "";
606
333
  }
@@ -668,23 +395,13 @@ async function renderRootIndex(input) {
668
395
  });
669
396
  }
670
397
  async function writeRootIndexProjection(vault, projection) {
671
- return atomicWriteText(join3(vault, "index.md"), projection.text);
398
+ return atomicWriteText(join2(vault, "index.md"), projection.text);
672
399
  }
673
400
 
674
401
  export {
675
- splitFrontmatter,
676
- extractFrontmatter,
677
- scanSensitiveContent,
678
- redactSensitiveContent,
679
402
  atomicWriteText,
680
403
  assertTargetInsideVault,
681
404
  prepareTypedPage,
682
- vaultIoConcurrency,
683
- resolveReadOnlyVaultRoot,
684
- mapWithConcurrency,
685
- scanVault,
686
- readPage,
687
- readPageCached,
688
405
  buildRootIndexUniverse,
689
406
  UNMANAGED_START,
690
407
  UNMANAGED_END,