@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,150 @@
1
+ import {
2
+ getProjectRoot
3
+ } from "./chunk-E2KFPEBT.js";
4
+
5
+ // src/engine/kumaAstValidator.ts
6
+ import fs from "fs";
7
+ import path from "path";
8
+ function loadImportWhitelist() {
9
+ try {
10
+ const root = getProjectRoot();
11
+ const whitelistPath = path.join(root, ".kuma", "import-whitelist.json");
12
+ if (fs.existsSync(whitelistPath)) {
13
+ return JSON.parse(fs.readFileSync(whitelistPath, "utf-8"));
14
+ }
15
+ } catch {
16
+ }
17
+ return {
18
+ allowed: [],
19
+ blocked: ["sql.js", "better-sqlite3", "mysql", "mssql"]
20
+ // dangerous native deps
21
+ };
22
+ }
23
+ function validateCodeContent(code, filePath) {
24
+ const findings = [];
25
+ const lines = code.split("\n");
26
+ const whitelist = loadImportWhitelist();
27
+ for (let i = 0; i < lines.length; i++) {
28
+ const line = lines[i];
29
+ const lineNum = i + 1;
30
+ if (/\/\/\s*(expect|assert|should|test|it\.)\s*\(/.test(line) || /(\/\*[\s\S]*?\*\/)/.test(line) && /(expect|assert|should|test)/.test(line)) {
31
+ findings.push({
32
+ line: lineNum,
33
+ severity: "error",
34
+ category: "assertion-deletion",
35
+ message: `Test assertion appears to be commented out on line ${lineNum}`,
36
+ suggestion: "Restore the assertion or write an equivalent test for the new behavior"
37
+ });
38
+ }
39
+ if (/catch\s*\([^)]*\)\s*\{\s*\}/.test(line) || /catch\s*\([^)]*\)\s*\{/.test(line) && lines[i + 1]?.trim() === "}") {
40
+ findings.push({
41
+ line: lineNum,
42
+ severity: "error",
43
+ category: "exception-swallowing",
44
+ message: `Empty catch block on line ${lineNum} \u2014 exceptions are being swallowed`,
45
+ suggestion: "Handle the error: log it, throw a meaningful error, or add a comment explaining why it's safe to ignore"
46
+ });
47
+ }
48
+ if (filePath?.includes(".test.") || filePath?.includes(".spec.")) {
49
+ if (/\breturn\s+(true|false|null|undefined|0|""|'')\s*;/.test(line) || /\breturn\s+\d+\s*;/.test(line) || /\bPromise\.resolve\s*\(\s*(true|false|null|undefined|0|""|'')\s*\)/.test(line)) {
50
+ findings.push({
51
+ line: lineNum,
52
+ severity: "warning",
53
+ category: "reward-hacking",
54
+ message: `Possible hardcoded return in test file on line ${lineNum}: ${line.trim().substring(0, 60)}`,
55
+ suggestion: "Implement the actual logic instead of returning a hardcoded value to pass tests"
56
+ });
57
+ }
58
+ }
59
+ if (!filePath?.includes(".test.") && !filePath?.includes(".spec.") && /\breturn\s+(true|false|null)\s*;/.test(line) && ((lines[i - 1] || "").includes("TODO") || (lines[i - 1] || "").includes("FIXME") || (lines[i - 1] || "").includes("HACK"))) {
60
+ findings.push({
61
+ line: lineNum,
62
+ severity: "warning",
63
+ category: "hardcoded-return",
64
+ message: `Hardcoded return value on line ${lineNum} (possibly temporary/hack)`,
65
+ suggestion: "Implement proper logic or add a clear comment explaining why this is correct"
66
+ });
67
+ }
68
+ const importMatch = line.match(/import\s+(?:\{[^}]*\}\s+from\s+)?['"]([^'"]+)['"]/);
69
+ if (importMatch) {
70
+ const imported = importMatch[1];
71
+ if (whitelist.blocked.some((b) => imported.includes(b))) {
72
+ findings.push({
73
+ line: lineNum,
74
+ severity: "error",
75
+ category: "import-violation",
76
+ message: `Blocked import: "${imported}" is not allowed per security whitelist`,
77
+ suggestion: `Remove or replace the import. Allowed packages: ${whitelist.allowed.slice(0, 5).join(", ") || "(none specified)"}`
78
+ });
79
+ }
80
+ }
81
+ }
82
+ return findings;
83
+ }
84
+ function validateFile(filePath) {
85
+ try {
86
+ const root = getProjectRoot();
87
+ const fullPath = path.resolve(root, filePath);
88
+ if (!fs.existsSync(fullPath)) return [];
89
+ const content = fs.readFileSync(fullPath, "utf-8");
90
+ return validateCodeContent(content, filePath);
91
+ } catch {
92
+ return [];
93
+ }
94
+ }
95
+ function formatValidationFindings(findings, filePath) {
96
+ if (findings.length === 0) {
97
+ return "\u2705 **AST Validation** \u2014 No structural issues found.";
98
+ }
99
+ const errors = findings.filter((f) => f.severity === "error");
100
+ const warnings = findings.filter((f) => f.severity === "warning");
101
+ const lines = [
102
+ "\u{1F52C} **AST Code Validation Report**",
103
+ "\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",
104
+ "",
105
+ `${findings.length} finding(s): ${errors.length} errors, ${warnings.length} warnings`,
106
+ filePath ? `\u{1F4C4} ${filePath}` : "",
107
+ ""
108
+ ];
109
+ for (const f of findings) {
110
+ const icon = f.severity === "error" ? "\u{1F534}" : f.severity === "warning" ? "\u{1F7E1}" : "\u{1F7E2}";
111
+ lines.push(`${icon} L${f.line} [${f.category}]`);
112
+ lines.push(` ${f.message}`);
113
+ lines.push(` \u{1F4A1} ${f.suggestion}`);
114
+ lines.push("");
115
+ }
116
+ return lines.join("\n");
117
+ }
118
+ function validateDiff(oldContent, newContent, filePath) {
119
+ const findings = [];
120
+ const oldFindings = validateCodeContent(oldContent, filePath);
121
+ const newFindings = validateCodeContent(newContent, filePath);
122
+ const oldAssertions = oldFindings.filter((f) => f.category === "assertion-deletion");
123
+ const newAssertions = newFindings.filter((f) => f.category === "assertion-deletion");
124
+ for (const oldAssertion of oldAssertions) {
125
+ if (!newAssertions.some((f) => f.line === oldAssertion.line && f.message === oldAssertion.message)) {
126
+ continue;
127
+ }
128
+ }
129
+ const oldLines = oldContent.split("\n");
130
+ const newLines = newContent.split("\n");
131
+ for (let i = 0; i < newLines.length; i++) {
132
+ if (i >= oldLines.length || newLines[i] !== oldLines[i]) {
133
+ const changedLineFindings = validateCodeContent(newLines[i], filePath);
134
+ for (const f of changedLineFindings) {
135
+ findings.push({
136
+ ...f,
137
+ line: i + 1,
138
+ message: `[NEW] ${f.message}`
139
+ });
140
+ }
141
+ }
142
+ }
143
+ return findings;
144
+ }
145
+ export {
146
+ formatValidationFindings,
147
+ validateCodeContent,
148
+ validateDiff,
149
+ validateFile
150
+ };
@@ -28,7 +28,7 @@ import {
28
28
  saveVerification,
29
29
  updateDecisionStatus,
30
30
  updateTodoStatus
31
- } from "./chunk-GDNAWLHF.js";
31
+ } from "./chunk-NAM7SCBT.js";
32
32
  import "./chunk-E2KFPEBT.js";
