@zosmaai/pi-llm-wiki 0.10.9 → 0.11.0
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 +4 -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 +31 -10
- 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 +71 -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 +310 -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 +499 -0
- package/dist/extensions/llm-wiki/lib/model-command.js +86 -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 +191 -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 +172 -0
- package/dist/extensions/llm-wiki/lib/tools.js +1192 -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 +347 -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/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-okf-foundation-release-remediation.md +1174 -0
- package/docs/superpowers/specs/2026-08-02-okf-foundation-design.md +578 -0
- package/docs/superpowers/specs/2026-08-02-okf-v0.2-interoperability-design.md +538 -0
- package/extensions/llm-wiki/index.ts +22 -36
- package/extensions/llm-wiki/lib/bootstrap.ts +84 -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 +170 -29
- package/extensions/llm-wiki/lib/knowledge-document.ts +661 -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 +531 -116
- 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/source-extractors.ts +12 -17
- package/extensions/llm-wiki/lib/source-packet.ts +44 -31
- package/extensions/llm-wiki/lib/tools.ts +404 -342
- package/extensions/llm-wiki/lib/trajectory.ts +15 -1
- package/extensions/llm-wiki/lib/utils.ts +120 -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 +8 -6
|
@@ -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
|
}
|
|
@@ -528,11 +520,16 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
528
520
|
}),
|
|
529
521
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
530
522
|
const paths = getPaths(ctx.cwd);
|
|
531
|
-
const vaultCheck =
|
|
523
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
532
524
|
if (!vaultCheck.ok) {
|
|
533
525
|
return {
|
|
534
|
-
content: [
|
|
535
|
-
|
|
526
|
+
content: [
|
|
527
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
528
|
+
],
|
|
529
|
+
details: {
|
|
530
|
+
error: vaultCheck.diagnostics[0].code,
|
|
531
|
+
diagnostics: vaultCheck.diagnostics,
|
|
532
|
+
} as Record<string, unknown>,
|
|
536
533
|
isError: true,
|
|
537
534
|
};
|
|
538
535
|
}
|
|
@@ -567,9 +564,19 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
567
564
|
}
|
|
568
565
|
|
|
569
566
|
const today = fmtDate();
|
|
570
|
-
const
|
|
567
|
+
const body = params.content ?? buildPageBody(type, params.title);
|
|
568
|
+
const doc = createKnowledgeDocument(
|
|
569
|
+
`${folder}/${slug}.md`,
|
|
570
|
+
{
|
|
571
|
+
type,
|
|
572
|
+
title: params.title,
|
|
573
|
+
created: today,
|
|
574
|
+
updated: today,
|
|
575
|
+
},
|
|
576
|
+
body,
|
|
577
|
+
);
|
|
571
578
|
mkdirSync(join(paths.wiki, folder), { recursive: true });
|
|
572
|
-
|
|
579
|
+
writeKnowledgeDocumentFile(pagePath, doc);
|
|
573
580
|
|
|
574
581
|
appendEvent(paths, {
|
|
575
582
|
kind: "ensure_page",
|
|
@@ -595,151 +602,135 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
595
602
|
});
|
|
596
603
|
}
|
|
597
604
|
|
|
598
|
-
function
|
|
599
|
-
type
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
): string {
|
|
604
|
-
if (customContent) return customContent;
|
|
605
|
+
function buildPageBody(type: string, title: string): string {
|
|
606
|
+
if (type === "entity") {
|
|
607
|
+
return `# ${title}
|
|
608
|
+
|
|
609
|
+
One-line description.
|
|
605
610
|
|
|
606
|
-
|
|
611
|
+
## Overview
|
|
607
612
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
613
|
+
[Key facts]
|
|
614
|
+
|
|
615
|
+
## Links
|
|
616
|
+
|
|
617
|
+
- [related-page](/concepts/related-page.md)`;
|
|
612
618
|
}
|
|
613
619
|
if (type === "concept") {
|
|
614
|
-
return
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
+
return `# ${title}
|
|
621
|
+
|
|
622
|
+
One-line definition.
|
|
623
|
+
|
|
624
|
+
## Definition
|
|
625
|
+
|
|
626
|
+
[Clear explanation]
|
|
627
|
+
|
|
628
|
+
## Links
|
|
629
|
+
|
|
630
|
+
- [related-page](/concepts/related-page.md)`;
|
|
620
631
|
}
|
|
621
632
|
if (type === "synthesis") {
|
|
622
|
-
return
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
633
|
+
return `# ${title}
|
|
634
|
+
|
|
635
|
+
Cross-cutting analysis.
|
|
636
|
+
|
|
637
|
+
## Question
|
|
638
|
+
|
|
639
|
+
[What drove this?]
|
|
640
|
+
|
|
641
|
+
## Links
|
|
642
|
+
|
|
643
|
+
- [related-page](/concepts/related-page.md)`;
|
|
628
644
|
}
|
|
629
645
|
if (type === "analysis") {
|
|
630
|
-
return
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
646
|
+
return `# ${title}
|
|
647
|
+
|
|
648
|
+
Durable answer from a query.
|
|
649
|
+
|
|
650
|
+
## Question
|
|
651
|
+
|
|
652
|
+
[Original question]
|
|
653
|
+
|
|
654
|
+
## Links
|
|
655
|
+
|
|
656
|
+
- [related-page](/concepts/related-page.md)`;
|
|
634
657
|
}
|
|
635
658
|
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");
|
|
659
|
+
return `# ${title}
|
|
660
|
+
|
|
661
|
+
_One-line summary of the reusable pattern this skill captures._
|
|
662
|
+
|
|
663
|
+
## When to Use
|
|
664
|
+
|
|
665
|
+
[Trigger conditions — when this pattern applies]
|
|
666
|
+
|
|
667
|
+
## Procedure
|
|
668
|
+
|
|
669
|
+
1. [Step 1]
|
|
670
|
+
2. [Step 2]
|
|
671
|
+
|
|
672
|
+
## Pitfalls
|
|
673
|
+
|
|
674
|
+
- [Known failure mode or caveat]
|
|
675
|
+
|
|
676
|
+
## Distilled From
|
|
677
|
+
|
|
678
|
+
_Trajectories this skill was generalized from._
|
|
679
|
+
|
|
680
|
+
- [trajectories/TRJ-...](/trajectories/TRJ-....md)`;
|
|
670
681
|
}
|
|
671
682
|
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");
|
|
683
|
+
return `# ${title}
|
|
684
|
+
|
|
685
|
+
_One-line summary of the specific task this case records._
|
|
686
|
+
|
|
687
|
+
## Task
|
|
688
|
+
|
|
689
|
+
[What was requested]
|
|
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-...](/trajectories/TRJ-....md) — captured tool-call run`;
|
|
704
702
|
}
|
|
705
703
|
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");
|
|
704
|
+
return `# ${title}
|
|
705
|
+
|
|
706
|
+
## Description
|
|
707
|
+
|
|
708
|
+
[Clear description of what this requirement entails]
|
|
709
|
+
|
|
710
|
+
## Acceptance Criteria
|
|
711
|
+
|
|
712
|
+
- [ ] [Criterion 1]
|
|
713
|
+
- [ ] [Criterion 2]
|
|
714
|
+
|
|
715
|
+
## Dependencies
|
|
716
|
+
|
|
717
|
+
_Pages this requirement depends on._
|
|
718
|
+
|
|
719
|
+
## Implementation Notes
|
|
720
|
+
|
|
721
|
+
[Optional notes]
|
|
722
|
+
|
|
723
|
+
## Sources
|
|
724
|
+
|
|
725
|
+
- [sources/SRC-...](/sources/SRC-....md) — original concept capture`;
|
|
741
726
|
}
|
|
742
|
-
return
|
|
727
|
+
return `# ${title}
|
|
728
|
+
|
|
729
|
+
[Description to be filled]
|
|
730
|
+
|
|
731
|
+
## Links
|
|
732
|
+
|
|
733
|
+
- [related-page](/concepts/related-page.md)`;
|
|
743
734
|
}
|
|
744
735
|
|
|
745
736
|
// ─── 5. wiki_search ─────────────────────────────────────
|
|
@@ -757,29 +748,15 @@ export function registerWikiSearch(pi: ExtensionAPI): void {
|
|
|
757
748
|
}),
|
|
758
749
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
759
750
|
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) {
|
|
751
|
+
const result = searchRegistry(paths, params.query, params.type);
|
|
752
|
+
|
|
753
|
+
if (result.matches.length === 0) {
|
|
780
754
|
return {
|
|
781
755
|
content: [{ type: "text", text: `No pages found for "${params.query}"` }],
|
|
782
|
-
details: { query: params.query, matches: [] } as Record<
|
|
756
|
+
details: { query: params.query, matches: [], diagnostics: result.diagnostics } as Record<
|
|
757
|
+
string,
|
|
758
|
+
unknown
|
|
759
|
+
>,
|
|
783
760
|
};
|
|
784
761
|
}
|
|
785
762
|
|
|
@@ -788,13 +765,17 @@ export function registerWikiSearch(pi: ExtensionAPI): void {
|
|
|
788
765
|
{
|
|
789
766
|
type: "text",
|
|
790
767
|
text: [
|
|
791
|
-
`🔍 **${matches.length} result(s)** for "${params.query}":`,
|
|
768
|
+
`🔍 **${result.matches.length} result(s)** for "${params.query}":`,
|
|
792
769
|
"",
|
|
793
|
-
...matches.map((m) => `- [[${m.id}]] — *${m.type}* — ${m.title}`),
|
|
770
|
+
...result.matches.map((m) => `- [[${m.id}]] — *${m.type}* — ${m.title}`),
|
|
794
771
|
].join("\n"),
|
|
795
772
|
},
|
|
796
773
|
],
|
|
797
|
-
details: {
|
|
774
|
+
details: {
|
|
775
|
+
query: params.query,
|
|
776
|
+
matches: result.matches,
|
|
777
|
+
diagnostics: result.diagnostics,
|
|
778
|
+
} as Record<string, unknown>,
|
|
798
779
|
};
|
|
799
780
|
},
|
|
800
781
|
});
|
|
@@ -820,11 +801,16 @@ export function registerWikiLint(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
820
801
|
}),
|
|
821
802
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
822
803
|
const paths = getPaths(ctx.cwd);
|
|
823
|
-
const vaultCheck =
|
|
804
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
824
805
|
if (!vaultCheck.ok) {
|
|
825
806
|
return {
|
|
826
|
-
content: [
|
|
827
|
-
|
|
807
|
+
content: [
|
|
808
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
809
|
+
],
|
|
810
|
+
details: {
|
|
811
|
+
error: vaultCheck.diagnostics[0].code,
|
|
812
|
+
diagnostics: vaultCheck.diagnostics,
|
|
813
|
+
} as Record<string, unknown>,
|
|
828
814
|
isError: true,
|
|
829
815
|
};
|
|
830
816
|
}
|
|
@@ -846,82 +832,117 @@ export function registerWikiLint(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
846
832
|
* run off-thread via `dispatchReported`). Returns the human-readable summary.
|
|
847
833
|
*/
|
|
848
834
|
function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
835
|
+
assertWritableVault(paths);
|
|
836
|
+
let repair: ReturnType<typeof repairLegacyKnowledgeDocuments> | undefined;
|
|
837
|
+
if (autoFix) {
|
|
838
|
+
let projection = rebuildMetadata(paths);
|
|
839
|
+
repair = !projection.ok ? repairLegacyKnowledgeDocuments(paths) : undefined;
|
|
840
|
+
if (repair?.repaired) projection = rebuildMetadata(paths);
|
|
841
|
+
if (!projection.ok) {
|
|
842
|
+
return [
|
|
843
|
+
"# Wiki Lint Report",
|
|
844
|
+
"",
|
|
845
|
+
repair?.repaired ? `Legacy pages repaired: ${repair.repaired}` : "",
|
|
846
|
+
repair?.manifestPath ? `Repair manifest: ${repair.manifestPath}` : "",
|
|
847
|
+
"Projection-blocking diagnostics:",
|
|
848
|
+
...projection.diagnostics.map(
|
|
849
|
+
(diagnostic) => `- ${diagnostic.code}: ${diagnostic.path}: ${diagnostic.message}`,
|
|
850
|
+
),
|
|
851
|
+
]
|
|
852
|
+
.filter(Boolean)
|
|
853
|
+
.join("\n");
|
|
854
|
+
}
|
|
855
|
+
} else {
|
|
856
|
+
const vault = inspectVaultFormat(paths);
|
|
857
|
+
const audit = discoverKnowledgeDocuments(paths);
|
|
858
|
+
const diagnostics = [...vault.diagnostics, ...audit.diagnostics];
|
|
859
|
+
if (vault.blocking || audit.blocking) {
|
|
860
|
+
return [
|
|
861
|
+
"# Wiki Lint Report",
|
|
862
|
+
"",
|
|
863
|
+
"Projection-blocking diagnostics:",
|
|
864
|
+
...diagnostics.map(
|
|
865
|
+
(diagnostic) => `- ${diagnostic.code}: ${diagnostic.path}: ${diagnostic.message}`,
|
|
866
|
+
),
|
|
867
|
+
].join("\n");
|
|
868
|
+
}
|
|
869
|
+
}
|
|
852
870
|
|
|
871
|
+
const discovery = discoverKnowledgeDocuments(paths);
|
|
872
|
+
const pages = discovery.documents;
|
|
873
|
+
const knownIds = new Set(pages.map((page) => page.id));
|
|
874
|
+
const inbound = Object.fromEntries(pages.map((page) => [page.id, 0]));
|
|
875
|
+
const gapSources = new Map<string, Set<string>>();
|
|
853
876
|
const findings: string[] = [];
|
|
854
|
-
let orphans = 0;
|
|
855
877
|
let missingPages = 0;
|
|
856
878
|
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
879
|
|
|
862
880
|
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
|
-
}
|
|
881
|
+
const resolved = buildResolvedBacklinks(page.id, page.body, knownIds);
|
|
882
|
+
for (const target of resolved.targets) inbound[target]++;
|
|
883
|
+
for (const unresolved of resolved.unresolved) {
|
|
884
|
+
const sources = gapSources.get(unresolved.target) ?? new Set<string>();
|
|
885
|
+
sources.add(page.id);
|
|
886
|
+
gapSources.set(unresolved.target, sources);
|
|
887
|
+
missingPages++;
|
|
888
|
+
findings.push(`Missing page: ${unresolved.target} (in ${page.id})`);
|
|
878
889
|
}
|
|
879
890
|
}
|
|
880
891
|
|
|
892
|
+
let orphans = 0;
|
|
881
893
|
for (const page of pages) {
|
|
882
|
-
if (
|
|
894
|
+
if (inbound[page.id] === 0) {
|
|
883
895
|
orphans++;
|
|
884
|
-
findings.push(`Orphan:
|
|
896
|
+
findings.push(`Orphan: ${page.id} has no inbound links`);
|
|
885
897
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
for (const page of pages) {
|
|
889
|
-
if (page.content.includes("⚠️ **Contradiction")) {
|
|
898
|
+
if (page.body.includes("⚠️ **Contradiction")) {
|
|
890
899
|
contradictions++;
|
|
891
|
-
findings.push(`Contradiction flagged in
|
|
900
|
+
findings.push(`Contradiction flagged in ${page.id}`);
|
|
892
901
|
}
|
|
893
902
|
}
|
|
894
903
|
|
|
904
|
+
const gaps = [...gapSources.entries()]
|
|
905
|
+
.map(([topic, sources]) => ({ topic, mentionedBy: [...sources].sort(compareCodePoint) }))
|
|
906
|
+
.sort((left, right) => compareCodePoint(left.topic, right.topic));
|
|
895
907
|
let fixesApplied = 0;
|
|
896
908
|
if (autoFix) {
|
|
897
909
|
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
|
-
|
|
910
|
+
if (gap.mentionedBy.length < 2) continue;
|
|
911
|
+
const parts = gap.topic.split("/");
|
|
912
|
+
const name =
|
|
913
|
+
parts.length === 1
|
|
914
|
+
? parts[0]
|
|
915
|
+
: parts.length === 2 && parts[0] === "concepts"
|
|
916
|
+
? parts[1]
|
|
917
|
+
: "";
|
|
918
|
+
if (!name || slugify(name) !== name) continue;
|
|
919
|
+
const pagePath = join(paths.wiki, "concepts", `${name}.md`);
|
|
920
|
+
mkdirSync(join(paths.wiki, "concepts"), { recursive: true });
|
|
921
|
+
const document = createKnowledgeDocument(
|
|
922
|
+
`concepts/${name}.md`,
|
|
923
|
+
{
|
|
924
|
+
type: "concept",
|
|
925
|
+
title: name.replace(/-/g, " "),
|
|
926
|
+
created: fmtDate(),
|
|
927
|
+
updated: fmtDate(),
|
|
928
|
+
status: "stub",
|
|
929
|
+
},
|
|
930
|
+
`_Stub auto-created by lint. Expand with content from: ${gap.mentionedBy
|
|
931
|
+
.map((source) => `[${source}](/${source}.md)`)
|
|
932
|
+
.join(", ")}_`,
|
|
933
|
+
);
|
|
934
|
+
try {
|
|
935
|
+
writeFileSync(pagePath, serializeKnowledgeDocument(document), {
|
|
936
|
+
encoding: "utf8",
|
|
937
|
+
flag: "wx",
|
|
938
|
+
});
|
|
939
|
+
fixesApplied++;
|
|
940
|
+
} catch (error: unknown) {
|
|
941
|
+
if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
|
|
916
942
|
}
|
|
917
943
|
}
|
|
918
944
|
}
|
|
919
945
|
|
|
920
|
-
writeJson(join(paths.discoveries, "gaps.json"), {
|
|
921
|
-
gaps,
|
|
922
|
-
generated: new Date().toISOString(),
|
|
923
|
-
});
|
|
924
|
-
|
|
925
946
|
const reportLines = [
|
|
926
947
|
"# Wiki Lint Report",
|
|
927
948
|
`Generated: ${fmtDate()}`,
|
|
@@ -931,26 +952,32 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
931
952
|
`- Orphans: ${orphans}`,
|
|
932
953
|
`- Missing pages: ${missingPages}`,
|
|
933
954
|
`- Contradictions: ${contradictions}`,
|
|
934
|
-
autoFix ? `-
|
|
955
|
+
autoFix ? `- Missing-page fixes applied: ${fixesApplied}` : "",
|
|
956
|
+
repair?.repaired ? `- Legacy pages repaired: ${repair.repaired}` : "",
|
|
957
|
+
repair?.manifestPath ? `- Repair manifest: ${repair.manifestPath}` : "",
|
|
935
958
|
"",
|
|
936
959
|
"## Findings",
|
|
937
|
-
findings.length
|
|
960
|
+
findings.length ? findings.map((finding) => `- ${finding}`).join("\n") : "✅ No issues found!",
|
|
938
961
|
"",
|
|
939
962
|
].filter(Boolean);
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
963
|
+
const reportPath = autoFix ? join(paths.outputs, `lint-${fmtDate()}.md`) : undefined;
|
|
964
|
+
if (autoFix && reportPath) {
|
|
965
|
+
writeJson(join(paths.discoveries, "gaps.json"), {
|
|
966
|
+
gaps,
|
|
967
|
+
generated: new Date().toISOString(),
|
|
968
|
+
});
|
|
969
|
+
mkdirSync(paths.outputs, { recursive: true });
|
|
970
|
+
writeFileSync(reportPath, `${reportLines.join("\n")}\n`, "utf8");
|
|
971
|
+
appendEvent(paths, {
|
|
972
|
+
kind: "lint",
|
|
973
|
+
orphans,
|
|
974
|
+
missing_pages: missingPages,
|
|
975
|
+
contradictions,
|
|
976
|
+
auto_fix: true,
|
|
977
|
+
legacy_pages_repaired: repair?.repaired ?? 0,
|
|
978
|
+
});
|
|
979
|
+
rebuildMetadataLight(paths);
|
|
980
|
+
}
|
|
954
981
|
|
|
955
982
|
return [
|
|
956
983
|
"🧹 **LLM Wiki lint complete**",
|
|
@@ -959,10 +986,12 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
959
986
|
`- Orphans: ${orphans}`,
|
|
960
987
|
`- Missing: ${missingPages}`,
|
|
961
988
|
`- Contradictions: ${contradictions}`,
|
|
962
|
-
autoFix ? `-
|
|
989
|
+
autoFix ? `- Missing-page fixes: ${fixesApplied}` : "",
|
|
990
|
+
repair?.repaired ? `- Legacy pages repaired: ${repair.repaired}` : "",
|
|
963
991
|
"",
|
|
964
|
-
`📄 Report: \`${reportPath}
|
|
965
|
-
|
|
992
|
+
reportPath ? `📄 Report: \`${reportPath}\`` : "",
|
|
993
|
+
repair?.manifestPath ? `🛟 Repair manifest: \`${repair.manifestPath}\`` : "",
|
|
994
|
+
gaps.length ? `💡 ${gaps.length} knowledge gap(s) tracked` : "",
|
|
966
995
|
]
|
|
967
996
|
.filter(Boolean)
|
|
968
997
|
.join("\n");
|
|
@@ -989,18 +1018,9 @@ export function registerWikiStatus(pi: ExtensionAPI): void {
|
|
|
989
1018
|
};
|
|
990
1019
|
}
|
|
991
1020
|
|
|
992
|
-
const
|
|
993
|
-
version: "1.0",
|
|
994
|
-
last_updated: "",
|
|
995
|
-
pages: {},
|
|
996
|
-
});
|
|
997
|
-
const backlinks = readJson<Record<string, string[]>>(join(paths.meta, "backlinks.json"), {});
|
|
1021
|
+
const status = getWikiStatus(paths);
|
|
998
1022
|
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
|
-
}
|
|
1023
|
+
const backlinks = readJson<Record<string, string[]>>(join(paths.meta, "backlinks.json"), {});
|
|
1004
1024
|
|
|
1005
1025
|
const orphanCount = Object.entries(backlinks).filter(
|
|
1006
1026
|
([, inbound]) => inbound.length === 0,
|
|
@@ -1010,23 +1030,30 @@ export function registerWikiStatus(pi: ExtensionAPI): void {
|
|
|
1010
1030
|
});
|
|
1011
1031
|
|
|
1012
1032
|
const health =
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1033
|
+
status.totalPages === 0 ? "🔴 Empty" : orphanCount > 5 ? "⚠️ Warning" : "✅ Good";
|
|
1034
|
+
|
|
1035
|
+
const diagLines =
|
|
1036
|
+
status.blockingDiagnostics.length > 0
|
|
1037
|
+
? [
|
|
1038
|
+
"",
|
|
1039
|
+
"⚠️ Blocking diagnostics:",
|
|
1040
|
+
...status.blockingDiagnostics.map((d) => ` - ${d.code}: ${d.message}`),
|
|
1041
|
+
]
|
|
1042
|
+
: [];
|
|
1018
1043
|
|
|
1019
1044
|
const lines = [
|
|
1020
1045
|
"📊 LLM Wiki Status",
|
|
1021
1046
|
"══════════════════",
|
|
1022
1047
|
`Topic: ${config.topic || "Unknown"}`,
|
|
1023
1048
|
`Mode: ${config.mode || "personal"}`,
|
|
1024
|
-
`
|
|
1025
|
-
|
|
1049
|
+
`Knowledge format: ${status.knowledgeFormat}`,
|
|
1050
|
+
`Pages: ${status.totalPages}`,
|
|
1051
|
+
...Object.entries(status.byType).map(([t, c]) => ` - ${t}s: ${c}`),
|
|
1026
1052
|
`Orphans: ${orphanCount}`,
|
|
1027
1053
|
`Gaps: ${gaps.gaps?.length || 0}`,
|
|
1028
1054
|
`Health: ${health}`,
|
|
1029
|
-
`Last updated: ${
|
|
1055
|
+
`Last updated: ${status.lastUpdated || "Never"}`,
|
|
1056
|
+
...diagLines,
|
|
1030
1057
|
];
|
|
1031
1058
|
|
|
1032
1059
|
return {
|
|
@@ -1034,11 +1061,13 @@ export function registerWikiStatus(pi: ExtensionAPI): void {
|
|
|
1034
1061
|
details: {
|
|
1035
1062
|
topic: config.topic,
|
|
1036
1063
|
mode: config.mode,
|
|
1037
|
-
|
|
1038
|
-
|
|
1064
|
+
knowledgeFormat: status.knowledgeFormat,
|
|
1065
|
+
totalPages: status.totalPages,
|
|
1066
|
+
byType: status.byType,
|
|
1039
1067
|
orphans: orphanCount,
|
|
1040
1068
|
gaps: gaps.gaps?.length || 0,
|
|
1041
1069
|
health,
|
|
1070
|
+
blockingDiagnostics: status.blockingDiagnostics,
|
|
1042
1071
|
} as Record<string, unknown>,
|
|
1043
1072
|
};
|
|
1044
1073
|
},
|
|
@@ -1057,11 +1086,16 @@ export function registerWikiRebuildMeta(pi: ExtensionAPI, runtime?: Runtime): vo
|
|
|
1057
1086
|
parameters: Type.Object({}),
|
|
1058
1087
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
1059
1088
|
const paths = getPaths(ctx.cwd);
|
|
1060
|
-
const vaultCheck =
|
|
1089
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
1061
1090
|
if (!vaultCheck.ok) {
|
|
1062
1091
|
return {
|
|
1063
|
-
content: [
|
|
1064
|
-
|
|
1092
|
+
content: [
|
|
1093
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
1094
|
+
],
|
|
1095
|
+
details: {
|
|
1096
|
+
error: vaultCheck.diagnostics[0].code,
|
|
1097
|
+
diagnostics: vaultCheck.diagnostics,
|
|
1098
|
+
} as Record<string, unknown>,
|
|
1065
1099
|
isError: true,
|
|
1066
1100
|
};
|
|
1067
1101
|
}
|
|
@@ -1073,8 +1107,11 @@ export function registerWikiRebuildMeta(pi: ExtensionAPI, runtime?: Runtime): vo
|
|
|
1073
1107
|
started:
|
|
1074
1108
|
"\u{1F9E0} LLM Wiki: metadata rebuild started in the background — the result will be reported when it completes.",
|
|
1075
1109
|
work: async () => {
|
|
1076
|
-
rebuildMetadata(paths);
|
|
1077
|
-
|
|
1110
|
+
const result = rebuildMetadata(paths);
|
|
1111
|
+
// No rebuild_meta event — rebuild is a projection, not an authoritative mutation
|
|
1112
|
+
if (!result.ok) {
|
|
1113
|
+
return `⚠️ LLM Wiki: rebuild had issues — ${result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("; ")}`;
|
|
1114
|
+
}
|
|
1078
1115
|
const registry = readJson<Registry>(join(paths.meta, "registry.json"), {
|
|
1079
1116
|
version: "1.0",
|
|
1080
1117
|
last_updated: "",
|
|
@@ -1109,11 +1146,16 @@ export function registerWikiReindexEmbeddings(pi: ExtensionAPI, runtime?: Runtim
|
|
|
1109
1146
|
}),
|
|
1110
1147
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1111
1148
|
const paths = getPaths(ctx.cwd);
|
|
1112
|
-
const vaultCheck =
|
|
1149
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
1113
1150
|
if (!vaultCheck.ok) {
|
|
1114
1151
|
return {
|
|
1115
|
-
content: [
|
|
1116
|
-
|
|
1152
|
+
content: [
|
|
1153
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
1154
|
+
],
|
|
1155
|
+
details: {
|
|
1156
|
+
error: vaultCheck.diagnostics[0].code,
|
|
1157
|
+
diagnostics: vaultCheck.diagnostics,
|
|
1158
|
+
} as Record<string, unknown>,
|
|
1117
1159
|
isError: true,
|
|
1118
1160
|
};
|
|
1119
1161
|
}
|
|
@@ -1167,25 +1209,45 @@ export function registerWikiLogEvent(pi: ExtensionAPI): void {
|
|
|
1167
1209
|
}),
|
|
1168
1210
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1169
1211
|
const paths = getPaths(ctx.cwd);
|
|
1170
|
-
const vaultCheck =
|
|
1212
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
1171
1213
|
if (!vaultCheck.ok) {
|
|
1172
1214
|
return {
|
|
1173
|
-
content: [
|
|
1174
|
-
|
|
1215
|
+
content: [
|
|
1216
|
+
{ type: "text", text: `Wiki vault error: ${vaultCheck.diagnostics[0].message}` },
|
|
1217
|
+
],
|
|
1218
|
+
details: {
|
|
1219
|
+
error: vaultCheck.diagnostics[0].code,
|
|
1220
|
+
diagnostics: vaultCheck.diagnostics,
|
|
1221
|
+
} as Record<string, unknown>,
|
|
1175
1222
|
isError: true,
|
|
1176
1223
|
};
|
|
1177
1224
|
}
|
|
1178
1225
|
|
|
1179
|
-
|
|
1226
|
+
const kind = typeof params.kind === "string" ? params.kind.trim() : "";
|
|
1227
|
+
if (!kind) {
|
|
1228
|
+
return {
|
|
1229
|
+
content: [{ type: "text", text: "Event kind must be a non-empty string" }],
|
|
1230
|
+
details: { error: "event_missing_kind" } as Record<string, unknown>,
|
|
1231
|
+
isError: true,
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
const details = params.details ?? {};
|
|
1235
|
+
if (Object.hasOwn(details, "kind") || Object.hasOwn(details, "timestamp")) {
|
|
1236
|
+
return {
|
|
1237
|
+
content: [{ type: "text", text: "Event details cannot override kind or timestamp" }],
|
|
1238
|
+
details: { error: "event_reserved_field" } as Record<string, unknown>,
|
|
1239
|
+
isError: true,
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1180
1242
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1243
|
+
appendEvent(paths, { kind, ...details });
|
|
1244
|
+
|
|
1245
|
+
// Regenerate projections
|
|
1246
|
+
rebuildMetadata(paths);
|
|
1185
1247
|
|
|
1186
1248
|
return {
|
|
1187
|
-
content: [{ type: "text", text: `✅ Event logged: ${
|
|
1188
|
-
details: { kind
|
|
1249
|
+
content: [{ type: "text", text: `✅ Event logged: ${kind}` }],
|
|
1250
|
+
details: { kind } as Record<string, unknown>,
|
|
1189
1251
|
};
|
|
1190
1252
|
},
|
|
1191
1253
|
});
|