@plumpslabs/kuma 2.3.20 → 2.3.22
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.md +18 -0
- package/dist/index.js +10221 -332
- package/package.json +2 -2
- package/packages/ide/studio/dist/index.js +37 -5
- package/packages/ide/studio/public/index.html +239 -68
- package/dist/agentDetector-YOWQVJFR.js +0 -186
- package/dist/chunk-3BRBJZ7P.js +0 -1055
- package/dist/chunk-3OHYYXYN.js +0 -71
- package/dist/chunk-ABKE45T4.js +0 -1264
- package/dist/chunk-E2KFPEBT.js +0 -183
- package/dist/chunk-FKRSI5U5.js +0 -282
- package/dist/chunk-GFLSAXAH.js +0 -155
- package/dist/chunk-L7F67KUP.js +0 -172
- package/dist/chunk-LVKOGXLC.js +0 -658
- package/dist/chunk-PRUTTZBS.js +0 -1113
- package/dist/contextDigest-QB5XHPXE.js +0 -177
- package/dist/domainRules-QLPAQASB.js +0 -20
- package/dist/init-PL4XL662.js +0 -15
- package/dist/kumaAstValidator-CNM7FHYA.js +0 -150
- package/dist/kumaCheckpoint-J2LDQMEO.js +0 -207
- package/dist/kumaCodeScanner-J6B2EHGI.js +0 -563
- package/dist/kumaContractEngine-KX27T4N7.js +0 -305
- package/dist/kumaDb-4XZ5S2LH.js +0 -65
- package/dist/kumaDriftDetector-TOORILSZ.js +0 -237
- package/dist/kumaGotchas-XRGFFBTA.js +0 -151
- package/dist/kumaGraph-UMXZNGYF.js +0 -44
- package/dist/kumaMemory-FBJMV77G.js +0 -16
- package/dist/kumaMiner-XJETL7TL.js +0 -176
- package/dist/kumaPolicyEngine-2QDJDLM7.js +0 -311
- package/dist/kumaProgressiveContext-MWEDRXOH.js +0 -231
- package/dist/kumaSearch-PV4QTKE7.js +0 -321
- package/dist/kumaTrajectory-7NOAVNG2.js +0 -460
- package/dist/kumaVerifier-6YEGC77M.js +0 -265
- package/dist/kumaVisualize-264OEBGJ.js +0 -264
- package/dist/pathValidator-V4DC6U6Z.js +0 -22
- package/dist/safetyAudit-O45SPNTS.js +0 -12
- package/dist/safetyScore-TMMRD2MV.js +0 -333
- package/dist/sessionMemory-YPKVIOMV.js +0 -6
- package/dist/skillGenerator-PWEJKZNX.js +0 -304
|
@@ -1,460 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
sessionMemory
|
|
3
|
-
} from "./chunk-LVKOGXLC.js";
|
|
4
|
-
import {
|
|
5
|
-
getDb,
|
|
6
|
-
saveDb
|
|
7
|
-
} from "./chunk-3BRBJZ7P.js";
|
|
8
|
-
import {
|
|
9
|
-
getProjectRoot
|
|
10
|
-
} from "./chunk-E2KFPEBT.js";
|
|
11
|
-
|
|
12
|
-
// src/engine/kumaTrajectory.ts
|
|
13
|
-
import fs from "fs";
|
|
14
|
-
import path from "path";
|
|
15
|
-
async function ensureTrajectorySchema() {
|
|
16
|
-
const db = await getDb();
|
|
17
|
-
db.exec(`
|
|
18
|
-
CREATE TABLE IF NOT EXISTS trajectories (
|
|
19
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
20
|
-
goal TEXT NOT NULL,
|
|
21
|
-
steps TEXT NOT NULL DEFAULT '[]',
|
|
22
|
-
total_duration_ms INTEGER DEFAULT 0,
|
|
23
|
-
success_rate REAL DEFAULT 0.0,
|
|
24
|
-
complexity INTEGER DEFAULT 0,
|
|
25
|
-
created_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
|
|
26
|
-
);
|
|
27
|
-
CREATE INDEX IF NOT EXISTS idx_traj_goal ON trajectories(goal);
|
|
28
|
-
CREATE INDEX IF NOT EXISTS idx_traj_complexity ON trajectories(complexity);
|
|
29
|
-
CREATE INDEX IF NOT EXISTS idx_traj_created ON trajectories(created_at);
|
|
30
|
-
`);
|
|
31
|
-
db.exec(`
|
|
32
|
-
CREATE TABLE IF NOT EXISTS distilled_skills (
|
|
33
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
34
|
-
name TEXT NOT NULL UNIQUE,
|
|
35
|
-
description TEXT NOT NULL,
|
|
36
|
-
pattern TEXT NOT NULL, -- JSON: tool sequence pattern
|
|
37
|
-
parameters TEXT DEFAULT '[]', -- JSON: parameterized inputs
|
|
38
|
-
success_count INTEGER DEFAULT 1,
|
|
39
|
-
avg_duration_ms INTEGER DEFAULT 0,
|
|
40
|
-
source_trajectory_id INTEGER,
|
|
41
|
-
last_used_at INTEGER,
|
|
42
|
-
created_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
|
|
43
|
-
);
|
|
44
|
-
CREATE INDEX IF NOT EXISTS idx_skills_name ON distilled_skills(name);
|
|
45
|
-
CREATE INDEX IF NOT EXISTS idx_skills_used ON distilled_skills(last_used_at);
|
|
46
|
-
`);
|
|
47
|
-
db.exec(`
|
|
48
|
-
CREATE TABLE IF NOT EXISTS generated_tests (
|
|
49
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
50
|
-
trajectory_id INTEGER,
|
|
51
|
-
file_path TEXT NOT NULL,
|
|
52
|
-
test_framework TEXT NOT NULL,
|
|
53
|
-
description TEXT,
|
|
54
|
-
test_code TEXT NOT NULL,
|
|
55
|
-
created_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
|
|
56
|
-
);
|
|
57
|
-
CREATE INDEX IF NOT EXISTS idx_gen_tests_traj ON generated_tests(trajectory_id);
|
|
58
|
-
`);
|
|
59
|
-
saveDb();
|
|
60
|
-
}
|
|
61
|
-
async function recordTrajectory(goal) {
|
|
62
|
-
try {
|
|
63
|
-
await ensureTrajectorySchema();
|
|
64
|
-
const calls = sessionMemory.getToolCallHistory(100);
|
|
65
|
-
const steps = calls.map((c) => ({
|
|
66
|
-
toolName: c.toolName,
|
|
67
|
-
params: c.params,
|
|
68
|
-
success: true,
|
|
69
|
-
durationMs: 0,
|
|
70
|
-
timestamp: c.timestamp
|
|
71
|
-
}));
|
|
72
|
-
const totalDurationMs = steps.length > 0 ? steps[steps.length - 1].timestamp - steps[0].timestamp : 0;
|
|
73
|
-
const errorCalls = steps.filter((s) => {
|
|
74
|
-
const action = s.params.action;
|
|
75
|
-
return action === "verify" && s.params.success === false;
|
|
76
|
-
}).length;
|
|
77
|
-
const successRate = steps.length > 0 ? (steps.length - errorCalls) / steps.length : 1;
|
|
78
|
-
const complexity = Math.min(
|
|
79
|
-
100,
|
|
80
|
-
Math.round(
|
|
81
|
-
steps.length * 5 + // 5 pts per step
|
|
82
|
-
errorCalls * 15 + // 15 pts per error
|
|
83
|
-
Math.min(totalDurationMs / 6e4 * 10, 30)
|
|
84
|
-
// 10 pts per minute (max 30)
|
|
85
|
-
)
|
|
86
|
-
);
|
|
87
|
-
const db2 = await getDb();
|
|
88
|
-
db2.run(
|
|
89
|
-
`INSERT INTO trajectories (goal, steps, total_duration_ms, success_rate, complexity)
|
|
90
|
-
VALUES (?, ?, ?, ?, ?)`,
|
|
91
|
-
[
|
|
92
|
-
goal.substring(0, 200),
|
|
93
|
-
JSON.stringify(steps),
|
|
94
|
-
totalDurationMs,
|
|
95
|
-
successRate,
|
|
96
|
-
complexity
|
|
97
|
-
]
|
|
98
|
-
);
|
|
99
|
-
saveDb();
|
|
100
|
-
const result = db2.exec("SELECT last_insert_rowid() as id");
|
|
101
|
-
const id = result[0]?.values[0]?.[0];
|
|
102
|
-
if (id !== null && complexity > 40 && successRate > 0.8) {
|
|
103
|
-
await distillSkill(id, goal, steps).catch(() => {
|
|
104
|
-
});
|
|
105
|
-
if (goal.toLowerCase().includes("fix") || goal.toLowerCase().includes("bug") || goal.toLowerCase().includes("error")) {
|
|
106
|
-
await generateTestFromTrajectory(id, goal, steps).catch(() => {
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return id ?? null;
|
|
111
|
-
} catch (err) {
|
|
112
|
-
console.error(`[Trajectory] Record error: ${err}`);
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
async function distillSkill(trajectoryId, goal, steps) {
|
|
117
|
-
try {
|
|
118
|
-
const db = await getDb();
|
|
119
|
-
const toolSequence = steps.map((s) => s.toolName);
|
|
120
|
-
const patternKey = toolSequence.join(" \u2192 ");
|
|
121
|
-
const uniqueTools = [...new Set(toolSequence)];
|
|
122
|
-
const skillName = `trajectory:${uniqueTools.slice(0, 3).join("-")}`;
|
|
123
|
-
const checkStmt = db.prepare(
|
|
124
|
-
"SELECT id, success_count, avg_duration_ms FROM distilled_skills WHERE name = ?"
|
|
125
|
-
);
|
|
126
|
-
checkStmt.bind([skillName]);
|
|
127
|
-
const exists = checkStmt.step();
|
|
128
|
-
let existingRow = null;
|
|
129
|
-
if (exists) {
|
|
130
|
-
existingRow = checkStmt.getAsObject();
|
|
131
|
-
}
|
|
132
|
-
checkStmt.free();
|
|
133
|
-
const totalDuration = steps.reduce((sum, s) => sum + s.durationMs, 0);
|
|
134
|
-
if (existingRow) {
|
|
135
|
-
const existingId = existingRow.id;
|
|
136
|
-
const existingCount = existingRow.success_count;
|
|
137
|
-
const existingAvg = existingRow.avg_duration_ms;
|
|
138
|
-
db.run(
|
|
139
|
-
`UPDATE distilled_skills
|
|
140
|
-
SET success_count = ?, avg_duration_ms = ?, last_used_at = strftime('%s','now')
|
|
141
|
-
WHERE id = ?`,
|
|
142
|
-
[
|
|
143
|
-
existingCount + 1,
|
|
144
|
-
Math.round((existingAvg * existingCount + totalDuration) / (existingCount + 1)),
|
|
145
|
-
existingId
|
|
146
|
-
]
|
|
147
|
-
);
|
|
148
|
-
} else {
|
|
149
|
-
const description = [
|
|
150
|
-
`Distilled trajectory pattern for "${goal.substring(0, 60)}"`,
|
|
151
|
-
`Tool sequence: ${patternKey}`,
|
|
152
|
-
`${steps.length} steps, ${uniqueTools.length} unique tools`
|
|
153
|
-
].join(". ");
|
|
154
|
-
db.run(
|
|
155
|
-
`INSERT INTO distilled_skills (name, description, pattern, parameters, success_count, avg_duration_ms, source_trajectory_id, last_used_at)
|
|
156
|
-
VALUES (?, ?, ?, ?, 1, ?, ?, strftime('%s','now'))`,
|
|
157
|
-
[
|
|
158
|
-
skillName,
|
|
159
|
-
description,
|
|
160
|
-
JSON.stringify(toolSequence),
|
|
161
|
-
JSON.stringify(extractParameters(steps)),
|
|
162
|
-
totalDuration,
|
|
163
|
-
trajectoryId
|
|
164
|
-
]
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
saveDb();
|
|
168
|
-
console.error(`[Trajectory] Distilled skill "${skillName}" from trajectory #${trajectoryId}`);
|
|
169
|
-
} catch (err) {
|
|
170
|
-
console.error(`[Trajectory] Distill error: ${err}`);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
function extractParameters(steps) {
|
|
174
|
-
const params = /* @__PURE__ */ new Set();
|
|
175
|
-
for (const step of steps) {
|
|
176
|
-
for (const [key] of Object.entries(step.params)) {
|
|
177
|
-
if (["scope", "target", "query", "filePath", "action"].includes(key)) {
|
|
178
|
-
params.add(key);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return Array.from(params);
|
|
183
|
-
}
|
|
184
|
-
async function generateTestFromTrajectory(trajectoryId, goal, steps) {
|
|
185
|
-
try {
|
|
186
|
-
await ensureTrajectorySchema();
|
|
187
|
-
const modifiedFiles = steps.filter((s) => s.params.filePath || s.params.target).map((s) => s.params.filePath || s.params.target).filter(Boolean);
|
|
188
|
-
if (modifiedFiles.length === 0) return null;
|
|
189
|
-
const framework = detectTestFramework();
|
|
190
|
-
const primaryFile = modifiedFiles[0];
|
|
191
|
-
const testCode = synthesizeTestCode(goal, primaryFile, modifiedFiles, framework);
|
|
192
|
-
const testFilePath = determineTestPath(primaryFile, framework);
|
|
193
|
-
const genTest = {
|
|
194
|
-
filePath: testFilePath,
|
|
195
|
-
framework,
|
|
196
|
-
code: testCode,
|
|
197
|
-
description: `Auto-generated from trajectory #${trajectoryId}: ${goal.substring(0, 80)}`
|
|
198
|
-
};
|
|
199
|
-
const db = await getDb();
|
|
200
|
-
db.run(
|
|
201
|
-
`INSERT INTO generated_tests (trajectory_id, file_path, test_framework, description, test_code)
|
|
202
|
-
VALUES (?, ?, ?, ?, ?)`,
|
|
203
|
-
[trajectoryId, testFilePath, framework, genTest.description, testCode]
|
|
204
|
-
);
|
|
205
|
-
saveDb();
|
|
206
|
-
const root = getProjectRoot();
|
|
207
|
-
const fullPath = path.resolve(root, testFilePath);
|
|
208
|
-
const dir = path.dirname(fullPath);
|
|
209
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
210
|
-
fs.writeFileSync(fullPath, testCode, "utf-8");
|
|
211
|
-
console.error(`[Trajectory] Generated test: ${testFilePath} from trajectory #${trajectoryId}`);
|
|
212
|
-
return genTest;
|
|
213
|
-
} catch (err) {
|
|
214
|
-
console.error(`[Trajectory] Test generation error: ${err}`);
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
async function generateTestFromTrajectoryId(trajectoryId) {
|
|
219
|
-
try {
|
|
220
|
-
await ensureTrajectorySchema();
|
|
221
|
-
const db = await getDb();
|
|
222
|
-
const stmt = db.prepare("SELECT id, goal, steps FROM trajectories WHERE id = ?");
|
|
223
|
-
stmt.bind([trajectoryId]);
|
|
224
|
-
if (!stmt.step()) {
|
|
225
|
-
stmt.free();
|
|
226
|
-
return `\u274C Trajectory #${trajectoryId} not found.`;
|
|
227
|
-
}
|
|
228
|
-
const row = stmt.getAsObject();
|
|
229
|
-
stmt.free();
|
|
230
|
-
const goal = row.goal;
|
|
231
|
-
const steps = JSON.parse(row.steps);
|
|
232
|
-
const result = await generateTestFromTrajectory(trajectoryId, goal, steps);
|
|
233
|
-
if (!result) {
|
|
234
|
-
return "\u26A0\uFE0F Could not generate test \u2014 no modified files found in trajectory.";
|
|
235
|
-
}
|
|
236
|
-
return [
|
|
237
|
-
`\u{1F9EA} **Test Generated** from trajectory #${trajectoryId}`,
|
|
238
|
-
`\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
|
|
239
|
-
``,
|
|
240
|
-
`\u{1F4C1} **File**: ${result.filePath}`,
|
|
241
|
-
`\u26A1 **Framework**: ${result.framework}`,
|
|
242
|
-
`\u{1F4DD} **Description**: ${result.description}`,
|
|
243
|
-
``,
|
|
244
|
-
`\`\`\`${result.framework === "jest" ? "typescript" : "javascript"}`,
|
|
245
|
-
result.code.substring(0, 800),
|
|
246
|
-
result.code.length > 800 ? "..." : "",
|
|
247
|
-
`\`\`\``,
|
|
248
|
-
``,
|
|
249
|
-
`\u{1F4A1} Test file has been written to disk. Run your test suite to verify.`
|
|
250
|
-
].filter(Boolean).join("\n");
|
|
251
|
-
} catch (err) {
|
|
252
|
-
return `\u274C Test generation failed: ${err}`;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
async function listGeneratedTests() {
|
|
256
|
-
try {
|
|
257
|
-
await ensureTrajectorySchema();
|
|
258
|
-
const db = await getDb();
|
|
259
|
-
const stmt = db.prepare(`
|
|
260
|
-
SELECT gt.*, t.goal FROM generated_tests gt
|
|
261
|
-
LEFT JOIN trajectories t ON t.id = gt.trajectory_id
|
|
262
|
-
ORDER BY gt.created_at DESC LIMIT 20
|
|
263
|
-
`);
|
|
264
|
-
const results = [];
|
|
265
|
-
while (stmt.step()) results.push(stmt.getAsObject());
|
|
266
|
-
stmt.free();
|
|
267
|
-
if (results.length === 0) {
|
|
268
|
-
return "\u{1F9EA} **No generated tests yet.** Tests are auto-generated from successful fix trajectories.";
|
|
269
|
-
}
|
|
270
|
-
const lines = [
|
|
271
|
-
"\u{1F9EA} **Generated Tests**",
|
|
272
|
-
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
273
|
-
""
|
|
274
|
-
];
|
|
275
|
-
for (const r of results) {
|
|
276
|
-
const time = new Date(r.created_at * 1e3).toLocaleString();
|
|
277
|
-
lines.push(` \u{1F4C4} **${r.file_path}**`);
|
|
278
|
-
lines.push(` \u26A1 ${r.test_framework} | \u{1F550} ${time}`);
|
|
279
|
-
if (r.goal) lines.push(` \u{1F3AF} ${r.goal.substring(0, 60)}`);
|
|
280
|
-
lines.push("");
|
|
281
|
-
}
|
|
282
|
-
return lines.join("\n");
|
|
283
|
-
} catch (err) {
|
|
284
|
-
return `Error: ${err}`;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
function detectTestFramework() {
|
|
288
|
-
const root = getProjectRoot();
|
|
289
|
-
try {
|
|
290
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf-8"));
|
|
291
|
-
if (pkg.devDependencies?.vitest) return "vitest";
|
|
292
|
-
if (pkg.devDependencies?.jest || pkg.devDependencies?.["@jest/globals"]) return "jest";
|
|
293
|
-
} catch {
|
|
294
|
-
}
|
|
295
|
-
if (fs.existsSync(path.join(root, "vitest.config.ts")) || fs.existsSync(path.join(root, "vitest.config.js"))) return "vitest";
|
|
296
|
-
if (fs.existsSync(path.join(root, "jest.config.ts")) || fs.existsSync(path.join(root, "jest.config.js"))) return "jest";
|
|
297
|
-
return "node";
|
|
298
|
-
}
|
|
299
|
-
function determineTestPath(filePath, _framework) {
|
|
300
|
-
const dir = path.dirname(filePath);
|
|
301
|
-
const basename = path.basename(filePath, path.extname(filePath));
|
|
302
|
-
return path.join(dir, `__tests__`, `${basename}.fix.test.ts`);
|
|
303
|
-
}
|
|
304
|
-
function synthesizeTestCode(goal, primaryFile, modifiedFiles, framework) {
|
|
305
|
-
const importPath = primaryFile.replace(/\.ts$/, "").replace(/\.js$/, "");
|
|
306
|
-
const describeBlock = `describe('Fix: ${goal.substring(0, 60)}', () => {`;
|
|
307
|
-
const testBody = `
|
|
308
|
-
it('should not regress the fix applied in ${path.basename(primaryFile)}', async () => {
|
|
309
|
-
// Auto-generated from Kuma trajectory \u2014 regression test
|
|
310
|
-
// Source file: ${primaryFile}
|
|
311
|
-
// Goal: ${goal}
|
|
312
|
-
// Modified files: ${modifiedFiles.slice(0, 3).join(", ")}
|
|
313
|
-
|
|
314
|
-
// TODO: Replace with actual test logic
|
|
315
|
-
// const { yourFunction } = await import('${importPath}');
|
|
316
|
-
// const result = yourFunction();
|
|
317
|
-
// expect(result).toBeDefined();
|
|
318
|
-
|
|
319
|
-
expect(true).toBe(true);
|
|
320
|
-
});
|
|
321
|
-
`;
|
|
322
|
-
const closeBlock = `});`;
|
|
323
|
-
switch (framework) {
|
|
324
|
-
case "vitest":
|
|
325
|
-
case "jest":
|
|
326
|
-
return [
|
|
327
|
-
`// ============================================================`,
|
|
328
|
-
`// AUTO-GENERATED REGRESSION TEST`,
|
|
329
|
-
`// Generated by Kuma Trajectory-to-Test Generator (Issue #28)`,
|
|
330
|
-
`// ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
331
|
-
`// Goal: ${goal}`,
|
|
332
|
-
`// Files: ${modifiedFiles.join(", ")}`,
|
|
333
|
-
`// ============================================================`,
|
|
334
|
-
``,
|
|
335
|
-
`import { describe, it, expect } from '@jest/globals';`,
|
|
336
|
-
``,
|
|
337
|
-
describeBlock,
|
|
338
|
-
testBody,
|
|
339
|
-
closeBlock,
|
|
340
|
-
``
|
|
341
|
-
].join("\n");
|
|
342
|
-
default:
|
|
343
|
-
return [
|
|
344
|
-
`// AUTO-GENERATED REGRESSION TEST`,
|
|
345
|
-
`// Goal: ${goal}`,
|
|
346
|
-
`// Files: ${modifiedFiles.join(", ")}`,
|
|
347
|
-
``,
|
|
348
|
-
`const assert = require('assert');`,
|
|
349
|
-
``,
|
|
350
|
-
describeBlock,
|
|
351
|
-
testBody.replace("import", "// ").replace("expect", "// expect"),
|
|
352
|
-
closeBlock,
|
|
353
|
-
``
|
|
354
|
-
].join("\n");
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
async function listDistilledSkills() {
|
|
358
|
-
try {
|
|
359
|
-
await ensureTrajectorySchema();
|
|
360
|
-
const db = await getDb();
|
|
361
|
-
const stmt = db.prepare(`
|
|
362
|
-
SELECT * FROM distilled_skills ORDER BY success_count DESC, last_used_at DESC LIMIT 20
|
|
363
|
-
`);
|
|
364
|
-
const results = [];
|
|
365
|
-
while (stmt.step()) results.push(stmt.getAsObject());
|
|
366
|
-
stmt.free();
|
|
367
|
-
if (results.length === 0) {
|
|
368
|
-
return "\u{1F9E0} **No distilled skills yet** \u2014 skills are auto-generated from successful trajectories.";
|
|
369
|
-
}
|
|
370
|
-
const lines = [
|
|
371
|
-
"\u{1F9E0} **Distilled Skills** \u2014 auto-generated from trajectories",
|
|
372
|
-
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
373
|
-
""
|
|
374
|
-
];
|
|
375
|
-
for (const s of results) {
|
|
376
|
-
const pattern = JSON.parse(s.pattern || "[]");
|
|
377
|
-
const patternStr = pattern.slice(0, 5).join(" \u2192 ");
|
|
378
|
-
lines.push(` \u26A1 **${s.name}**`);
|
|
379
|
-
lines.push(` Pattern: ${patternStr}${pattern.length > 5 ? ` (+${pattern.length - 5} more)` : ""}`);
|
|
380
|
-
lines.push(` Used ${s.success_count}x | Avg ${s.avg_duration_ms}ms`);
|
|
381
|
-
lines.push("");
|
|
382
|
-
}
|
|
383
|
-
return lines.join("\n");
|
|
384
|
-
} catch (err) {
|
|
385
|
-
return `Error: ${err}`;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
async function findSimilarTrajectories(errorPattern, limit = 5) {
|
|
389
|
-
try {
|
|
390
|
-
await ensureTrajectorySchema();
|
|
391
|
-
const db = await getDb();
|
|
392
|
-
const stmt = db.prepare(`
|
|
393
|
-
SELECT id, goal, steps, total_duration_ms, success_rate, complexity, created_at
|
|
394
|
-
FROM trajectories
|
|
395
|
-
WHERE steps LIKE ?
|
|
396
|
-
ORDER BY complexity DESC, created_at DESC
|
|
397
|
-
LIMIT ?
|
|
398
|
-
`);
|
|
399
|
-
stmt.bind([`%${errorPattern}%`, limit]);
|
|
400
|
-
const results = [];
|
|
401
|
-
while (stmt.step()) results.push(stmt.getAsObject());
|
|
402
|
-
stmt.free();
|
|
403
|
-
if (results.length === 0) return "";
|
|
404
|
-
const lines = [
|
|
405
|
-
"\u{1F504} **Similar Past Trajectories Found**",
|
|
406
|
-
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
407
|
-
""
|
|
408
|
-
];
|
|
409
|
-
for (const r of results) {
|
|
410
|
-
const successIcon = r.success_rate > 0.8 ? "\u2705" : "\u26A0\uFE0F";
|
|
411
|
-
lines.push(`${successIcon} #${r.id} \u2014 ${r.goal.substring(0, 60)}`);
|
|
412
|
-
lines.push(` Complexity: ${r.complexity} | Duration: ${Math.round(r.total_duration_ms / 1e3)}s | Rate: ${Math.round(r.success_rate * 100)}%`);
|
|
413
|
-
lines.push("");
|
|
414
|
-
}
|
|
415
|
-
return lines.join("\n");
|
|
416
|
-
} catch {
|
|
417
|
-
return "";
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
async function listTrajectories(limit = 10) {
|
|
421
|
-
try {
|
|
422
|
-
await ensureTrajectorySchema();
|
|
423
|
-
const db = await getDb();
|
|
424
|
-
const stmt = db.prepare(`
|
|
425
|
-
SELECT id, goal, total_duration_ms, success_rate, complexity, created_at
|
|
426
|
-
FROM trajectories ORDER BY created_at DESC LIMIT ?
|
|
427
|
-
`);
|
|
428
|
-
stmt.bind([limit]);
|
|
429
|
-
const results = [];
|
|
430
|
-
while (stmt.step()) results.push(stmt.getAsObject());
|
|
431
|
-
stmt.free();
|
|
432
|
-
if (results.length === 0) {
|
|
433
|
-
return "\u{1F4C8} **No trajectories recorded yet.** Trajectories are logged automatically as agents work.";
|
|
434
|
-
}
|
|
435
|
-
const lines = [
|
|
436
|
-
"\u{1F4C8} **Agent Trajectories**",
|
|
437
|
-
"\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501",
|
|
438
|
-
""
|
|
439
|
-
];
|
|
440
|
-
for (const r of results) {
|
|
441
|
-
const time = new Date(r.created_at * 1e3).toLocaleString();
|
|
442
|
-
const successIcon = r.success_rate > 0.8 ? "\u2705" : "\u26A0\uFE0F";
|
|
443
|
-
lines.push(` ${successIcon} #${r.id} \u2014 ${r.goal.substring(0, 50)} @ ${time}`);
|
|
444
|
-
lines.push(` ${Math.round(r.total_duration_ms / 1e3)}s | ${Math.round(r.success_rate * 100)}% success | complexity: ${r.complexity}`);
|
|
445
|
-
lines.push("");
|
|
446
|
-
}
|
|
447
|
-
return lines.join("\n");
|
|
448
|
-
} catch (err) {
|
|
449
|
-
return `Error: ${err}`;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
export {
|
|
453
|
-
findSimilarTrajectories,
|
|
454
|
-
generateTestFromTrajectory,
|
|
455
|
-
generateTestFromTrajectoryId,
|
|
456
|
-
listDistilledSkills,
|
|
457
|
-
listGeneratedTests,
|
|
458
|
-
listTrajectories,
|
|
459
|
-
recordTrajectory
|
|
460
|
-
};
|