portable-agent-layer 0.8.1 → 0.10.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.
@@ -1,234 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * Principle Evaluation — generate, regenerate, or compare candidate principles.
4
- *
5
- * Reads failures (capture.md) and learnings (frontmatter .md) and uses Haiku
6
- * to generate candidate principles. Useful for tuning prompt quality.
7
- *
8
- * Modes:
9
- * --dry-run Preview which files would be updated
10
- * --evaluate Show current vs new principle for comparison (does not write)
11
- * --force Regenerate principles even if one already exists
12
- * (default) Generate missing principles only
13
- *
14
- * Usage:
15
- * bun run tool:eval # generate missing
16
- * bun run tool:eval -- --dry-run # preview
17
- * bun run tool:eval -- --evaluate # compare current vs new
18
- * bun run tool:eval -- --force # regenerate all
19
- */
20
-
21
- import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
22
- import { resolve } from "node:path";
23
- import { hasFrontmatter, parse, stringify } from "../hooks/lib/frontmatter";
24
- import { inference } from "../hooks/lib/inference";
25
- import { palHome } from "../hooks/lib/paths";
26
- import {
27
- FAILURE_PRINCIPLE_PROMPT,
28
- LEARNING_PRINCIPLE_PROMPT,
29
- } from "../hooks/lib/prompts";
30
-
31
- const args = process.argv.slice(2);
32
- const dryRun = args.includes("--dry-run");
33
- const evaluate = args.includes("--evaluate");
34
- const force = args.includes("--force");
35
-
36
- const home = palHome();
37
- let processed = 0;
38
- let skipped = 0;
39
- let failed = 0;
40
-
41
- async function generatePrinciple(systemPrompt: string, context: string): Promise<string> {
42
- const result = await inference({
43
- system: systemPrompt,
44
- user: context,
45
- maxTokens: 100,
46
- timeout: 10000,
47
- jsonSchema: {
48
- type: "object" as const,
49
- additionalProperties: false,
50
- properties: {
51
- principle: { type: "string" as const },
52
- },
53
- required: ["principle"],
54
- },
55
- });
56
-
57
- if (result.success && result.output) {
58
- const parsed = JSON.parse(result.output) as { principle?: string };
59
- const principle = parsed.principle?.trim() || "";
60
- if (principle.length > 10) return principle;
61
- }
62
- return "";
63
- }
64
-
65
- // ── Failures ──
66
-
67
- async function processFailures() {
68
- const failuresDir = resolve(home, "memory", "learning", "failures");
69
- if (!existsSync(failuresDir)) return;
70
-
71
- for (const year of readdirSync(failuresDir)) {
72
- const yearDir = resolve(failuresDir, year);
73
- for (const month of readdirSync(yearDir)) {
74
- const monthDir = resolve(yearDir, month);
75
- for (const slug of readdirSync(monthDir)) {
76
- const capturePath = resolve(monthDir, slug, "capture.md");
77
- if (!existsSync(capturePath)) continue;
78
-
79
- const content = readFileSync(capturePath, "utf-8");
80
- if (!hasFrontmatter(content)) continue;
81
-
82
- const { meta, body } = parse<{
83
- principle?: string;
84
- context?: string;
85
- rating?: number;
86
- }>(content);
87
-
88
- const hasPrinciple = !!meta.principle;
89
- if (hasPrinciple && !force && !evaluate) {
90
- skipped++;
91
- continue;
92
- }
93
-
94
- const context = meta.context || "";
95
- if (!context) {
96
- skipped++;
97
- continue;
98
- }
99
-
100
- const inputContext = `Rating: ${meta.rating}/10\nContext: ${context}\n\n${body.slice(0, 400)}`;
101
-
102
- if (dryRun) {
103
- console.log(` [failure] ${slug.slice(0, 60)}`);
104
- processed++;
105
- continue;
106
- }
107
-
108
- try {
109
- const newPrinciple = await generatePrinciple(
110
- FAILURE_PRINCIPLE_PROMPT,
111
- inputContext
112
- );
113
- if (!newPrinciple) {
114
- skipped++;
115
- continue;
116
- }
117
-
118
- if (evaluate) {
119
- console.log(` [failure] ${slug.slice(0, 50)}`);
120
- if (hasPrinciple) {
121
- console.log(` OLD: ${meta.principle}`);
122
- }
123
- console.log(` NEW: ${newPrinciple}`);
124
- console.log("");
125
- processed++;
126
- continue;
127
- }
128
-
129
- const newMeta = { ...meta, principle: newPrinciple } as Record<string, unknown>;
130
- writeFileSync(capturePath, stringify(newMeta, body), "utf-8");
131
- console.log(` [failure] ${slug.slice(0, 60)}`);
132
- processed++;
133
- } catch {
134
- failed++;
135
- }
136
- }
137
- }
138
- }
139
- }
140
-
141
- // ── Learnings ──
142
-
143
- async function processLearnings() {
144
- const learningDir = resolve(home, "memory", "learning", "session");
145
- if (!existsSync(learningDir)) return;
146
-
147
- for (const year of readdirSync(learningDir)) {
148
- const yearDir = resolve(learningDir, year);
149
- for (const month of readdirSync(yearDir)) {
150
- const monthDir = resolve(yearDir, month);
151
- for (const file of readdirSync(monthDir).filter((f) => f.endsWith(".md"))) {
152
- const filepath = resolve(monthDir, file);
153
- const content = readFileSync(filepath, "utf-8");
154
-
155
- if (!hasFrontmatter(content)) {
156
- skipped++;
157
- continue;
158
- }
159
-
160
- const { meta, body } = parse<{
161
- principle?: string;
162
- title?: string;
163
- }>(content);
164
-
165
- const hasPrinciple = !!meta.principle;
166
- if (hasPrinciple && !force && !evaluate) {
167
- skipped++;
168
- continue;
169
- }
170
-
171
- const title = meta.title || "";
172
- if (!title) {
173
- skipped++;
174
- continue;
175
- }
176
-
177
- const inputContext = `Title: ${title}\n\n${body.slice(0, 400)}`;
178
-
179
- if (dryRun) {
180
- console.log(` [learning] ${file.slice(0, 60)}`);
181
- processed++;
182
- continue;
183
- }
184
-
185
- try {
186
- const newPrinciple = await generatePrinciple(
187
- LEARNING_PRINCIPLE_PROMPT,
188
- inputContext
189
- );
190
- if (!newPrinciple) {
191
- skipped++;
192
- continue;
193
- }
194
-
195
- if (evaluate) {
196
- console.log(` [learning] ${file.slice(0, 50)}`);
197
- if (hasPrinciple) {
198
- console.log(` OLD: ${meta.principle}`);
199
- }
200
- console.log(` NEW: ${newPrinciple}`);
201
- console.log("");
202
- processed++;
203
- continue;
204
- }
205
-
206
- const newMeta = { ...meta, principle: newPrinciple } as Record<string, unknown>;
207
- writeFileSync(filepath, stringify(newMeta, body), "utf-8");
208
- console.log(` [learning] ${file.slice(0, 60)}`);
209
- processed++;
210
- } catch {
211
- failed++;
212
- }
213
- }
214
- }
215
- }
216
- }
217
-
218
- // ── Main ──
219
-
220
- const mode = evaluate
221
- ? "evaluate"
222
- : force
223
- ? "force regenerate"
224
- : dryRun
225
- ? "dry run"
226
- : "backfill";
227
- console.log(`\n Principle ${mode}...\n`);
228
-
229
- await processFailures();
230
- await processLearnings();
231
-
232
- console.log(
233
- `\n Done: ${processed} ${evaluate ? "compared" : "processed"}, ${skipped} skipped, ${failed} failed\n`
234
- );