@plumpslabs/kuma 2.3.0 → 2.3.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.
@@ -1,304 +0,0 @@
1
- import {
2
- getKumaDir
3
- } from "./chunk-IXMWW5WA.js";
4
-
5
- // src/engine/kumaDb.ts
6
- import initSqlJs from "sql.js";
7
- import fs from "fs";
8
- import path from "path";
9
- var DB_FILENAME = "kuma.db";
10
- var dbInstance = null;
11
- var initPromise = null;
12
- async function getDb() {
13
- if (dbInstance) return dbInstance;
14
- if (initPromise) return initPromise;
15
- initPromise = initDb();
16
- return initPromise;
17
- }
18
- async function initDb() {
19
- const SQL = await initSqlJs();
20
- const kumaDir = getKumaDir();
21
- const dbPath = path.join(kumaDir, DB_FILENAME);
22
- if (!fs.existsSync(kumaDir)) {
23
- fs.mkdirSync(kumaDir, { recursive: true });
24
- }
25
- let db;
26
- if (fs.existsSync(dbPath)) {
27
- const buffer = fs.readFileSync(dbPath);
28
- db = new SQL.Database(buffer);
29
- } else {
30
- db = new SQL.Database();
31
- }
32
- db.run("PRAGMA journal_mode=WAL");
33
- db.run("PRAGMA synchronous=NORMAL");
34
- createSchema(db);
35
- saveDb(db);
36
- dbInstance = db;
37
- return db;
38
- }
39
- function saveDb(db) {
40
- const d = db ?? dbInstance;
41
- if (!d) return;
42
- try {
43
- const kumaDir = getKumaDir();
44
- const dbPath = path.join(kumaDir, DB_FILENAME);
45
- const data = d.export();
46
- const buffer = Buffer.from(data);
47
- fs.writeFileSync(dbPath, buffer);
48
- } catch (err) {
49
- console.error(`[KumaDB] Failed to save database: ${err}`);
50
- }
51
- }
52
- function createSchema(db) {
53
- db.run(`
54
- CREATE TABLE IF NOT EXISTS nodes (
55
- id TEXT PRIMARY KEY,
56
- type TEXT NOT NULL CHECK(type IN ('function','file','api_route','db_table','test','class','interface','type','module','variable')),
57
- name TEXT NOT NULL,
58
- file_path TEXT,
59
- metadata TEXT DEFAULT '{}',
60
- created_at INTEGER NOT NULL DEFAULT (strftime('%s','now')),
61
- updated_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
62
- )
63
- `);
64
- db.run(`
65
- CREATE TABLE IF NOT EXISTS edges (
66
- id INTEGER PRIMARY KEY AUTOINCREMENT,
67
- source_id TEXT NOT NULL REFERENCES nodes(id),
68
- target_id TEXT NOT NULL REFERENCES nodes(id),
69
- type TEXT NOT NULL CHECK(type IN ('calls','imports','defines','tests','routes','implements','extends','depends_on','owns','modified_by')),
70
- weight REAL DEFAULT 1.0,
71
- metadata TEXT DEFAULT '{}',
72
- created_at INTEGER NOT NULL DEFAULT (strftime('%s','now')),
73
- UNIQUE(source_id, target_id, type)
74
- )
75
- `);
76
- db.run(`
77
- CREATE TABLE IF NOT EXISTS sessions (
78
- id INTEGER PRIMARY KEY AUTOINCREMENT,
79
- started_at INTEGER NOT NULL,
80
- ended_at INTEGER,
81
- goal TEXT,
82
- tool_calls INTEGER DEFAULT 0,
83
- edits INTEGER DEFAULT 0,
84
- rollbacks INTEGER DEFAULT 0,
85
- failures INTEGER DEFAULT 0,
86
- safety_score INTEGER
87
- )
88
- `);
89
- db.run(`
90
- CREATE TABLE IF NOT EXISTS tool_calls (
91
- id INTEGER PRIMARY KEY AUTOINCREMENT,
92
- session_id INTEGER REFERENCES sessions(id),
93
- tool_name TEXT NOT NULL,
94
- params TEXT,
95
- success INTEGER DEFAULT 1,
96
- duration_ms INTEGER,
97
- created_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
98
- )
99
- `);
100
- db.run(`
101
- CREATE TABLE IF NOT EXISTS experiences (
102
- id INTEGER PRIMARY KEY AUTOINCREMENT,
103
- tool_name TEXT NOT NULL,
104
- params_hash TEXT NOT NULL,
105
- success INTEGER NOT NULL DEFAULT 1,
106
- duration_ms INTEGER,
107
- error_pattern TEXT,
108
- context_file TEXT,
109
- context_action TEXT,
110
- created_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
111
- )
112
- `);
113
- db.run(`
114
- CREATE TABLE IF NOT EXISTS experience_patterns (
115
- id INTEGER PRIMARY KEY AUTOINCREMENT,
116
- antecedent_tool TEXT NOT NULL,
117
- antecedent_hash TEXT NOT NULL,
118
- consequent_tool TEXT NOT NULL,
119
- confidence REAL DEFAULT 0.0,
120
- count INTEGER DEFAULT 1,
121
- avg_duration_ms INTEGER DEFAULT 0,
122
- success_rate REAL DEFAULT 1.0,
123
- last_seen_at INTEGER NOT NULL DEFAULT (strftime('%s','now')),
124
- UNIQUE(antecedent_tool, antecedent_hash, consequent_tool)
125
- )
126
- `);
127
- try {
128
- db.run(`
129
- CREATE VIRTUAL TABLE IF NOT EXISTS nodes_fts USING fts5(
130
- name,
131
- metadata,
132
- content='nodes',
133
- content_rowid='rowid'
134
- )
135
- `);
136
- } catch {
137
- console.warn("[KumaDB] FTS5 not available, full-text search disabled");
138
- }
139
- db.run(`CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type)`);
140
- db.run(`CREATE INDEX IF NOT EXISTS idx_nodes_name ON nodes(name)`);
141
- db.run(`CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source_id)`);
142
- db.run(`CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target_id)`);
143
- db.run(`CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type)`);
144
- db.run(`CREATE INDEX IF NOT EXISTS idx_tool_calls_session ON tool_calls(session_id)`);
145
- db.run(`CREATE INDEX IF NOT EXISTS idx_tool_calls_created ON tool_calls(created_at)`);
146
- db.run(`CREATE INDEX IF NOT EXISTS idx_experiences_tool ON experiences(tool_name)`);
147
- db.run(`CREATE INDEX IF NOT EXISTS idx_experiences_hash ON experiences(params_hash)`);
148
- db.run(`CREATE INDEX IF NOT EXISTS idx_experiences_created ON experiences(created_at)`);
149
- db.run(`CREATE INDEX IF NOT EXISTS idx_patterns_antecedent ON experience_patterns(antecedent_tool)`);
150
- db.run(`CREATE INDEX IF NOT EXISTS idx_patterns_confidence ON experience_patterns(confidence DESC)`);
151
- db.run(`
152
- CREATE TABLE IF NOT EXISTS research_cache (
153
- id INTEGER PRIMARY KEY AUTOINCREMENT,
154
- scope TEXT NOT NULL UNIQUE,
155
- version INTEGER DEFAULT 1,
156
- confidence REAL DEFAULT 0.0,
157
- content_hash TEXT,
158
- record TEXT NOT NULL,
159
- created_at INTEGER NOT NULL DEFAULT (strftime('%s','now')),
160
- updated_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
161
- )
162
- `);
163
- db.run(`
164
- CREATE TABLE IF NOT EXISTS change_log (
165
- id INTEGER PRIMARY KEY AUTOINCREMENT,
166
- session_id INTEGER REFERENCES sessions(id),
167
- file_path TEXT NOT NULL,
168
- change_type TEXT NOT NULL CHECK(change_type IN ('modified','created','deleted','renamed')),
169
- symbol TEXT,
170
- diff_summary TEXT,
171
- git_commit_hash TEXT,
172
- created_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
173
- )
174
- `);
175
- db.run(`
176
- CREATE TABLE IF NOT EXISTS health_snapshots (
177
- id INTEGER PRIMARY KEY AUTOINCREMENT,
178
- score INTEGER NOT NULL,
179
- risk_level TEXT NOT NULL DEFAULT 'low',
180
- checks TEXT DEFAULT '[]',
181
- summary TEXT,
182
- created_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
183
- )
184
- `);
185
- db.run(`CREATE INDEX IF NOT EXISTS idx_research_scope ON research_cache(scope)`);
186
- db.run(`CREATE INDEX IF NOT EXISTS idx_research_updated ON research_cache(updated_at)`);
187
- db.run(`CREATE INDEX IF NOT EXISTS idx_change_log_session ON change_log(session_id)`);
188
- db.run(`CREATE INDEX IF NOT EXISTS idx_change_log_file ON change_log(file_path)`);
189
- db.run(`CREATE INDEX IF NOT EXISTS idx_change_log_created ON change_log(created_at)`);
190
- db.run(`CREATE INDEX IF NOT EXISTS idx_health_created ON health_snapshots(created_at)`);
191
- }
192
- async function getResearchCache(scope) {
193
- try {
194
- const db = await getDb();
195
- const stmt = db.prepare("SELECT record, content_hash, updated_at FROM research_cache WHERE scope = ?");
196
- stmt.bind([scope]);
197
- if (stmt.step()) {
198
- const row = stmt.getAsObject();
199
- stmt.free();
200
- return row.record;
201
- }
202
- stmt.free();
203
- return null;
204
- } catch {
205
- return null;
206
- }
207
- }
208
- async function saveResearchCache(scope, record, contentHash, confidence) {
209
- try {
210
- const db = await getDb();
211
- const stmt = db.prepare("SELECT id FROM research_cache WHERE scope = ?");
212
- stmt.bind([scope]);
213
- const hasExisting = stmt.step();
214
- stmt.free();
215
- if (hasExisting) {
216
- db.run(
217
- `UPDATE research_cache SET record = ?, content_hash = COALESCE(?, content_hash), confidence = COALESCE(?, confidence), version = version + 1, updated_at = strftime('%s','now') WHERE scope = ?`,
218
- [record, contentHash || null, confidence ?? null, scope]
219
- );
220
- } else {
221
- db.run(
222
- `INSERT INTO research_cache (scope, record, content_hash, confidence, version) VALUES (?, ?, ?, ?, 1)`,
223
- [scope, record, contentHash || null, confidence ?? null]
224
- );
225
- }
226
- saveDb();
227
- } catch (err) {
228
- console.error(`[KumaDB] Failed to save research cache: ${err}`);
229
- }
230
- }
231
- async function recordChange(entry) {
232
- try {
233
- const db = await getDb();
234
- db.run(
235
- `INSERT INTO change_log (session_id, file_path, change_type, symbol, diff_summary, git_commit_hash) VALUES (?, ?, ?, ?, ?, ?)`,
236
- [entry.sessionId ?? null, entry.filePath, entry.changeType, entry.symbol ?? null, entry.diffSummary ?? null, entry.gitCommitHash ?? null]
237
- );
238
- saveDb();
239
- } catch (err) {
240
- console.error(`[KumaDB] Failed to record change: ${err}`);
241
- }
242
- }
243
- async function getChanges(params) {
244
- try {
245
- const db = await getDb();
246
- const { sessionId, filePath, since, limit = 50 } = params;
247
- let sql = `SELECT cl.*, s.goal FROM change_log cl LEFT JOIN sessions s ON s.id = cl.session_id WHERE 1=1`;
248
- const bind = [];
249
- if (sessionId) {
250
- sql += ` AND cl.session_id = ?`;
251
- bind.push(sessionId);
252
- }
253
- if (filePath) {
254
- sql += ` AND cl.file_path LIKE ?`;
255
- bind.push(`%${filePath}%`);
256
- }
257
- if (since) {
258
- sql += ` AND cl.created_at >= ?`;
259
- bind.push(since);
260
- }
261
- sql += ` ORDER BY cl.created_at DESC LIMIT ?`;
262
- bind.push(limit);
263
- const stmt = db.prepare(sql);
264
- stmt.bind(bind);
265
- const results = [];
266
- while (stmt.step()) {
267
- results.push(stmt.getAsObject());
268
- }
269
- stmt.free();
270
- if (results.length === 0) return "No changes found.";
271
- const lines = [`\u{1F4CB} **Change Log** \u2014 ${results.length} change(s)`];
272
- for (const r of results) {
273
- const icon = r.change_type === "deleted" ? "\u274C" : r.change_type === "created" ? "\u2728" : "\u{1F4DD}";
274
- lines.push(` ${icon} **${r.file_path}** (${r.change_type})`);
275
- if (r.symbol) lines.push(` Symbol: ${r.symbol}`);
276
- if (r.goal) lines.push(` Goal: ${r.goal}`);
277
- }
278
- return lines.join("\n");
279
- } catch (err) {
280
- return `Error getting changes: ${err}`;
281
- }
282
- }
283
- async function saveHealthSnapshot(score, riskLevel, checks, summary) {
284
- try {
285
- const db = await getDb();
286
- db.run(
287
- `INSERT INTO health_snapshots (score, risk_level, checks, summary) VALUES (?, ?, ?, ?)`,
288
- [score, riskLevel, checks, summary]
289
- );
290
- saveDb();
291
- } catch (err) {
292
- console.error(`[KumaDB] Failed to save health snapshot: ${err}`);
293
- }
294
- }
295
-
296
- export {
297
- getDb,
298
- saveDb,
299
- getResearchCache,
300
- saveResearchCache,
301
- recordChange,
302
- getChanges,
303
- saveHealthSnapshot
304
- };
@@ -1,19 +0,0 @@
1
- import {
2
- getChanges,
3
- getDb,
4
- getResearchCache,
5
- recordChange,
6
- saveDb,
7
- saveHealthSnapshot,
8
- saveResearchCache
9
- } from "./chunk-6NEMSUKP.js";
10
- import "./chunk-IXMWW5WA.js";
11
- export {
12
- getChanges,
13
- getDb,
14
- getResearchCache,
15
- recordChange,
16
- saveDb,
17
- saveHealthSnapshot,
18
- saveResearchCache
19
- };