@zosmaai/pi-llm-wiki 0.10.9 → 0.11.1

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 (82) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.de.md +35 -4
  3. package/README.es.md +260 -170
  4. package/README.fr.md +35 -4
  5. package/README.hi.md +35 -4
  6. package/README.ja.md +35 -4
  7. package/README.ko.md +35 -4
  8. package/README.md +41 -12
  9. package/README.pt.md +35 -4
  10. package/README.ru.md +35 -4
  11. package/README.zh.md +260 -170
  12. package/assets/demo.gif +0 -0
  13. package/dist/extensions/llm-wiki/lib/bootstrap.js +74 -0
  14. package/dist/extensions/llm-wiki/lib/embeddings.js +401 -0
  15. package/dist/extensions/llm-wiki/lib/guardrails.js +232 -0
  16. package/dist/extensions/llm-wiki/lib/indexing.js +78 -0
  17. package/dist/extensions/llm-wiki/lib/ingest-worker.js +410 -0
  18. package/dist/extensions/llm-wiki/lib/inject.js +65 -0
  19. package/dist/extensions/llm-wiki/lib/knowledge-document.js +442 -0
  20. package/dist/extensions/llm-wiki/lib/knowledge-links.js +206 -0
  21. package/dist/extensions/llm-wiki/lib/legacy-repair.js +443 -0
  22. package/dist/extensions/llm-wiki/lib/metadata.js +505 -0
  23. package/dist/extensions/llm-wiki/lib/model-command.js +85 -0
  24. package/dist/extensions/llm-wiki/lib/observation.js +283 -0
  25. package/dist/extensions/llm-wiki/lib/recall.js +875 -0
  26. package/dist/extensions/llm-wiki/lib/retro.js +158 -0
  27. package/dist/extensions/llm-wiki/lib/runtime.js +187 -0
  28. package/dist/extensions/llm-wiki/lib/source-extractors.js +426 -0
  29. package/dist/extensions/llm-wiki/lib/source-packet.js +229 -0
  30. package/dist/extensions/llm-wiki/lib/subagent.js +41 -0
  31. package/dist/extensions/llm-wiki/lib/task-config.js +201 -0
  32. package/dist/extensions/llm-wiki/lib/tools.js +1199 -0
  33. package/dist/extensions/llm-wiki/lib/trajectories-command.js +51 -0
  34. package/dist/extensions/llm-wiki/lib/trajectory.js +467 -0
  35. package/dist/extensions/llm-wiki/lib/utils.js +353 -0
  36. package/dist/extensions/llm-wiki/lib/vault-format.js +247 -0
  37. package/dist/extensions/llm-wiki/lib/visible-status.js +31 -0
  38. package/dist/extensions/llm-wiki/lib/wiki-service.js +128 -0
  39. package/dist/mcp/exec.js +121 -0
  40. package/dist/mcp/index.js +229 -0
  41. package/dist/mcp/operations.js +130 -0
  42. package/dist/package.json +1 -0
  43. package/docs/api.md +5 -2
  44. package/docs/architecture.md +5 -2
  45. package/docs/configuration.md +25 -0
  46. package/docs/superpowers/plans/2026-08-02-okf-foundation.md +1579 -0
  47. package/docs/superpowers/plans/2026-08-03-okf-foundation-remediation.md +3005 -0
  48. package/docs/superpowers/plans/2026-08-06-authoritative-event-history-phase-1-foundation-hardening.md +937 -0
  49. package/docs/superpowers/plans/2026-08-06-okf-foundation-release-remediation.md +1174 -0
  50. package/docs/superpowers/plans/2026-08-07-synthesis-language.md +98 -0
  51. package/docs/superpowers/specs/2026-08-02-okf-foundation-design.md +593 -0
  52. package/docs/superpowers/specs/2026-08-02-okf-v0.2-interoperability-design.md +542 -0
  53. package/docs/superpowers/specs/2026-08-07-synthesis-language-design.md +94 -0
  54. package/extensions/llm-wiki/index.ts +22 -36
  55. package/extensions/llm-wiki/lib/bootstrap.ts +87 -0
  56. package/extensions/llm-wiki/lib/embeddings.ts +9 -3
  57. package/extensions/llm-wiki/lib/guardrails.ts +26 -18
  58. package/extensions/llm-wiki/lib/indexing.ts +2 -1
  59. package/extensions/llm-wiki/lib/ingest-worker.ts +304 -28
  60. package/extensions/llm-wiki/lib/knowledge-document.ts +663 -0
  61. package/extensions/llm-wiki/lib/knowledge-links.ts +282 -0
  62. package/extensions/llm-wiki/lib/legacy-repair.ts +572 -0
  63. package/extensions/llm-wiki/lib/metadata.ts +550 -128
  64. package/extensions/llm-wiki/lib/model-command.ts +0 -1
  65. package/extensions/llm-wiki/lib/observation.ts +37 -43
  66. package/extensions/llm-wiki/lib/recall.ts +61 -33
  67. package/extensions/llm-wiki/lib/retro.ts +65 -41
  68. package/extensions/llm-wiki/lib/runtime.ts +0 -3
  69. package/extensions/llm-wiki/lib/source-extractors.ts +12 -17
  70. package/extensions/llm-wiki/lib/source-packet.ts +45 -32
  71. package/extensions/llm-wiki/lib/task-config.ts +36 -0
  72. package/extensions/llm-wiki/lib/tools.ts +413 -342
  73. package/extensions/llm-wiki/lib/trajectory.ts +15 -1
  74. package/extensions/llm-wiki/lib/utils.ts +127 -131
  75. package/extensions/llm-wiki/lib/vault-format.ts +363 -0
  76. package/extensions/llm-wiki/lib/wiki-service.ts +183 -0
  77. package/mcp/exec.ts +122 -0
  78. package/mcp/index.ts +60 -250
  79. package/mcp/operations.ts +176 -0
  80. package/package.json +8 -2
  81. package/scripts/migrate-llm-wiki.js +801 -0
  82. package/skills/llm-wiki/SKILL.md +12 -8
