@zosmaai/pi-llm-wiki 0.9.3 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
5
|
### Fixed
|
|
6
|
+
- **`buildIngestedSourcePage` omits folder prefix on entity/concept wikilinks** (Issue #89): `buildIngestedSourcePage()` in `lib/ingest-worker.ts` generated entity and concept wikilinks in ingested source pages as `[[entity-name]]` instead of `[[entities/entity-name]]`. The bare target never matched the page ID (which carries the folder prefix, e.g. `entities/entity-name`), leaving every entity and concept with zero inbound links and producing 177 orphans out of 180 pages in real vaults. The concept/entity page templates already used the correct `[[sources/...]]` prefix — only the source page template was broken. Fixed by adding the `entities/` and `concepts/` prefix to the generated wikilinks.
|
|
7
|
+
|
|
6
8
|
- **`wiki_watch` referred to a fictional `schedule_prompt` tool** (Issue #81): `wiki_watch` emitted instructions to run `schedule_prompt action=add ...` — a tool that doesn't exist in pi-coding-agent or any pi extension — so `/wiki-run --schedule weekly` printed a command the user couldn't execute. The emitted payload also contained the typo `/wiki:run` (real slash-command is `/wiki-run`), and the tool description claimed it scheduled jobs when it only ever printed instructions. Now emits a real, copy-pasteable **POSIX 5-field crontab line** wrapped in `/bin/bash -lc` (so npm-global / bun / nvm PATH is imported under cron's minimal env), with defensive `mkdir -p` of the log dir and a `# llm-wiki-autoupdate` removal tag. The tool description, output text, `prompts/wiki-run.md`, `docs/api.md` and all 10 i18n READMEs now explicitly say "prints — does not install". `details` now carries `cronLine` and `installed: false`. New `test/wiki-watch.test.ts` (10 tests) locks down all three regressions plus the portability contract (login-shell wrapper, defensive `mkdir`, quoted `$HOME`).
|
|
7
9
|
- **Personal wiki created at doubled path `~/.llm-wiki/.llm-wiki/…`**: `getPersonalWikiRoot()` returned the dot-dir itself (`~/.llm-wiki`) while `getVaultPaths()` then appended another `.llm-wiki/` segment, so the personal vault was written to `~/.llm-wiki/.llm-wiki/wiki/…`. Fixed by aligning `getPersonalWikiRoot()` with the same "root = parent of `.llm-wiki/`" contract used by project vaults. `WIKI_HOME` continues to override the parent.
|
|
8
10
|
|
package/README.md
CHANGED
|
@@ -422,17 +422,17 @@ Thanks to everyone who has contributed! This list is regenerated automatically b
|
|
|
422
422
|
</a>
|
|
423
423
|
</td>
|
|
424
424
|
<td align="center">
|
|
425
|
-
<a href="https://github.com/
|
|
426
|
-
<img src="https://avatars.githubusercontent.com/u/
|
|
425
|
+
<a href="https://github.com/Shanvit7">
|
|
426
|
+
<img src="https://avatars.githubusercontent.com/u/64424817?v=4" width="64;" alt="Shanvit7"/>
|
|
427
427
|
<br />
|
|
428
|
-
<sub><b>
|
|
428
|
+
<sub><b>Shanvit S Shetty</b></sub>
|
|
429
429
|
</a>
|
|
430
430
|
</td>
|
|
431
431
|
<td align="center">
|
|
432
|
-
<a href="https://github.com/
|
|
433
|
-
<img src="https://avatars.githubusercontent.com/u/
|
|
432
|
+
<a href="https://github.com/jfraser">
|
|
433
|
+
<img src="https://avatars.githubusercontent.com/u/165964?v=4" width="64;" alt="jfraser"/>
|
|
434
434
|
<br />
|
|
435
|
-
<sub><b>
|
|
435
|
+
<sub><b>James Fraser</b></sub>
|
|
436
436
|
</a>
|
|
437
437
|
</td>
|
|
438
438
|
<td align="center">
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import { basename, join } from "node:path";
|
|
3
3
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
4
4
|
import { installGuardrails } from "./lib/guardrails.js";
|
|
5
|
-
import {
|
|
5
|
+
import { buildAgentStartInjection } from "./lib/inject.js";
|
|
6
6
|
import { registerWikiModelCommand } from "./lib/model-command.js";
|
|
7
7
|
import {
|
|
8
8
|
buildSessionNotice,
|
|
@@ -216,7 +216,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
const prompt = event.prompt || "";
|
|
219
|
-
|
|
219
|
+
// Volatile, per-turn content (recall results + one-time topic-inference
|
|
220
|
+
// directive) MUST NOT go into the system prompt (issue #92). The system
|
|
221
|
+
// prompt is the provider's primary cache prefix; rewriting it every turn
|
|
222
|
+
// (recall is keyed on event.prompt, so it differs each turn) invalidates
|
|
223
|
+
// the whole prompt cache, forcing a full re-prompt-fill every turn. Collect
|
|
224
|
+
// it here and deliver it as a tail conversation message instead, which
|
|
225
|
+
// leaves the cached system-prompt prefix stable.
|
|
226
|
+
let dynamicContext = "";
|
|
220
227
|
|
|
221
228
|
// Topic inference on first turn after auto-creation
|
|
222
229
|
if (needsTopicInference && prompt.trim()) {
|
|
@@ -238,7 +245,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
238
245
|
// ignore
|
|
239
246
|
}
|
|
240
247
|
|
|
241
|
-
|
|
248
|
+
dynamicContext += `
|
|
242
249
|
|
|
243
250
|
## Wiki Setup Required
|
|
244
251
|
The LLM Wiki was just auto-created but needs its topic and mode configured. Before responding to the user, analyze their prompt and this project's context to infer:
|
|
@@ -279,7 +286,7 @@ Then call wiki_bootstrap with the inferred topic and mode to finalize the setup.
|
|
|
279
286
|
skillInlineMax: runtime.config?.recallSkillInlineMax,
|
|
280
287
|
});
|
|
281
288
|
if (recallContext) {
|
|
282
|
-
|
|
289
|
+
dynamicContext += `\n\n${recallContext}`;
|
|
283
290
|
}
|
|
284
291
|
// Recall-aware status line (issue #77): make it visible that recall
|
|
285
292
|
// actually fired and how many pages matched. Purely a UI signal — no
|
|
@@ -294,11 +301,19 @@ Then call wiki_bootstrap with the inferred topic and mode to finalize the setup.
|
|
|
294
301
|
}
|
|
295
302
|
}
|
|
296
303
|
|
|
297
|
-
//
|
|
298
|
-
//
|
|
299
|
-
|
|
304
|
+
// Split into a cache-stable system prompt (static footer only) and a
|
|
305
|
+
// volatile tail message (issue #92). See lib/inject.ts for the contract.
|
|
306
|
+
const { systemPrompt, message } = buildAgentStartInjection(event.systemPrompt || "", [
|
|
307
|
+
dynamicContext,
|
|
308
|
+
]);
|
|
300
309
|
|
|
301
|
-
|
|
302
|
-
|
|
310
|
+
// Only claim a systemPrompt change when the footer actually altered the
|
|
311
|
+
// string (a carry-forward turn already carries it, so this no-ops).
|
|
312
|
+
const systemPromptChanged = systemPrompt !== event.systemPrompt;
|
|
313
|
+
if (!systemPromptChanged && !message) return;
|
|
314
|
+
return {
|
|
315
|
+
...(systemPromptChanged ? { systemPrompt } : {}),
|
|
316
|
+
...(message ? { message } : {}),
|
|
317
|
+
};
|
|
303
318
|
});
|
|
304
319
|
}
|
|
@@ -116,11 +116,11 @@ export function buildIngestedSourcePage(
|
|
|
116
116
|
: "- [None recorded]";
|
|
117
117
|
const entities =
|
|
118
118
|
data.entities.length > 0
|
|
119
|
-
? data.entities.map((e) => `- [[
|
|
119
|
+
? data.entities.map((e) => `- [[entities/${slugify(e.title)}]]`).join("\n")
|
|
120
120
|
: "- [None]";
|
|
121
121
|
const concepts =
|
|
122
122
|
data.concepts.length > 0
|
|
123
|
-
? data.concepts.map((c) => `- [[
|
|
123
|
+
? data.concepts.map((c) => `- [[concepts/${slugify(c.title)}]]`).join("\n")
|
|
124
124
|
: "- [None]";
|
|
125
125
|
const quotes =
|
|
126
126
|
data.quotes && data.quotes.length > 0
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* System-prompt context injection primitives (
|
|
2
|
+
* System-prompt context injection primitives (issues #87, #92).
|
|
3
3
|
*
|
|
4
4
|
* The `before_agent_start` hook augments the chained system prompt with a
|
|
5
5
|
* visible wiki-status footer. This module isolates that append so it can be
|
|
6
6
|
* unit-tested for idempotency — a turn that aborts (network error / ESC) and is
|
|
7
7
|
* retried can carry the prior injection forward, and a naive append stacks the
|
|
8
8
|
* footer 2x, 3x, ...
|
|
9
|
+
*
|
|
10
|
+
* It also owns the cache-safety split (issue #92): VOLATILE per-turn context
|
|
11
|
+
* (recall results, one-time topic-inference directive) must never enter the
|
|
12
|
+
* system prompt — that is the provider's primary cache prefix, so per-turn
|
|
13
|
+
* variation there forces a full cache miss every turn. Volatile content is
|
|
14
|
+
* routed into a tail conversation message instead. `buildAgentStartInjection`
|
|
15
|
+
* is the single, pure decision point for that split.
|
|
9
16
|
*/
|
|
10
17
|
|
|
11
18
|
/** The always-injected wiki-status footer (sans surrounding whitespace). */
|
|
@@ -25,3 +32,54 @@ export function appendWikiStatus(systemPrompt: string): string {
|
|
|
25
32
|
const base = systemPrompt.split(`\n\n${WIKI_STATUS_BLOCK}`).join("");
|
|
26
33
|
return `${base}\n\n${WIKI_STATUS_BLOCK}`;
|
|
27
34
|
}
|
|
35
|
+
|
|
36
|
+
/** customType of the hidden tail message carrying volatile per-turn context. */
|
|
37
|
+
export const WIKI_RECALL_MESSAGE_TYPE = "wiki-recall-context";
|
|
38
|
+
|
|
39
|
+
/** A hidden, LLM-visible tail message carrying volatile per-turn wiki context. */
|
|
40
|
+
export interface WikiRecallMessage {
|
|
41
|
+
customType: typeof WIKI_RECALL_MESSAGE_TYPE;
|
|
42
|
+
content: string;
|
|
43
|
+
display: false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Result of the cache-safe split for one `before_agent_start` turn. */
|
|
47
|
+
export interface AgentStartInjection {
|
|
48
|
+
/**
|
|
49
|
+
* The system prompt to return. ONLY ever the base plus the static footer —
|
|
50
|
+
* never any volatile content — so it is byte-identical turn over turn and
|
|
51
|
+
* the provider's prompt cache stays warm (issue #92).
|
|
52
|
+
*/
|
|
53
|
+
systemPrompt: string;
|
|
54
|
+
/** Volatile blocks, delivered as a tail message. Omitted when empty. */
|
|
55
|
+
message?: WikiRecallMessage;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Split a turn's injection into a cache-stable system prompt and a volatile
|
|
60
|
+
* tail message (issue #92).
|
|
61
|
+
*
|
|
62
|
+
* - `systemPrompt` is always `appendWikiStatus(baseSystemPrompt)` — the static
|
|
63
|
+
* footer only. It carries NONE of `dynamicBlocks`, so it does not vary with
|
|
64
|
+
* recall results and never breaks the provider cache prefix.
|
|
65
|
+
* - `dynamicBlocks` (recall context, topic-inference directive, ...) are
|
|
66
|
+
* trimmed, emptied entries dropped, and joined with a blank line into the
|
|
67
|
+
* message body. When nothing survives, no message is emitted.
|
|
68
|
+
*
|
|
69
|
+
* Pure and side-effect free — see test/agent-start-injection.test.ts.
|
|
70
|
+
*/
|
|
71
|
+
export function buildAgentStartInjection(
|
|
72
|
+
baseSystemPrompt: string,
|
|
73
|
+
dynamicBlocks: Array<string | undefined>,
|
|
74
|
+
): AgentStartInjection {
|
|
75
|
+
const systemPrompt = appendWikiStatus(baseSystemPrompt);
|
|
76
|
+
const content = dynamicBlocks
|
|
77
|
+
.map((b) => b?.trim())
|
|
78
|
+
.filter((b): b is string => Boolean(b))
|
|
79
|
+
.join("\n\n");
|
|
80
|
+
if (!content) return { systemPrompt };
|
|
81
|
+
return {
|
|
82
|
+
systemPrompt,
|
|
83
|
+
message: { customType: WIKI_RECALL_MESSAGE_TYPE, content, display: false },
|
|
84
|
+
};
|
|
85
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zosmaai/pi-llm-wiki",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
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",
|
|
@@ -47,22 +47,16 @@
|
|
|
47
47
|
"publishConfig": {
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
|
-
"scripts": {
|
|
51
|
-
"test": "vitest run",
|
|
52
|
-
"test:watch": "vitest",
|
|
53
|
-
"test:coverage": "vitest run --coverage",
|
|
54
|
-
"typecheck": "tsc --noEmit",
|
|
55
|
-
"lint": "biome check .",
|
|
56
|
-
"lint:fix": "biome check --apply .",
|
|
57
|
-
"release:patch": "node scripts/release.js patch",
|
|
58
|
-
"release:minor": "node scripts/release.js minor",
|
|
59
|
-
"release:major": "node scripts/release.js major",
|
|
60
|
-
"release:push": "git push origin main --tags"
|
|
61
|
-
},
|
|
62
50
|
"pi": {
|
|
63
|
-
"extensions": [
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
"extensions": [
|
|
52
|
+
"./extensions"
|
|
53
|
+
],
|
|
54
|
+
"skills": [
|
|
55
|
+
"./skills"
|
|
56
|
+
],
|
|
57
|
+
"prompts": [
|
|
58
|
+
"./prompts"
|
|
59
|
+
],
|
|
66
60
|
"image": "https://raw.githubusercontent.com/zosmaai/pi-llm-wiki/main/assets/screenshot.png",
|
|
67
61
|
"mcpservers": {
|
|
68
62
|
"llm-wiki": "node ./mcp/index.js"
|
|
@@ -81,11 +75,26 @@
|
|
|
81
75
|
},
|
|
82
76
|
"devDependencies": {
|
|
83
77
|
"@biomejs/biome": "^1.9.4",
|
|
78
|
+
"@mariozechner/pi-agent-core": "^0.70.2",
|
|
79
|
+
"@mariozechner/pi-ai": "^0.70.2",
|
|
84
80
|
"@mariozechner/pi-coding-agent": "^0.70.2",
|
|
85
81
|
"@mermaid-js/mermaid-cli": "^11.12.0",
|
|
82
|
+
"@types/node": "^22",
|
|
86
83
|
"@vitest/coverage-v8": "^3.2.4",
|
|
87
84
|
"typebox": "^1.1.34",
|
|
88
85
|
"typescript": "^5.7.0",
|
|
89
86
|
"vitest": "^3.0.0"
|
|
87
|
+
},
|
|
88
|
+
"scripts": {
|
|
89
|
+
"test": "vitest run",
|
|
90
|
+
"test:watch": "vitest",
|
|
91
|
+
"test:coverage": "vitest run --coverage",
|
|
92
|
+
"typecheck": "tsc --noEmit",
|
|
93
|
+
"lint": "biome check .",
|
|
94
|
+
"lint:fix": "biome check --apply .",
|
|
95
|
+
"release:patch": "node scripts/release.js patch",
|
|
96
|
+
"release:minor": "node scripts/release.js minor",
|
|
97
|
+
"release:major": "node scripts/release.js major",
|
|
98
|
+
"release:push": "git push origin main --tags"
|
|
90
99
|
}
|
|
91
|
-
}
|
|
100
|
+
}
|