@plumpslabs/kuma 2.3.33 → 2.4.1
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 +50 -98
- package/dist/index.js +3708 -6492
- package/package.json +1 -1
- package/packages/ide/studio/dist/index.js +24 -10
- package/packages/ide/studio/public/index.html +23 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumpslabs/kuma",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "Safety-first context & orchestration engine for AI coding agents. MCP server with mandatory research pipeline, knowledge graph, impact analysis, decision memory, and safety guard — works with any MCP client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -154,12 +154,7 @@ async function getDashboardData() {
|
|
|
154
154
|
const stats = {
|
|
155
155
|
node_count: first(`SELECT COUNT(*) as c FROM nodes`, "c"),
|
|
156
156
|
edge_count: first(`SELECT COUNT(*) as c FROM edges`, "c"),
|
|
157
|
-
gotcha_count: first(`SELECT COUNT(*) as c FROM known_gotchas`, "c")
|
|
158
|
-
feature_count: first(`SELECT COUNT(*) as c FROM nodes WHERE type = 'feature'`, "c"),
|
|
159
|
-
health_score: first(
|
|
160
|
-
`SELECT COALESCE((SELECT score FROM health_snapshots ORDER BY created_at DESC LIMIT 1), 0) as c`,
|
|
161
|
-
"c"
|
|
162
|
-
)
|
|
157
|
+
gotcha_count: first(`SELECT COUNT(*) as c FROM known_gotchas`, "c")
|
|
163
158
|
};
|
|
164
159
|
const nodes = jsonRows(
|
|
165
160
|
`SELECT json_group_array(json_object('id',id,'name',name,'type',type,'file_path',file_path,'severity',COALESCE(severity,'medium'),'confidence',COALESCE(confidence,0.8),'metadata',COALESCE(metadata,'{}'))) FROM (SELECT * FROM nodes ORDER BY updated_at DESC)`
|
|
@@ -173,9 +168,28 @@ async function getDashboardData() {
|
|
|
173
168
|
const features = jsonRows(
|
|
174
169
|
`SELECT json_group_array(json_object('id',id,'name',name,'metadata',COALESCE(metadata,'{}'))) FROM (SELECT * FROM nodes WHERE type = 'feature' ORDER BY updated_at DESC)`
|
|
175
170
|
);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
171
|
+
let injectionCount = 0;
|
|
172
|
+
let injectionSavedMs = 0;
|
|
173
|
+
try {
|
|
174
|
+
const root = projectRootFromDb(dbPath);
|
|
175
|
+
const injPath = path.join(root, ".kuma", "injections.jsonl");
|
|
176
|
+
if (fs.existsSync(injPath)) {
|
|
177
|
+
const lines = fs.readFileSync(injPath, "utf-8").split("\n").filter(Boolean);
|
|
178
|
+
const now = Date.now();
|
|
179
|
+
for (const line of lines.slice(-200)) {
|
|
180
|
+
try {
|
|
181
|
+
const entry = JSON.parse(line);
|
|
182
|
+
const age = now - (entry.ts || 0);
|
|
183
|
+
if (age < 24 * 60 * 60 * 1e3) {
|
|
184
|
+
injectionCount++;
|
|
185
|
+
injectionSavedMs += entry.saved_ms || 5e3;
|
|
186
|
+
}
|
|
187
|
+
} catch {
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
179
193
|
const sessionMetrics = readSessionMetrics(dbPath);
|
|
180
194
|
const verifTotal = first(`SELECT COUNT(*) as c FROM verifications`, "c");
|
|
181
195
|
const verifPassed = first(`SELECT COUNT(*) as c FROM verifications WHERE passed = 1`, "c");
|
|
@@ -205,7 +219,7 @@ async function getDashboardData() {
|
|
|
205
219
|
recentSessions
|
|
206
220
|
};
|
|
207
221
|
const staleness = detectStaleNodes(db, dbPath);
|
|
208
|
-
return { stats, nodes, edges, gotchas,
|
|
222
|
+
return { stats, nodes, edges, gotchas, efficiency, staleness, injections: { count: injectionCount, savedMs: injectionSavedMs, savedFormatted: Math.round(injectionSavedMs / 6e4) + " min" } };
|
|
209
223
|
} finally {
|
|
210
224
|
db.close();
|
|
211
225
|
}
|
|
@@ -250,7 +250,7 @@ header .status .dot.off { background: var(--red); }
|
|
|
250
250
|
<div class="tabs">
|
|
251
251
|
<div class="tab active" data-tab="features" title="Features"><i data-lucide="star" style="width:12px;height:12px"></i><span class="tab-label">Features</span></div>
|
|
252
252
|
<div class="tab" data-tab="gotchas" title="Gotchas"><i data-lucide="alert-triangle" style="width:12px;height:12px"></i><span class="tab-label">Gotchas</span></div>
|
|
253
|
-
<div class="tab" data-tab="
|
|
253
|
+
<div class="tab" data-tab="injections" title="Shadow Memory"><i data-lucide="zap" style="width:12px;height:12px"></i><span class="tab-label">Injections</span></div>
|
|
254
254
|
<div class="tab" data-tab="efficiency" title="Efficiency"><i data-lucide="zap" style="width:12px;height:12px"></i><span class="tab-label">Efficiency</span></div>
|
|
255
255
|
<div class="tab" data-tab="staleness" title="Staleness"><i data-lucide="activity" style="width:12px;height:12px"></i><span class="tab-label">Staleness</span></div>
|
|
256
256
|
<div class="tab" data-tab="activity" title="Activity"><i data-lucide="bar-chart-3" style="width:12px;height:12px"></i><span class="tab-label">Activity</span></div>
|
|
@@ -337,7 +337,7 @@ async function init() {
|
|
|
337
337
|
renderGraph(data);
|
|
338
338
|
renderFeatures(data);
|
|
339
339
|
renderGotchas(data);
|
|
340
|
-
|
|
340
|
+
renderInjections(data);
|
|
341
341
|
renderEfficiency(data);
|
|
342
342
|
renderStaleness(data);
|
|
343
343
|
renderActivity(data);
|
|
@@ -355,15 +355,15 @@ function showError(msg) {
|
|
|
355
355
|
|
|
356
356
|
function renderStats(data) {
|
|
357
357
|
var s = data.stats || {};
|
|
358
|
-
var
|
|
359
|
-
var
|
|
358
|
+
var inj = data.injections || {};
|
|
359
|
+
var savedMin = inj.savedFormatted || '0 min';
|
|
360
360
|
document.getElementById("stats-bar").innerHTML =
|
|
361
361
|
'<div class="stat"><span class="num">'+(s.node_count||0)+'</span><span class="lbl">nodes</span></div>'+
|
|
362
362
|
'<div class="stat"><span class="num">'+(s.edge_count||0)+'</span><span class="lbl">edges</span></div>'+
|
|
363
|
-
'<div class="stat"><span class="num" style="color:var(--accent-bright)">'+(s.feature_count||0)+'</span><span class="lbl">features</span></div>'+
|
|
364
363
|
'<div class="stat"><span class="num">'+(s.gotcha_count||0)+'</span><span class="lbl">gotchas</span></div>'+
|
|
365
364
|
'<div class="stat"><span class="num" style="color:var(--accent)">'+currentDbSize+'</span><span class="lbl">kuma.db</span></div>'+
|
|
366
|
-
'<div class="stat"><span class="num" style="color:
|
|
365
|
+
'<div class="stat"><span class="num" style="color:var(--blue)">'+inj.count+'</span><span class="lbl">injections</span></div>'+
|
|
366
|
+
'<div class="stat"><span class="num" style="font-size:13px;color:var(--green)">'+savedMin+'</span><span class="lbl">time saved</span></div>';
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
function truncateLabel(name, maxLen) {
|
|
@@ -791,7 +791,7 @@ async function refetch() {
|
|
|
791
791
|
if (status.ok) { dot.className = 'dot on'; txt.textContent = status.project || 'connected'; } else { dot.className = 'dot off'; txt.textContent = 'no kuma.db found'; }
|
|
792
792
|
var data = await fetch(API+'/dashboard').then(function(r){return r.json()});
|
|
793
793
|
if (data.error) { showError(data.error); return; }
|
|
794
|
-
renderStats(data); renderGraph(data);
|
|
794
|
+
renderStats(data); renderGraph(data); renderGotchas(data); renderEfficiency(data); renderStaleness(data); renderInjections(data);
|
|
795
795
|
lucide.createIcons();
|
|
796
796
|
} catch(e) { showError('Refetch failed: ' + e.message); }
|
|
797
797
|
btn.innerHTML = '<i data-lucide="refresh-cw" style="width:13px;height:13px;vertical-align:middle;margin-right:3px"></i> Refetch';
|
|
@@ -809,7 +809,7 @@ function setupTabs(){
|
|
|
809
809
|
content.innerHTML =
|
|
810
810
|
'<div class="panel active" id="panel-features"><div class="empty">Loading...</div></div>' +
|
|
811
811
|
'<div class="panel" id="panel-gotchas"><div class="empty">Loading...</div></div>' +
|
|
812
|
-
'<div class="panel" id="panel-
|
|
812
|
+
'<div class="panel" id="panel-injections"><div class="empty">Loading...</div></div>' +
|
|
813
813
|
'<div class="panel" id="panel-efficiency"><div class="empty">Loading...</div></div>' +
|
|
814
814
|
'<div class="panel" id="panel-staleness"><div class="empty">Loading...</div></div>' +
|
|
815
815
|
'<div class="panel" id="panel-activity"><div class="empty">Loading...</div></div>';
|
|
@@ -864,17 +864,22 @@ function renderGotchas(data){
|
|
|
864
864
|
lucide.createIcons();
|
|
865
865
|
}
|
|
866
866
|
|
|
867
|
-
function
|
|
868
|
-
var
|
|
869
|
-
var el = document.getElementById("panel-
|
|
867
|
+
function renderInjections(data) {
|
|
868
|
+
var inj = data.injections || {};
|
|
869
|
+
var el = document.getElementById("panel-injections");
|
|
870
870
|
if(!el) return;
|
|
871
|
-
if(!
|
|
872
|
-
el.innerHTML =
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
871
|
+
if(!inj.count){el.innerHTML='<div class="empty">No shadow memory injections yet. Enable hooks via `kuma init --claude`.</div>';return;}
|
|
872
|
+
el.innerHTML = '<div class="section-title">Shadow Memory (24h)</div>'+
|
|
873
|
+
'<div class="efficiency-grid">'+
|
|
874
|
+
'<div class="eff-item"><span class="eff-num">'+inj.count+'</span><span class="eff-lbl">Injections</span></div>'+
|
|
875
|
+
'<div class="eff-item"><span class="eff-num" style="color:var(--green)">'+inj.savedFormatted+'</span><span class="eff-lbl">Time Saved</span></div>'+
|
|
876
|
+
'<div class="eff-item"><span class="eff-num" style="color:var(--blue)">~'+Math.round(inj.savedMs/5000)+'x</span><span class="eff-lbl">Multiplier</span></div>'+
|
|
877
|
+
'</div>'+
|
|
878
|
+
'<div class="section-title" style="margin-top:16px">Auto-Inject Hooks</div>'+
|
|
879
|
+
'<div class="gotcha-item">Pre-Edit: <code>kuma hook pre-edit</code> — injects gotchas + decisions + history</div>'+
|
|
880
|
+
'<div class="gotcha-item">Pre-Bash: <code>kuma hook pre-bash</code> — injects command-triggered gotchas</div>'+
|
|
881
|
+
'<div class="gotcha-item">Dedupe: files not re-injected within 15 min (I5)</div>'+
|
|
882
|
+
'<div class="gotcha-item">Loop Capture: 4+ edits within 30 min auto-records a gotcha (I3)</div>';
|
|
878
883
|
}
|
|
879
884
|
|
|
880
885
|
// ============ EFFICIENCY PANEL (GAP 1) ============
|