33
33
  export {
34
34
  addContextNote,
@@ -0,0 +1,237 @@
1
+ import {
2
+ getDb,
3
+ saveDb
4
+ } from "./chunk-NAM7SCBT.js";
5
+ import {
6
+ getProjectRoot
7
+ } from "./chunk-E2KFPEBT.js";
8
+
9
+ // src/engine/kumaDriftDetector.ts
10
+ import fs from "fs";
11
+ import path from "path";
12
+ import crypto from "crypto";
13
+ function hashFile(filePath) {
14
+ try {
15
+ const root = getProjectRoot();
16
+ const fullPath = path.resolve(root, filePath);
17
+ if (!fs.existsSync(fullPath)) return null;
18
+ const content = fs.readFileSync(fullPath, "utf-8");
19
+ return crypto.createHash("sha256").update(content).digest("hex");
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ async function detectDrift() {
25
+ const records = [];
26
+ const now = Math.floor(Date.now() / 1e3);
27
+ try {
28
+ const db = await getDb();
29
+ const rcStmt = db.prepare(
30
+ "SELECT id, scope, content_hash, updated_at FROM research_cache WHERE content_hash IS NOT NULL AND length(content_hash) > 0 LIMIT 100"
31
+ );
32
+ while (rcStmt.step()) {
33
+ const row = rcStmt.getAsObject();
34
+ const scope = row.scope;
35
+ const storedHash = row.content_hash;
36
+ const updatedAt = row.updated_at;
37
+ const age = Math.floor((now - updatedAt) / 86400);
38
+ const currentHash = computeScopeHash(scope);
39
+ const stale = currentHash && currentHash !== storedHash;
40
+ records.push({
41
+ id: row.id,
42
+ source: "research_cache",
43
+ description: scope,
44
+ filePath: null,
45
+ oldHash: storedHash,
46
+ currentHash: currentHash || "",
47
+ age: `${age}d`,
48
+ severity: !currentHash ? "fresh" : stale ? "stale" : age > 30 ? "warning" : "fresh"
49
+ });
50
+ }
51
+ rcStmt.free();
52
+ const fsStmt = db.prepare(
53
+ "SELECT id, file_path, content_hash FROM file_summaries WHERE content_hash IS NOT NULL AND length(content_hash) > 0 LIMIT 100"
54
+ );
55
+ while (fsStmt.step()) {
56
+ const row = fsStmt.getAsObject();
57
+ const filePath = row.file_path;
58
+ const storedHash = row.content_hash;
59
+ const currentHash = hashFile(filePath);
60
+ if (currentHash === null) {
61
+ records.push({
62
+ id: row.id,
63
+ source: "file_summaries",
64
+ description: filePath,
65
+ filePath,
66
+ oldHash: storedHash,
67
+ currentHash: "",
68
+ age: "\u2014",
69
+ severity: "missing"
70
+ });
71
+ } else if (currentHash !== storedHash) {
72
+ records.push({
73
+ id: row.id,
74
+ source: "file_summaries",
75
+ description: filePath,
76
+ filePath,
77
+ oldHash: storedHash,
78
+ currentHash,
79
+ age: "\u2014",
80
+ severity: "stale"
81
+ });
82
+ }
83
+ }
84
+ fsStmt.free();
85
+ const dlStmt = db.prepare(
86
+ "SELECT id, title, file_paths, created_at FROM decision_log WHERE file_paths IS NOT NULL ORDER BY created_at DESC LIMIT 50"
87
+ );
88
+ while (dlStmt.step()) {
89
+ const row = dlStmt.getAsObject();
90
+ const filePaths = [];
91
+ try {
92
+ filePaths.push(...JSON.parse(row.file_paths));
93
+ } catch {
94
+ }
95
+ let hasStaleFile = false;
96
+ for (const fp of filePaths) {
97
+ if (!fp) continue;
98
+ const fullPath = path.resolve(getProjectRoot(), fp);
99
+ if (!fs.existsSync(fullPath)) {
100
+ hasStaleFile = true;
101
+ break;
102
+ }
103
+ }
104
+ if (hasStaleFile) {
105
+ records.push({
106
+ id: row.id,
107
+ source: "decision_log",
108
+ description: row.title,
109
+ filePath: filePaths[0] || null,
110
+ oldHash: "",
111
+ currentHash: "",
112
+ age: "\u2014",
113
+ severity: "stale"
114
+ });
115
+ }
116
+ }
117
+ dlStmt.free();
118
+ } catch (err) {
119
+ console.error(`[DriftDetector] Error: ${err}`);
120
+ }
121
+ return records;
122
+ }
123
+ function computeScopeHash(scope) {
124
+ try {
125
+ const hash = crypto.createHash("sha256");
126
+ const root = getProjectRoot();
127
+ hash.update(scope);
128
+ let found = false;
129
+ try {
130
+ const files = fs.readdirSync(root);
131
+ for (const file of files) {
132
+ if (file.toLowerCase().includes(scope.toLowerCase())) {
133
+ try {
134
+ if (fs.statSync(path.join(root, file)).isFile()) {
135
+ const content = fs.readFileSync(path.join(root, file), "utf-8");
136
+ hash.update(file);
137
+ hash.update(content.substring(0, 1e4));
138
+ found = true;
139
+ }
140
+ } catch {
141
+ }
142
+ }
143
+ }
144
+ } catch {
145
+ }
146
+ const researchDir = path.join(root, ".kuma", "research");
147
+ if (fs.existsSync(researchDir)) {
148
+ const scopeFile = path.join(researchDir, `${scope}.json`);
149
+ if (fs.existsSync(scopeFile)) {
150
+ const content = fs.readFileSync(scopeFile, "utf-8");
151
+ hash.update(content);
152
+ found = true;
153
+ }
154
+ }
155
+ if (!found) return null;
156
+ return hash.digest("hex").substring(0, 16);
157
+ } catch {
158
+ return null;
159
+ }
160
+ }
161
+ async function flagStaleRecords() {
162
+ const staleRecords = await detectDrift();
163
+ let flagged = 0;
164
+ try {
165
+ const db = await getDb();
166
+ for (const record of staleRecords) {
167
+ if (record.severity !== "stale" && record.severity !== "missing") continue;
168
+ if (record.source === "research_cache") {
169
+ db.run(
170
+ `UPDATE research_cache SET confidence = MAX(confidence * 0.5, 0.1) WHERE id = ?`,
171
+ [record.id]
172
+ );
173
+ flagged++;
174
+ } else if (record.source === "file_summaries") {
175
+ db.run(
176
+ `UPDATE file_summaries SET content_hash = '' WHERE id = ?`,
177
+ [record.id]
178
+ );
179
+ flagged++;
180
+ } else if (record.source === "decision_log") {
181
+ db.run(
182
+ `UPDATE decision_log SET status = 'deprecated' WHERE id = ?`,
183
+ [record.id]
184
+ );
185
+ flagged++;
186
+ }
187
+ }
188
+ saveDb();
189
+ } catch (err) {
190
+ console.error(`[DriftDetector] Flag error: ${err}`);
191
+ }
192
+ return { flagged, total: staleRecords.length };
193
+ }
194
+ function formatDriftReport(records) {
195
+ if (records.length === 0) {
196
+ return "\u2705 **Drift Detection** \u2014 All memory records are fresh. No code drift detected.";
197
+ }
198
+ const fresh = records.filter((r) => r.severity === "fresh").length;
199
+ const warning = records.filter((r) => r.severity === "warning").length;
200
+ const stale = records.filter((r) => r.severity === "stale").length;
201
+ const missing = records.filter((r) => r.severity === "missing").length;
202
+ const lines = [
203
+ "\u{1F50D} **Code Drift Detection Report**",
204
+ "\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",
205
+ "",
206
+ `\u{1F4CA} ${records.length} total records checked: ${fresh} fresh, ${warning} aging, ${stale} stale, ${missing} missing`,
207
+ ""
208
+ ];
209
+ if (stale > 0 || missing > 0) {
210
+ lines.push("**Stale/Missing Records:**");
211
+ for (const r of records) {
212
+ if (r.severity === "stale" || r.severity === "missing") {
213
+ const icon = r.severity === "missing" ? "\u274C" : "\u26A0\uFE0F";
214
+ lines.push(` ${icon} [${r.source}] ${r.description}`);
215
+ if (r.filePath) lines.push(` \u{1F4CD} ${r.filePath}`);
216
+ }
217
+ }
218
+ lines.push("");
219
+ lines.push("\u{1F4A1} Run kuma_memory({ action: 'heal' }) to repair stale graph entries.");
220
+ lines.push("\u{1F4A1} Run kuma_context({ action: 'research', scope: '<stale-scope>' }) to refresh.");
221
+ }
222
+ return lines.join("\n");
223
+ }
224
+ async function getDriftSummary() {
225
+ const records = await detectDrift();
226
+ if (records.length === 0) return "\u2705 No code drift detected";
227
+ const staleCount = records.filter((r) => r.severity === "stale" || r.severity === "missing").length;
228
+ if (staleCount === 0) return "\u2705 All records fresh";
229
+ return `\u26A0\uFE0F ${staleCount} stale record(s) detected. Use kuma_memory({ action: 'heal' }) to repair.`;
230
+ }
231
+ export {
232
+ detectDrift,
233
+ flagStaleRecords,
234
+ formatDriftReport,
235
+ getDriftSummary,
236
+ hashFile
237
+ };
@@ -0,0 +1,151 @@
1
+ import {
2
+ appendToLayer,
3
+ checkFileGotchas,
4
+ getActiveGotchas
5
+ } from "./chunk-53J56QCQ.js";
6
+ import {
7
+ sessionMemory
8
+ } from "./chunk-SLRRDKQ2.js";
9
+ import {
10
+ getDb,
11
+ saveDb
12
+ } from "./chunk-NAM7SCBT.js";
13
+ import "./chunk-E2KFPEBT.js";
14
+
15
+ // src/engine/kumaGotchas.ts
16
+ async function ensureGotchasSchema() {
17
+ const db = await getDb();
18
+ db.exec(`
19
+ CREATE TABLE IF NOT EXISTS known_gotchas (
20
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
21
+ file_path TEXT NOT NULL,
22
+ description TEXT NOT NULL,
23
+ severity TEXT NOT NULL DEFAULT 'medium'
24
+ CHECK(severity IN ('low','medium','high','critical')),
25
+ workaround TEXT,
26
+ added_by TEXT DEFAULT 'agent',
27
+ created_at INTEGER NOT NULL DEFAULT (strftime('%s','now')),
28
+ updated_at INTEGER NOT NULL DEFAULT (strftime('%s','now'))
29
+ );
30
+ CREATE INDEX IF NOT EXISTS idx_gotchas_file ON known_gotchas(file_path);
31
+ CREATE INDEX IF NOT EXISTS idx_gotchas_severity ON known_gotchas(severity);
32
+ `);
33
+ saveDb();
34
+ }
35
+ async function addGotcha(entry) {
36
+ try {
37
+ await ensureGotchasSchema();
38
+ const db = await getDb();
39
+ const severity = entry.severity || "medium";
40
+ const formatted = [
41
+ `### ${entry.filePath} \u2014 ${entry.description}`,
42
+ `- **Issue**: ${entry.description}`,
43
+ `- **Severity**: ${severity}`,
44
+ entry.workaround ? `- **Workaround**: ${entry.workaround}` : "",
45
+ `- **Added**: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`
46
+ ].filter(Boolean).join("\n");
47
+ db.run(
48
+ `INSERT INTO known_gotchas (file_path, description, severity, workaround) VALUES (?, ?, ?, ?)`,
49
+ [entry.filePath, entry.description, severity, entry.workaround || null]
50
+ );
51
+ const mdResult = appendToLayer("gotcha", formatted);
52
+ saveDb();
53
+ sessionMemory.recordToolCall("kuma_gotcha_add", {
54
+ filePath: entry.filePath,
55
+ severity
56
+ });
57
+ return `\u2705 **Gotcha recorded**: ${entry.filePath} \u2014 ${entry.description}
58
+ ${mdResult}`;
59
+ } catch (err) {
60
+ return `\u274C Failed to add gotcha: ${err}`;
61
+ }
62
+ }
63
+ async function listGotchas(params) {
64
+ try {
65
+ await ensureGotchasSchema();
66
+ const db = await getDb();
67
+ let sql = "SELECT * FROM known_gotchas WHERE 1=1";
68
+ const bind = [];
69
+ if (params.filePath) {
70
+ sql += " AND file_path LIKE ?";
71
+ bind.push(`%${params.filePath}%`);
72
+ }
73
+ if (params.severity) {
74
+ sql += " AND severity = ?";
75
+ bind.push(params.severity);
76
+ }
77
+ sql += " ORDER BY severity DESC, created_at DESC LIMIT 50";
78
+ const stmt = db.prepare(sql);
79
+ stmt.bind(bind);
80
+ const results = [];
81
+ while (stmt.step()) results.push(stmt.getAsObject());
82
+ stmt.free();
83
+ if (results.length === 0) {
84
+ return "\u2705 **No gotchas recorded** \u2014 legacy codebase looks clean.";
85
+ }
86
+ const lines = [
87
+ `\u26A0\uFE0F **Known Gotchas** \u2014 ${results.length} recorded`,
88
+ "\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",
89
+ ""
90
+ ];
91
+ for (const g of results) {
92
+ const icon = g.severity === "critical" ? "\u{1F534}" : g.severity === "high" ? "\u{1F7E0}" : g.severity === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
93
+ lines.push(`${icon} [${g.severity}] ${g.file_path}`);
94
+ lines.push(` \u{1F4DD} ${g.description?.toString().substring(0, 100)}`);
95
+ if (g.workaround) lines.push(` \u{1F4A1} ${g.workaround.substring(0, 100)}`);
96
+ lines.push("");
97
+ }
98
+ return lines.join("\n");
99
+ } catch (err) {
100
+ return `Error: ${err}`;
101
+ }
102
+ }
103
+ function checkGotchasForFile(filePath) {
104
+ const warnings = [];
105
+ const markdownWarnings = checkFileGotchas(filePath);
106
+ try {
107
+ const gotchas = getActiveGotchas();
108
+ for (const g of gotchas) {
109
+ if (filePath.includes(g.filePath) || g.filePath.includes(filePath)) {
110
+ if (!markdownWarnings.some((w) => w.includes(g.description))) {
111
+ const icon = g.severity === "critical" ? "\u{1F534}" : g.severity === "high" ? "\u{1F7E0}" : g.severity === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
112
+ warnings.push(`${icon} **Known Gotcha**: ${g.description} (${g.severity})`);
113
+ }
114
+ }
115
+ }
116
+ } catch {
117
+ }
118
+ return [.../* @__PURE__ */ new Set([...markdownWarnings, ...warnings])];
119
+ }
120
+ async function syncGotchasToDb() {
121
+ try {
122
+ await ensureGotchasSchema();
123
+ const db = await getDb();
124
+ const gotchas = getActiveGotchas();
125
+ let synced = 0;
126
+ for (const g of gotchas) {
127
+ const checkStmt = db.prepare(
128
+ `SELECT id FROM known_gotchas WHERE file_path = ? AND description = ?`
129
+ );
130
+ checkStmt.bind([g.filePath, g.description]);
131
+ const exists = checkStmt.step();
132
+ checkStmt.free();
133
+ if (exists) continue;
134
+ db.run(
135
+ `INSERT INTO known_gotchas (file_path, description, severity) VALUES (?, ?, ?)`,
136
+ [g.filePath, g.description, g.severity]
137
+ );
138
+ synced++;
139
+ }
140
+ saveDb();
141
+ return { synced };
142
+ } catch {
143
+ return { synced: 0 };
144
+ }
145
+ }
146
+ export {
147
+ addGotcha,
148
+ checkGotchasForFile,
149
+ listGotchas,
150
+ syncGotchasToDb
151
+ };
@@ -14,8 +14,8 @@ import {
14
14
  searchGraph,
15
15
  traceFlow,
16
16
  upsertNode
17
- } from "./chunk-K64NSHBR.js";
18
- import "./chunk-GDNAWLHF.js";
17
+ } from "./chunk-4OB3XMHT.js";
18
+ import "./chunk-NAM7SCBT.js";
19
19
  import "./chunk-E2KFPEBT.js";
20
20
  export {
21
21
  addEdge,
@@ -4,8 +4,8 @@ import {
4
4
  recordDecision,
5
5
  scoreMemoryRelevance,
6
6
  shouldRecordDecision
7
- } from "./chunk-X5TPBDKO.js";
8
- import "./chunk-BI7KD3SG.js";
7
+ } from "./chunk-RTGLQDMI.js";
8
+ import "./chunk-SLRRDKQ2.js";
9
9
  import "./chunk-E2KFPEBT.js";
10
10
  export {
11
11
  formatDecisionTemplate,
@@ -1,10 +1,10 @@
1
- import {
2
- recordDecisionLog
3
- } from "./chunk-GDNAWLHF.js";
4
1
  import {
5
2
  recordDecision
6
- } from "./chunk-X5TPBDKO.js";
7
- import "./chunk-BI7KD3SG.js";
3
+ } from "./chunk-RTGLQDMI.js";
4
+ import "./chunk-SLRRDKQ2.js";
5
+ import {
6
+ recordDecisionLog
7
+ } from "./chunk-NAM7SCBT.js";
8
8
  import "./chunk-E2KFPEBT.js";
9
9
 
10
10
  // src/engine/kumaMiner.ts