@plumpslabs/kuma 2.3.7 → 2.3.9

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 (33) hide show
  1. package/README.md +25 -3
  2. package/dist/{chunk-GDNAWLHF.js → chunk-3TX6Q37T.js} +89 -2
  3. package/dist/{chunk-X5TPBDKO.js → chunk-OJALFQ4H.js} +2 -2
  4. package/dist/chunk-Q2444HWO.js +282 -0
  5. package/dist/{chunk-BI7KD3SG.js → chunk-R6B3VUSB.js} +2 -2
  6. package/dist/chunk-RI3DKY62.js +155 -0
  7. package/dist/{chunk-FOQQ2CSL.js → chunk-SPHI2BOO.js} +1 -1
  8. package/dist/{chunk-K64NSHBR.js → chunk-ZKDYTYMS.js} +108 -2
  9. package/dist/contextDigest-5JXLH56Z.js +177 -0
  10. package/dist/domainRules-ED6EOFVY.js +20 -0
  11. package/dist/index.js +393 -198
  12. package/dist/kumaAstValidator-CNM7FHYA.js +150 -0
  13. package/dist/kumaCheckpoint-XIQWRMGV.js +207 -0
  14. package/dist/kumaCodeScanner-LFJGPJNH.js +566 -0
  15. package/dist/kumaContractEngine-KX27T4N7.js +305 -0
  16. package/dist/{kumaDb-DJUDLYBJ.js → kumaDb-IC7UX7PU.js} +3 -1
  17. package/dist/kumaDriftDetector-QBY6OJOO.js +237 -0
  18. package/dist/kumaGotchas-5HODT5RI.js +151 -0
  19. package/dist/{kumaGraph-35TAIBWD.js → kumaGraph-GUQM75WL.js} +8 -2
  20. package/dist/{kumaMemory-5SR3TGRL.js → kumaMemory-FMOWIODH.js} +2 -2
  21. package/dist/{kumaMiner-P5KCUSF7.js → kumaMiner-3RXEOCBP.js} +3 -3
  22. package/dist/kumaPolicyEngine-ORBWL5PT.js +311 -0
  23. package/dist/kumaProgressiveContext-CVSNPY3W.js +231 -0
  24. package/dist/{kumaSearch-LG2OYEJY.js → kumaSearch-B5WVYHHD.js} +1 -1
  25. package/dist/kumaTrajectory-T6DXGOG4.js +460 -0
  26. package/dist/{kumaVerifier-LFRNIGSL.js → kumaVerifier-KAYJHR5K.js} +25 -2
  27. package/dist/{kumaVisualize-ODCWFSUY.js → kumaVisualize-AFL7STLL.js} +1 -1
  28. package/dist/safetyAudit-32WSA4Z5.js +12 -0
  29. package/dist/{safetyScore-PJGRRBWP.js → safetyScore-WU27EOG4.js} +5 -5
  30. package/dist/{sessionMemory-HBBXUSIP.js → sessionMemory-4UWA3E5J.js} +1 -1
  31. package/package.json +18 -13
  32. package/packages/ide/studio/dist/index.js +140 -0
  33. package/packages/ide/studio/public/index.html +500 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getDb,
3
3
  saveDb
4
- } from "./chunk-GDNAWLHF.js";
4
+ } from "./chunk-3TX6Q37T.js";
5
5
  import {
6
6
  getProjectRoot
7
7
  } from "./chunk-E2KFPEBT.js";
@@ -458,7 +458,7 @@ The two nodes may not be connected in the knowledge graph yet. Use more tools to
458
458
  }
