@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
@@ -1,6 +1,7 @@
1
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { existsSync, readFileSync } from "node:fs";
2
2
  import { basename, join } from "node:path";
3
3
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
4
+ import { bootstrapVault } from "./lib/bootstrap.js";
4
5
  import { installGuardrails } from "./lib/guardrails.js";
5
6
  import { buildAgentStartInjection, normalizeSystemPrompt } from "./lib/inject.js";
6
7
  import { registerWikiModelCommand } from "./lib/model-command.js";
@@ -39,14 +40,8 @@ import {
39
40
  registerWikiDistillSkills,
40
41
  registerWikiRecallSkill,
41
42
  } from "./lib/trajectory.js";
42
- import {
43
- ensureVaultStructure,
44
- fmtDate,
45
- getVaultPaths,
46
- migrateDoubledPersonalVault,
47
- resolveVaultPaths,
48
- writeJson,
49
- } from "./lib/utils.js";
43
+ import { migrateDoubledPersonalVault, resolveVaultPaths } from "./lib/utils.js";
44
+ import { inspectWritableVault } from "./lib/vault-format.js";
50
45
  import { applySessionStartStatus } from "./lib/visible-status.js";
51
46
 
52
47
  /**
@@ -144,33 +139,18 @@ export default function (pi: ExtensionAPI) {
144
139
 
145
140
  const paths = resolveVaultPaths(process.cwd());
146
141
  if (!existsSync(join(paths.dotWiki, "config.json"))) {
147
- // Silently create the wiki vault — no UI prompts
148
- // Topic/mode will be inferred from user's first prompt via before_agent_start
149
- const root = paths.root;
150
- const vaultPaths = getVaultPaths(root);
151
- ensureVaultStructure(vaultPaths);
152
-
153
- writeJson(join(vaultPaths.dotWiki, "config.json"), {
154
- name: "pending",
155
- mode: "personal",
156
- topic: "pending",
157
- created: fmtDate(),
158
- version: "1.0",
159
- });
160
-
161
- const schema = [
162
- "# LLM Wiki Schema",
163
- "",
164
- "## Ownership Rules",
165
- "",
166
- "| Path | Owner | Rule |",
167
- "|------|-------|------|",
168
- "| raw/** | extension | immutable after capture |",
169
- "| wiki/** | model + user | editable knowledge pages |",
170
- "| meta/* | extension | auto-generated |",
171
- "| . | human + explicit request | operating rules |",
172
- ].join("\n");
173
- writeFileSync(join(vaultPaths.dotWiki, "WIKI_SCHEMA.md"), schema, "utf-8");
142
+ // Silently create the wiki vault — no UI prompts. Topic/mode will be
143
+ // inferred from the user's first prompt via before_agent_start.
144
+ const result = bootstrapVault(paths, { topic: "pending", mode: "personal" });
145
+ if (!result.ok || !result.projection.ok) {
146
+ ctx.ui.setStatus(
147
+ "llm-wiki",
148
+ `🧠 Wiki setup blocked: ${
149
+ result.ok ? result.projection.diagnostics[0].message : result.diagnostics[0].message
150
+ }`,
151
+ );
152
+ return;
153
+ }
174
154
 
175
155
  needsTopicInference = true;
176
156
  // INTENTIONALLY NOT gated by `noticesEnabled` (issues #77, #84): one-shot
@@ -180,6 +160,12 @@ export default function (pi: ExtensionAPI) {
180
160
  return;
181
161
  }
182
162
 
163
+ const writable = inspectWritableVault(paths);
164
+ if (!writable.ok) {
165
+ ctx.ui.setStatus("llm-wiki", `🧠 Wiki setup blocked: ${writable.diagnostics[0].message}`);
166
+ return;
167
+ }
168
+
183
169
  // Surface the "wiki active" badge and the active background task model
184
170
  // (issue #69), both gated by `llm-wiki.notices` (issue #77, regression
185
171
  // fixed in #83, helper extracted in #84). `ensureConfig` MUST run first so
@@ -0,0 +1,87 @@
1
+ import { existsSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import type { KnowledgeDiagnostic } from "./knowledge-document.js";
4
+ import { type ProjectionResult, appendEvent, rebuildMetadata } from "./metadata.js";
5
+ import { type VaultPaths, ensureVaultStructure, fmtDate, writeJson } from "./utils.js";
6
+ import { inspectWritableVault, readVaultConfig } from "./vault-format.js";
7
+
8
+ export const WIKI_SCHEMA = [
9
+ "# LLM Wiki Schema",
10
+ "",
11
+ "## Ownership Rules",
12
+ "",
13
+ "| Path | Owner | Rule |",
14
+ "|------|-------|------|",
15
+ "| raw/** | extension | immutable after capture |",
16
+ "| wiki/** | model + user | editable knowledge pages |",
17
+ "| meta/events.jsonl | extension tools | append-only authoritative state |",
18
+ "| meta/* except events.jsonl | extension | generated projections |",
19
+ "| . | human + explicit request | operating rules |",
20
+ "",
21
+ "Back up `meta/events.jsonl` to preserve activity history. Generated logs cannot reconstruct it.",
22
+ "",
23
+ "## Source Packet Format",
24
+ "",
25
+ "```",
26
+ "raw/sources/SRC-YYYY-MM-DD-NNN/",
27
+ " manifest.json",
28
+ " original/",
29
+ " extracted.md",
30
+ " attachments/",
31
+ "```",
32
+ "",
33
+ "## Page Types",
34
+ "",
35
+ "- **source** — what this specific source says",
36
+ "- **entity** — people, orgs, tools, products",
37
+ "- **concept** — ideas, patterns, frameworks",
38
+ "- **synthesis** — cross-source theses and tensions",
39
+ "- **analysis** — durable filed answers from queries",
40
+ "- **requirement** — atomic requirements with status, priority, and traceability",
41
+ "",
42
+ "## Linking Style",
43
+ "",
44
+ "- New internal links: [label](/folder/page.md)",
45
+ "- Legacy readable links: [[folder/page]]",
46
+ "- Source citation: [source](/sources/SRC-YYYY-MM-DD-NNN.md)",
47
+ "",
48
+ ].join("\n");
49
+
50
+ export interface BootstrapInput {
51
+ topic: string;
52
+ mode: string;
53
+ }
54
+
55
+ export type BootstrapResult =
56
+ | { ok: true; created: boolean; projection: ProjectionResult }
57
+ | { ok: false; created: false; diagnostics: KnowledgeDiagnostic[] };
58
+
59
+ export function bootstrapVault(paths: VaultPaths, input: BootstrapInput): BootstrapResult {
60
+ const configPath = join(paths.dotWiki, "config.json");
61
+ const created = !existsSync(paths.dotWiki);
62
+ let existing: Record<string, unknown> = {};
63
+
64
+ if (!created) {
65
+ const writable = inspectWritableVault(paths);
66
+ if (!writable.ok) return { ok: false, created: false, diagnostics: writable.diagnostics };
67
+ const config = readVaultConfig(paths);
68
+ if (!config.ok) return { ok: false, created: false, diagnostics: [config.diagnostic] };
69
+ existing = config.config;
70
+ }
71
+
72
+ const config: Record<string, unknown> = {
73
+ ...existing,
74
+ name: input.topic,
75
+ mode: input.mode,
76
+ topic: input.topic,
77
+ created: existing.created ?? fmtDate(),
78
+ version: existing.version ?? "1.0",
79
+ ...(created ? { knowledge_format: "okf-0.2" } : {}),
80
+ };
81
+
82
+ ensureVaultStructure(paths);
83
+ writeJson(configPath, config);
84
+ writeFileSync(join(paths.dotWiki, "WIKI_SCHEMA.md"), WIKI_SCHEMA, "utf8");
85
+ appendEvent(paths, { kind: "bootstrap", topic: input.topic, mode: input.mode });
86
+ return { ok: true, created, projection: rebuildMetadata(paths) };
87
+ }
@@ -3,10 +3,12 @@ import { existsSync, readFileSync } from "node:fs";
3
3
  import { request as httpRequest } from "node:http";
4
4
  import { request as httpsRequest } from "node:https";
5
5
  import { join } from "node:path";
6
+ import { parseKnowledgeDocument } from "./knowledge-document.js";
6
7
  import type { Registry } from "./metadata.js";
7
8
  import type { LaunchCtx, Runtime } from "./runtime.js";
8
9
  import type { TaskConfig } from "./task-config.js";
9
- import { type VaultPaths, parseFrontmatter, readJson, writeJson } from "./utils.js";
10
+ import { type VaultPaths, readJson, writeJson } from "./utils.js";
11
+ import { assertWritableVault } from "./vault-format.js";
10
12
 
11
13
  /**
12
14
  * Background semantic embeddings, computed at write time (issue #66, epic #63).
@@ -166,6 +168,7 @@ export function readEmbeddingStore(paths: VaultPaths): EmbeddingStore {
166
168
  }
167
169
 
168
170
  export function writeEmbeddingStore(paths: VaultPaths, store: EmbeddingStore): void {
171
+ assertWritableVault(paths);
169
172
  writeJson(embeddingStorePath(paths), store);
170
173
  }
171
174
 
@@ -189,8 +192,9 @@ function readPageText(paths: VaultPaths, id: string): PageText | undefined {
189
192
  const pagePath = join(paths.wiki, `${id}.md`);
190
193
  if (!existsSync(pagePath)) return undefined;
191
194
  const raw = readFileSync(pagePath, "utf-8");
192
- const { frontmatter, body } = parseFrontmatter(raw);
193
- const text = buildEmbeddingText(id, frontmatter, body);
195
+ const result = parseKnowledgeDocument(raw, `${id}.md`);
196
+ if (!result.ok) return undefined;
197
+ const text = buildEmbeddingText(id, result.document.frontmatter, result.document.body);
194
198
  return { id, text, hash: contentHash(text) };
195
199
  }
196
200
 
@@ -205,6 +209,7 @@ export async function embedPages(
205
209
  embedder: Embedder,
206
210
  opts: { force?: boolean } = {},
207
211
  ): Promise<EmbedStats> {
212
+ assertWritableVault(paths);
208
213
  const store = readEmbeddingStore(paths);
209
214
  const targets: PageText[] = [];
210
215
  let skipped = 0;
@@ -251,6 +256,7 @@ export async function reindexEmbeddings(
251
256
  embedder: Embedder,
252
257
  opts: { force?: boolean } = {},
253
258
  ): Promise<ReindexStats> {
259
+ assertWritableVault(paths);
254
260
  const registry = readJson<Registry>(join(paths.meta, "registry.json"), {
255
261
  version: "1.0",
256
262
  last_updated: "",
@@ -1,10 +1,11 @@
1
- import { resolve, sep } from "node:path";
2
1
  import { isToolCallEventType } from "@mariozechner/pi-coding-agent";
3
2
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
4
3
  import { scheduleReindex } from "./indexing.js";
5
4
  import { rebuildMetadataLight } from "./metadata.js";
6
5
  import type { Runtime } from "./runtime.js";
7
- import { isProtectedPath, resolveVaultPaths } from "./utils.js";
6
+ import { isPathWithin, isProtectedPath, resolveVaultPaths } from "./utils.js";
7
+ import type { VaultPaths } from "./utils.js";
8
+ import { inspectVaultFormat, isGeneratedOkfPath } from "./vault-format.js";
8
9
 
9
10
  /**
10
11
  * Guardrails and auto-rebuild hooks for the LLM Wiki extension.
@@ -172,26 +173,35 @@ export function extractMutationPaths(input: unknown): string[] {
172
173
 
173
174
  /** True when a write or patch-shaped edit targets a page in the wiki directory. */
