pi-para 0.5.2
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 +214 -0
- package/README.md +305 -0
- package/SETUP.md +171 -0
- package/dist/capture.d.ts +34 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +461 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +405 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +15 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +786 -0
- package/dist/commands.js.map +1 -0
- package/dist/context.d.ts +61 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +289 -0
- package/dist/context.js.map +1 -0
- package/dist/daemon.d.ts +49 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +226 -0
- package/dist/daemon.js.map +1 -0
- package/dist/frontmatter.d.ts +59 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +170 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/gepa/dataset.d.ts +36 -0
- package/dist/gepa/dataset.d.ts.map +1 -0
- package/dist/gepa/dataset.js +148 -0
- package/dist/gepa/dataset.js.map +1 -0
- package/dist/gepa/evaluator.d.ts +51 -0
- package/dist/gepa/evaluator.d.ts.map +1 -0
- package/dist/gepa/evaluator.js +317 -0
- package/dist/gepa/evaluator.js.map +1 -0
- package/dist/gepa/index.d.ts +66 -0
- package/dist/gepa/index.d.ts.map +1 -0
- package/dist/gepa/index.js +240 -0
- package/dist/gepa/index.js.map +1 -0
- package/dist/gepa/llm.d.ts +35 -0
- package/dist/gepa/llm.d.ts.map +1 -0
- package/dist/gepa/llm.js +268 -0
- package/dist/gepa/llm.js.map +1 -0
- package/dist/gepa/optimized/capture-prompt.txt +65 -0
- package/dist/gepa/optimizer.d.ts +29 -0
- package/dist/gepa/optimizer.d.ts.map +1 -0
- package/dist/gepa/optimizer.js +249 -0
- package/dist/gepa/optimizer.js.map +1 -0
- package/dist/gepa/targets.d.ts +39 -0
- package/dist/gepa/targets.d.ts.map +1 -0
- package/dist/gepa/targets.js +326 -0
- package/dist/gepa/targets.js.map +1 -0
- package/dist/gepa/types.d.ts +168 -0
- package/dist/gepa/types.d.ts.map +1 -0
- package/dist/gepa/types.js +124 -0
- package/dist/gepa/types.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +294 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest.d.ts +88 -0
- package/dist/ingest.d.ts.map +1 -0
- package/dist/ingest.js +105 -0
- package/dist/ingest.js.map +1 -0
- package/dist/link-discovery.d.ts +40 -0
- package/dist/link-discovery.d.ts.map +1 -0
- package/dist/link-discovery.js +122 -0
- package/dist/link-discovery.js.map +1 -0
- package/dist/link-utils.d.ts +30 -0
- package/dist/link-utils.d.ts.map +1 -0
- package/dist/link-utils.js +145 -0
- package/dist/link-utils.js.map +1 -0
- package/dist/lint.d.ts +39 -0
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +827 -0
- package/dist/lint.js.map +1 -0
- package/dist/maintainer.d.ts +24 -0
- package/dist/maintainer.d.ts.map +1 -0
- package/dist/maintainer.js +358 -0
- package/dist/maintainer.js.map +1 -0
- package/dist/processor.d.ts +14 -0
- package/dist/processor.d.ts.map +1 -0
- package/dist/processor.js +361 -0
- package/dist/processor.js.map +1 -0
- package/dist/query.d.ts +69 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +107 -0
- package/dist/query.js.map +1 -0
- package/dist/raw.d.ts +57 -0
- package/dist/raw.d.ts.map +1 -0
- package/dist/raw.js +219 -0
- package/dist/raw.js.map +1 -0
- package/dist/redact.d.ts +21 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +143 -0
- package/dist/redact.js.map +1 -0
- package/dist/scope.d.ts +54 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +161 -0
- package/dist/scope.js.map +1 -0
- package/dist/scripts/bulk-link-fix.d.ts +9 -0
- package/dist/scripts/bulk-link-fix.d.ts.map +1 -0
- package/dist/scripts/bulk-link-fix.js +106 -0
- package/dist/scripts/bulk-link-fix.js.map +1 -0
- package/dist/session-tools.d.ts +33 -0
- package/dist/session-tools.d.ts.map +1 -0
- package/dist/session-tools.js +211 -0
- package/dist/session-tools.js.map +1 -0
- package/dist/state.d.ts +54 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +176 -0
- package/dist/state.js.map +1 -0
- package/dist/store.d.ts +56 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +227 -0
- package/dist/store.js.map +1 -0
- package/dist/summarize.d.ts +56 -0
- package/dist/summarize.d.ts.map +1 -0
- package/dist/summarize.js +231 -0
- package/dist/summarize.js.map +1 -0
- package/dist/tag-registry.d.ts +56 -0
- package/dist/tag-registry.d.ts.map +1 -0
- package/dist/tag-registry.js +146 -0
- package/dist/tag-registry.js.map +1 -0
- package/dist/templates/prompts.d.ts +63 -0
- package/dist/templates/prompts.d.ts.map +1 -0
- package/dist/templates/prompts.js +260 -0
- package/dist/templates/prompts.js.map +1 -0
- package/dist/tools.d.ts +26 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +1033 -0
- package/dist/tools.js.map +1 -0
- package/dist/watcher.d.ts +25 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +84 -0
- package/dist/watcher.js.map +1 -0
- package/dist/webui/client/dist/index.html +1885 -0
- package/dist/webui/server.d.ts +31 -0
- package/dist/webui/server.d.ts.map +1 -0
- package/dist/webui/server.js +566 -0
- package/dist/webui/server.js.map +1 -0
- package/dist/wiki.d.ts +103 -0
- package/dist/wiki.d.ts.map +1 -0
- package/dist/wiki.js +428 -0
- package/dist/wiki.js.map +1 -0
- package/package.json +142 -0
- package/scripts/gepa/__pycache__/dataset.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/lm_providers.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/metric.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/program.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/wiki_reader.cpython-313.pyc +0 -0
- package/scripts/gepa/dataset.py +192 -0
- package/scripts/gepa/lm_providers.py +472 -0
- package/scripts/gepa/metric.py +279 -0
- package/scripts/gepa/optimize.py +367 -0
- package/scripts/gepa/program.py +99 -0
- package/scripts/gepa/pyproject.toml +19 -0
- package/scripts/gepa/run-all.sh +53 -0
- package/scripts/gepa/uv.lock +2241 -0
- package/scripts/gepa/wiki_reader.py +113 -0
- package/skills/para/SKILL.md +77 -0
- package/skills/setup/SKILL.md +20 -0
- package/src/capture.ts +563 -0
- package/src/cli.ts +416 -0
- package/src/commands.ts +878 -0
- package/src/context.ts +390 -0
- package/src/daemon.ts +288 -0
- package/src/frontmatter.ts +219 -0
- package/src/gepa/index.ts +287 -0
- package/src/gepa/optimized/capture-prompt.txt +65 -0
- package/src/index.ts +384 -0
- package/src/ingest.ts +177 -0
- package/src/link-discovery.ts +170 -0
- package/src/link-utils.ts +169 -0
- package/src/lint.ts +1018 -0
- package/src/maintainer.ts +404 -0
- package/src/processor.ts +415 -0
- package/src/python/__pycache__/minimax_lm.cpython-312.pyc +0 -0
- package/src/python/minimax_lm.py +198 -0
- package/src/python/rlm_capture.py +215 -0
- package/src/query.ts +148 -0
- package/src/raw.ts +276 -0
- package/src/redact.ts +159 -0
- package/src/scope.ts +214 -0
- package/src/scripts/bulk-link-fix.ts +126 -0
- package/src/session-tools.ts +260 -0
- package/src/state.ts +271 -0
- package/src/store.ts +288 -0
- package/src/summarize.ts +273 -0
- package/src/tag-registry.ts +157 -0
- package/src/templates/index.md +17 -0
- package/src/templates/prompts.ts +274 -0
- package/src/templates/schema.md +116 -0
- package/src/tools.ts +1293 -0
- package/src/watcher.ts +101 -0
- package/src/webui/client/dist/index.html +1885 -0
- package/src/webui/server.ts +765 -0
- package/src/wiki.ts +550 -0
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main daemon loop — watches for completed sessions and processes them.
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import { openStore, closeStore } from "./store.js";
|
|
8
|
+
import { StateDB } from "./state.js";
|
|
9
|
+
import { RegistryWatcher } from "./watcher.js";
|
|
10
|
+
import { processSession } from "./processor.js";
|
|
11
|
+
import { runMaintenance } from "./maintainer.js";
|
|
12
|
+
import { startServer } from "./webui/server.js";
|
|
13
|
+
export class Daemon {
|
|
14
|
+
config;
|
|
15
|
+
state;
|
|
16
|
+
watcher;
|
|
17
|
+
store = null;
|
|
18
|
+
queue = [];
|
|
19
|
+
processing = false;
|
|
20
|
+
running = false;
|
|
21
|
+
maintenanceTimer = null;
|
|
22
|
+
maintenanceRunning = false;
|
|
23
|
+
webServer = null;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
this.state = new StateDB(config.wikiDir);
|
|
27
|
+
this.watcher = new RegistryWatcher(config.wikiDir, (entries) => this.onNewEntries(entries), config.pollIntervalMs ?? 5000);
|
|
28
|
+
}
|
|
29
|
+
/** Start the daemon. */
|
|
30
|
+
async start() {
|
|
31
|
+
console.log(`[daemon] Starting — wiki: ${this.config.wikiDir}`);
|
|
32
|
+
// Open qmd store
|
|
33
|
+
try {
|
|
34
|
+
this.store = await openStore(this.config.wikiDir);
|
|
35
|
+
console.log("[daemon] qmd store opened");
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.error(`[daemon] Failed to open store: ${err instanceof Error ? err.message : err}`);
|
|
39
|
+
this.store = null;
|
|
40
|
+
}
|
|
41
|
+
this.running = true;
|
|
42
|
+
this.state.setState("daemon_started_at", new Date().toISOString());
|
|
43
|
+
this.state.setState("daemon_pid", String(process.pid));
|
|
44
|
+
// Start watching
|
|
45
|
+
this.watcher.start();
|
|
46
|
+
// Process any unprocessed sessions from registry
|
|
47
|
+
const existing = this.watcher.getAllEntries();
|
|
48
|
+
const unprocessed = existing.filter((e) => !this.state.isProcessed(e.sessionPath));
|
|
49
|
+
if (unprocessed.length > 0) {
|
|
50
|
+
console.log(`[daemon] Found ${unprocessed.length} unprocessed session(s)`);
|
|
51
|
+
this.onNewEntries(unprocessed);
|
|
52
|
+
}
|
|
53
|
+
// Start periodic maintenance (link discovery + lint)
|
|
54
|
+
const maintenanceMs = this.config.maintenanceIntervalMs ?? 30 * 60 * 1000;
|
|
55
|
+
this.maintenanceTimer = setInterval(() => this.runMaintenancePass(), maintenanceMs);
|
|
56
|
+
// Run first maintenance after a delay to let the store warm up
|
|
57
|
+
setTimeout(() => this.runMaintenancePass(), 60_000);
|
|
58
|
+
// Start web wiki server if enabled
|
|
59
|
+
if (this.config.webWiki?.enabled) {
|
|
60
|
+
try {
|
|
61
|
+
this.webServer = startServer(this.config.wikiDir, this.store, this.config.webWiki);
|
|
62
|
+
console.log(`[daemon] Web wiki: ${this.webServer.url}`);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
console.error(`[daemon] Web wiki failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
console.log(`[daemon] Running (maintenance every ${Math.round(maintenanceMs / 60000)}m). Press Ctrl+C to stop.`);
|
|
69
|
+
}
|
|
70
|
+
/** Stop the daemon. */
|
|
71
|
+
async stop() {
|
|
72
|
+
console.log("[daemon] Stopping...");
|
|
73
|
+
this.running = false;
|
|
74
|
+
this.watcher.stop();
|
|
75
|
+
if (this.maintenanceTimer) {
|
|
76
|
+
clearInterval(this.maintenanceTimer);
|
|
77
|
+
this.maintenanceTimer = null;
|
|
78
|
+
}
|
|
79
|
+
// Stop web wiki server
|
|
80
|
+
if (this.webServer) {
|
|
81
|
+
try {
|
|
82
|
+
await this.webServer.close();
|
|
83
|
+
console.log("[daemon] Web wiki stopped");
|
|
84
|
+
}
|
|
85
|
+
catch { }
|
|
86
|
+
this.webServer = null;
|
|
87
|
+
}
|
|
88
|
+
if (this.store) {
|
|
89
|
+
try {
|
|
90
|
+
await closeStore(this.store);
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
this.store = null;
|
|
94
|
+
}
|
|
95
|
+
this.state.close();
|
|
96
|
+
console.log("[daemon] Stopped.");
|
|
97
|
+
}
|
|
98
|
+
/** Get the web server URL (if running). */
|
|
99
|
+
getWebUrl() {
|
|
100
|
+
return this.webServer?.url ?? null;
|
|
101
|
+
}
|
|
102
|
+
/** Process a single session file (for CLI `process` command). */
|
|
103
|
+
async processOne(sessionPath) {
|
|
104
|
+
if (!existsSync(sessionPath)) {
|
|
105
|
+
console.error(`[daemon] Session file not found: ${sessionPath}`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (!this.store) {
|
|
109
|
+
try {
|
|
110
|
+
this.store = await openStore(this.config.wikiDir);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
console.error(`[daemon] Failed to open store: ${err instanceof Error ? err.message : err}`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const scope = detectScopeFromPath(sessionPath);
|
|
118
|
+
console.log(`[daemon] Processing: ${sessionPath} (scope: ${scope})`);
|
|
119
|
+
try {
|
|
120
|
+
const result = await processSession(sessionPath, this.config.wikiDir, this.store, scope, this.config.model, this.config.getApiKey);
|
|
121
|
+
if (result.skipped) {
|
|
122
|
+
console.log(`[daemon] Skipped: ${result.reason}`);
|
|
123
|
+
this.state.recordSuccess(sessionPath, scope, [], []);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
console.log(`[daemon] Done: ${result.pagesCreated.length} created, ${result.pagesUpdated.length} updated`);
|
|
127
|
+
this.state.recordSuccess(sessionPath, scope, result.pagesCreated, result.pagesUpdated);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
132
|
+
console.error(`[daemon] Failed: ${msg}`);
|
|
133
|
+
this.state.recordFailure(sessionPath, scope, msg);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** Handle new entries from the registry watcher. */
|
|
137
|
+
onNewEntries(entries) {
|
|
138
|
+
// Filter already-processed
|
|
139
|
+
const newEntries = entries.filter((e) => existsSync(e.sessionPath) && !this.state.isProcessed(e.sessionPath));
|
|
140
|
+
if (newEntries.length === 0)
|
|
141
|
+
return;
|
|
142
|
+
console.log(`[daemon] Queued ${newEntries.length} session(s) for processing`);
|
|
143
|
+
this.queue.push(...newEntries);
|
|
144
|
+
this.processQueue();
|
|
145
|
+
}
|
|
146
|
+
/** Process queued sessions sequentially. */
|
|
147
|
+
async processQueue() {
|
|
148
|
+
if (this.processing || !this.running)
|
|
149
|
+
return;
|
|
150
|
+
this.processing = true;
|
|
151
|
+
while (this.queue.length > 0 && this.running) {
|
|
152
|
+
const entry = this.queue.shift();
|
|
153
|
+
await this.processOne(entry.sessionPath);
|
|
154
|
+
}
|
|
155
|
+
this.processing = false;
|
|
156
|
+
}
|
|
157
|
+
/** Run periodic maintenance via LLM agent. */
|
|
158
|
+
async runMaintenancePass() {
|
|
159
|
+
if (this.maintenanceRunning || !this.running || !this.store)
|
|
160
|
+
return;
|
|
161
|
+
this.maintenanceRunning = true;
|
|
162
|
+
try {
|
|
163
|
+
console.log("[daemon] Running maintenance agent...");
|
|
164
|
+
const result = await runMaintenance(this.config.wikiDir, this.store, this.config.model, this.config.getApiKey);
|
|
165
|
+
console.log(`[daemon] Maintenance done: ${result.pagesUpdated} updated, ${result.pagesMerged} merged`);
|
|
166
|
+
if (result.summary) {
|
|
167
|
+
// Log first 200 chars of summary
|
|
168
|
+
console.log(`[daemon] Summary: ${result.summary.slice(0, 200)}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
console.error(`[daemon] Maintenance error: ${err instanceof Error ? err.message : String(err)}`);
|
|
173
|
+
}
|
|
174
|
+
this.maintenanceRunning = false;
|
|
175
|
+
}
|
|
176
|
+
/** Get processing history. */
|
|
177
|
+
getHistory(scope, limit) {
|
|
178
|
+
return this.state.getHistory(scope, limit);
|
|
179
|
+
}
|
|
180
|
+
/** Get failed sessions. */
|
|
181
|
+
getFailed() {
|
|
182
|
+
return this.state.getFailed();
|
|
183
|
+
}
|
|
184
|
+
/** Retry all failed sessions. */
|
|
185
|
+
async retryFailed() {
|
|
186
|
+
const failed = this.state.getFailed();
|
|
187
|
+
if (failed.length === 0) {
|
|
188
|
+
console.log("[daemon] No failed sessions to retry.");
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
console.log(`[daemon] Retrying ${failed.length} failed session(s)...`);
|
|
192
|
+
for (const session of failed) {
|
|
193
|
+
await this.processOne(session.sessionPath);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/** Extract project scope from session path or header. */
|
|
198
|
+
function detectScopeFromPath(sessionPath) {
|
|
199
|
+
// 1. Try reading the session header — most reliable, has the real cwd
|
|
200
|
+
try {
|
|
201
|
+
const { readFileSync } = require("node:fs");
|
|
202
|
+
const firstLine = readFileSync(sessionPath, "utf-8").split("\n")[0];
|
|
203
|
+
const header = JSON.parse(firstLine);
|
|
204
|
+
if (header.cwd) {
|
|
205
|
+
const parts = header.cwd.split("/");
|
|
206
|
+
return parts[parts.length - 1] ?? "unknown";
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch { }
|
|
210
|
+
// 2. Fallback: decode from directory name
|
|
211
|
+
// Path format: ~/.pi/agent/sessions/--home-ubuntu-projects-pi-mono--/file.jsonl
|
|
212
|
+
// The dir name encodes the cwd path with / replaced by -
|
|
213
|
+
// But project names can contain hyphens, so we can't just replace all - with /
|
|
214
|
+
// Instead, find the last segment after "projects-" which is the project name
|
|
215
|
+
const dirName = sessionPath.split("/").slice(-2, -1)[0] ?? "";
|
|
216
|
+
if (dirName.startsWith("--") && dirName.endsWith("--")) {
|
|
217
|
+
const inner = dirName.slice(2, -2); // e.g. "home-ubuntu-projects-agent-board"
|
|
218
|
+
// Look for "projects-" marker — everything after it is the project name
|
|
219
|
+
const projectsIdx = inner.indexOf("projects-");
|
|
220
|
+
if (projectsIdx >= 0) {
|
|
221
|
+
return inner.slice(projectsIdx + "projects-".length); // "agent-board"
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return "unknown";
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML frontmatter parsing and serialization for wiki pages.
|
|
3
|
+
*
|
|
4
|
+
* Handles the `---\n...\n---` frontmatter block in markdown files.
|
|
5
|
+
* Uses the `yaml` package for robust parsing. Preserves unknown fields.
|
|
6
|
+
*/
|
|
7
|
+
import type { PageFrontmatter } from "./wiki.js";
|
|
8
|
+
/** Current schema version. Bump when frontmatter/body format changes. */
|
|
9
|
+
export declare const CURRENT_SCHEMA_VERSION = 1;
|
|
10
|
+
/** A migration transforms pages from one schema version to the next. */
|
|
11
|
+
export interface Migration {
|
|
12
|
+
from: number;
|
|
13
|
+
to: number;
|
|
14
|
+
migrate: (fm: Record<string, unknown>, body: string) => {
|
|
15
|
+
fm: Record<string, unknown>;
|
|
16
|
+
body: string;
|
|
17
|
+
};
|
|
18
|
+
description: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Registry of all schema migrations, ordered by `from` version.
|
|
22
|
+
* Empty while CURRENT_SCHEMA_VERSION = 1 — add entries when bumping.
|
|
23
|
+
*/
|
|
24
|
+
export declare const MIGRATIONS: Migration[];
|
|
25
|
+
/**
|
|
26
|
+
* Apply all applicable migrations to bring a page up to CURRENT_SCHEMA_VERSION.
|
|
27
|
+
*
|
|
28
|
+
* Chains migrations sequentially: 1→2, 2→3, etc.
|
|
29
|
+
* If `schemaVersion` is already >= CURRENT_SCHEMA_VERSION, returns as-is (no downgrade).
|
|
30
|
+
* If `schemaVersion` is missing, defaults to 1.
|
|
31
|
+
*/
|
|
32
|
+
export declare function migrateToLatest(fm: Record<string, unknown>, body: string): {
|
|
33
|
+
fm: Record<string, unknown>;
|
|
34
|
+
body: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Parse YAML frontmatter from markdown content.
|
|
38
|
+
*
|
|
39
|
+
* Expects content starting with `---\n...\n---`. If no frontmatter block
|
|
40
|
+
* is found, returns default frontmatter and the entire content as body.
|
|
41
|
+
* If the YAML is malformed, throws with a descriptive error.
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseFrontmatter(content: string): {
|
|
44
|
+
frontmatter: PageFrontmatter;
|
|
45
|
+
body: string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Serialize frontmatter and body back to a markdown string with YAML
|
|
49
|
+
* frontmatter block.
|
|
50
|
+
*/
|
|
51
|
+
export declare function serializeFrontmatter(frontmatter: PageFrontmatter, body: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Validate and normalize a raw frontmatter object into a PageFrontmatter.
|
|
54
|
+
*
|
|
55
|
+
* Required field: `title` (defaults to "Untitled" if missing).
|
|
56
|
+
* All other fields get sensible defaults. Unknown fields are preserved.
|
|
57
|
+
*/
|
|
58
|
+
export declare function validateFrontmatter(fm: Record<string, unknown>): PageFrontmatter;
|
|
59
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAI/D,yEAAyE;AACzE,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACtG,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,SAAS,EAAO,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3B,IAAI,EAAE,MAAM,GACX;IAAE,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAyB/C;AAaD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IACjD,WAAW,EAAE,eAAe,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd,CA+BA;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,eAAe,EAC5B,IAAI,EAAE,MAAM,GACX,MAAM,CAKR;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC1B,eAAe,CAyDjB"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAML frontmatter parsing and serialization for wiki pages.
|
|
3
|
+
*
|
|
4
|
+
* Handles the `---\n...\n---` frontmatter block in markdown files.
|
|
5
|
+
* Uses the `yaml` package for robust parsing. Preserves unknown fields.
|
|
6
|
+
*/
|
|
7
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
8
|
+
// -- Schema versioning -------------------------------------------------------
|
|
9
|
+
/** Current schema version. Bump when frontmatter/body format changes. */
|
|
10
|
+
export const CURRENT_SCHEMA_VERSION = 1;
|
|
11
|
+
/**
|
|
12
|
+
* Registry of all schema migrations, ordered by `from` version.
|
|
13
|
+
* Empty while CURRENT_SCHEMA_VERSION = 1 — add entries when bumping.
|
|
14
|
+
*/
|
|
15
|
+
export const MIGRATIONS = [];
|
|
16
|
+
/**
|
|
17
|
+
* Apply all applicable migrations to bring a page up to CURRENT_SCHEMA_VERSION.
|
|
18
|
+
*
|
|
19
|
+
* Chains migrations sequentially: 1→2, 2→3, etc.
|
|
20
|
+
* If `schemaVersion` is already >= CURRENT_SCHEMA_VERSION, returns as-is (no downgrade).
|
|
21
|
+
* If `schemaVersion` is missing, defaults to 1.
|
|
22
|
+
*/
|
|
23
|
+
export function migrateToLatest(fm, body) {
|
|
24
|
+
let version = typeof fm.schemaVersion === "number" ? fm.schemaVersion : 1;
|
|
25
|
+
// Don't downgrade pages ahead of current version
|
|
26
|
+
if (version >= CURRENT_SCHEMA_VERSION) {
|
|
27
|
+
return { fm: { ...fm, schemaVersion: version }, body };
|
|
28
|
+
}
|
|
29
|
+
let currentFm = { ...fm };
|
|
30
|
+
let currentBody = body;
|
|
31
|
+
while (version < CURRENT_SCHEMA_VERSION) {
|
|
32
|
+
const migration = MIGRATIONS.find((m) => m.from === version);
|
|
33
|
+
if (!migration) {
|
|
34
|
+
// No migration path — stop at current version
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
const result = migration.migrate(currentFm, currentBody);
|
|
38
|
+
currentFm = result.fm;
|
|
39
|
+
currentBody = result.body;
|
|
40
|
+
version = migration.to;
|
|
41
|
+
}
|
|
42
|
+
currentFm.schemaVersion = version;
|
|
43
|
+
return { fm: currentFm, body: currentBody };
|
|
44
|
+
}
|
|
45
|
+
const VALID_PARA_CATEGORIES = new Set([
|
|
46
|
+
"projects",
|
|
47
|
+
"areas",
|
|
48
|
+
"resources",
|
|
49
|
+
"archives",
|
|
50
|
+
]);
|
|
51
|
+
const FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n?---\n?([\s\S]*)$/;
|
|
52
|
+
// -- Functions ---------------------------------------------------------------
|
|
53
|
+
/**
|
|
54
|
+
* Parse YAML frontmatter from markdown content.
|
|
55
|
+
*
|
|
56
|
+
* Expects content starting with `---\n...\n---`. If no frontmatter block
|
|
57
|
+
* is found, returns default frontmatter and the entire content as body.
|
|
58
|
+
* If the YAML is malformed, throws with a descriptive error.
|
|
59
|
+
*/
|
|
60
|
+
export function parseFrontmatter(content) {
|
|
61
|
+
const match = content.match(FRONTMATTER_REGEX);
|
|
62
|
+
if (!match) {
|
|
63
|
+
return {
|
|
64
|
+
frontmatter: validateFrontmatter({}),
|
|
65
|
+
body: content,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const rawYaml = match[1];
|
|
69
|
+
const body = match[2];
|
|
70
|
+
let parsed;
|
|
71
|
+
try {
|
|
72
|
+
parsed = parseYaml(rawYaml);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
76
|
+
throw new Error(`Malformed YAML frontmatter: ${msg}`);
|
|
77
|
+
}
|
|
78
|
+
if (parsed == null || typeof parsed !== "object") {
|
|
79
|
+
return {
|
|
80
|
+
frontmatter: validateFrontmatter({}),
|
|
81
|
+
body,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
frontmatter: validateFrontmatter(parsed),
|
|
86
|
+
body,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Serialize frontmatter and body back to a markdown string with YAML
|
|
91
|
+
* frontmatter block.
|
|
92
|
+
*/
|
|
93
|
+
export function serializeFrontmatter(frontmatter, body) {
|
|
94
|
+
// Always write the current schema version on serialize
|
|
95
|
+
const fmWithVersion = { ...frontmatter, schemaVersion: CURRENT_SCHEMA_VERSION };
|
|
96
|
+
const yaml = stringifyYaml(fmWithVersion, { lineWidth: 0 }).trimEnd();
|
|
97
|
+
return `---\n${yaml}\n---\n${body}`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Validate and normalize a raw frontmatter object into a PageFrontmatter.
|
|
101
|
+
*
|
|
102
|
+
* Required field: `title` (defaults to "Untitled" if missing).
|
|
103
|
+
* All other fields get sensible defaults. Unknown fields are preserved.
|
|
104
|
+
*/
|
|
105
|
+
export function validateFrontmatter(fm) {
|
|
106
|
+
const now = new Date().toISOString();
|
|
107
|
+
const title = typeof fm.title === "string" && fm.title.length > 0
|
|
108
|
+
? fm.title
|
|
109
|
+
: "Untitled";
|
|
110
|
+
const para = validateParaCategory(fm.para);
|
|
111
|
+
const scope = toStringArray(fm.scope);
|
|
112
|
+
const tags = toStringArray(fm.tags);
|
|
113
|
+
const sources = toStringArray(fm.sources);
|
|
114
|
+
const links = toStringArray(fm.links);
|
|
115
|
+
const created = typeof fm.created === "string" && fm.created.length > 0
|
|
116
|
+
? fm.created
|
|
117
|
+
: now;
|
|
118
|
+
const updated = typeof fm.updated === "string" && fm.updated.length > 0
|
|
119
|
+
? fm.updated
|
|
120
|
+
: now;
|
|
121
|
+
const schemaVersion = typeof fm.schemaVersion === "number" ? fm.schemaVersion : 1;
|
|
122
|
+
// Build result with known fields first, then spread unknown fields underneath.
|
|
123
|
+
// Known fields override any unknown fields with the same name.
|
|
124
|
+
const knownKeys = new Set([
|
|
125
|
+
"title",
|
|
126
|
+
"para",
|
|
127
|
+
"scope",
|
|
128
|
+
"tags",
|
|
129
|
+
"sources",
|
|
130
|
+
"created",
|
|
131
|
+
"updated",
|
|
132
|
+
"links",
|
|
133
|
+
"schemaVersion",
|
|
134
|
+
]);
|
|
135
|
+
const unknownFields = {};
|
|
136
|
+
for (const [key, value] of Object.entries(fm)) {
|
|
137
|
+
if (!knownKeys.has(key)) {
|
|
138
|
+
unknownFields[key] = value;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
...unknownFields,
|
|
143
|
+
title,
|
|
144
|
+
para,
|
|
145
|
+
scope,
|
|
146
|
+
tags,
|
|
147
|
+
sources,
|
|
148
|
+
created,
|
|
149
|
+
updated,
|
|
150
|
+
links,
|
|
151
|
+
schemaVersion,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// -- Helpers -----------------------------------------------------------------
|
|
155
|
+
function validateParaCategory(value) {
|
|
156
|
+
if (typeof value === "string" && VALID_PARA_CATEGORIES.has(value)) {
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
return "resources";
|
|
160
|
+
}
|
|
161
|
+
function toStringArray(value) {
|
|
162
|
+
if (Array.isArray(value)) {
|
|
163
|
+
return value.filter((v) => typeof v === "string");
|
|
164
|
+
}
|
|
165
|
+
if (typeof value === "string") {
|
|
166
|
+
return [value];
|
|
167
|
+
}
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../src/frontmatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GEPA dataset extraction — builds evaluation context from wiki state and session history.
|
|
3
|
+
*
|
|
4
|
+
* The evaluation context gives the LLM judge grounding:
|
|
5
|
+
* it knows about the wiki's current size, structure, common patterns,
|
|
6
|
+
* and recent capture results to judge whether a prompt would work well.
|
|
7
|
+
*/
|
|
8
|
+
/** Summary of the current wiki state for evaluation context. */
|
|
9
|
+
export interface WikiContext {
|
|
10
|
+
/** Total number of wiki pages. */
|
|
11
|
+
totalPages: number;
|
|
12
|
+
/** Pages per PARA category. */
|
|
13
|
+
categoryCounts: Record<string, number>;
|
|
14
|
+
/** Number of unique scopes. */
|
|
15
|
+
scopeCount: number;
|
|
16
|
+
/** Most common scopes (top 5). */
|
|
17
|
+
topScopes: string[];
|
|
18
|
+
/** Number of unique tags. */
|
|
19
|
+
tagCount: number;
|
|
20
|
+
/** Most common tags (top 10). */
|
|
21
|
+
topTags: string[];
|
|
22
|
+
/** Sample page titles (up to 15). */
|
|
23
|
+
sampleTitles: string[];
|
|
24
|
+
}
|
|
25
|
+
/** Full evaluation context. */
|
|
26
|
+
export interface EvalContext {
|
|
27
|
+
/** Formatted context string for the LLM judge. */
|
|
28
|
+
contextString: string;
|
|
29
|
+
/** Raw wiki stats. */
|
|
30
|
+
wikiStats: WikiContext;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build a formatted evaluation context string from wiki state.
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildEvalContext(wikiDir?: string): Promise<EvalContext>;
|
|
36
|
+
//# sourceMappingURL=dataset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataset.d.ts","sourceRoot":"","sources":["../../src/gepa/dataset.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IAEnB,+BAA+B;IAC/B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEvC,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IAEnB,kCAAkC;IAClC,SAAS,EAAE,MAAM,EAAE,CAAC;IAEpB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IAEjB,iCAAiC;IACjC,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB,qCAAqC;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,+BAA+B;AAC/B,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,aAAa,EAAE,MAAM,CAAC;IAEtB,sBAAsB;IACtB,SAAS,EAAE,WAAW,CAAC;CACxB;AAyHD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA8B7E"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GEPA dataset extraction — builds evaluation context from wiki state and session history.
|
|
3
|
+
*
|
|
4
|
+
* The evaluation context gives the LLM judge grounding:
|
|
5
|
+
* it knows about the wiki's current size, structure, common patterns,
|
|
6
|
+
* and recent capture results to judge whether a prompt would work well.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
11
|
+
import { homedir } from "node:os";
|
|
12
|
+
// -- Wiki state extraction ---------------------------------------------------
|
|
13
|
+
async function extractWikiStats(wikiDir) {
|
|
14
|
+
const categories = ["projects", "areas", "resources", "archives"];
|
|
15
|
+
const categoryCounts = {};
|
|
16
|
+
const allScopes = [];
|
|
17
|
+
const allTags = [];
|
|
18
|
+
const sampleTitles = [];
|
|
19
|
+
let totalPages = 0;
|
|
20
|
+
for (const cat of categories) {
|
|
21
|
+
const catDir = join(wikiDir, cat);
|
|
22
|
+
if (!existsSync(catDir)) {
|
|
23
|
+
categoryCounts[cat] = 0;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const files = await readdir(catDir);
|
|
28
|
+
const mdFiles = files.filter((f) => f.endsWith(".md"));
|
|
29
|
+
categoryCounts[cat] = mdFiles.length;
|
|
30
|
+
totalPages += mdFiles.length;
|
|
31
|
+
// Parse frontmatter from each page (lightweight — just YAML header)
|
|
32
|
+
for (const file of mdFiles.slice(0, 30)) {
|
|
33
|
+
try {
|
|
34
|
+
const content = await readFile(join(catDir, file), "utf-8");
|
|
35
|
+
const fm = parseFrontmatter(content);
|
|
36
|
+
if (fm) {
|
|
37
|
+
if (fm.title && sampleTitles.length < 15) {
|
|
38
|
+
sampleTitles.push(fm.title);
|
|
39
|
+
}
|
|
40
|
+
if (fm.scope)
|
|
41
|
+
allScopes.push(...fm.scope);
|
|
42
|
+
if (fm.tags)
|
|
43
|
+
allTags.push(...fm.tags);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Skip unreadable pages
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
categoryCounts[cat] = 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const scopeCounts = countOccurrences(allScopes);
|
|
56
|
+
const tagCounts = countOccurrences(allTags);
|
|
57
|
+
return {
|
|
58
|
+
totalPages,
|
|
59
|
+
categoryCounts,
|
|
60
|
+
scopeCount: Object.keys(scopeCounts).length,
|
|
61
|
+
topScopes: topN(scopeCounts, 5),
|
|
62
|
+
tagCount: Object.keys(tagCounts).length,
|
|
63
|
+
topTags: topN(tagCounts, 10),
|
|
64
|
+
sampleTitles,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** Minimal frontmatter parser — extract title, scope, tags from YAML header. */
|
|
68
|
+
function parseFrontmatter(content) {
|
|
69
|
+
const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
70
|
+
if (!match)
|
|
71
|
+
return null;
|
|
72
|
+
const yaml = match[1];
|
|
73
|
+
const result = {};
|
|
74
|
+
// Extract title
|
|
75
|
+
const titleMatch = yaml.match(/^title:\s*(.+)$/m);
|
|
76
|
+
if (titleMatch) {
|
|
77
|
+
result.title = titleMatch[1].replace(/^["']|["']$/g, "").trim();
|
|
78
|
+
}
|
|
79
|
+
// Extract scope (inline array)
|
|
80
|
+
const scopeMatch = yaml.match(/^scope:\s*\[([^\]]*)\]/m);
|
|
81
|
+
if (scopeMatch) {
|
|
82
|
+
result.scope = scopeMatch[1].split(",").map((s) => s.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Multi-line array format
|
|
86
|
+
const scopeSection = yaml.match(/^scope:\s*\n((?:\s+-\s+.+\n?)*)/m);
|
|
87
|
+
if (scopeSection) {
|
|
88
|
+
result.scope = scopeSection[1].match(/^\s+-\s+(.+)$/gm)?.map((l) => l.replace(/^\s+-\s+/, "").replace(/^["']|["']$/g, "").trim()) ?? [];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Extract tags (inline array)
|
|
92
|
+
const tagsMatch = yaml.match(/^tags:\s*\[([^\]]*)\]/m);
|
|
93
|
+
if (tagsMatch) {
|
|
94
|
+
result.tags = tagsMatch[1].split(",").map((s) => s.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const tagsSection = yaml.match(/^tags:\s*\n((?:\s+-\s+.+\n?)*)/m);
|
|
98
|
+
if (tagsSection) {
|
|
99
|
+
result.tags = tagsSection[1].match(/^\s+-\s+(.+)$/gm)?.map((l) => l.replace(/^\s+-\s+/, "").replace(/^["']|["']$/g, "").trim()) ?? [];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
function countOccurrences(items) {
|
|
105
|
+
const counts = {};
|
|
106
|
+
for (const item of items) {
|
|
107
|
+
counts[item] = (counts[item] ?? 0) + 1;
|
|
108
|
+
}
|
|
109
|
+
return counts;
|
|
110
|
+
}
|
|
111
|
+
function topN(counts, n) {
|
|
112
|
+
return Object.entries(counts)
|
|
113
|
+
.sort((a, b) => b[1] - a[1])
|
|
114
|
+
.slice(0, n)
|
|
115
|
+
.map(([key]) => key);
|
|
116
|
+
}
|
|
117
|
+
// -- Context building --------------------------------------------------------
|
|
118
|
+
/**
|
|
119
|
+
* Build a formatted evaluation context string from wiki state.
|
|
120
|
+
*/
|
|
121
|
+
export async function buildEvalContext(wikiDir) {
|
|
122
|
+
const dir = wikiDir ?? join(homedir(), ".pi", "wiki");
|
|
123
|
+
const wikiStats = await extractWikiStats(dir);
|
|
124
|
+
const lines = [
|
|
125
|
+
"## Wiki State Summary",
|
|
126
|
+
"",
|
|
127
|
+
`Total pages: ${wikiStats.totalPages}`,
|
|
128
|
+
`Categories: ${Object.entries(wikiStats.categoryCounts).map(([k, v]) => `${k}=${v}`).join(", ")}`,
|
|
129
|
+
`Scopes: ${wikiStats.scopeCount} unique (top: ${wikiStats.topScopes.join(", ") || "none"})`,
|
|
130
|
+
`Tags: ${wikiStats.tagCount} unique (top: ${wikiStats.topTags.slice(0, 5).join(", ") || "none"})`,
|
|
131
|
+
"",
|
|
132
|
+
];
|
|
133
|
+
if (wikiStats.sampleTitles.length > 0) {
|
|
134
|
+
lines.push("Sample page titles:");
|
|
135
|
+
for (const title of wikiStats.sampleTitles.slice(0, 10)) {
|
|
136
|
+
lines.push(` - ${title}`);
|
|
137
|
+
}
|
|
138
|
+
lines.push("");
|
|
139
|
+
}
|
|
140
|
+
// Check for recent processing history
|
|
141
|
+
const stateDbPath = join(dir, ".daemon.sqlite");
|
|
142
|
+
if (existsSync(stateDbPath)) {
|
|
143
|
+
lines.push("Daemon: active (session processing enabled)");
|
|
144
|
+
}
|
|
145
|
+
const contextString = lines.join("\n");
|
|
146
|
+
return { contextString, wikiStats };
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=dataset.js.map
|