@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.
- package/CHANGELOG.md +6 -0
- package/README.de.md +35 -4
- package/README.es.md +260 -170
- package/README.fr.md +35 -4
- package/README.hi.md +35 -4
- package/README.ja.md +35 -4
- package/README.ko.md +35 -4
- package/README.md +41 -12
- package/README.pt.md +35 -4
- package/README.ru.md +35 -4
- package/README.zh.md +260 -170
- package/assets/demo.gif +0 -0
- package/dist/extensions/llm-wiki/lib/bootstrap.js +74 -0
- package/dist/extensions/llm-wiki/lib/embeddings.js +401 -0
- package/dist/extensions/llm-wiki/lib/guardrails.js +232 -0
- package/dist/extensions/llm-wiki/lib/indexing.js +78 -0
- package/dist/extensions/llm-wiki/lib/ingest-worker.js +410 -0
- package/dist/extensions/llm-wiki/lib/inject.js +65 -0
- package/dist/extensions/llm-wiki/lib/knowledge-document.js +442 -0
- package/dist/extensions/llm-wiki/lib/knowledge-links.js +206 -0
- package/dist/extensions/llm-wiki/lib/legacy-repair.js +443 -0
- package/dist/extensions/llm-wiki/lib/metadata.js +505 -0
- package/dist/extensions/llm-wiki/lib/model-command.js +85 -0
- package/dist/extensions/llm-wiki/lib/observation.js +283 -0
- package/dist/extensions/llm-wiki/lib/recall.js +875 -0
- package/dist/extensions/llm-wiki/lib/retro.js +158 -0
- package/dist/extensions/llm-wiki/lib/runtime.js +187 -0
- package/dist/extensions/llm-wiki/lib/source-extractors.js +426 -0
- package/dist/extensions/llm-wiki/lib/source-packet.js +229 -0
- package/dist/extensions/llm-wiki/lib/subagent.js +41 -0
- package/dist/extensions/llm-wiki/lib/task-config.js +201 -0
- package/dist/extensions/llm-wiki/lib/tools.js +1199 -0
- package/dist/extensions/llm-wiki/lib/trajectories-command.js +51 -0
- package/dist/extensions/llm-wiki/lib/trajectory.js +467 -0
- package/dist/extensions/llm-wiki/lib/utils.js +353 -0
- package/dist/extensions/llm-wiki/lib/vault-format.js +247 -0
- package/dist/extensions/llm-wiki/lib/visible-status.js +31 -0
- package/dist/extensions/llm-wiki/lib/wiki-service.js +128 -0
- package/dist/mcp/exec.js +121 -0
- package/dist/mcp/index.js +229 -0
- package/dist/mcp/operations.js +130 -0
- package/dist/package.json +1 -0
- package/docs/api.md +5 -2
- package/docs/architecture.md +5 -2
- package/docs/configuration.md +25 -0
- package/docs/superpowers/plans/2026-08-02-okf-foundation.md +1579 -0
- package/docs/superpowers/plans/2026-08-03-okf-foundation-remediation.md +3005 -0
- package/docs/superpowers/plans/2026-08-06-authoritative-event-history-phase-1-foundation-hardening.md +937 -0
- package/docs/superpowers/plans/2026-08-06-okf-foundation-release-remediation.md +1174 -0
- package/docs/superpowers/plans/2026-08-07-synthesis-language.md +98 -0
- package/docs/superpowers/specs/2026-08-02-okf-foundation-design.md +593 -0
- package/docs/superpowers/specs/2026-08-02-okf-v0.2-interoperability-design.md +542 -0
- package/docs/superpowers/specs/2026-08-07-synthesis-language-design.md +94 -0
- package/extensions/llm-wiki/index.ts +22 -36
- package/extensions/llm-wiki/lib/bootstrap.ts +87 -0
- package/extensions/llm-wiki/lib/embeddings.ts +9 -3
- package/extensions/llm-wiki/lib/guardrails.ts +26 -18
- package/extensions/llm-wiki/lib/indexing.ts +2 -1
- package/extensions/llm-wiki/lib/ingest-worker.ts +304 -28
- package/extensions/llm-wiki/lib/knowledge-document.ts +663 -0
- package/extensions/llm-wiki/lib/knowledge-links.ts +282 -0
- package/extensions/llm-wiki/lib/legacy-repair.ts +572 -0
- package/extensions/llm-wiki/lib/metadata.ts +550 -128
- package/extensions/llm-wiki/lib/model-command.ts +0 -1
- package/extensions/llm-wiki/lib/observation.ts +37 -43
- package/extensions/llm-wiki/lib/recall.ts +61 -33
- package/extensions/llm-wiki/lib/retro.ts +65 -41
- package/extensions/llm-wiki/lib/runtime.ts +0 -3
- package/extensions/llm-wiki/lib/source-extractors.ts +12 -17
- package/extensions/llm-wiki/lib/source-packet.ts +45 -32
- package/extensions/llm-wiki/lib/task-config.ts +36 -0
- package/extensions/llm-wiki/lib/tools.ts +413 -342
- package/extensions/llm-wiki/lib/trajectory.ts +15 -1
- package/extensions/llm-wiki/lib/utils.ts +127 -131
- package/extensions/llm-wiki/lib/vault-format.ts +363 -0
- package/extensions/llm-wiki/lib/wiki-service.ts +183 -0
- package/mcp/exec.ts +122 -0
- package/mcp/index.ts +60 -250
- package/mcp/operations.ts +176 -0
- package/package.json +8 -2
- package/scripts/migrate-llm-wiki.js +801 -0
- package/skills/llm-wiki/SKILL.md +12 -8
|
@@ -2,26 +2,24 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from
|
|
|
2
2
|
import { join, relative } from "node:path";
|
|
3
3
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
4
4
|
import { Type } from "typebox";
|
|
5
|
+
import { bootstrapVault } from "./bootstrap.js";
|
|
5
6
|
import { launchEmbedPages, reindexEmbeddings, resolveEmbedder } from "./embeddings.js";
|
|
6
7
|
import { scheduleReindex } from "./indexing.js";
|
|
7
8
|
import { runIngestSynthesis } from "./ingest-worker.js";
|
|
8
9
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "./metadata.js";
|
|
10
|
+
createKnowledgeDocument,
|
|
11
|
+
serializeKnowledgeDocument,
|
|
12
|
+
writeKnowledgeDocumentFile,
|
|
13
|
+
} from "./knowledge-document.js";
|
|
14
|
+
import { buildResolvedBacklinks } from "./knowledge-links.js";
|
|
15
|
+
import { repairLegacyKnowledgeDocuments } from "./legacy-repair.js";
|
|
16
|
+
import { type Registry, appendEvent, rebuildMetadata, rebuildMetadataLight } from "./metadata.js";
|
|
16
17
|
import type { Runtime } from "./runtime.js";
|
|
17
18
|
import { captureFile, captureText, captureUrl } from "./source-packet.js";
|
|
18
19
|
import { parseModelRef } from "./task-config.js";
|
|
19
20
|
import {
|
|
20
21
|
type VaultPaths,
|
|
21
22
|
detectVaultFormat,
|
|
22
|
-
ensureVaultStructure,
|
|
23
|
-
extractWikilinks,
|
|
24
|
-
findWikiPages,
|
|
25
23
|
fmtDate,
|
|
26
24
|
getVaultPaths,
|
|
27
25
|
readJson,
|
|
@@ -29,6 +27,14 @@ import {
|
|
|
29
27
|
slugify,
|
|
30
28
|
writeJson,
|
|
31
29
|
} from "./utils.js";
|
|
30
|
+
import {
|
|
31
|
+
assertWritableVault,
|
|
32
|
+
compareCodePoint,
|
|
33
|
+
discoverKnowledgeDocuments,
|
|
34
|
+
inspectVaultFormat,
|
|
35
|
+
inspectWritableVault,
|
|
36
|
+
} from "./vault-format.js";
|
|
37
|
+
import { getWikiStatus, searchRegistry } from "./wiki-service.js";
|
|
32
38
|
|
|
33
39
|
/**
|
|
34
40
|
* All LLM Wiki custom tools.
|
|
@@ -116,59 +122,35 @@ export function registerWikiBootstrap(pi: ExtensionAPI): void {
|
|
|
116
122
|
const root = params.root ?? ctx.cwd ?? process.cwd();
|
|
117
123
|
const mode = params.mode || "personal";
|
|
118
124
|
const paths = getVaultPaths(root);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
" original/",
|
|
149
|
-
" extracted.md",
|
|
150
|
-
" attachments/",
|
|
151
|
-
"```",
|
|
152
|
-
"",
|
|
153
|
-
"## Page Types",
|
|
154
|
-
"",
|
|
155
|
-
"- **source** — what this specific source says",
|
|
156
|
-
"- **entity** — people, orgs, tools, products",
|
|
157
|
-
"- **concept** — ideas, patterns, frameworks",
|
|
158
|
-
"- **synthesis** — cross-source theses and tensions",
|
|
159
|
-
"- **analysis** — durable filed answers from queries",
|
|
160
|
-
"- **requirement** — atomic requirements with status, priority, and traceability",
|
|
161
|
-
"",
|
|
162
|
-
"## Linking Style",
|
|
163
|
-
"",
|
|
164
|
-
"- Internal: [[folder/page-name]]",
|
|
165
|
-
"- Citation: [[sources/SRC-YYYY-MM-DD-NNN]]",
|
|
166
|
-
"",
|
|
167
|
-
].join("\n");
|
|
168
|
-
writeFileSync(join(paths.dotWiki, "WIKI_SCHEMA.md"), schema, "utf-8");
|
|
169
|
-
|
|
170
|
-
rebuildMetadata(paths);
|
|
171
|
-
appendEvent(paths, { kind: "bootstrap", topic: params.topic, mode });
|
|
125
|
+
const result = bootstrapVault(paths, { topic: params.topic, mode });
|
|
126
|
+
if (!result.ok) {
|
|
127
|
+
return {
|
|
128
|
+
content: [{ type: "text", text: `Wiki vault error: ${result.diagnostics[0].message}` }],
|
|
129
|
+
details: {
|
|
130
|
+
error: result.diagnostics[0].code,
|
|
131
|
+
diagnostics: result.diagnostics,
|
|
132
|
+
} as Record<string, unknown>,
|
|
133
|
+
isError: true,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (!result.projection.ok) {
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{
|
|
140
|
+
type: "text",
|
|
141
|
+
text: `✅ Wiki bootstrapped but projection rebuild had issues: ${result.projection.diagnostics
|
|
142
|
+
.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`)
|
|
143
|
+
.join("; ")}`,
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
details: {
|
|
147
|
+
root,
|
|
148
|
+
mode,
|
|
149
|
+
topic: params.topic,
|
|
150
|
+
diagnostics: result.projection.diagnostics,
|
|
151
|
+
} as Record<string, unknown>,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
172
154
|
|
|
173
155
|
return {
|
|
174
156
|
content: [
|
|
@@ -216,11 +198,16 @@ export function registerWikiCaptureSource(pi: ExtensionAPI, runtime?: Runtime):
|
|
|
216
198
|
}),
|
|
217
199
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
218
200
|
const paths = getPaths(ctx.cwd);
|
|
219
|
-
const vaultCheck =
|
|
201
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
220
202
|
if (!vaultCheck.ok) {
|
|
221
203
|
return {
|
|
222
|
-
content: [
|
|
223
|
-
|
|
204
|
+
content: [
|
|
205
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
206
|
+
],
|
|
207
|
+
details: {
|
|
208
|
+
error: vaultCheck.diagnostics[0].code,
|
|
209
|
+
diagnostics: vaultCheck.diagnostics,
|
|
210
|
+
} as Record<string, unknown>,
|
|
224
211
|
isError: true,
|
|
225
212
|
};
|
|
226
213
|
}
|
|
@@ -315,11 +302,16 @@ export function registerWikiIngest(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
315
302
|
}),
|
|
316
303
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
317
304
|
const paths = getPaths(ctx.cwd);
|
|
318
|
-
const vaultCheck =
|
|
305
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
319
306
|
if (!vaultCheck.ok) {
|
|
320
307
|
return {
|
|
321
|
-
content: [
|
|
322
|
-
|
|
308
|
+
content: [
|
|
309
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
310
|
+
],
|
|
311
|
+
details: {
|
|
312
|
+
error: vaultCheck.diagnostics[0].code,
|
|
313
|
+
diagnostics: vaultCheck.diagnostics,
|
|
314
|
+
} as Record<string, unknown>,
|
|
323
315
|
isError: true,
|
|
324
316
|
};
|
|
325
317
|
}
|
|
@@ -422,6 +414,7 @@ export function registerWikiIngest(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
422
414
|
sourceId: s.id,
|
|
423
415
|
manifest: s.manifest,
|
|
424
416
|
extracted: s.extracted,
|
|
417
|
+
synthesisLanguage: runtime.config.synthesisLanguage,
|
|
425
418
|
});
|
|
426
419
|
if (committed) {
|
|
427
420
|
// Background semantic embeddings (#66): embed the pages this
|
|
@@ -528,11 +521,16 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
528
521
|
}),
|
|
529
522
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
530
523
|
const paths = getPaths(ctx.cwd);
|
|
531
|
-
const vaultCheck =
|
|
524
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
532
525
|
if (!vaultCheck.ok) {
|
|
533
526
|
return {
|
|
534
|
-
content: [
|
|
535
|
-
|
|
527
|
+
content: [
|
|
528
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
529
|
+
],
|
|
530
|
+
details: {
|
|
531
|
+
error: vaultCheck.diagnostics[0].code,
|
|
532
|
+
diagnostics: vaultCheck.diagnostics,
|
|
533
|
+
} as Record<string, unknown>,
|
|
536
534
|
isError: true,
|
|
537
535
|
};
|
|
538
536
|
}
|
|
@@ -567,9 +565,19 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
567
565
|
}
|
|
568
566
|
|
|
569
567
|
const today = fmtDate();
|
|
570
|
-
const
|
|
568
|
+
const body = params.content ?? buildPageBody(type, params.title);
|
|
569
|
+
const doc = createKnowledgeDocument(
|
|
570
|
+
`${folder}/${slug}.md`,
|
|
571
|
+
{
|
|
572
|
+
type,
|
|
573
|
+
title: params.title,
|
|
574
|
+
created: today,
|
|
575
|
+
updated: today,
|
|
576
|
+
},
|
|
577
|
+
body,
|
|
578
|
+
);
|
|
571
579
|
mkdirSync(join(paths.wiki, folder), { recursive: true });
|
|
572
|
-
|
|
580
|
+
writeKnowledgeDocumentFile(pagePath, doc);
|
|
573
581
|
|
|
574
582
|
appendEvent(paths, {
|
|
575
583
|
kind: "ensure_page",
|
|
@@ -595,151 +603,135 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
595
603
|
});
|
|
596
604
|
}
|
|
597
605
|
|
|
598
|
-
function
|
|
599
|
-
type
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
): string {
|
|
604
|
-
if (customContent) return customContent;
|
|
606
|
+
function buildPageBody(type: string, title: string): string {
|
|
607
|
+
if (type === "entity") {
|
|
608
|
+
return `# ${title}
|
|
609
|
+
|
|
610
|
+
One-line description.
|
|
605
611
|
|
|
606
|
-
|
|
612
|
+
## Overview
|
|
607
613
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
614
|
+
[Key facts]
|
|
615
|
+
|
|
616
|
+
## Links
|
|
617
|
+
|
|
618
|
+
- [related-page](/concepts/related-page.md)`;
|
|
612
619
|
}
|
|
613
620
|
if (type === "concept") {
|
|
614
|
-
return
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
621
|
+
return `# ${title}
|
|
622
|
+
|
|
623
|
+
One-line definition.
|
|
624
|
+
|
|
625
|
+
## Definition
|
|
626
|
+
|
|
627
|
+
[Clear explanation]
|
|
628
|
+
|
|
629
|
+
## Links
|
|
630
|
+
|
|
631
|
+
- [related-page](/concepts/related-page.md)`;
|
|
620
632
|
}
|
|
621
633
|
if (type === "synthesis") {
|
|
622
|
-
return
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
634
|
+
return `# ${title}
|
|
635
|
+
|
|
636
|
+
Cross-cutting analysis.
|
|
637
|
+
|
|
638
|
+
## Question
|
|
639
|
+
|
|
640
|
+
[What drove this?]
|
|
641
|
+
|
|
642
|
+
## Links
|
|
643
|
+
|
|
644
|
+
- [related-page](/concepts/related-page.md)`;
|
|
628
645
|
}
|
|
629
646
|
if (type === "analysis") {
|
|
630
|
-
return
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
647
|
+
return `# ${title}
|
|
648
|
+
|
|
649
|
+
Durable answer from a query.
|
|
650
|
+
|
|
651
|
+
## Question
|
|
652
|
+
|
|
653
|
+
[Original question]
|
|
654
|
+
|
|
655
|
+
## Links
|
|
656
|
+
|
|
657
|
+
- [related-page](/concepts/related-page.md)`;
|
|
634
658
|
}
|
|
635
659
|
if (type === "skill") {
|
|
636
|
-
return
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
"",
|
|
659
|
-
"## Pitfalls",
|
|
660
|
-
"",
|
|
661
|
-
"- [Known failure mode or caveat]",
|
|
662
|
-
"",
|
|
663
|
-
"## Distilled From",
|
|
664
|
-
"",
|
|
665
|
-
"_Trajectories this skill was generalized from._",
|
|
666
|
-
"",
|
|
667
|
-
"- [[trajectories/TRJ-...]]",
|
|
668
|
-
"",
|
|
669
|
-
].join("\n");
|
|
660
|
+
return `# ${title}
|
|
661
|
+
|
|
662
|
+
_One-line summary of the reusable pattern this skill captures._
|
|
663
|
+
|
|
664
|
+
## When to Use
|
|
665
|
+
|
|
666
|
+
[Trigger conditions — when this pattern applies]
|
|
667
|
+
|
|
668
|
+
## Procedure
|
|
669
|
+
|
|
670
|
+
1. [Step 1]
|
|
671
|
+
2. [Step 2]
|
|
672
|
+
|
|
673
|
+
## Pitfalls
|
|
674
|
+
|
|
675
|
+
- [Known failure mode or caveat]
|
|
676
|
+
|
|
677
|
+
## Distilled From
|
|
678
|
+
|
|
679
|
+
_Trajectories this skill was generalized from._
|
|
680
|
+
|
|
681
|
+
- [trajectories/TRJ-...](/trajectories/TRJ-....md)`;
|
|
670
682
|
}
|
|
671
683
|
if (type === "case") {
|
|
672
|
-
return
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
"## Approach",
|
|
692
|
-
"",
|
|
693
|
-
"[How the agent solved it — key steps and decisions]",
|
|
694
|
-
"",
|
|
695
|
-
"## Outcome",
|
|
696
|
-
"",
|
|
697
|
-
"[Result, and anything worth reusing or avoiding next time]",
|
|
698
|
-
"",
|
|
699
|
-
"## Trajectory",
|
|
700
|
-
"",
|
|
701
|
-
"- [[trajectories/TRJ-...]] — captured tool-call run",
|
|
702
|
-
"",
|
|
703
|
-
].join("\n");
|
|
684
|
+
return `# ${title}
|
|
685
|
+
|
|
686
|
+
_One-line summary of the specific task this case records._
|
|
687
|
+
|
|
688
|
+
## Task
|
|
689
|
+
|
|
690
|
+
[What was requested]
|
|
691
|
+
|
|
692
|
+
## Approach
|
|
693
|
+
|
|
694
|
+
[How the agent solved it — key steps and decisions]
|
|
695
|
+
|
|
696
|
+
## Outcome
|
|
697
|
+
|
|
698
|
+
[Result, and anything worth reusing or avoiding next time]
|
|
699
|
+
|
|
700
|
+
## Trajectory
|
|
701
|
+
|
|
702
|
+
- [trajectories/TRJ-...](/trajectories/TRJ-....md) — captured tool-call run`;
|
|
704
703
|
}
|
|
705
704
|
if (type === "requirement") {
|
|
706
|
-
return
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
"## Dependencies",
|
|
729
|
-
"",
|
|
730
|
-
"_Pages this requirement depends on._",
|
|
731
|
-
"",
|
|
732
|
-
"## Implementation Notes",
|
|
733
|
-
"",
|
|
734
|
-
"[Optional notes]",
|
|
735
|
-
"",
|
|
736
|
-
"## Sources",
|
|
737
|
-
"",
|
|
738
|
-
"- [[sources/SRC-...]] — original concept capture",
|
|
739
|
-
"",
|
|
740
|
-
].join("\n");
|
|
705
|
+
return `# ${title}
|
|
706
|
+
|
|
707
|
+
## Description
|
|
708
|
+
|
|
709
|
+
[Clear description of what this requirement entails]
|
|
710
|
+
|
|
711
|
+
## Acceptance Criteria
|
|
712
|
+
|
|
713
|
+
- [ ] [Criterion 1]
|
|
714
|
+
- [ ] [Criterion 2]
|
|
715
|
+
|
|
716
|
+
## Dependencies
|
|
717
|
+
|
|
718
|
+
_Pages this requirement depends on._
|
|
719
|
+
|
|
720
|
+
## Implementation Notes
|
|
721
|
+
|
|
722
|
+
[Optional notes]
|
|
723
|
+
|
|
724
|
+
## Sources
|
|
725
|
+
|
|
726
|
+
- [sources/SRC-...](/sources/SRC-....md) — original concept capture`;
|
|
741
727
|
}
|
|
742
|
-
return
|
|
728
|
+
return `# ${title}
|
|
729
|
+
|
|
730
|
+
[Description to be filled]
|
|
731
|
+
|
|
732
|
+
## Links
|
|
733
|
+
|
|
734
|
+
- [related-page](/concepts/related-page.md)`;
|
|
743
735
|
}
|
|
744
736
|
|
|
745
737
|
// ─── 5. wiki_search ─────────────────────────────────────
|
|
@@ -757,29 +749,15 @@ export function registerWikiSearch(pi: ExtensionAPI): void {
|
|
|
757
749
|
}),
|
|
758
750
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
759
751
|
const paths = getPaths(ctx.cwd);
|
|
760
|
-
const
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
pages: {},
|
|
764
|
-
});
|
|
765
|
-
const q = params.query.toLowerCase();
|
|
766
|
-
|
|
767
|
-
const matches = Object.entries(registry.pages)
|
|
768
|
-
.filter(([id, entry]) => {
|
|
769
|
-
const matchesQuery =
|
|
770
|
-
id.toLowerCase().includes(q) ||
|
|
771
|
-
String(entry.title).toLowerCase().includes(q) ||
|
|
772
|
-
String(entry.type).toLowerCase().includes(q);
|
|
773
|
-
const matchesType =
|
|
774
|
-
!params.type || String(entry.type).toLowerCase() === params.type.toLowerCase();
|
|
775
|
-
return matchesQuery && matchesType;
|
|
776
|
-
})
|
|
777
|
-
.map(([id, entry]) => ({ id, title: entry.title, type: entry.type }));
|
|
778
|
-
|
|
779
|
-
if (matches.length === 0) {
|
|
752
|
+
const result = searchRegistry(paths, params.query, params.type);
|
|
753
|
+
|
|
754
|
+
if (result.matches.length === 0) {
|
|
780
755
|
return {
|
|
781
756
|
content: [{ type: "text", text: `No pages found for "${params.query}"` }],
|
|
782
|
-
details: { query: params.query, matches: [] } as Record<
|
|
757
|
+
details: { query: params.query, matches: [], diagnostics: result.diagnostics } as Record<
|
|
758
|
+
string,
|
|
759
|
+
unknown
|
|
760
|
+
>,
|
|
783
761
|
};
|
|
784
762
|
}
|
|
785
763
|
|
|
@@ -788,13 +766,17 @@ export function registerWikiSearch(pi: ExtensionAPI): void {
|
|
|
788
766
|
{
|
|
789
767
|
type: "text",
|
|
790
768
|
text: [
|
|
791
|
-
`🔍 **${matches.length} result(s)** for "${params.query}":`,
|
|
769
|
+
`🔍 **${result.matches.length} result(s)** for "${params.query}":`,
|
|
792
770
|
"",
|
|
793
|
-
...matches.map((m) => `- [[${m.id}]] — *${m.type}* — ${m.title}`),
|
|
771
|
+
...result.matches.map((m) => `- [[${m.id}]] — *${m.type}* — ${m.title}`),
|
|
794
772
|
].join("\n"),
|
|
795
773
|
},
|
|
796
774
|
],
|
|
797
|
-
details: {
|
|
775
|
+
details: {
|
|
776
|
+
query: params.query,
|
|
777
|
+
matches: result.matches,
|
|
778
|
+
diagnostics: result.diagnostics,
|
|
779
|
+
} as Record<string, unknown>,
|
|
798
780
|
};
|
|
799
781
|
},
|
|
800
782
|
});
|
|
@@ -820,11 +802,16 @@ export function registerWikiLint(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
820
802
|
}),
|
|
821
803
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
822
804
|
const paths = getPaths(ctx.cwd);
|
|
823
|
-
const vaultCheck =
|
|
805
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
824
806
|
if (!vaultCheck.ok) {
|
|
825
807
|
return {
|
|
826
|
-
content: [
|
|
827
|
-
|
|
808
|
+
content: [
|
|
809
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
810
|
+
],
|
|
811
|
+
details: {
|
|
812
|
+
error: vaultCheck.diagnostics[0].code,
|
|
813
|
+
diagnostics: vaultCheck.diagnostics,
|
|
814
|
+
} as Record<string, unknown>,
|
|
828
815
|
isError: true,
|
|
829
816
|
};
|
|
830
817
|
}
|
|
@@ -846,82 +833,117 @@ export function registerWikiLint(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
846
833
|
* run off-thread via `dispatchReported`). Returns the human-readable summary.
|
|
847
834
|
*/
|
|
848
835
|
function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
836
|
+
assertWritableVault(paths);
|
|
837
|
+
let repair: ReturnType<typeof repairLegacyKnowledgeDocuments> | undefined;
|
|
838
|
+
if (autoFix) {
|
|
839
|
+
let projection = rebuildMetadata(paths);
|
|
840
|
+
repair = !projection.ok ? repairLegacyKnowledgeDocuments(paths) : undefined;
|
|
841
|
+
if (repair?.repaired) projection = rebuildMetadata(paths);
|
|
842
|
+
if (!projection.ok) {
|
|
843
|
+
return [
|
|
844
|
+
"# Wiki Lint Report",
|
|
845
|
+
"",
|
|
846
|
+
repair?.repaired ? `Legacy pages repaired: ${repair.repaired}` : "",
|
|
847
|
+
repair?.manifestPath ? `Repair manifest: ${repair.manifestPath}` : "",
|
|
848
|
+
"Projection-blocking diagnostics:",
|
|
849
|
+
...projection.diagnostics.map(
|
|
850
|
+
(diagnostic) => `- ${diagnostic.code}: ${diagnostic.path}: ${diagnostic.message}`,
|
|
851
|
+
),
|
|
852
|
+
]
|
|
853
|
+
.filter(Boolean)
|
|
854
|
+
.join("\n");
|
|
855
|
+
}
|
|
856
|
+
} else {
|
|
857
|
+
const vault = inspectVaultFormat(paths);
|
|
858
|
+
const audit = discoverKnowledgeDocuments(paths);
|
|
859
|
+
const diagnostics = [...vault.diagnostics, ...audit.diagnostics];
|
|
860
|
+
if (vault.blocking || audit.blocking) {
|
|
861
|
+
return [
|
|
862
|
+
"# Wiki Lint Report",
|
|
863
|
+
"",
|
|
864
|
+
"Projection-blocking diagnostics:",
|
|
865
|
+
...diagnostics.map(
|
|
866
|
+
(diagnostic) => `- ${diagnostic.code}: ${diagnostic.path}: ${diagnostic.message}`,
|
|
867
|
+
),
|
|
868
|
+
].join("\n");
|
|
869
|
+
}
|
|
870
|
+
}
|
|
852
871
|
|
|
872
|
+
const discovery = discoverKnowledgeDocuments(paths);
|
|
873
|
+
const pages = discovery.documents;
|
|
874
|
+
const knownIds = new Set(pages.map((page) => page.id));
|
|
875
|
+
const inbound = Object.fromEntries(pages.map((page) => [page.id, 0]));
|
|
876
|
+
const gapSources = new Map<string, Set<string>>();
|
|
853
877
|
const findings: string[] = [];
|
|
854
|
-
let orphans = 0;
|
|
855
878
|
let missingPages = 0;
|
|
856
879
|
let contradictions = 0;
|
|
857
|
-
const gaps: Array<{ topic: string; mentionedBy: string[] }> = [];
|
|
858
|
-
|
|
859
|
-
const allPageIds = new Set(pages.map((p) => p.relative));
|
|
860
|
-
const linkCounts: Record<string, number> = {};
|
|
861
880
|
|
|
862
881
|
for (const page of pages) {
|
|
863
|
-
const
|
|
864
|
-
for (const
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
existing.mentionedBy.push(page.relative);
|
|
872
|
-
} else {
|
|
873
|
-
gaps.push({ topic: link, mentionedBy: [page.relative] });
|
|
874
|
-
}
|
|
875
|
-
} else {
|
|
876
|
-
linkCounts[link] = (linkCounts[link] || 0) + 1;
|
|
877
|
-
}
|
|
882
|
+
const resolved = buildResolvedBacklinks(page.id, page.body, knownIds);
|
|
883
|
+
for (const target of resolved.targets) inbound[target]++;
|
|
884
|
+
for (const unresolved of resolved.unresolved) {
|
|
885
|
+
const sources = gapSources.get(unresolved.target) ?? new Set<string>();
|
|
886
|
+
sources.add(page.id);
|
|
887
|
+
gapSources.set(unresolved.target, sources);
|
|
888
|
+
missingPages++;
|
|
889
|
+
findings.push(`Missing page: ${unresolved.target} (in ${page.id})`);
|
|
878
890
|
}
|
|
879
891
|
}
|
|
880
892
|
|
|
893
|
+
let orphans = 0;
|
|
881
894
|
for (const page of pages) {
|
|
882
|
-
if (
|
|
895
|
+
if (inbound[page.id] === 0) {
|
|
883
896
|
orphans++;
|
|
884
|
-
findings.push(`Orphan:
|
|
897
|
+
findings.push(`Orphan: ${page.id} has no inbound links`);
|
|
885
898
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
for (const page of pages) {
|
|
889
|
-
if (page.content.includes("⚠️ **Contradiction")) {
|
|
899
|
+
if (page.body.includes("⚠️ **Contradiction")) {
|
|
890
900
|
contradictions++;
|
|
891
|
-
findings.push(`Contradiction flagged in
|
|
901
|
+
findings.push(`Contradiction flagged in ${page.id}`);
|
|
892
902
|
}
|
|
893
903
|
}
|
|
894
904
|
|
|
905
|
+
const gaps = [...gapSources.entries()]
|
|
906
|
+
.map(([topic, sources]) => ({ topic, mentionedBy: [...sources].sort(compareCodePoint) }))
|
|
907
|
+
.sort((left, right) => compareCodePoint(left.topic, right.topic));
|
|
895
908
|
let fixesApplied = 0;
|
|
896
909
|
if (autoFix) {
|
|
897
910
|
for (const gap of gaps) {
|
|
898
|
-
if (gap.mentionedBy.length
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
911
|
+
if (gap.mentionedBy.length < 2) continue;
|
|
912
|
+
const parts = gap.topic.split("/");
|
|
913
|
+
const name =
|
|
914
|
+
parts.length === 1
|
|
915
|
+
? parts[0]
|
|
916
|
+
: parts.length === 2 && parts[0] === "concepts"
|
|
917
|
+
? parts[1]
|
|
918
|
+
: "";
|
|
919
|
+
if (!name || slugify(name) !== name) continue;
|
|
920
|
+
const pagePath = join(paths.wiki, "concepts", `${name}.md`);
|
|
921
|
+
mkdirSync(join(paths.wiki, "concepts"), { recursive: true });
|
|
922
|
+
const document = createKnowledgeDocument(
|
|
923
|
+
`concepts/${name}.md`,
|
|
924
|
+
{
|
|
925
|
+
type: "concept",
|
|
926
|
+
title: name.replace(/-/g, " "),
|
|
927
|
+
created: fmtDate(),
|
|
928
|
+
updated: fmtDate(),
|
|
929
|
+
status: "stub",
|
|
930
|
+
},
|
|
931
|
+
`_Stub auto-created by lint. Expand with content from: ${gap.mentionedBy
|
|
932
|
+
.map((source) => `[${source}](/${source}.md)`)
|
|
933
|
+
.join(", ")}_`,
|
|
934
|
+
);
|
|
935
|
+
try {
|
|
936
|
+
writeFileSync(pagePath, serializeKnowledgeDocument(document), {
|
|
937
|
+
encoding: "utf8",
|
|
938
|
+
flag: "wx",
|
|
939
|
+
});
|
|
940
|
+
fixesApplied++;
|
|
941
|
+
} catch (error: unknown) {
|
|
942
|
+
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
916
943
|
}
|
|
917
944
|
}
|
|
918
945
|
}
|
|
919
946
|
|
|
920
|
-
writeJson(join(paths.discoveries, "gaps.json"), {
|
|
921
|
-
gaps,
|
|
922
|
-
generated: new Date().toISOString(),
|
|
923
|
-
});
|
|
924
|
-
|
|
925
947
|
const reportLines = [
|
|
926
948
|
"# Wiki Lint Report",
|
|
927
949
|
`Generated: ${fmtDate()}`,
|
|
@@ -931,26 +953,32 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
931
953
|
`- Orphans: ${orphans}`,
|
|
932
954
|
`- Missing pages: ${missingPages}`,
|
|
933
955
|
`- Contradictions: ${contradictions}`,
|
|
934
|
-
autoFix ? `-
|
|
956
|
+
autoFix ? `- Missing-page fixes applied: ${fixesApplied}` : "",
|
|
957
|
+
repair?.repaired ? `- Legacy pages repaired: ${repair.repaired}` : "",
|
|
958
|
+
repair?.manifestPath ? `- Repair manifest: ${repair.manifestPath}` : "",
|
|
935
959
|
"",
|
|
936
960
|
"## Findings",
|
|
937
|
-
findings.length
|
|
961
|
+
findings.length ? findings.map((finding) => `- ${finding}`).join("\n") : "✅ No issues found!",
|
|
938
962
|
"",
|
|
939
963
|
].filter(Boolean);
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
964
|
+
const reportPath = autoFix ? join(paths.outputs, `lint-${fmtDate()}.md`) : undefined;
|
|
965
|
+
if (autoFix && reportPath) {
|
|
966
|
+
writeJson(join(paths.discoveries, "gaps.json"), {
|
|
967
|
+
gaps,
|
|
968
|
+
generated: new Date().toISOString(),
|
|
969
|
+
});
|
|
970
|
+
mkdirSync(paths.outputs, { recursive: true });
|
|
971
|
+
writeFileSync(reportPath, `${reportLines.join("\n")}\n`, "utf8");
|
|
972
|
+
appendEvent(paths, {
|
|
973
|
+
kind: "lint",
|
|
974
|
+
orphans,
|
|
975
|
+
missing_pages: missingPages,
|
|
976
|
+
contradictions,
|
|
977
|
+
auto_fix: true,
|
|
978
|
+
legacy_pages_repaired: repair?.repaired ?? 0,
|
|
979
|
+
});
|
|
980
|
+
rebuildMetadataLight(paths);
|
|
981
|
+
}
|
|
954
982
|
|
|
955
983
|
return [
|
|
956
984
|
"🧹 **LLM Wiki lint complete**",
|
|
@@ -959,10 +987,12 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
959
987
|
`- Orphans: ${orphans}`,
|
|
960
988
|
`- Missing: ${missingPages}`,
|
|
961
989
|
`- Contradictions: ${contradictions}`,
|
|
962
|
-
autoFix ? `-
|
|
990
|
+
autoFix ? `- Missing-page fixes: ${fixesApplied}` : "",
|
|
991
|
+
repair?.repaired ? `- Legacy pages repaired: ${repair.repaired}` : "",
|
|
963
992
|
"",
|
|
964
|
-
`📄 Report: \`${reportPath}
|
|
965
|
-
|
|
993
|
+
reportPath ? `📄 Report: \`${reportPath}\`` : "",
|
|
994
|
+
repair?.manifestPath ? `🛟 Repair manifest: \`${repair.manifestPath}\`` : "",
|
|
995
|
+
gaps.length ? `💡 ${gaps.length} knowledge gap(s) tracked` : "",
|
|
966
996
|
]
|
|
967
997
|
.filter(Boolean)
|
|
968
998
|
.join("\n");
|
|
@@ -989,18 +1019,9 @@ export function registerWikiStatus(pi: ExtensionAPI): void {
|
|
|
989
1019
|
};
|
|
990
1020
|
}
|
|
991
1021
|
|
|
992
|
-
const
|
|
993
|
-
version: "1.0",
|
|
994
|
-
last_updated: "",
|
|
995
|
-
pages: {},
|
|
996
|
-
});
|
|
997
|
-
const backlinks = readJson<Record<string, string[]>>(join(paths.meta, "backlinks.json"), {});
|
|
1022
|
+
const status = getWikiStatus(paths);
|
|
998
1023
|
const config = readJson<Record<string, unknown>>(join(paths.dotWiki, "config.json"), {});
|
|
999
|
-
|
|
1000
|
-
const byType: Record<string, number> = {};
|
|
1001
|
-
for (const entry of Object.values(registry.pages)) {
|
|
1002
|
-
byType[entry.type] = (byType[entry.type] || 0) + 1;
|
|
1003
|
-
}
|
|
1024
|
+
const backlinks = readJson<Record<string, string[]>>(join(paths.meta, "backlinks.json"), {});
|
|
1004
1025
|
|
|
1005
1026
|
const orphanCount = Object.entries(backlinks).filter(
|
|
1006
1027
|
([, inbound]) => inbound.length === 0,
|
|
@@ -1010,23 +1031,30 @@ export function registerWikiStatus(pi: ExtensionAPI): void {
|
|
|
1010
1031
|
});
|
|
1011
1032
|
|
|
1012
1033
|
const health =
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1034
|
+
status.totalPages === 0 ? "🔴 Empty" : orphanCount > 5 ? "⚠️ Warning" : "✅ Good";
|
|
1035
|
+
|
|
1036
|
+
const diagLines =
|
|
1037
|
+
status.blockingDiagnostics.length > 0
|
|
1038
|
+
? [
|
|
1039
|
+
"",
|
|
1040
|
+
"⚠️ Blocking diagnostics:",
|
|
1041
|
+
...status.blockingDiagnostics.map((d) => ` - ${d.code}: ${d.message}`),
|
|
1042
|
+
]
|
|
1043
|
+
: [];
|
|
1018
1044
|
|
|
1019
1045
|
const lines = [
|
|
1020
1046
|
"📊 LLM Wiki Status",
|
|
1021
1047
|
"══════════════════",
|
|
1022
1048
|
`Topic: ${config.topic || "Unknown"}`,
|
|
1023
1049
|
`Mode: ${config.mode || "personal"}`,
|
|
1024
|
-
`
|
|
1025
|
-
|
|
1050
|
+
`Knowledge format: ${status.knowledgeFormat}`,
|
|
1051
|
+
`Pages: ${status.totalPages}`,
|
|
1052
|
+
...Object.entries(status.byType).map(([t, c]) => ` - ${t}s: ${c}`),
|
|
1026
1053
|
`Orphans: ${orphanCount}`,
|
|
1027
1054
|
`Gaps: ${gaps.gaps?.length || 0}`,
|
|
1028
1055
|
`Health: ${health}`,
|
|
1029
|
-
`Last updated: ${
|
|
1056
|
+
`Last updated: ${status.lastUpdated || "Never"}`,
|
|
1057
|
+
...diagLines,
|
|
1030
1058
|
];
|
|
1031
1059
|
|
|
1032
1060
|
return {
|
|
@@ -1034,11 +1062,13 @@ export function registerWikiStatus(pi: ExtensionAPI): void {
|
|
|
1034
1062
|
details: {
|
|
1035
1063
|
topic: config.topic,
|
|
1036
1064
|
mode: config.mode,
|
|
1037
|
-
|
|
1038
|
-
|
|
1065
|
+
knowledgeFormat: status.knowledgeFormat,
|
|
1066
|
+
totalPages: status.totalPages,
|
|
1067
|
+
byType: status.byType,
|
|
1039
1068
|
orphans: orphanCount,
|
|
1040
1069
|
gaps: gaps.gaps?.length || 0,
|
|
1041
1070
|
health,
|
|
1071
|
+
blockingDiagnostics: status.blockingDiagnostics,
|
|
1042
1072
|
} as Record<string, unknown>,
|
|
1043
1073
|
};
|
|
1044
1074
|
},
|
|
@@ -1057,11 +1087,16 @@ export function registerWikiRebuildMeta(pi: ExtensionAPI, runtime?: Runtime): vo
|
|
|
1057
1087
|
parameters: Type.Object({}),
|
|
1058
1088
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
1059
1089
|
const paths = getPaths(ctx.cwd);
|
|
1060
|
-
const vaultCheck =
|
|
1090
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
1061
1091
|
if (!vaultCheck.ok) {
|
|
1062
1092
|
return {
|
|
1063
|
-
content: [
|
|
1064
|
-
|
|
1093
|
+
content: [
|
|
1094
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
1095
|
+
],
|
|
1096
|
+
details: {
|
|
1097
|
+
error: vaultCheck.diagnostics[0].code,
|
|
1098
|
+
diagnostics: vaultCheck.diagnostics,
|
|
1099
|
+
} as Record<string, unknown>,
|
|
1065
1100
|
isError: true,
|
|
1066
1101
|
};
|
|
1067
1102
|
}
|
|
@@ -1073,8 +1108,19 @@ export function registerWikiRebuildMeta(pi: ExtensionAPI, runtime?: Runtime): vo
|
|
|
1073
1108
|
started:
|
|
1074
1109
|
"\u{1F9E0} LLM Wiki: metadata rebuild started in the background — the result will be reported when it completes.",
|
|
1075
1110
|
work: async () => {
|
|
1076
|
-
rebuildMetadata(paths);
|
|
1077
|
-
|
|
1111
|
+
const result = rebuildMetadata(paths);
|
|
1112
|
+
// No rebuild_meta event — rebuild is a projection, not an authoritative mutation
|
|
1113
|
+
if (!result.ok) {
|
|
1114
|
+
return `⚠️ LLM Wiki: rebuild had issues — ${result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("; ")}`;
|
|
1115
|
+
}
|
|
1116
|
+
const warnings = result.diagnostics.filter(
|
|
1117
|
+
(diagnostic) => diagnostic.severity === "warning",
|
|
1118
|
+
);
|
|
1119
|
+
if (warnings.length > 0) {
|
|
1120
|
+
return `⚠️ LLM Wiki: metadata rebuilt with warnings — ${warnings
|
|
1121
|
+
.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`)
|
|
1122
|
+
.join("; ")}`;
|
|
1123
|
+
}
|
|
1078
1124
|
const registry = readJson<Registry>(join(paths.meta, "registry.json"), {
|
|
1079
1125
|
version: "1.0",
|
|
1080
1126
|
last_updated: "",
|
|
@@ -1109,11 +1155,16 @@ export function registerWikiReindexEmbeddings(pi: ExtensionAPI, runtime?: Runtim
|
|
|
1109
1155
|
}),
|
|
1110
1156
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1111
1157
|
const paths = getPaths(ctx.cwd);
|
|
1112
|
-
const vaultCheck =
|
|
1158
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
1113
1159
|
if (!vaultCheck.ok) {
|
|
1114
1160
|
return {
|
|
1115
|
-
content: [
|
|
1116
|
-
|
|
1161
|
+
content: [
|
|
1162
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
1163
|
+
],
|
|
1164
|
+
details: {
|
|
1165
|
+
error: vaultCheck.diagnostics[0].code,
|
|
1166
|
+
diagnostics: vaultCheck.diagnostics,
|
|
1167
|
+
} as Record<string, unknown>,
|
|
1117
1168
|
isError: true,
|
|
1118
1169
|
};
|
|
1119
1170
|
}
|
|
@@ -1167,25 +1218,45 @@ export function registerWikiLogEvent(pi: ExtensionAPI): void {
|
|
|
1167
1218
|
}),
|
|
1168
1219
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1169
1220
|
const paths = getPaths(ctx.cwd);
|
|
1170
|
-
const vaultCheck =
|
|
1221
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
1171
1222
|
if (!vaultCheck.ok) {
|
|
1172
1223
|
return {
|
|
1173
|
-
content: [
|
|
1174
|
-
|
|
1224
|
+
content: [
|
|
1225
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
1226
|
+
],
|
|
1227
|
+
details: {
|
|
1228
|
+
error: vaultCheck.diagnostics[0].code,
|
|
1229
|
+
diagnostics: vaultCheck.diagnostics,
|
|
1230
|
+
} as Record<string, unknown>,
|
|
1175
1231
|
isError: true,
|
|
1176
1232
|
};
|
|
1177
1233
|
}
|
|
1178
1234
|
|
|
1179
|
-
|
|
1235
|
+
const kind = typeof params.kind === "string" ? params.kind.trim() : "";
|
|
1236
|
+
if (!kind) {
|
|
1237
|
+
return {
|
|
1238
|
+
content: [{ type: "text", text: "Event kind must be a non-empty string" }],
|
|
1239
|
+
details: { error: "event_missing_kind" } as Record<string, unknown>,
|
|
1240
|
+
isError: true,
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
const details = params.details ?? {};
|
|
1244
|
+
if (Object.hasOwn(details, "kind") || Object.hasOwn(details, "timestamp")) {
|
|
1245
|
+
return {
|
|
1246
|
+
content: [{ type: "text", text: "Event details cannot override kind or timestamp" }],
|
|
1247
|
+
details: { error: "event_reserved_field" } as Record<string, unknown>,
|
|
1248
|
+
isError: true,
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1180
1251
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1252
|
+
appendEvent(paths, { kind, ...details });
|
|
1253
|
+
|
|
1254
|
+
// Regenerate projections
|
|
1255
|
+
rebuildMetadata(paths);
|
|
1185
1256
|
|
|
1186
1257
|
return {
|
|
1187
|
-
content: [{ type: "text", text: `✅ Event logged: ${
|
|
1188
|
-
details: { kind
|
|
1258
|
+
content: [{ type: "text", text: `✅ Event logged: ${kind}` }],
|
|
1259
|
+
details: { kind } as Record<string, unknown>,
|
|
1189
1260
|
};
|
|
1190
1261
|
},
|
|
1191
1262
|
});
|