174
175
  export function hasWikiMutation(input: unknown, wikiPath: string): boolean {
175
- const resolvedWikiPath = resolve(wikiPath);
176
- return extractMutationPaths(input).some((path) => {
177
- const resolvedPath = resolve(path);
178
- return (
179
- resolvedPath === resolvedWikiPath || resolvedPath.startsWith(`${resolvedWikiPath}${sep}`)
180
- );
181
- });
176
+ return extractMutationPaths(input).some((path) => isPathWithin(wikiPath, path));
177
+ }
178
+
179
+ export function mutationBlockReason(path: string, paths: VaultPaths): string | undefined {
180
+ const protectedPath = isProtectedPath(path, paths);
181
+ if (protectedPath.protected) return protectedPath.reason;
182
+
183
+ if (isPathWithin(paths.dotWiki, path)) {
184
+ const state = inspectVaultFormat(paths);
185
+ if (state.blocking) {
186
+ return `Wiki vault configuration is invalid: ${state.diagnostics[0].message}`;
187
+ }
188
+ }
189
+
190
+ if (isGeneratedOkfPath(path, paths)) {
191
+ return "Generated OKF indexes and log are read-only. Use wiki_rebuild_meta or the page-producing tool that owns the source mutation.";
192
+ }
193
+ return undefined;
182
194
  }
