@plumpslabs/kuma 2.3.30 → 2.3.31
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/dist/index.js +839 -571
- package/package.json +1 -1
- package/packages/ide/studio/dist/index.js +9 -5
- package/packages/ide/studio/public/index.html +45 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumpslabs/kuma",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.31",
|
|
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",
|
|
@@ -62,13 +62,13 @@ function getDashboardData() {
|
|
|
62
62
|
)
|
|
63
63
|
`),
|
|
64
64
|
nodes: queryJson(
|
|
65
|
-
`SELECT json_group_array(json_object('id',id,'name',name,'type',type,'file_path',file_path,'metadata',COALESCE(metadata,'{}'))) FROM nodes ORDER BY updated_at DESC`
|
|
65
|
+
`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 nodes ORDER BY updated_at DESC`
|
|
66
66
|
),
|
|
67
67
|
edges: queryJson(
|
|
68
68
|
`SELECT json_group_array(json_object('source',source_id,'target',target_id,'relation',type,'weight',weight)) FROM edges`
|
|
69
69
|
),
|
|
70
70
|
gotchas: queryJson(
|
|
71
|
-
`SELECT json_group_array(json_object('id',id,'file_path',file_path,'description',REPLACE(REPLACE(description,char(10),' '),char(13),''),'severity',severity,'workaround',REPLACE(REPLACE(COALESCE(workaround,''),char(10),' '),char(13),''))) FROM known_gotchas ORDER BY severity DESC`
|
|
71
|
+
`SELECT json_group_array(json_object('id',id,'file_path',file_path,'description',REPLACE(REPLACE(description,char(10),' '),char(13),''),'severity',severity,'workaround',REPLACE(REPLACE(COALESCE(workaround,''),char(10),' '),char(13),''),'added_by',COALESCE(added_by,'agent'),'created_at',created_at)) FROM known_gotchas ORDER BY severity DESC`
|
|
72
72
|
),
|
|
73
73
|
features: queryJson(
|
|
74
74
|
`SELECT json_group_array(json_object('id',id,'name',name,'metadata',COALESCE(metadata,'{}'))) FROM nodes WHERE type = 'feature' ORDER BY name`
|
|
@@ -80,9 +80,12 @@ function getDashboardData() {
|
|
|
80
80
|
}
|
|
81
81
|
function getNodeDetail(nodeId) {
|
|
82
82
|
const escaped = nodeId.replace(/'/g, "''");
|
|
83
|
-
const
|
|
83
|
+
const parts = nodeId.split("::");
|
|
84
|
+
const shortName = parts.pop()?.replace(/'/g, "''") || "";
|
|
85
|
+
const filePath = parts[0] === "gotcha" && parts.length >= 2 ? parts[1]?.replace(/'/g, "''") : "";
|
|
86
|
+
const scope = parts[0] === "research" && parts.length >= 2 ? parts.slice(1).join("::").replace(/'/g, "''") : "";
|
|
84
87
|
const node = queryJson(
|
|
85
|
-
`SELECT json_object('id',id,'name',name,'type',type,'file_path',file_path,'metadata',COALESCE(metadata,'{}'),'updated_at',updated_at) FROM nodes WHERE id = '${escaped}'`
|
|
88
|
+
`SELECT json_object('id',id,'name',name,'type',type,'file_path',COALESCE(file_path,''),'metadata',COALESCE(metadata,'{}'),'severity',COALESCE(severity,'medium'),'confidence',COALESCE(confidence,0.8),'last_verified_at',last_verified_at,'created_at',created_at,'updated_at',updated_at) FROM nodes WHERE id = '${escaped}'`
|
|
86
89
|
);
|
|
87
90
|
const nodeObj = Array.isArray(node) ? node[0] : node;
|
|
88
91
|
if (!nodeObj) return null;
|
|
@@ -106,8 +109,9 @@ function getNodeDetail(nodeId) {
|
|
|
106
109
|
return null;
|
|
107
110
|
}
|
|
108
111
|
}).filter(Boolean) : [];
|
|
112
|
+
const gotchaFilter = filePath ? `file_path = '${filePath}'` : `file_path = '${escaped}' OR file_path LIKE '%${shortName}%'`;
|
|
109
113
|
const rawGotcha = query(
|
|
110
|
-
`SELECT json_object('id',id,'description',REPLACE(REPLACE(description,char(10),' '),char(13),''),'severity',severity) FROM known_gotchas WHERE
|
|
114
|
+
`SELECT json_object('id',id,'file_path',file_path,'description',REPLACE(REPLACE(description,char(10),' '),char(13),''),'severity',severity,'workaround',REPLACE(REPLACE(COALESCE(workaround,''),char(10),' '),char(13),''),'added_by',COALESCE(added_by,'agent'),'created_at',created_at) FROM known_gotchas WHERE ${gotchaFilter}`
|
|
111
115
|
);
|
|
112
116
|
const gotchas = rawGotcha ? rawGotcha.split("\n").filter(Boolean).map((r) => {
|
|
113
117
|
try {
|
|
@@ -658,13 +658,49 @@ async function openNodeModal(nodeId) {
|
|
|
658
658
|
html += '<div class="modal-section">';
|
|
659
659
|
html += '<h3>Info</h3>';
|
|
660
660
|
html += '<div class="modal-kv"><span class="key">Type</span><span class="val"><span style="color:var(--accent)">'+escapeHtml(n.type)+'</span></span></div>';
|
|
661
|
+
html += '<div class="modal-kv"><span class="key">ID</span><span class="val" style="font-family:monospace;font-size:10px;color:var(--muted)">'+escapeHtml(n.id)+'</span></div>';
|
|
661
662
|
if (n.file_path) html += '<div class="modal-kv"><span class="key">Path</span><span class="val" style="color:var(--accent2)">'+escapeHtml(n.file_path)+'</span></div>';
|
|
662
|
-
if (
|
|
663
|
-
if (
|
|
664
|
-
if (
|
|
663
|
+
if (n.severity) html += '<div class="modal-kv"><span class="key">Severity</span><span class="val" style="color:'+(n.severity==='critical'?'var(--red)':n.severity==='high'?'var(--orange)':n.severity==='medium'?'var(--yellow)':'var(--green)')+'">'+escapeHtml(n.severity)+'</span></div>';
|
|
664
|
+
if (n.confidence !== undefined && n.confidence !== null) html += '<div class="modal-kv"><span class="key">Confidence</span><span class="val" style="color:var(--accent)">'+escapeHtml(String(n.confidence))+'</span></div>';
|
|
665
|
+
if (n.last_verified_at) html += '<div class="modal-kv"><span class="key">Last Verified</span><span class="val">'+new Date(n.last_verified_at*1000).toLocaleString()+'</span></div>';
|
|
666
|
+
if (n.created_at) html += '<div class="modal-kv"><span class="key">Created</span><span class="val">'+new Date(n.created_at*1000).toLocaleString()+'</span></div>';
|
|
665
667
|
if (n.updated_at) html += '<div class="modal-kv"><span class="key">Updated</span><span class="val">'+new Date(n.updated_at*1000).toLocaleString()+'</span></div>';
|
|
666
668
|
html += '</div>';
|
|
667
669
|
|
|
670
|
+
// ALL metadata fields — render every key dynamically
|
|
671
|
+
var metaKeys = Object.keys(meta);
|
|
672
|
+
if (metaKeys.length > 0) {
|
|
673
|
+
html += '<div class="modal-section">';
|
|
674
|
+
html += '<h3>Metadata ('+metaKeys.length+' fields)</h3>';
|
|
675
|
+
metaKeys.forEach(function(key) {
|
|
676
|
+
var val = meta[key];
|
|
677
|
+
if (val === null || val === undefined || val === '') return;
|
|
678
|
+
var display = '';
|
|
679
|
+
var color = 'var(--text)';
|
|
680
|
+
if (Array.isArray(val)) {
|
|
681
|
+
if (val.length === 0) return;
|
|
682
|
+
display = val.join(' → ');
|
|
683
|
+
color = 'var(--accent2)';
|
|
684
|
+
} else if (typeof val === 'object') {
|
|
685
|
+
display = JSON.stringify(val, null, 2);
|
|
686
|
+
color = 'var(--muted)';
|
|
687
|
+
} else if (typeof val === 'number') {
|
|
688
|
+
display = String(val);
|
|
689
|
+
color = 'var(--accent)';
|
|
690
|
+
} else if (key === 'severity' || key === 'risk') {
|
|
691
|
+
display = String(val);
|
|
692
|
+
color = val === 'critical' ? 'var(--red)' : val === 'high' ? 'var(--orange)' : val === 'medium' ? 'var(--yellow)' : 'var(--green)';
|
|
693
|
+
} else if (key === 'stale') {
|
|
694
|
+
display = val === 1 ? 'YES — needs heal' : 'No';
|
|
695
|
+
color = val === 1 ? 'var(--red)' : 'var(--green)';
|
|
696
|
+
} else {
|
|
697
|
+
display = String(val);
|
|
698
|
+
}
|
|
699
|
+
html += '<div class="modal-kv"><span class="key">'+escapeHtml(key)+'</span><span class="val" style="color:'+color+'">'+escapeHtml(display)+'</span></div>';
|
|
700
|
+
});
|
|
701
|
+
html += '</div>';
|
|
702
|
+
}
|
|
703
|
+
|
|
668
704
|
// Outgoing relations
|
|
669
705
|
if (outgoing.length) {
|
|
670
706
|
html += '<div class="modal-section"><h3>Outgoing ('+outgoing.length+')</h3>';
|
|
@@ -704,8 +740,12 @@ async function openNodeModal(nodeId) {
|
|
|
704
740
|
var got = typeof g === 'string' ? JSON.parse(g) : g;
|
|
705
741
|
html += '<div class="gotcha-item" style="border-color:var(--'+(got.severity==='critical'?'red':got.severity==='high'?'orange':got.severity==='medium'?'yellow':'green')+')">';
|
|
706
742
|
html += '<div class="desc">'+escapeHtml(got.description)+'</div>';
|
|
707
|
-
html += '<
|
|
708
|
-
html += '</
|
|
743
|
+
html += '<div style="display:flex;gap:8px;align-items:center;margin-top:4px">';
|
|
744
|
+
html += '<span class="sev-tag sev-'+got.severity+'">'+escapeHtml(got.severity)+'</span>';
|
|
745
|
+
if (got.workaround) html += '<span style="color:var(--accent2);font-size:10px">Workaround: '+escapeHtml(got.workaround)+'</span>';
|
|
746
|
+
if (got.added_by) html += '<span style="color:var(--muted);font-size:10px">by: '+escapeHtml(got.added_by)+'</span>';
|
|
747
|
+
if (got.created_at) html += '<span style="color:var(--muted);font-size:10px">'+new Date(got.created_at*1000).toLocaleDateString()+'</span>';
|
|
748
|
+
html += '</div></div>';
|
|
709
749
|
});
|
|
710
750
|
html += '</div>';
|
|
711
751
|
}
|