@plumpslabs/kuma 2.3.20 → 2.3.23

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.
Files changed (39) hide show
  1. package/README.md +18 -0
  2. package/dist/index.js +10316 -380
  3. package/package.json +2 -2
  4. package/packages/ide/studio/dist/index.js +90 -9
  5. package/packages/ide/studio/public/index.html +528 -233
  6. package/dist/agentDetector-YOWQVJFR.js +0 -186
  7. package/dist/chunk-3BRBJZ7P.js +0 -1055
  8. package/dist/chunk-3OHYYXYN.js +0 -71
  9. package/dist/chunk-ABKE45T4.js +0 -1264
  10. package/dist/chunk-E2KFPEBT.js +0 -183
  11. package/dist/chunk-FKRSI5U5.js +0 -282
  12. package/dist/chunk-GFLSAXAH.js +0 -155
  13. package/dist/chunk-L7F67KUP.js +0 -172
  14. package/dist/chunk-LVKOGXLC.js +0 -658
  15. package/dist/chunk-PRUTTZBS.js +0 -1113
  16. package/dist/contextDigest-QB5XHPXE.js +0 -177
  17. package/dist/domainRules-QLPAQASB.js +0 -20
  18. package/dist/init-PL4XL662.js +0 -15
  19. package/dist/kumaAstValidator-CNM7FHYA.js +0 -150
  20. package/dist/kumaCheckpoint-J2LDQMEO.js +0 -207
  21. package/dist/kumaCodeScanner-J6B2EHGI.js +0 -563
  22. package/dist/kumaContractEngine-KX27T4N7.js +0 -305
  23. package/dist/kumaDb-4XZ5S2LH.js +0 -65
  24. package/dist/kumaDriftDetector-TOORILSZ.js +0 -237
  25. package/dist/kumaGotchas-XRGFFBTA.js +0 -151
  26. package/dist/kumaGraph-UMXZNGYF.js +0 -44
  27. package/dist/kumaMemory-FBJMV77G.js +0 -16
  28. package/dist/kumaMiner-XJETL7TL.js +0 -176
  29. package/dist/kumaPolicyEngine-2QDJDLM7.js +0 -311
  30. package/dist/kumaProgressiveContext-MWEDRXOH.js +0 -231
  31. package/dist/kumaSearch-PV4QTKE7.js +0 -321
  32. package/dist/kumaTrajectory-7NOAVNG2.js +0 -460
  33. package/dist/kumaVerifier-6YEGC77M.js +0 -265
  34. package/dist/kumaVisualize-264OEBGJ.js +0 -264
  35. package/dist/pathValidator-V4DC6U6Z.js +0 -22
  36. package/dist/safetyAudit-O45SPNTS.js +0 -12
  37. package/dist/safetyScore-TMMRD2MV.js +0 -333
  38. package/dist/sessionMemory-YPKVIOMV.js +0 -6
  39. 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
- };