@plumpslabs/kuma 2.3.6 → 2.3.8

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.
@@ -0,0 +1,248 @@
1
+ import {
2
+ getDb
3
+ } from "./chunk-NAM7SCBT.js";
4
+ import "./chunk-E2KFPEBT.js";
5
+
6
+ // src/engine/kumaVisualize.ts
7
+ async function visualizeGraph(options = {}) {
8
+ const {
9
+ type = "flowchart",
10
+ scope,
11
+ maxNodes = 30,
12
+ // depth unused: kept for API consistency
13
+ format = "mermaid"
14
+ } = options;
15
+ try {
16
+ const db = await getDb();
17
+ let nodeSql = `SELECT id, type, name, file_path FROM nodes WHERE 1=1`;
18
+ const nodeBind = [];
19
+ if (scope) {
20
+ nodeSql += ` AND (name LIKE ? OR file_path LIKE ? OR id LIKE ?)`;
21
+ nodeBind.push(`%${scope}%`, `%${scope}%`, `%${scope}%`);
22
+ }
23
+ nodeSql += ` ORDER BY updated_at DESC LIMIT ?`;
24
+ nodeBind.push(maxNodes);
25
+ const nodeStmt = db.prepare(nodeSql);
26
+ nodeStmt.bind(nodeBind);
27
+ const nodes = [];
28
+ while (nodeStmt.step()) {
29
+ nodes.push(nodeStmt.getAsObject());
30
+ }
31
+ nodeStmt.free();
32
+ if (nodes.length === 0) {
33
+ return format === "mermaid" ? "```mermaid\nflowchart TD\n Start[Empty Graph \u2014 No nodes found]\n```" : "\u{1F4ED} **Empty Graph** \u2014 No nodes found to visualize.";
34
+ }
35
+ const nodeIds = nodes.map((n) => n.id);
36
+ const edgeSql = `
37
+ SELECT e.source_id, e.target_id, e.type, e.weight,
38
+ sn.name AS source_name, tn.name AS target_name
39
+ FROM edges e
40
+ JOIN nodes sn ON sn.id = e.source_id
41
+ JOIN nodes tn ON tn.id = e.target_id
42
+ WHERE (e.source_id IN (${nodeIds.map(() => "?").join(",")})
43
+ OR e.target_id IN (${nodeIds.map(() => "?").join(",")}))
44
+ AND e.source_id != e.target_id
45
+ ORDER BY e.weight DESC
46
+ LIMIT 100
47
+ `;
48
+ const edgeBind = [...nodeIds, ...nodeIds];
49
+ const edgeStmt = db.prepare(edgeSql);
50
+ edgeStmt.bind(edgeBind);
51
+ const edges = [];
52
+ while (edgeStmt.step()) {
53
+ edges.push(edgeStmt.getAsObject());
54
+ }
55
+ edgeStmt.free();
56
+ switch (type) {
57
+ case "flowchart":
58
+ return formatFlowchart(nodes, edges, format);
59
+ case "dependency":
60
+ return formatDependencyGraph(nodes, edges, format);
61
+ case "mindmap":
62
+ return formatMindMap(nodes, edges, format);
63
+ default:
64
+ return formatFlowchart(nodes, edges, format);
65
+ }
66
+ } catch (err) {
67
+ return `Error generating visualization: ${err}`;
68
+ }
69
+ }
70
+ function formatFlowchart(nodes, edges, _format) {
71
+ void _format;
72
+ const lines = ["```mermaid", "flowchart TD"];
73
+ for (const node of nodes) {
74
+ const id = sanitizeId(node.id);
75
+ const name = truncate(node.name, 30);
76
+ const nodeType = node.type;
77
+ const shape = getNodeShape(nodeType);
78
+ if (shape) {
79
+ lines.push(` ${id}${shape}${name}${reverseShape(shape)}`);
80
+ } else {
81
+ lines.push(` ${id}[${name}]`);
82
+ }
83
+ }
84
+ for (const edge of edges) {
85
+ const sourceId = sanitizeId(edge.source_id);
86
+ const targetId = sanitizeId(edge.target_id);
87
+ const edgeType = edge.type;
88
+ void edge.weight;
89
+ const label = truncate(edgeType, 15);
90
+ const edgeStyle = getEdgeStyle(edgeType);
91
+ lines.push(` ${sourceId}${edgeStyle}|${label}|${targetId}`);
92
+ }
93
+ lines.push("```");
94
+ return lines.join("\n");
95
+ }
96
+ function formatDependencyGraph(nodes, edges, _format) {
97
+ void _format;
98
+ const lines = ["```mermaid", "flowchart LR"];
99
+ const grouped = /* @__PURE__ */ new Map();
100
+ for (const node of nodes) {
101
+ const type = node.type || "unknown";
102
+ if (!grouped.has(type)) grouped.set(type, []);
103
+ grouped.get(type).push(node);
104
+ }
105
+ let subgraphIndex = 0;
106
+ for (const [type, typeNodes] of grouped) {
107
+ if (typeNodes.length < 1) continue;
108
+ lines.push(` subgraph ${type.toUpperCase()}[${type.toUpperCase()}]`);
109
+ for (const node of typeNodes) {
110
+ const id = sanitizeId(node.id);
111
+ const name = truncate(node.name, 25);
112
+ lines.push(` ${id}(${name})`);
113
+ }
114
+ lines.push(" end");
115
+ subgraphIndex++;
116
+ }
117
+ for (const edge of edges) {
118
+ const sourceId = sanitizeId(edge.source_id);
119
+ const targetId = sanitizeId(edge.target_id);
120
+ const edgeType = edge.type;
121
+ const style = getEdgeStyle(edgeType);
122
+ lines.push(` ${sourceId}${style}|${edgeType}|${targetId}`);
123
+ }
124
+ lines.push("```");
125
+ return lines.join("\n");
126
+ }
127
+ function formatMindMap(nodes, edges, _format) {
128
+ void _format;
129
+ const lines = ["```mermaid", "mindmap"];
130
+ const hasIncoming = /* @__PURE__ */ new Set();
131
+ for (const edge of edges) {
132
+ hasIncoming.add(edge.target_id);
133
+ }
134
+ const roots = nodes.filter((n) => !hasIncoming.has(n.id));
135
+ if (roots.length === 0 && nodes.length > 0) {
136
+ const root = nodes[0];
137
+ lines.push(` root((${truncate(root.name, 25)}))`);
138
+ for (const node of nodes.slice(1)) {
139
+ lines.push(` ${sanitizeId(node.id)}(${truncate(node.name, 25)})`);
140
+ }
141
+ } else {
142
+ for (const root of roots.slice(0, 3)) {
143
+ lines.push(` root((${truncate(root.name, 25)}))`);
144
+ }
145
+ const others = nodes.filter((n) => !roots.includes(n));
146
+ for (const node of others.slice(0, 10)) {
147
+ const parent = edges.find((e) => e.source_id === node.id || e.target_id === node.id);
148
+ const indent = parent ? " " : " ";
149
+ lines.push(`${indent}${sanitizeId(node.id)}(${truncate(node.name, 25)})`);
150
+ }
151
+ }
152
+ lines.push("```");
153
+ return lines.join("\n");
154
+ }
155
+ function sanitizeId(id) {
156
+ const safe = id.replace(/[^a-zA-Z0-9_]/g, "_").replace(/^(\d)/, "n$1").substring(0, 40);
157
+ return safe || "n0";
158
+ }
159
+ function truncate(str, maxLen) {
160
+ if (str.length <= maxLen) return str;
161
+ return str.substring(0, maxLen - 3) + "...";
162
+ }
163
+ function getNodeShape(type) {
164
+ switch (type) {
165
+ case "function":
166
+ return "([";
167
+ case "file":
168
+ return "[";
169
+ case "test":
170
+ return "{";
171
+ case "api_route":
172
+ return "[[";
173
+ case "db_table":
174
+ return ">";
175
+ // database shape approximation
176
+ case "class":
177
+ return "[";
178
+ case "interface":
179
+ return "(";
180
+ case "module":
181
+ return "[";
182
+ case "variable":
183
+ return "(";
184
+ default:
185
+ return "[";
186
+ }
187
+ }
188
+ function reverseShape(shape) {
189
+ const map = {
190
+ "([": "])",
191
+ "[": "]",
192
+ "{": "}",
193
+ "[[": "]]",
194
+ ">": "<]",
195
+ "(": ")"
196
+ };
197
+ return map[shape] || "]";
198
+ }
199
+ function getEdgeStyle(type) {
200
+ switch (type) {
201
+ case "calls":
202
+ return " ==> ";
203
+ case "imports":
204
+ return " -.-> ";
205
+ case "defines":
206
+ return " --- ";
207
+ case "tests":
208
+ return " -.-> ";
209
+ case "routes":
210
+ return " ==> ";
211
+ case "implements":
212
+ return " -.-> ";
213
+ case "extends":
214
+ return " ==> ";
215
+ case "depends_on":
216
+ return " -.-> ";
217
+ case "owns":
218
+ return " --- ";
219
+ case "modified_by":
220
+ return " -.-> ";
221
+ default:
222
+ return " --- ";
223
+ }
224
+ }
225
+ async function generateVisualizeReport(options = {}) {
226
+ const diagram = await visualizeGraph(options);
227
+ const lines = [
228
+ "\u{1F3A8} **Knowledge Graph Visualization**",
229
+ "\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",
230
+ "",
231
+ diagram,
232
+ "",
233
+ "\u{1F4CB} **Rendering Instructions:**",
234
+ "- Paste the Mermaid code above into any Mermaid-compatible viewer",
235
+ "- GitHub: Mermaid code blocks render automatically",
236
+ "- VS Code: Install 'Markdown Preview Mermaid Support' extension",
237
+ "- Online: https://mermaid.live",
238
+ "",
239
+ "\u{1F4A1} Use `kuma_visualize({ type: 'dependency' })` for clustered view",
240
+ "\u{1F4A1} Use `kuma_visualize({ type: 'mindmap' })` for overview",
241
+ "\u{1F4A1} Use `kuma_visualize({ scope: 'auth' })` to filter by topic"
242
+ ];
243
+ return lines.join("\n");
244
+ }
245
+ export {
246
+ generateVisualizeReport,
247
+ visualizeGraph
248
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ auditStats,
3
+ queryAudit,
4
+ recordAudit
5
+ } from "./chunk-PTEPJK6M.js";
6
+ import "./chunk-NAM7SCBT.js";
7
+ import "./chunk-E2KFPEBT.js";
8
+ export {
9
+ auditStats,
10
+ queryAudit,
11
+ recordAudit
12
+ };
@@ -2,10 +2,10 @@ import {
2
2
  getGitDiffStat,
3
3
  getSessionStats,
4
4
  getUnresolvedCount
5
- } from "./chunk-FOQQ2CSL.js";
5
+ } from "./chunk-FL2TLLMX.js";
6
6
  import {
7
7
  sessionMemory
8
- } from "./chunk-BI7KD3SG.js";
8
+ } from "./chunk-SLRRDKQ2.js";
9
9
  import "./chunk-E2KFPEBT.js";
