@zosmaai/pi-llm-wiki 0.11.5 → 0.11.7
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/README.de.md +1 -0
- package/README.es.md +1 -0
- package/README.fr.md +1 -0
- package/README.hi.md +1 -0
- package/README.ja.md +1 -0
- package/README.ko.md +1 -0
- package/README.md +1 -0
- package/README.pt.md +1 -0
- package/README.ru.md +1 -0
- package/README.zh.md +1 -0
- package/dist/extensions/llm-wiki/lib/ingest-worker.js +43 -20
- package/dist/extensions/llm-wiki/lib/knowledge-links.js +127 -24
- package/dist/extensions/llm-wiki/lib/metadata.js +5 -5
- package/dist/extensions/llm-wiki/lib/retro.js +38 -4
- package/dist/extensions/llm-wiki/lib/runtime.js +2 -2
- package/dist/extensions/llm-wiki/lib/task-config.js +35 -0
- package/dist/extensions/llm-wiki/lib/tools.js +53 -12
- package/dist/mcp/index.js +2 -1
- package/dist/mcp/operations.js +21 -2
- package/docs/configuration.md +1 -0
- package/docs/obsidian.md +6 -6
- package/docs/superpowers/plans/2026-08-27-wikilink-resolver-normalization.md +735 -0
- package/docs/superpowers/plans/2026-08-29-wikilink-gate-ensure-page-retro.md +642 -0
- package/docs/superpowers/plans/2026-08-29-wikilink-write-validation.md +695 -0
- package/extensions/llm-wiki/lib/ingest-worker.ts +60 -27
- package/extensions/llm-wiki/lib/knowledge-document.ts +1 -0
- package/extensions/llm-wiki/lib/knowledge-links.ts +201 -32
- package/extensions/llm-wiki/lib/metadata.ts +9 -5
- package/extensions/llm-wiki/lib/retro.ts +48 -4
- package/extensions/llm-wiki/lib/runtime.ts +2 -2
- package/extensions/llm-wiki/lib/task-config.ts +59 -0
- package/extensions/llm-wiki/lib/tools.ts +68 -20
- package/mcp/index.ts +12 -1
- package/mcp/operations.ts +32 -2
- package/package.json +8 -3
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
resolveGlobalSettingsPath,
|
|
10
10
|
resolveProjectSettingsPath,
|
|
11
11
|
} from "./host.js";
|
|
12
|
+
import type { WikilinkValidationMode } from "./knowledge-links.js";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Configuration for the background-task lane (issue #64, part of #63).
|
|
@@ -147,6 +148,27 @@ export interface TaskConfig {
|
|
|
147
148
|
* response truncates before commit_synthesis can be called.
|
|
148
149
|
*/
|
|
149
150
|
synthesisMaxTokens?: number;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Wikilink gate applied to the ingested source body before pages are
|
|
154
|
+
* written (issue #172, Layer 2). Reuses the Layer 1 resolver.
|
|
155
|
+
* - "off" : no-op.
|
|
156
|
+
* - "warn" : write proceeds; unresolved/ambiguous links are reported.
|
|
157
|
+
* - "strict" : block the write (commit returns ok:false) if any link is unresolvable.
|
|
158
|
+
* - "normalize" : rewrite resolvable links to their canonical id, then write.
|
|
159
|
+
* Default "warn". See `resolveWikilinkValidation`.
|
|
160
|
+
*/
|
|
161
|
+
wikilinkValidation?: WikilinkValidationMode;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* User-defined page types for wiki_ensure_page (issue #169). Merges with
|
|
165
|
+
* the 7 built-in types (entity, concept, synthesis, analysis, requirement,
|
|
166
|
+
* skill, case). Each key is the type name; each value is the folder name
|
|
167
|
+
* inside wiki/. Example: { "decision": "decisions", "metric": "metrics" }
|
|
168
|
+
* → wiki_ensure_page(type="decision") creates wiki/decisions/<slug>.md.
|
|
169
|
+
* Custom types use a generic page template (no per-type templates).
|
|
170
|
+
*/
|
|
171
|
+
customTypes?: Record<string, string>;
|
|
150
172
|
}
|
|
151
173
|
|
|
152
174
|
export const TASK_DEFAULTS: TaskConfig = {};
|
|
@@ -159,6 +181,24 @@ export function noticesEnabled(config: TaskConfig | undefined): boolean {
|
|
|
159
181
|
return config?.notices !== false;
|
|
160
182
|
}
|
|
161
183
|
|
|
184
|
+
const WIKILINK_VALIDATION_MODES: readonly WikilinkValidationMode[] = [
|
|
185
|
+
"off",
|
|
186
|
+
"warn",
|
|
187
|
+
"strict",
|
|
188
|
+
"normalize",
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Resolve the wikilink write-gate mode (issue #172, Layer 2). Defaults to
|
|
193
|
+
* `warn` — ingest always writes and reports; only an explicit `strict` blocks.
|
|
194
|
+
* Unknown values fall back to `warn` rather than failing the ingest.
|
|
195
|
+
*/
|
|
196
|
+
export function resolveWikilinkValidation(config: TaskConfig | undefined): WikilinkValidationMode {
|
|
197
|
+
const v = config?.wikilinkValidation;
|
|
198
|
+
if (v && (WIKILINK_VALIDATION_MODES as readonly string[]).includes(v)) return v;
|
|
199
|
+
return "warn";
|
|
200
|
+
}
|
|
201
|
+
|
|
162
202
|
/**
|
|
163
203
|
* Resolve whether the personal vault may serve as this project's ambient
|
|
164
204
|
* vault. Explicit `ambientPersonalVault` wins; otherwise the host decides
|
|
@@ -251,6 +291,23 @@ function readNamespacedConfig(path: string): Partial<TaskConfig> {
|
|
|
251
291
|
out.synthesisMaxTokens = Math.floor(maxTokens);
|
|
252
292
|
}
|
|
253
293
|
|
|
294
|
+
const wl = section.wikilinkValidation;
|
|
295
|
+
if (typeof wl === "string" && (WIKILINK_VALIDATION_MODES as readonly string[]).includes(wl)) {
|
|
296
|
+
out.wikilinkValidation = wl as WikilinkValidationMode;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const ct = section.customTypes;
|
|
300
|
+
if (ct && typeof ct === "object" && !Array.isArray(ct)) {
|
|
301
|
+
const entries = Object.entries(ct as Record<string, unknown>);
|
|
302
|
+
const valid: Record<string, string> = {};
|
|
303
|
+
for (const [k, v] of entries) {
|
|
304
|
+
if (typeof k === "string" && typeof v === "string" && k && v) {
|
|
305
|
+
valid[k] = v;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (Object.keys(valid).length) out.customTypes = valid;
|
|
309
|
+
}
|
|
310
|
+
|
|
254
311
|
return out;
|
|
255
312
|
} catch {
|
|
256
313
|
return {};
|
|
@@ -438,6 +495,8 @@ const KNOWN_KEYS = [
|
|
|
438
495
|
"trajectories",
|
|
439
496
|
"synthesisLanguage",
|
|
440
497
|
"synthesisMaxTokens",
|
|
498
|
+
"wikilinkValidation",
|
|
499
|
+
"customTypes",
|
|
441
500
|
] as const;
|
|
442
501
|
|
|
443
502
|
export function loadTaskConfigSources(
|
|
@@ -11,12 +11,16 @@ import {
|
|
|
11
11
|
serializeKnowledgeDocument,
|
|
12
12
|
writeKnowledgeDocumentFile,
|
|
13
13
|
} from "./knowledge-document.js";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
applyWikilinkGate,
|
|
16
|
+
buildResolvedBacklinks,
|
|
17
|
+
buildWikilinkIndex,
|
|
18
|
+
} from "./knowledge-links.js";
|
|
15
19
|
import { repairLegacyKnowledgeDocuments } from "./legacy-repair.js";
|
|
16
20
|
import { type Registry, appendEvent, rebuildMetadata, rebuildMetadataLight } from "./metadata.js";
|
|
17
21
|
import type { Runtime } from "./runtime.js";
|
|
18
22
|
import { captureFile, captureText, captureUrl } from "./source-packet.js";
|
|
19
|
-
import { parseModelRef } from "./task-config.js";
|
|
23
|
+
import { loadTaskConfig, parseModelRef, resolveWikilinkValidation } from "./task-config.js";
|
|
20
24
|
import {
|
|
21
25
|
type VaultPaths,
|
|
22
26
|
detectVaultFormat,
|
|
@@ -415,6 +419,7 @@ export function registerWikiIngest(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
415
419
|
manifest: s.manifest,
|
|
416
420
|
extracted: s.extracted,
|
|
417
421
|
synthesisLanguage: runtime.config.synthesisLanguage,
|
|
422
|
+
wikilinkValidation: runtime.config.wikilinkValidation,
|
|
418
423
|
});
|
|
419
424
|
if (committed) {
|
|
420
425
|
// Background semantic embeddings (#66): embed the pages this
|
|
@@ -428,8 +433,10 @@ export function registerWikiIngest(pi: ExtensionAPI, runtime?: Runtime): void {
|
|
|
428
433
|
];
|
|
429
434
|
launchEmbedPages(runtime, launchCtx, paths, pageIds, `embed:ingest:${s.id}`);
|
|
430
435
|
}
|
|
436
|
+
const wl = committed?.wikilinkDiagnostics?.length ?? 0;
|
|
437
|
+
const wlNote = wl > 0 ? `, ${wl} wikilink issue${wl === 1 ? "" : "s"}` : "";
|
|
431
438
|
const summary = committed
|
|
432
|
-
? `LLM Wiki: ingested ${s.id} → ${committed.entitiesCreated.length} entit${committed.entitiesCreated.length === 1 ? "y" : "ies"}, ${committed.conceptsCreated.length} concept${committed.conceptsCreated.length === 1 ? "" : "s"}`
|
|
439
|
+
? `LLM Wiki: ingested ${s.id} → ${committed.entitiesCreated.length} entit${committed.entitiesCreated.length === 1 ? "y" : "ies"}, ${committed.conceptsCreated.length} concept${committed.conceptsCreated.length === 1 ? "" : "s"}${wlNote}`
|
|
433
440
|
: `LLM Wiki: ${s.id} produced no synthesis`;
|
|
434
441
|
if (ctx.hasUI) {
|
|
435
442
|
ctx.ui.notify(summary, committed ? "info" : "warning");
|
|
@@ -512,7 +519,7 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
512
519
|
parameters: Type.Object({
|
|
513
520
|
type: Type.String({
|
|
514
521
|
description:
|
|
515
|
-
"Page type: entity | concept | synthesis | analysis | requirement | skill | case",
|
|
522
|
+
"Page type: entity | concept | synthesis | analysis | requirement | skill | case (built-in) or any user-defined type from llm-wiki.customTypes config",
|
|
516
523
|
}),
|
|
517
524
|
title: Type.String({ description: "Page title" }),
|
|
518
525
|
content: Type.Optional(
|
|
@@ -535,17 +542,8 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
535
542
|
};
|
|
536
543
|
}
|
|
537
544
|
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
| "concept"
|
|
541
|
-
| "synthesis"
|
|
542
|
-
| "analysis"
|
|
543
|
-
| "requirement"
|
|
544
|
-
| "skill"
|
|
545
|
-
| "case";
|
|
546
|
-
const slug = slugify(params.title);
|
|
547
|
-
|
|
548
|
-
const folderMap: Record<string, string> = {
|
|
545
|
+
const config = loadTaskConfig(ctx.cwd);
|
|
546
|
+
const builtInFolderMap: Record<string, string> = {
|
|
549
547
|
entity: "entities",
|
|
550
548
|
concept: "concepts",
|
|
551
549
|
synthesis: "syntheses",
|
|
@@ -554,6 +552,9 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
554
552
|
skill: "skills",
|
|
555
553
|
case: "cases",
|
|
556
554
|
};
|
|
555
|
+
const folderMap = { ...builtInFolderMap, ...config.customTypes };
|
|
556
|
+
const type = params.type as string;
|
|
557
|
+
const slug = slugify(params.title);
|
|
557
558
|
const folder = folderMap[type] || "concepts";
|
|
558
559
|
const pagePath = join(paths.wiki, folder, `${slug}.md`);
|
|
559
560
|
|
|
@@ -565,7 +566,42 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
565
566
|
}
|
|
566
567
|
|
|
567
568
|
const today = fmtDate();
|
|
568
|
-
|
|
569
|
+
let body = params.content ?? buildPageBody(type, params.title);
|
|
570
|
+
|
|
571
|
+
// Pre-write wikilink gate (#172): validate/normalize caller-supplied content.
|
|
572
|
+
const mode = resolveWikilinkValidation(loadTaskConfig(ctx.cwd));
|
|
573
|
+
let wikilinkIssues: string[] = [];
|
|
574
|
+
if (mode !== "off") {
|
|
575
|
+
const registry = readJson<{ pages: Record<string, unknown> }>(
|
|
576
|
+
join(paths.meta, "registry.json"),
|
|
577
|
+
{ pages: {} },
|
|
578
|
+
);
|
|
579
|
+
const gate = applyWikilinkGate(
|
|
580
|
+
body,
|
|
581
|
+
buildWikilinkIndex(Object.keys(registry.pages)),
|
|
582
|
+
`${folder}/${slug}`,
|
|
583
|
+
mode,
|
|
584
|
+
);
|
|
585
|
+
wikilinkIssues = gate.diagnostics.map((d) => d.message);
|
|
586
|
+
if (!gate.ok) {
|
|
587
|
+
return {
|
|
588
|
+
content: [
|
|
589
|
+
{
|
|
590
|
+
type: "text",
|
|
591
|
+
text: `Rejected write — unresolved/ambiguous wikilinks:\n${wikilinkIssues
|
|
592
|
+
.map((m) => `- ${m}`)
|
|
593
|
+
.join("\n")}`,
|
|
594
|
+
},
|
|
595
|
+
],
|
|
596
|
+
details: { error: "link_validation", issues: wikilinkIssues } as Record<
|
|
597
|
+
string,
|
|
598
|
+
unknown
|
|
599
|
+
>,
|
|
600
|
+
isError: true,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
if (mode === "normalize") body = gate.body;
|
|
604
|
+
}
|
|
569
605
|
const doc = createKnowledgeDocument(
|
|
570
606
|
`${folder}/${slug}.md`,
|
|
571
607
|
{
|
|
@@ -595,9 +631,16 @@ export function registerWikiEnsurePage(pi: ExtensionAPI, runtime?: Runtime): voi
|
|
|
595
631
|
rebuildMetadataLight(paths);
|
|
596
632
|
}
|
|
597
633
|
|
|
634
|
+
const gateNote = wikilinkIssues.length
|
|
635
|
+
? `\n\n⚠️ ${wikilinkIssues.length} wikilink issue(s):\n${wikilinkIssues.map((m) => `- ${m}`).join("\n")}`
|
|
636
|
+
: "";
|
|
598
637
|
return {
|
|
599
|
-
content: [{ type: "text", text: `✅ Created ${type} page: \`${pagePath}
|
|
600
|
-
details: {
|
|
638
|
+
content: [{ type: "text", text: `✅ Created ${type} page: \`${pagePath}\`${gateNote}` }],
|
|
639
|
+
details: {
|
|
640
|
+
path: pagePath,
|
|
641
|
+
created: true,
|
|
642
|
+
wikilinkIssues,
|
|
643
|
+
} as Record<string, unknown>,
|
|
601
644
|
};
|
|
602
645
|
},
|
|
603
646
|
});
|
|
@@ -871,7 +914,7 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
871
914
|
|
|
872
915
|
const discovery = discoverKnowledgeDocuments(paths);
|
|
873
916
|
const pages = discovery.documents;
|
|
874
|
-
const
|
|
917
|
+
const wikilinkIndex = buildWikilinkIndex(pages.map((page) => page.id));
|
|
875
918
|
const inbound = Object.fromEntries(pages.map((page) => [page.id, 0]));
|
|
876
919
|
const gapSources = new Map<string, Set<string>>();
|
|
877
920
|
const findings: string[] = [];
|
|
@@ -879,7 +922,7 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
879
922
|
let contradictions = 0;
|
|
880
923
|
|
|
881
924
|
for (const page of pages) {
|
|
882
|
-
const resolved = buildResolvedBacklinks(page.id, page.body,
|
|
925
|
+
const resolved = buildResolvedBacklinks(page.id, page.body, wikilinkIndex);
|
|
883
926
|
for (const target of resolved.targets) inbound[target]++;
|
|
884
927
|
for (const unresolved of resolved.unresolved) {
|
|
885
928
|
const sources = gapSources.get(unresolved.target) ?? new Set<string>();
|
|
@@ -888,6 +931,11 @@ function runWikiLint(paths: VaultPaths, autoFix: boolean): string {
|
|
|
888
931
|
missingPages++;
|
|
889
932
|
findings.push(`Missing page: ${unresolved.target} (in ${page.id})`);
|
|
890
933
|
}
|
|
934
|
+
for (const d of resolved.diagnostics) {
|
|
935
|
+
if (d.code === "link_ambiguous") {
|
|
936
|
+
findings.push(d.message.replace("Ambiguous wikilink: ", "Ambiguous: "));
|
|
937
|
+
}
|
|
938
|
+
}
|
|
891
939
|
}
|
|
892
940
|
|
|
893
941
|
let orphans = 0;
|
package/mcp/index.ts
CHANGED
|
@@ -15,6 +15,10 @@ import { join } from "node:path";
|
|
|
15
15
|
import { McpServer } from "@modelcontextprotocol/server";
|
|
16
16
|
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
17
17
|
import * as z from "zod/v4";
|
|
18
|
+
import {
|
|
19
|
+
loadTaskConfig,
|
|
20
|
+
resolveWikilinkValidation,
|
|
21
|
+
} from "../extensions/llm-wiki/lib/task-config.js";
|
|
18
22
|
import { getVaultPaths, resolveVaultPaths } from "../extensions/llm-wiki/lib/utils.js";
|
|
19
23
|
import { createExecApi } from "./exec.js";
|
|
20
24
|
import {
|
|
@@ -265,7 +269,14 @@ server.registerTool(
|
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
const paths = getPaths();
|
|
268
|
-
const result = await retroOperation(
|
|
272
|
+
const result = await retroOperation(
|
|
273
|
+
paths,
|
|
274
|
+
slug,
|
|
275
|
+
title,
|
|
276
|
+
body,
|
|
277
|
+
category,
|
|
278
|
+
resolveWikilinkValidation(loadTaskConfig(process.cwd())),
|
|
279
|
+
);
|
|
269
280
|
|
|
270
281
|
if (!result.ok) {
|
|
271
282
|
return {
|
package/mcp/operations.ts
CHANGED
|
@@ -6,13 +6,20 @@
|
|
|
6
6
|
* registry entries, or builds page strings itself.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { join } from "node:path";
|
|
9
10
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
10
11
|
import { bootstrapVault } from "../extensions/llm-wiki/lib/bootstrap.js";
|
|
12
|
+
import {
|
|
13
|
+
type WikilinkValidationMode,
|
|
14
|
+
applyWikilinkGate,
|
|
15
|
+
buildWikilinkIndex,
|
|
16
|
+
} from "../extensions/llm-wiki/lib/knowledge-links.js";
|
|
11
17
|
import { type ProjectionResult, rebuildMetadata } from "../extensions/llm-wiki/lib/metadata.js";
|
|
12
18
|
import { type RecallResult, searchWikiLayered } from "../extensions/llm-wiki/lib/recall.js";
|
|
13
19
|
import { saveInsight } from "../extensions/llm-wiki/lib/retro.js";
|
|
14
20
|
import { captureFile, captureText, captureUrl } from "../extensions/llm-wiki/lib/source-packet.js";
|
|
15
|
-
import
|
|
21
|
+
import { resolveWikilinkValidation } from "../extensions/llm-wiki/lib/task-config.js";
|
|
22
|
+
import { type VaultPaths, readJson } from "../extensions/llm-wiki/lib/utils.js";
|
|
16
23
|
import {
|
|
17
24
|
VaultWriteError,
|
|
18
25
|
inspectVaultFormat,
|
|
@@ -134,6 +141,7 @@ export async function retroOperation(
|
|
|
134
141
|
title: string,
|
|
135
142
|
body: string,
|
|
136
143
|
category?: string,
|
|
144
|
+
wikilinkValidation?: WikilinkValidationMode,
|
|
137
145
|
): Promise<
|
|
138
146
|
| { ok: true; slug: string; sourcePagePath: string }
|
|
139
147
|
| { ok: false; diagnostics: Array<{ code: string; message: string }> }
|
|
@@ -145,8 +153,30 @@ export async function retroOperation(
|
|
|
145
153
|
diagnostics: vaultCheck.diagnostics.map((d) => ({ code: d.code, message: d.message })),
|
|
146
154
|
};
|
|
147
155
|
}
|
|
156
|
+
// Pre-write wikilink gate (#172): validate/normalize caller-supplied body.
|
|
157
|
+
const mode = resolveWikilinkValidation({ wikilinkValidation });
|
|
158
|
+
let gateBody = body;
|
|
159
|
+
if (mode !== "off") {
|
|
160
|
+
const registry = readJson<{ pages: Record<string, unknown> }>(
|
|
161
|
+
join(paths.meta, "registry.json"),
|
|
162
|
+
{ pages: {} },
|
|
163
|
+
);
|
|
164
|
+
const gate = applyWikilinkGate(
|
|
165
|
+
body,
|
|
166
|
+
buildWikilinkIndex(Object.keys(registry.pages)),
|
|
167
|
+
`sources/${slug}`,
|
|
168
|
+
mode,
|
|
169
|
+
);
|
|
170
|
+
if (!gate.ok) {
|
|
171
|
+
return {
|
|
172
|
+
ok: false,
|
|
173
|
+
diagnostics: gate.diagnostics.map((d) => ({ code: "link_validation", message: d.message })),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
if (mode === "normalize") gateBody = gate.body;
|
|
177
|
+
}
|
|
148
178
|
try {
|
|
149
|
-
const result = saveInsight(paths, slug, title,
|
|
179
|
+
const result = saveInsight(paths, slug, title, gateBody, category, { rebuild: false });
|
|
150
180
|
const projection = projectionOutcome(rebuildMetadata(paths));
|
|
151
181
|
if (!projection.ok) return projection;
|
|
152
182
|
return { ok: true, slug: result.slug, sourcePagePath: result.sourcePagePath };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zosmaai/pi-llm-wiki",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.7",
|
|
4
4
|
"description": "Self-maintaining LLM Wiki for Pi — Karpathy-pattern knowledge base with immutable source capture, automated ingestion, search, linting, and Obsidian-compatible vault. auto-updating personal & company wiki.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
"zod": "^4.0"
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
|
+
"@astrojs/starlight": "^0.41.10",
|
|
94
95
|
"@biomejs/biome": "^1.9.4",
|
|
95
96
|
"@mariozechner/pi-agent-core": "^0.70.2",
|
|
96
97
|
"@mariozechner/pi-ai": "^0.70.2",
|
|
@@ -99,6 +100,7 @@
|
|
|
99
100
|
"@types/mdast": "^4.0.4",
|
|
100
101
|
"@types/node": "^22",
|
|
101
102
|
"@vitest/coverage-v8": "^3.2.4",
|
|
103
|
+
"astro": "^7.2.9",
|
|
102
104
|
"typescript": "^5.7.0",
|
|
103
105
|
"vitest": "^3.0.0"
|
|
104
106
|
},
|
|
@@ -110,10 +112,13 @@
|
|
|
110
112
|
"build:mcp": "node scripts/build-mcp.js",
|
|
111
113
|
"typecheck": "tsc --noEmit",
|
|
112
114
|
"lint": "biome check .",
|
|
113
|
-
"lint:fix": "biome check --
|
|
115
|
+
"lint:fix": "biome check --write .",
|
|
114
116
|
"release:patch": "node scripts/release.js patch",
|
|
115
117
|
"release:minor": "node scripts/release.js minor",
|
|
116
118
|
"release:major": "node scripts/release.js major",
|
|
117
|
-
"release:push": "git push origin main --tags"
|
|
119
|
+
"release:push": "git push origin main --tags",
|
|
120
|
+
"docs:sync": "node scripts/sync-docs.js",
|
|
121
|
+
"docs:dev": "astro dev",
|
|
122
|
+
"docs:build": "node scripts/sync-docs.js && astro build"
|
|
118
123
|
}
|
|
119
124
|
}
|