@@ -0,0 +1,282 @@
1
+ import type { Definition, Link, LinkReference, Nodes, Root } from "mdast";
2
+ import { fromMarkdown } from "mdast-util-from-markdown";
3
+ import type { KnowledgeDiagnostic } from "./knowledge-document.js";
4
+ import { compareCodePoint } from "./vault-format.js";
5
+
6
+ export interface ExtractedLink {
7
+ target: string;
8
+ offset: number;
9
+ }
10
+
11
+ export interface KnowledgeLinks {
12
+ markdown: ExtractedLink[];
13
+ wikilinks: ExtractedLink[];
14
+ }
15
+
16
+ export interface UnresolvedKnowledgeLink {
17
+ target: string;
18
+ syntax: "markdown" | "wikilink";
19
+ }
20
+
21
+ export interface ResolvedBacklinks {
22
+ targets: string[];
23
+ unresolved: UnresolvedKnowledgeLink[];
24
+ diagnostics: KnowledgeDiagnostic[];
25
+ }
26
+
27
+ function diag(
28
+ severity: "warning" | "error",
29
+ code: KnowledgeDiagnostic["code"],
30
+ path: string,
31
+ message: string,
32
+ ): KnowledgeDiagnostic {
33
+ return { severity, code, path, message };
34
+ }
35
+
36
+ export function extractKnowledgeLinks(body: string): KnowledgeLinks {
37
+ const markdown: ExtractedLink[] = [];
38
+ const wikilinks: ExtractedLink[] = [];
39
+
40
+ // Extract legacy wikilinks
41
+ for (const match of body.matchAll(/\[\[([^\]|]+)(?:\|[^\]]*)?\]\]/g)) {
42
+ wikilinks.push({ target: match[1].trim(), offset: match.index ?? 0 });
43
+ }
44
+
45
+ // Parse with CommonMark AST
46
+ let tree: Root;
47
+ try {
48
+ tree = fromMarkdown(body);
49
+ } catch {
50
+ return { markdown, wikilinks };
51
+ }
52
+
53
+ // Build definition map (case-insensitive)
54
+ const defs = new Map<string, Definition>();
55
+ function collectDefs(node: Nodes) {
56
+ if (node.type === "definition") {
57
+ defs.set(node.identifier.toLowerCase(), node);
58
+ }
59
+ if ("children" in node && Array.isArray((node as { children?: Nodes[] }).children)) {
60
+ for (const child of (node as { children: Nodes[] }).children) {
61
+ collectDefs(child);
62
+ }
63
+ }
64
+ }
65
+ collectDefs(tree);
66
+
67
+ // Track used definitions
68
+ const usedDefs = new Set<string>();
69
+
70
+ // Visit nodes for links
71
+ function visit(node: Nodes) {
72
+ // Skip code spans, fenced/indented code blocks, and raw HTML
73
+ if (node.type === "inlineCode" || node.type === "code" || node.type === "html") return;
74
+
75
+ if (node.type === "link") {
76
+ const link = node as Link;
77
+ // Skip autolinks (source starts with <)
78
+ if (link.url && link.position) {
79
+ const source = body.slice(link.position.start.offset, link.position.end.offset);
80
+ if (!source.startsWith("<")) {
81
+ markdown.push({ target: link.url, offset: link.position.start.offset ?? 0 });
82
+ }
83
+ }
84
+ }
85
+
86
+ if (node.type === "linkReference") {
87
+ const ref = node as LinkReference;
88
+ const ident = (ref.identifier ?? "").toLowerCase();
89
+ const def = defs.get(ident);
90
+ if (def && !usedDefs.has(ident)) {
91
+ usedDefs.add(ident);
92
+ if (ref.position) {
93
+ markdown.push({ target: def.url, offset: ref.position.start.offset ?? 0 });
94
+ }
95
+ }
96
+ }
97
+
98
+ // Recurse into children
99
+ if ("children" in node && Array.isArray((node as { children?: Nodes[] }).children)) {
100
+ for (const child of (node as { children: Nodes[] }).children) {
101
+ visit(child);
102
+ }
103
+ }
104
+ }
105
+
106
+ visit(tree);
107
+
108
+ return { markdown, wikilinks };
109
+ }
110
+
111
+ export function extractLegacyWikilinks(body: string): ExtractedLink[] {
112
+ const links: ExtractedLink[] = [];
113
+ for (const match of body.matchAll(/\[\[([^\]|]+)(?:\|[^\]]*)?\]\]/g)) {
114
+ links.push({ target: match[1].trim(), offset: match.index ?? 0 });
115
+ }
116
+ return links;
117
+ }
118
+
119
+ function resolveMarkdownTarget(
120
+ target: string,
121
+ sourceId: string,
122
+ ):
123
+ | { kind: "concept"; id: string }
124
+ | { kind: "escape" }
125
+ | { kind: "external" }
126
+ | { kind: "empty" }
127
+ | { kind: "invalid" } {
128
+ // Strip query and fragment (earliest delimiter)
129
+ const qIndex = target.indexOf("?");
130
+ const fIndex = target.indexOf("#");
131
+ let clean = target;
132
+ let cut = -1;
133
+ if (qIndex !== -1 && (fIndex === -1 || qIndex < fIndex)) cut = qIndex;
134
+ else if (fIndex !== -1) cut = fIndex;
135
+ if (cut !== -1) clean = target.slice(0, cut);
136
+
137
+ // Ignore empty fragment-only targets
138
+ if (!clean || clean === "#") return { kind: "empty" };
139
+
140
+ // Ignore external URI schemes
141
+ if (/^[a-z][a-z0-9+.-]*:/i.test(clean)) return { kind: "external" };
142
+
143
+ // Percent-decode each segment once, but never let malformed user input escape
144
+ // the link diagnostics boundary.
145
+ let decoded: string[];
146
+ try {
147
+ decoded = clean.split("/").map((segment) => decodeURIComponent(segment));
148
+ } catch {
149
+ return { kind: "invalid" };
150
+ }
151
+
152
+ // Convert decoded backslashes to /
153
+ const normalized = decoded.map((s) => s.replace(/\\/g, "/")).join("/");
154
+
155
+ const sourceDir = sourceId.replace(/[^\/]*$/, ""); // directory of source
156
+ const parts = normalized.split("/");
157
+ const isRootRelative = normalized.startsWith("/");
158
+
159
+ if (isRootRelative) {
160
+ // Root-relative: resolve with explicit stack
161
+ const stack: string[] = [];
162
+ for (const part of parts) {
163
+ if (part === "") continue;
164
+ if (part === ".") continue;
165
+ if (part === "..") {
166
+ if (stack.length === 0) return { kind: "escape" };
167
+ stack.pop();
168
+ } else {
169
+ stack.push(part);
170
+ }
171
+ }
172
+ const resolved = stack.join("/");
173
+ if (!resolved.endsWith(".md")) return { kind: "empty" };
174
+ return { kind: "concept", id: resolved.slice(0, -3) };
175
+ }
176
+
177
+ // For file-relative paths, resolve against source directory
178
+ const baseParts = sourceDir.split("/").filter(Boolean);
179
+ const allParts = [...baseParts];
180
+
181
+ for (const part of parts) {
182
+ if (part === "" || part === ".") {
183
+ } else if (part === "..") {
184
+ if (allParts.length === 0) {
185
+ return { kind: "escape" };
186
+ }
187
+ allParts.pop();
188
+ } else {
189
+ allParts.push(part);
190
+ }
191
+ }
192
+
193
+ const resolved = allParts.join("/");
194
+
195
+ // Require .md suffix for Markdown links
196
+ if (resolved.endsWith(".md")) {
197
+ return { kind: "concept", id: resolved.slice(0, -3) };
198
+ }
199
+
200
+ return { kind: "empty" };
201
+ }
202
+
203
+ function resolveWikilinkTarget(
204
+ target: string,
205
+ ): { kind: "concept"; id: string } | { kind: "empty" } {
206
+ // Wikilinks are already bundle-relative concept IDs
207
+ const cleaned = target.trim();
208
+ if (!cleaned) return { kind: "empty" };
209
+ return { kind: "concept", id: cleaned };
210
+ }
211
+
212
+ export function buildResolvedBacklinks(
213
+ sourceId: string,
214
+ body: string,
215
+ knownIds: Set<string>,
216
+ ): ResolvedBacklinks {
217
+ const diagnostics: KnowledgeDiagnostic[] = [];
218
+ const unresolved: UnresolvedKnowledgeLink[] = [];
219
+ const targets = new Set<string>();
220
+ const allLinks = extractKnowledgeLinks(body);
221
+
222
+ // Process Markdown links
223
+ for (const link of allLinks.markdown) {
224
+ const resolved = resolveMarkdownTarget(link.target, sourceId);
225
+ if (resolved.kind === "escape") {
226
+ diagnostics.push(
227
+ diag(
228
+ "warning",
229
+ "link_path_escape",
230
+ `${sourceId}.md`,
231
+ `Link escapes bundle root: ${link.target}`,
232
+ ),
233
+ );
234
+ } else if (resolved.kind === "invalid") {
235
+ diagnostics.push(
236
+ diag(
237
+ "warning",
238
+ "link_unresolved",
239
+ `${sourceId}.md`,
240
+ `Malformed percent-encoded link: ${link.target}`,
241
+ ),
242
+ );
243
+ } else if (resolved.kind === "concept") {
244
+ const normalizedId = resolved.id.normalize("NFC");
245
+ if (knownIds.has(normalizedId)) {
246
+ targets.add(normalizedId);
247
+ } else {
248
+ unresolved.push({ target: normalizedId, syntax: "markdown" });
249
+ diagnostics.push(
250
+ diag("warning", "link_unresolved", `${sourceId}.md`, `Unresolved link: ${normalizedId}`),
251
+ );
252
+ }
253
+ }
254
+ // external and empty are silently ignored
255
+ }
256
+
257
+ // Process wikilinks
258
+ for (const link of allLinks.wikilinks) {
259
+ const resolved = resolveWikilinkTarget(link.target);
260
+ if (resolved.kind === "concept") {
261
+ const normalizedId = resolved.id.normalize("NFC");
262
+ if (knownIds.has(normalizedId)) {
263
+ targets.add(normalizedId);
264
+ } else {
265
+ unresolved.push({ target: normalizedId, syntax: "wikilink" });
266
+ diagnostics.push(
267
+ diag(
268
+ "warning",
269
+ "link_unresolved",
270
+ `${sourceId}.md`,
271
+ `Unresolved wikilink: ${normalizedId}`,
272
+ ),
273
+ );
274
+ }
275
+ }
276
+ }
277
+
278
+ // Sort and deduplicate
279
+ const sorted = [...targets].sort(compareCodePoint);
280
+
281
+ return { targets: sorted, unresolved, diagnostics };
282
+ }