@zosmaai/pi-llm-wiki 0.10.7 → 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 +38 -3
- 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 +174 -29
- 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 +406 -348
- package/extensions/llm-wiki/lib/trajectory.ts +15 -1
- package/extensions/llm-wiki/lib/utils.ts +121 -130
- 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,32 +2,39 @@ 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,
|
|
28
26
|
resolveVaultPaths,
|
|
27
|
+
slugify,
|
|
29
28
|
writeJson,
|
|
30
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";
|
|
31
38
|
|
|
32
39
|
/**
|
|
33
40
|
* All LLM Wiki custom tools.
|
|
@@ -115,59 +122,35 @@ export function registerWikiBootstrap(pi: ExtensionAPI): void {
|
|
|
115
122
|
const root = params.root ?? ctx.cwd ?? process.cwd();
|
|
116
123
|
const mode = params.mode || "personal";
|
|
117
124
|
const paths = getVaultPaths(root);
|
|
118
|
-
|
|
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
|
-
" original/",
|
|
148
|
-
" extracted.md",
|
|
149
|
-
" attachments/",
|
|
150
|
-
"```",
|
|
151
|
-
"",
|
|
152
|
-
"## Page Types",
|
|
153
|
-
"",
|
|
154
|
-
"- **source** — what this specific source says",
|
|
155
|
-
"- **entity** — people, orgs, tools, products",
|
|
156
|
-
"- **concept** — ideas, patterns, frameworks",
|
|
157
|
-
"- **synthesis** — cross-source theses and tensions",
|
|
158
|
-
"- **analysis** — durable filed answers from queries",
|
|
159
|
-
"- **requirement** — atomic requirements with status, priority, and traceability",
|
|
160
|
-
"",
|
|
161
|
-
"## Linking Style",
|
|
162
|
-
"",
|
|
163
|
-
"- Internal: [[folder/page-name]]",
|
|
164
|
-
"- Citation: [[sources/SRC-YYYY-MM-DD-NNN]]",
|
|
165
|
-
"",
|
|
166
|
-
].join("\n");
|
|
167
|
-
writeFileSync(join(paths.dotWiki, "WIKI_SCHEMA.md"), schema, "utf-8");
|
|
168
|
-
|
|
169
|
-
rebuildMetadata(paths);
|
|
170
|
-
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
|
+
}
|
|
171
154
|
|
|
172
155
|
return {
|
|
173
156
|
content: [
|
|
@@ -215,11 +198,16 @@ export function registerWikiCaptureSource(pi: ExtensionAPI, runtime?: Runtime):
|
|
|
215
198
|
}),
|
|
216
199
|
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
217
200
|
const paths = getPaths(ctx.cwd);
|
|
218
|
-
const vaultCheck =
|
|
201
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
219
202
|
if (!vaultCheck.ok) {
|
|
220
203
|
return {
|
|
221
|
-
content: [
|
|
222
|
-
|
|
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>,
|
|
223
211
|
isError: true,
|
|
224
212
|
};
|
|
225
213
|
}
|
|
@@ -314,11 +302,16 @@ export function registerWikiIngest(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
314
302
|
}),
|
|
315
303
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
316
304
|
const paths = getPaths(ctx.cwd);
|
|
317
|
-
const vaultCheck =
|
|
305
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
318
306
|
if (!vaultCheck.ok) {
|
|
319
307
|
return {
|
|
320
|
-
content: [
|
|
321
|
-
|
|
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>,
|
|
322
315
|
isError: true,
|
|
323
316
|
};
|
|
324
317
|
}
|
|
@@ -527,11 +520,16 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
527
520
|
}),
|
|
528
521
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
529
522
|
const paths = getPaths(ctx.cwd);
|
|
530
|
-
const vaultCheck =
|
|
523
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
531
524
|
if (!vaultCheck.ok) {
|
|
532
525
|
return {
|
|
533
|
-
content: [
|
|
534
|
-
|
|
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>,
|
|
535
533
|
isError: true,
|
|
536
534
|
};
|
|
537
535
|
}
|
|
@@ -544,12 +542,7 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
544
542
|
| "requirement"
|
|
545
543
|
| "skill"
|
|
546
544
|
| "case";
|
|
547
|
-
const slug = params.title
|
|
548
|
-
.toLowerCase()
|
|
549
|
-
.replace(/[^a-z0-9\s-]/g, "")
|
|
550
|
-
.trim()
|
|
551
|
-
.replace(/\s+/g, "-")
|
|
552
|
-
.slice(0, 80);
|
|
545
|
+
const slug = slugify(params.title);
|
|
553
546
|
|
|
554
547
|
const folderMap: Record<string, string> = {
|
|
555
548
|
entity: "entities",
|
|
@@ -571,9 +564,19 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
571
564
|
}
|
|
572
565
|
|
|
573
566
|
const today = fmtDate();
|
|
574
|
-
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
|
+
);
|
|
575
578
|
mkdirSync(join(paths.wiki, folder), { recursive: true });
|
|
576
|
-
|
|
579
|
+
writeKnowledgeDocumentFile(pagePath, doc);
|
|
577
580
|
|
|
578
581
|
appendEvent(paths, {
|
|
579
582
|
kind: "ensure_page",
|
|
@@ -599,151 +602,135 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
599
602
|
});
|
|
600
603
|
}
|
|
601
604
|
|
|
602
|
-
function
|
|
603
|
-
type
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
): string {
|
|
608
|
-
if (customContent) return customContent;
|
|
605
|
+
function buildPageBody(type: string, title: string): string {
|
|
606
|
+
if (type === "entity") {
|
|
607
|
+
return `# ${title}
|
|
608
|
+
|
|
609
|
+
One-line description.
|
|
609
610
|
|
|
610
|
-
|
|
611
|
+
## Overview
|
|
611
612
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
613
|
+
[Key facts]
|
|
614
|
+
|
|
615
|
+
## Links
|
|
616
|
+
|
|
617
|
+
- [related-page](/concepts/related-page.md)`;
|
|
616
618
|
}
|
|
617
619
|
if (type === "concept") {
|
|
618
|
-
return
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
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)`;
|
|
624
631
|
}
|
|
625
632
|
if (type === "synthesis") {
|
|
626
|
-
return
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
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)`;
|
|
632
644
|
}
|
|
633
645
|
if (type === "analysis") {
|
|
634
|
-
return
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
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)`;
|
|
638
657
|
}
|
|
639
658
|
if (type === "skill") {
|
|
640
|
-
return
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
"",
|
|
663
|
-
"## Pitfalls",
|
|
664
|
-
"",
|
|
665
|
-
"- [Known failure mode or caveat]",
|
|
666
|
-
"",
|
|
667
|
-
"## Distilled From",
|
|
668
|
-
"",
|
|
669
|
-
"_Trajectories this skill was generalized from._",
|
|
670
|
-
"",
|
|
671
|
-
"- [[trajectories/TRJ-...]]",
|
|
672
|
-
"",
|
|
673
|
-
].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)`;
|
|
674
681
|
}
|
|
675
682
|
if (type === "case") {
|
|
676
|
-
return
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
"## Approach",
|
|
696
|
-
"",
|
|
697
|
-
"[How the agent solved it — key steps and decisions]",
|
|
698
|
-
"",
|
|
699
|
-
"## Outcome",
|
|
700
|
-
"",
|
|
701
|
-
"[Result, and anything worth reusing or avoiding next time]",
|
|
702
|
-
"",
|
|
703
|
-
"## Trajectory",
|
|
704
|
-
"",
|
|
705
|
-
"- [[trajectories/TRJ-...]] — captured tool-call run",
|
|
706
|
-
"",
|
|
707
|
-
].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`;
|
|
708
702
|
}
|
|
709
703
|
if (type === "requirement") {
|
|
710
|
-
return
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
"## Dependencies",
|
|
733
|
-
"",
|
|
734
|
-
"_Pages this requirement depends on._",
|
|
735
|
-
"",
|
|
736
|
-
"## Implementation Notes",
|
|
737
|
-
"",
|
|
738
|
-
"[Optional notes]",
|
|
739
|
-
"",
|
|
740
|
-
"## Sources",
|
|
741
|
-
"",
|
|
742
|
-
"- [[sources/SRC-...]] — original concept capture",
|
|
743
|
-
"",
|
|
744
|
-
].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`;
|
|
745
726
|
}
|
|
746
|
-
return
|
|
727
|
+
return `# ${title}
|
|
728
|
+
|
|
729
|
+
[Description to be filled]
|
|
730
|
+
|
|
731
|
+
## Links
|
|
732
|
+
|
|
733
|
+
- [related-page](/concepts/related-page.md)`;
|
|
747
734
|
}
|
|
748
735
|
|
|
749
736
|
// ─── 5. wiki_search ─────────────────────────────────────
|
|
@@ -761,29 +748,15 @@ export function registerWikiSearch(pi: ExtensionAPI): void {
|
|
|
761
748
|
}),
|
|
762
749
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
763
750
|
const paths = getPaths(ctx.cwd);
|
|
764
|
-
const
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
pages: {},
|
|
768
|
-
});
|
|
769
|
-
const q = params.query.toLowerCase();
|
|
770
|
-
|
|
771
|
-
const matches = Object.entries(registry.pages)
|
|
772
|
-
.filter(([id, entry]) => {
|
|
773
|
-
const matchesQuery =
|
|
774
|
-
id.toLowerCase().includes(q) ||
|
|
775
|
-
String(entry.title).toLowerCase().includes(q) ||
|
|
776
|
-
String(entry.type).toLowerCase().includes(q);
|
|
777
|
-
const matchesType =
|
|
778
|
-
!params.type || String(entry.type).toLowerCase() === params.type.toLowerCase();
|
|
779
|
-
return matchesQuery && matchesType;
|
|
780
|
-
})
|
|
781
|
-
.map(([id, entry]) => ({ id, title: entry.title, type: entry.type }));
|
|
782
|
-
|
|
783
|
-
if (matches.length === 0) {
|
|
751
|
+
const result = searchRegistry(paths, params.query, params.type);
|
|
752
|
+
|
|
753
|
+
if (result.matches.length === 0) {
|
|
784
754
|
return {
|
|
785
755
|
content: [{ type: "text", text: `No pages found for "${params.query}"` }],
|
|
786
|
-
details: { query: params.query, matches: [] } as Record<
|
|
756
|
+
details: { query: params.query, matches: [], diagnostics: result.diagnostics } as Record<
|
|
757
|
+
string,
|
|
758
|
+
unknown
|
|
759
|
+
>,
|
|
787
760
|
};
|
|
788
761
|
}
|
|
789
762
|
|
|
@@ -792,13 +765,17 @@ export function registerWikiSearch(pi: ExtensionAPI): void {
|
|
|
792
765
|
{
|
|
793
766
|
type: "text",
|
|
794
767
|
text: [
|
|
795
|
-
`🔍 **${matches.length} result(s)** for "${params.query}":`,
|
|
768
|
+
`🔍 **${result.matches.length} result(s)** for "${params.query}":`,
|
|
796
769
|
"",
|
|
797
|
-
...matches.map((m) => `- [[${m.id}]] — *${m.type}* — ${m.title}`),
|
|
770
|
+
...result.matches.map((m) => `- [[${m.id}]] — *${m.type}* — ${m.title}`),
|
|
798
771
|
].join("\n"),
|
|
799
772
|
},
|
|
800
773
|
],
|
|
801
|
-
details: {
|
|
774
|
+
details: {
|
|
775
|
+
query: params.query,
|
|
776
|
+
matches: result.matches,
|
|
777
|
+
diagnostics: result.diagnostics,
|
|
778
|
+
} as Record<string, unknown>,
|
|
802
779
|
};
|
|
803
780
|
},
|
|
804
781
|
});
|
|
@@ -824,11 +801,16 @@ export function registerWikiLint(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
824
801
|
}),
|
|
825
802
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
826
803
|
const paths = getPaths(ctx.cwd);
|
|
827
|
-
const vaultCheck =
|
|
804
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
828
805
|
if (!vaultCheck.ok) {
|
|
829
806
|
return {
|
|
830
|
-
content: [
|
|
831
|
-
|
|
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>,
|
|
832
814
|
isError: true,
|
|
833
815
|
};
|
|
834
816
|
}
|
|
@@ -850,82 +832,117 @@ export function registerWikiLint(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
850
832
|
* run off-thread via `dispatchReported`). Returns the human-readable summary.
|
|
851
833
|
*/
|
|
852
834
|
function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
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
|
+
}
|
|
856
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>>();
|
|
857
876
|
const findings: string[] = [];
|
|
858
|
-
let orphans = 0;
|
|
859
877
|
let missingPages = 0;
|
|
860
878
|
let contradictions = 0;
|
|
861
|
-
const gaps: Array<{ topic: string; mentionedBy: string[] }> = [];
|
|
862
|
-
|
|
863
|
-
const allPageIds = new Set(pages.map((p) => p.relative));
|
|
864
|
-
const linkCounts: Record<string, number> = {};
|
|
865
879
|
|
|
866
880
|
for (const page of pages) {
|
|
867
|
-
const
|
|
868
|
-
for (const
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
existing.mentionedBy.push(page.relative);
|
|
876
|
-
} else {
|
|
877
|
-
gaps.push({ topic: link, mentionedBy: [page.relative] });
|
|
878
|
-
}
|
|
879
|
-
} else {
|
|
880
|
-
linkCounts[link] = (linkCounts[link] || 0) + 1;
|
|
881
|
-
}
|
|
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})`);
|
|
882
889
|
}
|
|
883
890
|
}
|
|
884
891
|
|
|
892
|
+
let orphans = 0;
|
|
885
893
|
for (const page of pages) {
|
|
886
|
-
if (
|
|
894
|
+
if (inbound[page.id] === 0) {
|
|
887
895
|
orphans++;
|
|
888
|
-
findings.push(`Orphan:
|
|
896
|
+
findings.push(`Orphan: ${page.id} has no inbound links`);
|
|
889
897
|
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
for (const page of pages) {
|
|
893
|
-
if (page.content.includes("⚠️ **Contradiction")) {
|
|
898
|
+
if (page.body.includes("⚠️ **Contradiction")) {
|
|
894
899
|
contradictions++;
|
|
895
|
-
findings.push(`Contradiction flagged in
|
|
900
|
+
findings.push(`Contradiction flagged in ${page.id}`);
|
|
896
901
|
}
|
|
897
902
|
}
|
|
898
903
|
|
|
904
|
+
const gaps = [...gapSources.entries()]
|
|
905
|
+
.map(([topic, sources]) => ({ topic, mentionedBy: [...sources].sort(compareCodePoint) }))
|
|
906
|
+
.sort((left, right) => compareCodePoint(left.topic, right.topic));
|
|
899
907
|
let fixesApplied = 0;
|
|
900
908
|
if (autoFix) {
|
|
901
909
|
for (const gap of gaps) {
|
|
902
|
-
if (gap.mentionedBy.length
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
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;
|
|
920
942
|
}
|
|
921
943
|
}
|
|
922
944
|
}
|
|
923
945
|
|
|
924
|
-
writeJson(join(paths.discoveries, "gaps.json"), {
|
|
925
|
-
gaps,
|
|
926
|
-
generated: new Date().toISOString(),
|
|
927
|
-
});
|
|
928
|
-
|
|
929
946
|
const reportLines = [
|
|
930
947
|
"# Wiki Lint Report",
|
|
931
948
|
`Generated: ${fmtDate()}`,
|
|
@@ -935,26 +952,32 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
935
952
|
`- Orphans: ${orphans}`,
|
|
936
953
|
`- Missing pages: ${missingPages}`,
|
|
937
954
|
`- Contradictions: ${contradictions}`,
|
|
938
|
-
autoFix ? `-
|
|
955
|
+
autoFix ? `- Missing-page fixes applied: ${fixesApplied}` : "",
|
|
956
|
+
repair?.repaired ? `- Legacy pages repaired: ${repair.repaired}` : "",
|
|
957
|
+
repair?.manifestPath ? `- Repair manifest: ${repair.manifestPath}` : "",
|
|
939
958
|
"",
|
|
940
959
|
"## Findings",
|
|
941
|
-
findings.length
|
|
960
|
+
findings.length ? findings.map((finding) => `- ${finding}`).join("\n") : "✅ No issues found!",
|
|
942
961
|
"",
|
|
943
962
|
].filter(Boolean);
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
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
|
+
}
|
|
958
981
|
|
|
959
982
|
return [
|
|
960
983
|
"🧹 **LLM Wiki lint complete**",
|
|
@@ -963,10 +986,12 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
963
986
|
`- Orphans: ${orphans}`,
|
|
964
987
|
`- Missing: ${missingPages}`,
|
|
965
988
|
`- Contradictions: ${contradictions}`,
|
|
966
|
-
autoFix ? `-
|
|
989
|
+
autoFix ? `- Missing-page fixes: ${fixesApplied}` : "",
|
|
990
|
+
repair?.repaired ? `- Legacy pages repaired: ${repair.repaired}` : "",
|
|
967
991
|
"",
|
|
968
|
-
`📄 Report: \`${reportPath}
|
|
969
|
-
|
|
992
|
+
reportPath ? `📄 Report: \`${reportPath}\`` : "",
|
|
993
|
+
repair?.manifestPath ? `🛟 Repair manifest: \`${repair.manifestPath}\`` : "",
|
|
994
|
+
gaps.length ? `💡 ${gaps.length} knowledge gap(s) tracked` : "",
|
|
970
995
|
]
|
|
971
996
|
.filter(Boolean)
|
|
972
997
|
.join("\n");
|
|
@@ -993,18 +1018,9 @@ export function registerWikiStatus(pi: ExtensionAPI): void {
|
|
|
993
1018
|
};
|
|
994
1019
|
}
|
|
995
1020
|
|
|
996
|
-
const
|
|
997
|
-
version: "1.0",
|
|
998
|
-
last_updated: "",
|
|
999
|
-
pages: {},
|
|
1000
|
-
});
|
|
1001
|
-
const backlinks = readJson<Record<string, string[]>>(join(paths.meta, "backlinks.json"), {});
|
|
1021
|
+
const status = getWikiStatus(paths);
|
|
1002
1022
|
const config = readJson<Record<string, unknown>>(join(paths.dotWiki, "config.json"), {});
|
|
1003
|
-
|
|
1004
|
-
const byType: Record<string, number> = {};
|
|
1005
|
-
for (const entry of Object.values(registry.pages)) {
|
|
1006
|
-
byType[entry.type] = (byType[entry.type] || 0) + 1;
|
|
1007
|
-
}
|
|
1023
|
+
const backlinks = readJson<Record<string, string[]>>(join(paths.meta, "backlinks.json"), {});
|
|
1008
1024
|
|
|
1009
1025
|
const orphanCount = Object.entries(backlinks).filter(
|
|
1010
1026
|
([, inbound]) => inbound.length === 0,
|
|
@@ -1014,23 +1030,30 @@ export function registerWikiStatus(pi: ExtensionAPI): void {
|
|
|
1014
1030
|
});
|
|
1015
1031
|
|
|
1016
1032
|
const health =
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
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
|
+
: [];
|
|
1022
1043
|
|
|
1023
1044
|
const lines = [
|
|
1024
1045
|
"📊 LLM Wiki Status",
|
|
1025
1046
|
"══════════════════",
|
|
1026
1047
|
`Topic: ${config.topic || "Unknown"}`,
|
|
1027
1048
|
`Mode: ${config.mode || "personal"}`,
|
|
1028
|
-
`
|
|
1029
|
-
|
|
1049
|
+
`Knowledge format: ${status.knowledgeFormat}`,
|
|
1050
|
+
`Pages: ${status.totalPages}`,
|
|
1051
|
+
...Object.entries(status.byType).map(([t, c]) => ` - ${t}s: ${c}`),
|
|
1030
1052
|
`Orphans: ${orphanCount}`,
|
|
1031
1053
|
`Gaps: ${gaps.gaps?.length || 0}`,
|
|
1032
1054
|
`Health: ${health}`,
|
|
1033
|
-
`Last updated: ${
|
|
1055
|
+
`Last updated: ${status.lastUpdated || "Never"}`,
|
|
1056
|
+
...diagLines,
|
|
1034
1057
|
];
|
|
1035
1058
|
|
|
1036
1059
|
return {
|
|
@@ -1038,11 +1061,13 @@ export function registerWikiStatus(pi: ExtensionAPI): void {
|
|
|
1038
1061
|
details: {
|
|
1039
1062
|
topic: config.topic,
|
|
1040
1063
|
mode: config.mode,
|
|
1041
|
-
|
|
1042
|
-
|
|
1064
|
+
knowledgeFormat: status.knowledgeFormat,
|
|
1065
|
+
totalPages: status.totalPages,
|
|
1066
|
+
byType: status.byType,
|
|
1043
1067
|
orphans: orphanCount,
|
|
1044
1068
|
gaps: gaps.gaps?.length || 0,
|
|
1045
1069
|
health,
|
|
1070
|
+
blockingDiagnostics: status.blockingDiagnostics,
|
|
1046
1071
|
} as Record<string, unknown>,
|
|
1047
1072
|
};
|
|
1048
1073
|
},
|
|
@@ -1061,11 +1086,16 @@ export function registerWikiRebuildMeta(pi: ExtensionAPI, runtime?: Runtime): vo
|
|
|
1061
1086
|
parameters: Type.Object({}),
|
|
1062
1087
|
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
1063
1088
|
const paths = getPaths(ctx.cwd);
|
|
1064
|
-
const vaultCheck =
|
|
1089
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
1065
1090
|
if (!vaultCheck.ok) {
|
|
1066
1091
|
return {
|
|
1067
|
-
content: [
|
|
1068
|
-
|
|
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>,
|
|
1069
1099
|
isError: true,
|
|
1070
1100
|
};
|
|
1071
1101
|
}
|
|
@@ -1077,8 +1107,11 @@ export function registerWikiRebuildMeta(pi: ExtensionAPI, runtime?: Runtime): vo
|
|
|
1077
1107
|
started:
|
|
1078
1108
|
"\u{1F9E0} LLM Wiki: metadata rebuild started in the background — the result will be reported when it completes.",
|
|
1079
1109
|
work: async () => {
|
|
1080
|
-
rebuildMetadata(paths);
|
|
1081
|
-
|
|
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
|
+
}
|
|
1082
1115
|
const registry = readJson<Registry>(join(paths.meta, "registry.json"), {
|
|
1083
1116
|
version: "1.0",
|
|
1084
1117
|
last_updated: "",
|
|
@@ -1113,11 +1146,16 @@ export function registerWikiReindexEmbeddings(pi: ExtensionAPI, runtime?: Runtim
|
|
|
1113
1146
|
}),
|
|
1114
1147
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1115
1148
|
const paths = getPaths(ctx.cwd);
|
|
1116
|
-
const vaultCheck =
|
|
1149
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
1117
1150
|
if (!vaultCheck.ok) {
|
|
1118
1151
|
return {
|
|
1119
|
-
content: [
|
|
1120
|
-
|
|
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>,
|
|
1121
1159
|
isError: true,
|
|
1122
1160
|
};
|
|
1123
1161
|
}
|
|
@@ -1171,25 +1209,45 @@ export function registerWikiLogEvent(pi: ExtensionAPI): void {
|
|
|
1171
1209
|
}),
|
|
1172
1210
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
1173
1211
|
const paths = getPaths(ctx.cwd);
|
|
1174
|
-
const vaultCheck =
|
|
1212
|
+
const vaultCheck = inspectWritableVault(paths);
|
|
1175
1213
|
if (!vaultCheck.ok) {
|
|
1176
1214
|
return {
|
|
1177
|
-
content: [
|
|
1178
|
-
|
|
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>,
|
|
1179
1222
|
isError: true,
|
|
1180
1223
|
};
|
|
1181
1224
|
}
|
|
1182
1225
|
|
|
1183
|
-
|
|
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
|
+
}
|
|
1184
1242
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1243
|
+
appendEvent(paths, { kind, ...details });
|
|
1244
|
+
|
|
1245
|
+
// Regenerate projections
|
|
1246
|
+
rebuildMetadata(paths);
|
|
1189
1247
|
|
|
1190
1248
|
return {
|
|
1191
|
-
content: [{ type: "text", text: `✅ Event logged: ${
|
|
1192
|
-
details: { kind
|
|
1249
|
+
content: [{ type: "text", text: `✅ Event logged: ${kind}` }],
|
|
1250
|
+
details: { kind } as Record<string, unknown>,
|
|
1193
1251
|
};
|
|
1194
1252
|
},
|
|
1195
1253
|
});
|