183
195
 
184
196
  /** Install guardrails on the extension API. */
185
197
  export function installGuardrails(pi: ExtensionAPI, runtime?: Runtime): void {
186
- // Block direct edits to raw/ and meta/
198
+ // Block direct edits to raw/ and meta/, plus OKF generated projections
187
199
  pi.on("tool_call", async (event) => {
188
200
  if (isToolCallEventType("write", event)) {
189
201
  const path = event.input.path as string;
190
202
  const paths = resolveVaultPaths(process.cwd());
191
- const check = isProtectedPath(path, paths);
192
- if (check.protected) {
193
- return { block: true, reason: check.reason };
194
- }
203
+ const reason = mutationBlockReason(path, paths);
204
+ if (reason) return { block: true, reason };
195
205
  }
196
206
 
197
207
  if (isToolCallEventType("edit", event)) {
@@ -203,10 +213,8 @@ export function installGuardrails(pi: ExtensionAPI, runtime?: Runtime): void {
203
213
 
204
214
  const paths = resolveVaultPaths(process.cwd());
205
215
  for (const path of targetPaths) {
206
- const check = isProtectedPath(path, paths);
207
- if (check.protected) {
208
- return { block: true, reason: check.reason };
209
- }
216
+ const reason = mutationBlockReason(path, paths);
217
+ if (reason) return { block: true, reason };
210
218
  }
211
219
  }
212
220
  });
@@ -64,7 +64,8 @@ export function scheduleReindex(
64
64
  // that land during embedding are not lost.
65
65
  while (dirty.has(root)) {
66
66
  dirty.delete(root);
67
- rebuildMetadataLight(paths);
67
+ const projection = rebuildMetadataLight(paths);
68
+ if (!projection.ok) continue;
68
69
 
69
70
  // Refresh embeddings only after metadata is consistent. Stale-aware and
70
71
  // a no-op unless an embedder is configured.