459
459
  async function buildFromSessionMemory() {
460
460
  try {
461
- const { sessionMemory } = await import("./sessionMemory-HBBXUSIP.js");
461
+ const { sessionMemory } = await import("./sessionMemory-4UWA3E5J.js");
462
462
  const toolCalls = sessionMemory.getToolCallHistory(50);
463
463
  let edgeCount = 0;
464
464
  for (const call of toolCalls) {
@@ -630,6 +630,109 @@ async function codebaseSearchFallback(query, limit = 20) {
630
630
  }
631
631
  }
632
632
  }
633
+ async function resolveFederatedNode(uri) {
634
+ try {
635
+ if (!uri.startsWith("kuma://")) {
636
+ return `\u26A0\uFE0F Invalid URI scheme: "${uri.substring(0, 20)}...". Use kuma://project/node-id`;
637
+ }
638
+ const pathPart = uri.replace("kuma://", "");
639
+ const firstSlash = pathPart.indexOf("/");
640
+ if (firstSlash === -1) {
641
+ return `\u26A0\uFE0F Invalid federated URI: "${uri}". Format: kuma://<project>/<node-id>`;
642
+ }
643
+ const projectName = pathPart.substring(0, firstSlash);
644
+ const nodeRef = pathPart.substring(firstSlash + 1);
645
+ const db = await getDb();
646
+ const stmt = db.prepare(`
647
+ SELECT id, type, name, file_path, metadata FROM nodes
648
+ WHERE id = ? OR name LIKE ?
649
+ LIMIT 5
650
+ `);
651
+ stmt.bind([nodeRef, `%${nodeRef}%`]);
652
+ const results = [];
653
+ while (stmt.step()) results.push(stmt.getAsObject());
654
+ stmt.free();
655
+ if (results.length > 0) {
656
+ const lines = [
657
+ `\u{1F517} **Federated Node Resolved** (local)`,
658
+ `\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`,
659
+ `\u{1F4C1} Project: ${projectName}`,
660
+ `\u{1F517} URI: ${uri}`,
661
+ ""
662
+ ];
663
+ for (const r of results) {
664
+ lines.push(` \u2022 **${r.name}** (${r.type}) \u2014 ${r.file_path || "no path"}`);
665
+ }
666
+ lines.push("", "\u{1F4A1} Federated cross-repo resolution is active. Remote resolution via HTTP coming soon.");
667
+ return lines.join("\n");
668
+ }
669
+ const federatedNodes = await registerFederatedReference(uri, projectName, nodeRef);
670
+ return [
671
+ `\u{1F517} **Federated Reference**`,
672
+ `\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`,
673
+ `\u{1F4C1} Remote project: ${projectName}`,
674
+ `\u{1F517} URI: ${uri}`,
675
+ `\u{1F4CC} Node ref: ${nodeRef}`,
676
+ "",
677
+ `\u{1F4DD} Registered as federated reference for future resolution.`,
678
+ `\u{1F4A1} Remote graph resolution will be available when the target project is reachable.`,
679
+ federatedNodes > 0 ? `\u2705 Created ${federatedNodes} federated node(s) in local graph.` : ""
680
+ ].filter(Boolean).join("\n");
681
+ } catch (err) {
682
+ return `\u274C Federated resolution failed: ${err}`;
683
+ }
684
+ }
685
+ async function registerFederatedReference(uri, projectName, nodeRef) {
686
+ try {
687
+ await upsertNode({
688
+ id: `federated::${uri}`,
689
+ type: "module",
690
+ name: `[${projectName}] ${nodeRef}`,
691
+ metadata: {
692
+ federated: true,
693
+ uri,
694
+ project: projectName,
695
+ ref: nodeRef,
696
+ resolved: false
697
+ }
698
+ });
699
+ return 1;
700
+ } catch {
701
+ return 0;
702
+ }
703
+ }
704
+ async function listFederatedReferences() {
705
+ try {
706
+ const db = await getDb();
707
+ const stmt = db.prepare(`
708
+ SELECT id, name, metadata FROM nodes
709
+ WHERE metadata LIKE '%"federated":true%'
710
+ ORDER BY updated_at DESC
711
+ LIMIT 20
712
+ `);
713
+ const results = [];
714
+ while (stmt.step()) results.push(stmt.getAsObject());
715
+ stmt.free();
716
+ if (results.length === 0) {
717
+ return "\u{1F517} **No federated references.** Use kuma_memory({ action: 'federated', uri: 'kuma://project/node-id' }) to add one.";
718
+ }
719
+ const lines = [
720
+ "\u{1F517} **Federated References**",
721
+ "\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",
722
+ ""
723
+ ];
724
+ for (const r of results) {
725
+ const meta = JSON.parse(r.metadata || "{}");
726
+ lines.push(` \u{1F517} **${r.name}**`);
727
+ lines.push(` URI: ${meta.uri || "unknown"}`);
728
+ lines.push(` Resolved: ${meta.resolved ? "\u2705" : "\u23F3"}`);
729
+ lines.push("");
730
+ }
731
+ return lines.join("\n");
732
+ } catch (err) {
733
+ return `Error: ${err}`;
734
+ }
735
+ }
633
736
  async function getGraphStats() {
634
737
  try {
635
738
  const db = await getDb();
@@ -850,6 +953,7 @@ export {
850
953
  detectStaleNodes,
851
954
  autoHeal,
852
955
  formatHealReport,
956
+ nodeId,
853
957
  upsertNode,
854
958
  addEdge,
855
959
  recordFunctionCall,
@@ -860,6 +964,8 @@ export {
860
964
  queryGraph,
861
965
  buildFromSessionMemory,
862
966
  searchGraph,
967
+ resolveFederatedNode,
968
+ listFederatedReferences,
863
969
  getGraphStats,
864
970
  analyzeImpact,
865
971
  formatImpact,
@@ -0,0 +1,177 @@
1
+ import {
2
+ getActiveGotchas
3
+ } from "./chunk-Q2444HWO.js";
4
+ import {
5
+ sessionMemory
6
+ } from "./chunk-R6B3VUSB.js";
7
+ import {
8
+ getDb
9
+ } from "./chunk-3TX6Q37T.js";
10
+ import {
11
+ getProjectRoot
12
+ } from "./chunk-E2KFPEBT.js";
13
+
14
+ // src/engine/contextDigest.ts
15
+ import fs from "fs";
16
+ import path from "path";
17
+ function detectTechStack() {
18
+ const root = getProjectRoot();
19
+ const stack = {
20
+ languages: [],
21
+ framework: null,
22
+ database: null,
23
+ testRunner: null,
24
+ packageManager: null,
25
+ monorepo: false
26
+ };
27
+ try {
28
+ const pkgPath = path.join(root, "package.json");
29
+ if (fs.existsSync(pkgPath)) {
30
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
31
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
32
+ if (fs.existsSync(path.join(root, "pnpm-lock.yaml"))) stack.packageManager = "pnpm";
33
+ else if (fs.existsSync(path.join(root, "yarn.lock"))) stack.packageManager = "yarn";
34
+ else stack.packageManager = "npm";
35
+ stack.monorepo = !!pkg.workspaces;
36
+ if (deps.next) stack.framework = "Next.js";
37
+ else if (deps.react) stack.framework = "React";
38
+ else if (deps.vue) stack.framework = "Vue";
39
+ else if (deps.express) stack.framework = "Express";
40
+ else if (deps.fastify) stack.framework = "Fastify";
41
+ else if (deps.nest) stack.framework = "NestJS";
42
+ else if (deps["@remix-run/react"]) stack.framework = "Remix";
43
+ else if (deps.svelte) stack.framework = "Svelte";
44
+ else if (deps.angular) stack.framework = "Angular";
45
+ if (deps.prisma) stack.database = "Prisma";
46
+ else if (deps.typeorm) stack.database = "TypeORM";
47
+ else if (deps.mongoose) stack.database = "MongoDB";
48
+ else if (deps.pg || deps["@neondatabase/serverless"]) stack.database = "PostgreSQL";
49
+ else if (deps.redis) stack.database = "Redis";
50
+ else if (deps.better || deps.drizzle) stack.database = "Drizzle";
51
+ if (deps.jest || deps["@jest/core"]) stack.testRunner = "Jest";
52
+ else if (deps.vitest) stack.testRunner = "Vitest";
53
+ else if (deps.mocha) stack.testRunner = "Mocha";
54
+ else if (deps.playwright) stack.testRunner = "Playwright";
55
+ else if (deps.cypress) stack.testRunner = "Cypress";
56
+ if (fs.existsSync(path.join(root, "tsconfig.json"))) stack.languages.push("TypeScript");
57
+ if (deps.typescript) stack.languages.push("TypeScript");
58
+ if (fs.existsSync(path.join(root, "jsconfig.json"))) stack.languages.push("JavaScript");
59
+ if (fs.existsSync(path.join(root, "go.mod"))) stack.languages.push("Go");
60
+ if (fs.existsSync(path.join(root, "Cargo.toml"))) stack.languages.push("Rust");
61
+ if (fs.existsSync(path.join(root, "pyproject.toml"))) stack.languages.push("Python");
62
+ if (fs.existsSync(path.join(root, "Gemfile"))) stack.languages.push("Ruby");
63
+ if (stack.languages.length === 0) stack.languages.push("JavaScript");
64
+ }
65
+ } catch {
66
+ }
67
+ return stack;
68
+ }
69
+ function detectEntryPoints() {
70
+ const root = getProjectRoot();
71
+ const entryPoints = [];
72
+ const candidates = [
73
+ "src/index.ts",
74
+ "src/index.js",
75
+ "src/app.ts",
76
+ "src/app.js",
77
+ "index.ts",
78
+ "index.js",
79
+ "src/main.ts",
80
+ "src/main.js",
81
+ "src/server.ts",
82
+ "src/server.js",
83
+ "app.ts",
84
+ "app.js",
85
+ "pages/index.tsx",
86
+ "pages/index.jsx",
87
+ "src/App.tsx",
88
+ "src/App.js",
89
+ "lib/main.ts",
90
+ "lib/index.ts"
91
+ ];
92
+ for (const c of candidates) {
93
+ if (fs.existsSync(path.join(root, c))) {
94
+ entryPoints.push(c);
95
+ }
96
+ }
97
+ try {
98
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf-8"));
99
+ if (pkg.main && fs.existsSync(path.join(root, pkg.main))) {
100
+ if (!entryPoints.includes(pkg.main)) entryPoints.push(pkg.main);
101
+ }
102
+ } catch {
103
+ }
104
+ return entryPoints;
105
+ }
106
+ async function getActiveADRs() {
107
+ try {
108
+ const db = await getDb();
109
+ const stmt = db.prepare(
110
+ "SELECT title FROM decision_log WHERE status = 'active' ORDER BY created_at DESC LIMIT 5"
111
+ );
112
+ const results = [];
113
+ while (stmt.step()) {
114
+ const row = stmt.getAsObject();
115
+ results.push(row.title);
116
+ }
117
+ stmt.free();
118
+ return results;
119
+ } catch {
120
+ return [];
121
+ }
122
+ }
123
+ async function generateContextDigest() {
124
+ const stack = detectTechStack();
125
+ const entryPoints = detectEntryPoints();
126
+ const adrs = await getActiveADRs();
127
+ const gotchas = getActiveGotchas();
128
+ const summary = sessionMemory.getSummary();
129
+ const lines = [
130
+ "\u{1F4CB} **Kuma Digest** \u2014 <500 token briefing",
131
+ "\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",
132
+ ""
133
+ ];
134
+ const langStr = stack.languages.join("/");
135
+ const frameworkStr = stack.framework || "\u2014";
136
+ const dbStr = stack.database || "\u2014";
137
+ const testStr = stack.testRunner || "\u2014";
138
+ const pmStr = stack.packageManager || "\u2014";
139
+ lines.push(`\u{1F527} **Stack**: ${langStr} | ${frameworkStr} | ${dbStr} | ${testStr} | ${pmStr}${stack.monorepo ? " (monorepo)" : ""}`);
140
+ lines.push(`\u{1F4C1} **Root**: ${getProjectRoot().split("/").pop() || "?"}`);
141
+ if (entryPoints.length > 0) {
142
+ lines.push(`\u{1F6AA} **Entry**: ${entryPoints.slice(0, 3).join(", ")}`);
143
+ }
144
+ try {
145
+ const ruleFile = path.join(getProjectRoot(), ".kuma", "DOMAIN_RULES.md");
146
+ if (fs.existsSync(ruleFile)) {
147
+ const content = fs.readFileSync(ruleFile, "utf-8");
148
+ const rules = content.split("\n").filter((l) => /^- Rule \d+:?\s*/i.test(l)).map((l) => l.replace(/^- Rule \d+:?\s*/i, "").trim()).filter(Boolean);
149
+ if (rules.length > 0) {
150
+ lines.push(`\u{1F4CB} **Rules**: ${rules.slice(0, 5).join(" | ")}`);
151
+ }
152
+ }
153
+ } catch {
154
+ }
155
+ if (gotchas.length > 0) {
156
+ const critical = gotchas.filter((g) => g.severity === "critical" || g.severity === "high");
157
+ if (critical.length > 0) {
158
+ lines.push(`\u26A0\uFE0F **Gotchas**: ${critical.length} high/critical \u2014 ${critical.slice(0, 3).map((g) => g.filePath).join(", ")}`);
159
+ } else {
160
+ lines.push(`\u26A0\uFE0F **Gotchas**: ${gotchas.length} recorded`);
161
+ }
162
+ }
163
+ if (adrs.length > 0) {
164
+ lines.push(`\u{1F4DD} **ADRs**: ${adrs.slice(0, 3).join(" | ")}`);
165
+ }
166
+ lines.push(`\u{1F3AF} **Goal**: ${summary.currentGoal?.substring(0, 80) || "not set"}`);
167
+ const text = lines.join("\n");
168
+ const estimatedTokens = Math.ceil(text.length / 4);
169
+ if (estimatedTokens > 450) {
170
+ lines.push(`\u{1F4CA} *~${estimatedTokens} tokens, fits under 500 limit*`);
171
+ }
172
+ return lines.join("\n") + "\n\n\u{1F4A1} Use kuma_context({ action: 'sync' }) for full state.";
173
+ }
174
+ export {
175
+ generateContextDigest,
176
+ generateContextDigest as generateDigest
177
+ };
@@ -0,0 +1,20 @@
1
+ import {
2
+ appendToLayer,
3
+ checkFileGotchas,
4
+ generateDigest,
5
+ getActiveGotchas,
6
+ getLayersSummary,
7
+ readLayer,
8
+ writeLayer
9
+ } from "./chunk-Q2444HWO.js";
10
+ import "./chunk-R6B3VUSB.js";
11
+ import "./chunk-E2KFPEBT.js";
12
+ export {
13
+ appendToLayer,
14
+ checkFileGotchas,
15
+ generateDigest,
16
+ getActiveGotchas,
17
+ getLayersSummary,
18
+ readLayer,
19
+ writeLayer
20
+ };