10
10
 
11
11
  // src/engine/safetyScore.ts
@@ -60,7 +60,7 @@ async function computeSafetyScore(inputGoal) {
60
60
  totalScore += 20;
61
61
  }
62
62
  try {
63
- const { getDb } = await import("./kumaDb-DJUDLYBJ.js");
63
+ const { getDb } = await import("./kumaDb-6D53ERFP.js");
64
64
  const db = await getDb();
65
65
  const nodeCount = db.exec("SELECT COUNT(*) as c FROM nodes")[0]?.values[0][0] ?? 0;
66
66
  const edgeCount = db.exec("SELECT COUNT(*) as c FROM edges")[0]?.values[0][0] ?? 0;
@@ -91,7 +91,7 @@ async function computeSafetyScore(inputGoal) {
91
91
  totalScore += 5;
92
92
  }
93
93
  try {
94
- const { getDb } = await import("./kumaDb-DJUDLYBJ.js");
94
+ const { getDb } = await import("./kumaDb-6D53ERFP.js");
95
95
  const db = await getDb();
96
96
  const researchCount = db.exec("SELECT COUNT(*) as c FROM research_cache")[0]?.values[0][0] ?? 0;
97
97
  checks.push({
@@ -116,7 +116,7 @@ async function computeSafetyScore(inputGoal) {
116
116
  const hasRunTests = stats.hasRunTests;
117
117
  let latestVerif = null;
118
118
  try {
119
- const { getLatestVerifications } = await import("./kumaDb-DJUDLYBJ.js");
119
+ const { getLatestVerifications } = await import("./kumaDb-6D53ERFP.js");
120
120
  const verifs = await getLatestVerifications(1);
121
121
  if (verifs.length > 0) latestVerif = verifs[0];
122
122
  } catch {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  sessionMemory
3
- } from "./chunk-BI7KD3SG.js";
3
+ } from "./chunk-SLRRDKQ2.js";
4
4
  export {
5
5
  sessionMemory
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plumpslabs/kuma",
3
- "version": "2.3.6",
3
+ "version": "2.3.8",
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",