@plumpslabs/kuma 2.3.7 → 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.
- package/README.md +25 -3
- package/dist/{chunk-K64NSHBR.js → chunk-4OB3XMHT.js} +2 -2
- package/dist/chunk-53J56QCQ.js +282 -0
- package/dist/{chunk-FOQQ2CSL.js → chunk-FL2TLLMX.js} +1 -1
- package/dist/{chunk-GDNAWLHF.js → chunk-NAM7SCBT.js} +63 -1
- package/dist/chunk-PTEPJK6M.js +155 -0
- package/dist/{chunk-X5TPBDKO.js → chunk-RTGLQDMI.js} +2 -2
- package/dist/{chunk-BI7KD3SG.js → chunk-SLRRDKQ2.js} +2 -2
- package/dist/contextDigest-4PCK3DSM.js +177 -0
- package/dist/domainRules-LDZPOIGZ.js +20 -0
- package/dist/index.js +184 -177
- package/dist/kumaAstValidator-CNM7FHYA.js +150 -0
- package/dist/{kumaDb-DJUDLYBJ.js → kumaDb-6D53ERFP.js} +1 -1
- package/dist/kumaDriftDetector-OESI5GTC.js +237 -0
- package/dist/kumaGotchas-DU5H6N7X.js +151 -0
- package/dist/{kumaGraph-35TAIBWD.js → kumaGraph-AWP743TJ.js} +2 -2
- package/dist/{kumaMemory-5SR3TGRL.js → kumaMemory-7TCUDVZX.js} +2 -2
- package/dist/{kumaMiner-P5KCUSF7.js → kumaMiner-FFXSRHAO.js} +3 -3
- package/dist/kumaPolicyEngine-S2PXN3C7.js +311 -0
- package/dist/{kumaSearch-LG2OYEJY.js → kumaSearch-QGB4QVXS.js} +1 -1
- package/dist/{kumaVerifier-LFRNIGSL.js → kumaVerifier-ARSGPZAM.js} +25 -2
- package/dist/{kumaVisualize-ODCWFSUY.js → kumaVisualize-TECABHUY.js} +1 -1
- package/dist/safetyAudit-55IVCG5B.js +12 -0
- package/dist/{safetyScore-PJGRRBWP.js → safetyScore-GR5N55CU.js} +5 -5
- package/dist/{sessionMemory-HBBXUSIP.js → sessionMemory-CA34TCPF.js} +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,6 +4,11 @@ import {
|
|
|
4
4
|
formatInitResults,
|
|
5
5
|
runInit
|
|
6
6
|
} from "./chunk-L5WU2HTN.js";
|
|
7
|
+
import {
|
|
8
|
+
auditStats,
|
|
9
|
+
queryAudit,
|
|
10
|
+
recordAudit
|
|
11
|
+
} from "./chunk-PTEPJK6M.js";
|
|
7
12
|
import {
|
|
8
13
|
analyzeImpact,
|
|
9
14
|
autoHeal,
|
|
@@ -14,22 +19,22 @@ import {
|
|
|
14
19
|
getGraphStats,
|
|
15
20
|
searchGraph,
|
|
16
21
|
traceFlow
|
|
17
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-4OB3XMHT.js";
|
|
18
23
|
import {
|
|
19
24
|
formatDecisionTemplate,
|
|
20
25
|
getProactiveMemories,
|
|
21
26
|
recordDecision,
|
|
22
27
|
scoreMemoryRelevance
|
|
23
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-RTGLQDMI.js";
|
|
24
29
|
import {
|
|
25
30
|
buildDriftMessages,
|
|
26
31
|
getGitDiffStat,
|
|
27
32
|
getSessionStats,
|
|
28
33
|
getUnresolvedCount
|
|
29
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-FL2TLLMX.js";
|
|
30
35
|
import {
|
|
31
36
|
sessionMemory
|
|
32
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-SLRRDKQ2.js";
|
|
33
38
|
import {
|
|
34
39
|
addContextNote,
|
|
35
40
|
addSecurityFinding,
|
|
@@ -50,12 +55,11 @@ import {
|
|
|
50
55
|
runDoctor,
|
|
51
56
|
runGarbageCollection,
|
|
52
57
|
saveBenchmark,
|
|
53
|
-
saveDb,
|
|
54
58
|
saveHealthSnapshot,
|
|
55
59
|
saveResearchCache,
|
|
56
60
|
updateDecisionStatus,
|
|
57
61
|
updateTodoStatus
|
|
58
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-NAM7SCBT.js";
|
|
59
63
|
import {
|
|
60
64
|
getProjectRoot,
|
|
61
65
|
validateFilePath
|
|
@@ -124,7 +128,19 @@ var CONTEXT_ALIASES = {
|
|
|
124
128
|
"diagram": "visualize",
|
|
125
129
|
"flow": "visualize",
|
|
126
130
|
"viz": "visualize",
|
|
127
|
-
"kuma_visualize": "visualize"
|
|
131
|
+
"kuma_visualize": "visualize",
|
|
132
|
+
// Digest synonyms (Issue #18)
|
|
133
|
+
"digest": "digest",
|
|
134
|
+
"bootstrap": "digest",
|
|
135
|
+
"kuma_digest": "digest",
|
|
136
|
+
"kuma_bootstrap": "digest",
|
|
137
|
+
"briefing": "digest",
|
|
138
|
+
"overview": "digest",
|
|
139
|
+
// Drift detection synonyms (Issue #20)
|
|
140
|
+
"drift": "drift",
|
|
141
|
+
"staleness": "drift",
|
|
142
|
+
"code-drift": "drift",
|
|
143
|
+
"freshness": "drift"
|
|
128
144
|
};
|
|
129
145
|
async function handleContext(params) {
|
|
130
146
|
const rawAction = params.action || "init";
|
|
@@ -151,8 +167,12 @@ async function handleContext(params) {
|
|
|
151
167
|
return handleSync(params);
|
|
152
168
|
case "visualize":
|
|
153
169
|
return handleVisualize(params);
|
|
170
|
+
case "digest":
|
|
171
|
+
return handleDigest(params);
|
|
172
|
+
case "drift":
|
|
173
|
+
return handleDrift(params);
|
|
154
174
|
default:
|
|
155
|
-
return `Unknown action "${action}". Use: init, research, impact, navigate, changes, rollback, researches, health, sync, visualize`;
|
|
175
|
+
return `Unknown action "${action}". Use: init, research, impact, navigate, changes, rollback, researches, health, sync, visualize, digest, drift`;
|
|
156
176
|
}
|
|
157
177
|
}
|
|
158
178
|
async function handleInit(_params) {
|
|
@@ -213,8 +233,8 @@ async function handleInit(_params) {
|
|
|
213
233
|
lines.push(` \u{1F4DD} Modified: ${summary.modifiedFiles?.length || 0} file(s)`);
|
|
214
234
|
lines.push(` \u{1F6E0}\uFE0F Tool calls: ${summary.toolCallCount}`);
|
|
215
235
|
try {
|
|
216
|
-
const { computeSafetyScore, formatSafetyScore } = await import("./safetyScore-
|
|
217
|
-
const { saveHealthSnapshot: saveHealthSnapshot2 } = await import("./kumaDb-
|
|
236
|
+
const { computeSafetyScore, formatSafetyScore } = await import("./safetyScore-GR5N55CU.js");
|
|
237
|
+
const { saveHealthSnapshot: saveHealthSnapshot2 } = await import("./kumaDb-6D53ERFP.js");
|
|
218
238
|
const score = await computeSafetyScore(_params.goal);
|
|
219
239
|
const checksStr = JSON.stringify(score.checks);
|
|
220
240
|
await saveHealthSnapshot2(score.score, score.risk, checksStr, score.summary);
|
|
@@ -387,8 +407,8 @@ async function handleResearches(_params) {
|
|
|
387
407
|
async function handleHealth(_params) {
|
|
388
408
|
sessionMemory.recordToolCall("kuma_context_health", {});
|
|
389
409
|
try {
|
|
390
|
-
const { computeSafetyScore, formatSafetyScore } = await import("./safetyScore-
|
|
391
|
-
const { saveHealthSnapshot: saveHealthSnapshot2 } = await import("./kumaDb-
|
|
410
|
+
const { computeSafetyScore, formatSafetyScore } = await import("./safetyScore-GR5N55CU.js");
|
|
411
|
+
const { saveHealthSnapshot: saveHealthSnapshot2 } = await import("./kumaDb-6D53ERFP.js");
|
|
392
412
|
const score = await computeSafetyScore();
|
|
393
413
|
const checksStr = JSON.stringify(score.checks);
|
|
394
414
|
await saveHealthSnapshot2(score.score, score.risk, checksStr, score.summary);
|
|
@@ -415,8 +435,8 @@ async function handleSync(params) {
|
|
|
415
435
|
lines.push(` \u{1F6E0}\uFE0F Tool calls: ${summary.toolCallCount}`);
|
|
416
436
|
lines.push("");
|
|
417
437
|
try {
|
|
418
|
-
const { computeSafetyScore, formatSafetyScore } = await import("./safetyScore-
|
|
419
|
-
const { saveHealthSnapshot: saveHealthSnapshot2 } = await import("./kumaDb-
|
|
438
|
+
const { computeSafetyScore, formatSafetyScore } = await import("./safetyScore-GR5N55CU.js");
|
|
439
|
+
const { saveHealthSnapshot: saveHealthSnapshot2 } = await import("./kumaDb-6D53ERFP.js");
|
|
420
440
|
const score = await computeSafetyScore(params.goal);
|
|
421
441
|
const checksStr = JSON.stringify(score.checks);
|
|
422
442
|
await saveHealthSnapshot2(score.score, score.risk, checksStr, score.summary);
|
|
@@ -427,14 +447,14 @@ async function handleSync(params) {
|
|
|
427
447
|
}
|
|
428
448
|
lines.push("");
|
|
429
449
|
try {
|
|
430
|
-
const { getGraphStats: getGraphStats2 } = await import("./kumaGraph-
|
|
450
|
+
const { getGraphStats: getGraphStats2 } = await import("./kumaGraph-AWP743TJ.js");
|
|
431
451
|
lines.push("**Knowledge Graph**");
|
|
432
452
|
lines.push(await getGraphStats2());
|
|
433
453
|
} catch {
|
|
434
454
|
}
|
|
435
455
|
lines.push("");
|
|
436
456
|
try {
|
|
437
|
-
const { getProactiveMemories: getProactiveMemories2 } = await import("./kumaMemory-
|
|
457
|
+
const { getProactiveMemories: getProactiveMemories2 } = await import("./kumaMemory-7TCUDVZX.js");
|
|
438
458
|
const memories = getProactiveMemories2();
|
|
439
459
|
if (memories) {
|
|
440
460
|
lines.push("**Relevant Memories**");
|
|
@@ -448,13 +468,38 @@ async function handleSync(params) {
|
|
|
448
468
|
}
|
|
449
469
|
async function handleVisualize(params) {
|
|
450
470
|
const scope = params.scope;
|
|
451
|
-
const { generateVisualizeReport } = await import("./kumaVisualize-
|
|
471
|
+
const { generateVisualizeReport } = await import("./kumaVisualize-TECABHUY.js");
|
|
452
472
|
return await generateVisualizeReport({
|
|
453
473
|
scope,
|
|
454
474
|
type: "flowchart",
|
|
455
475
|
maxNodes: 40
|
|
456
476
|
});
|
|
457
477
|
}
|
|
478
|
+
async function handleDigest(_params) {
|
|
479
|
+
sessionMemory.recordToolCall("kuma_context_digest", {});
|
|
480
|
+
try {
|
|
481
|
+
const { generateContextDigest } = await import("./contextDigest-4PCK3DSM.js");
|
|
482
|
+
return await generateContextDigest();
|
|
483
|
+
} catch (err) {
|
|
484
|
+
try {
|
|
485
|
+
const { generateDigest } = await import("./domainRules-LDZPOIGZ.js");
|
|
486
|
+
return generateDigest();
|
|
487
|
+
} catch {
|
|
488
|
+
return `Error generating digest: ${err}`;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
async function handleDrift(_params) {
|
|
493
|
+
sessionMemory.recordToolCall("kuma_context_drift", {});
|
|
494
|
+
try {
|
|
495
|
+
const { detectDrift, formatDriftReport, flagStaleRecords } = await import("./kumaDriftDetector-OESI5GTC.js");
|
|
496
|
+
await flagStaleRecords();
|
|
497
|
+
const records = await detectDrift();
|
|
498
|
+
return formatDriftReport(records);
|
|
499
|
+
} catch (err) {
|
|
500
|
+
return `Error detecting drift: ${err}`;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
458
503
|
function computeProjectHash(scope) {
|
|
459
504
|
try {
|
|
460
505
|
const root = getProjectRoot();
|
|
@@ -536,7 +581,27 @@ var MEMORY_ALIASES = {
|
|
|
536
581
|
// Changes synonyms
|
|
537
582
|
"changes": "changes",
|
|
538
583
|
"change-log": "changes",
|
|
539
|
-
"history": "changes"
|
|
584
|
+
"history": "changes",
|
|
585
|
+
// Layer 1: Domain Rules (Issue #17)
|
|
586
|
+
"domain_rules": "domain_rules",
|
|
587
|
+
"domain-rules": "domain_rules",
|
|
588
|
+
"domain": "domain_rules",
|
|
589
|
+
"business-rules": "domain_rules",
|
|
590
|
+
// Layer 2: Architecture Flow (Issue #17)
|
|
591
|
+
"arch_flow": "arch_flow",
|
|
592
|
+
"arch-flow": "arch_flow",
|
|
593
|
+
"architecture": "arch_flow",
|
|
594
|
+
"flow-map": "arch_flow",
|
|
595
|
+
// Layer 3: Gotchas (Issue #17 / #21)
|
|
596
|
+
"gotcha": "gotcha",
|
|
597
|
+
"gotchas": "gotcha",
|
|
598
|
+
"known-gotchas": "gotcha",
|
|
599
|
+
"legacy": "gotcha",
|
|
600
|
+
"quirk": "gotcha",
|
|
601
|
+
// Layers summary
|
|
602
|
+
"layers": "layers",
|
|
603
|
+
"3-layer": "layers",
|
|
604
|
+
"memory-layers": "layers"
|
|
540
605
|
};
|
|
541
606
|
async function handleMemory(params) {
|
|
542
607
|
const rawAction = params.action || "session";
|
|
@@ -566,6 +631,14 @@ async function handleMemory(params) {
|
|
|
566
631
|
return handleBenchmark(params);
|
|
567
632
|
case "decision_log":
|
|
568
633
|
return handleDecisionLog(params);
|
|
634
|
+
case "domain_rules":
|
|
635
|
+
return handleLayerAction("domain_rules", params);
|
|
636
|
+
case "arch_flow":
|
|
637
|
+
return handleLayerAction("arch_flow", params);
|
|
638
|
+
case "gotcha":
|
|
639
|
+
return handleGotchaAction(params);
|
|
640
|
+
case "layers":
|
|
641
|
+
return handleLayersSummary(params);
|
|
569
642
|
default:
|
|
570
643
|
return `Unknown action "${action}".`;
|
|
571
644
|
}
|
|
@@ -576,7 +649,7 @@ async function handleDecision(params) {
|
|
|
576
649
|
case "template":
|
|
577
650
|
return formatDecisionTemplate();
|
|
578
651
|
case "suggest": {
|
|
579
|
-
const { shouldRecordDecision } = await import("./kumaMemory-
|
|
652
|
+
const { shouldRecordDecision } = await import("./kumaMemory-7TCUDVZX.js");
|
|
580
653
|
const check = shouldRecordDecision();
|
|
581
654
|
return check.worth ? `\u{1F4A1} Decision suggested: "${check.title}"
|
|
582
655
|
Use kuma_memory({ action: 'decision', title: '...', context: '...', rationale: '...', outcome: '...' }) to record.` : "\u2705 No decision needed at this time.";
|
|
@@ -654,11 +727,11 @@ async function handleSearch(params) {
|
|
|
654
727
|
if (!query) return "\u26A0\uFE0F query or scope parameter required.";
|
|
655
728
|
const limit = params.limit || 20;
|
|
656
729
|
const memResults = sessionMemory.searchMemory(query, limit);
|
|
657
|
-
const { searchGraph: searchGraph2 } = await import("./kumaGraph-
|
|
730
|
+
const { searchGraph: searchGraph2 } = await import("./kumaGraph-AWP743TJ.js");
|
|
658
731
|
const graphResults = await searchGraph2(query, Math.min(limit, 10));
|
|
659
732
|
let hybridResults = "";
|
|
660
733
|
try {
|
|
661
|
-
const { hybridSearch, formatHybridResults } = await import("./kumaSearch-
|
|
734
|
+
const { hybridSearch, formatHybridResults } = await import("./kumaSearch-QGB4QVXS.js");
|
|
662
735
|
const semanticResults = await hybridSearch(query, 8);
|
|
663
736
|
if (semanticResults.length > 0) {
|
|
664
737
|
hybridResults = "\n" + formatHybridResults(query, semanticResults);
|
|
@@ -742,7 +815,7 @@ async function handleDecisionLog(params) {
|
|
|
742
815
|
}
|
|
743
816
|
async function handleMine(params) {
|
|
744
817
|
sessionMemory.recordToolCall("kuma_memory_mine", { scope: params.scope });
|
|
745
|
-
const { mineHistoricalDecisions } = await import("./kumaMiner-
|
|
818
|
+
const { mineHistoricalDecisions } = await import("./kumaMiner-FFXSRHAO.js");
|
|
746
819
|
return await mineHistoricalDecisions({
|
|
747
820
|
scope: params.scope,
|
|
748
821
|
since: typeof params.since === "string" ? params.since : void 0,
|
|
@@ -750,6 +823,34 @@ async function handleMine(params) {
|
|
|
750
823
|
limit: params.limit
|
|
751
824
|
});
|
|
752
825
|
}
|
|
826
|
+
async function handleLayerAction(layer, params) {
|
|
827
|
+
const { readLayer, writeLayer } = await import("./domainRules-LDZPOIGZ.js");
|
|
828
|
+
if (params.content) {
|
|
829
|
+
return writeLayer(layer, params.content);
|
|
830
|
+
}
|
|
831
|
+
return readLayer(layer);
|
|
832
|
+
}
|
|
833
|
+
async function handleGotchaAction(params) {
|
|
834
|
+
if (params.content && params.scope) {
|
|
835
|
+
const { addGotcha } = await import("./kumaGotchas-DU5H6N7X.js");
|
|
836
|
+
return await addGotcha({
|
|
837
|
+
filePath: params.scope,
|
|
838
|
+
description: params.content,
|
|
839
|
+
severity: params.status || "medium",
|
|
840
|
+
workaround: params.description
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
const { listGotchas, syncGotchasToDb } = await import("./kumaGotchas-DU5H6N7X.js");
|
|
844
|
+
await syncGotchasToDb();
|
|
845
|
+
return await listGotchas({
|
|
846
|
+
filePath: params.scope,
|
|
847
|
+
severity: params.status
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
async function handleLayersSummary(_params) {
|
|
851
|
+
const { getLayersSummary } = await import("./domainRules-LDZPOIGZ.js");
|
|
852
|
+
return getLayersSummary();
|
|
853
|
+
}
|
|
753
854
|
|
|
754
855
|
// src/engine/kumaLock.ts
|
|
755
856
|
import fs3 from "fs";
|
|
@@ -858,151 +959,6 @@ function cleanStaleLocks() {
|
|
|
858
959
|
return count > 0 ? `\u{1F9F9} Cleaned ${count} stale lock(s).` : "\u2705 No stale locks found.";
|
|
859
960
|
}
|
|
860
961
|
|
|
861
|
-
// src/engine/safetyAudit.ts
|
|
862
|
-
var SCHEMA_SQL = `
|
|
863
|
-
CREATE TABLE IF NOT EXISTS safety_audit (
|
|
864
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
865
|
-
timestamp INTEGER NOT NULL,
|
|
866
|
-
tool_name TEXT NOT NULL,
|
|
867
|
-
action TEXT NOT NULL,
|
|
868
|
-
file_path TEXT,
|
|
869
|
-
risk_level TEXT NOT NULL DEFAULT 'low',
|
|
870
|
-
policy_violations INTEGER DEFAULT 0,
|
|
871
|
-
allowed INTEGER NOT NULL DEFAULT 1,
|
|
872
|
-
duration_ms INTEGER DEFAULT 0,
|
|
873
|
-
metadata TEXT DEFAULT '{}'
|
|
874
|
-
);
|
|
875
|
-
CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON safety_audit(timestamp);
|
|
876
|
-
CREATE INDEX IF NOT EXISTS idx_audit_tool ON safety_audit(tool_name);
|
|
877
|
-
CREATE INDEX IF NOT EXISTS idx_audit_risk ON safety_audit(risk_level);
|
|
878
|
-
CREATE INDEX IF NOT EXISTS idx_audit_allowed ON safety_audit(allowed);
|
|
879
|
-
`;
|
|
880
|
-
var schemaEnsured = false;
|
|
881
|
-
async function ensureSchema() {
|
|
882
|
-
if (schemaEnsured) return;
|
|
883
|
-
try {
|
|
884
|
-
const db = await getDb();
|
|
885
|
-
db.exec(SCHEMA_SQL);
|
|
886
|
-
saveDb();
|
|
887
|
-
schemaEnsured = true;
|
|
888
|
-
} catch (err) {
|
|
889
|
-
console.error(`[SafetyAudit] Failed to ensure schema: ${err}`);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
async function recordAudit(entry) {
|
|
893
|
-
try {
|
|
894
|
-
await ensureSchema();
|
|
895
|
-
const db = await getDb();
|
|
896
|
-
db.run(`
|
|
897
|
-
INSERT INTO safety_audit (timestamp, tool_name, action, file_path, risk_level, policy_violations, allowed, duration_ms, metadata)
|
|
898
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
899
|
-
`, [
|
|
900
|
-
entry.timestamp,
|
|
901
|
-
entry.toolName,
|
|
902
|
-
entry.action,
|
|
903
|
-
entry.filePath || null,
|
|
904
|
-
entry.riskLevel,
|
|
905
|
-
entry.policyViolations,
|
|
906
|
-
entry.allowed ? 1 : 0,
|
|
907
|
-
entry.durationMs,
|
|
908
|
-
JSON.stringify(entry.metadata || {})
|
|
909
|
-
]);
|
|
910
|
-
saveDb();
|
|
911
|
-
} catch (err) {
|
|
912
|
-
console.error(`[SafetyAudit] Failed to record audit: ${err}`);
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
async function queryAudit(params) {
|
|
916
|
-
try {
|
|
917
|
-
await ensureSchema();
|
|
918
|
-
const db = await getDb();
|
|
919
|
-
const { toolName, riskLevel, allowed, limit = 20, since } = params;
|
|
920
|
-
let sql = "SELECT * FROM safety_audit WHERE 1=1";
|
|
921
|
-
const bindParams = [];
|
|
922
|
-
if (toolName) {
|
|
923
|
-
sql += " AND tool_name = ?";
|
|
924
|
-
bindParams.push(toolName);
|
|
925
|
-
}
|
|
926
|
-
if (riskLevel) {
|
|
927
|
-
sql += " AND risk_level = ?";
|
|
928
|
-
bindParams.push(riskLevel);
|
|
929
|
-
}
|
|
930
|
-
if (allowed !== void 0) {
|
|
931
|
-
sql += " AND allowed = ?";
|
|
932
|
-
bindParams.push(allowed ? 1 : 0);
|
|
933
|
-
}
|
|
934
|
-
if (since) {
|
|
935
|
-
sql += " AND timestamp >= ?";
|
|
936
|
-
bindParams.push(since);
|
|
937
|
-
}
|
|
938
|
-
sql += " ORDER BY timestamp DESC LIMIT ?";
|
|
939
|
-
bindParams.push(limit);
|
|
940
|
-
const stmt = db.prepare(sql);
|
|
941
|
-
stmt.bind(bindParams);
|
|
942
|
-
const results = [];
|
|
943
|
-
while (stmt.step()) {
|
|
944
|
-
results.push(stmt.getAsObject());
|
|
945
|
-
}
|
|
946
|
-
stmt.free();
|
|
947
|
-
if (results.length === 0) {
|
|
948
|
-
return "\u{1F4CB} **Safety Audit** \u2014 No records found for the given filters.";
|
|
949
|
-
}
|
|
950
|
-
const lines = [
|
|
951
|
-
`\u{1F4CB} **Safety Audit** \u2014 ${results.length} record(s)`,
|
|
952
|
-
`\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`,
|
|
953
|
-
""
|
|
954
|
-
];
|
|
955
|
-
for (const r of results) {
|
|
956
|
-
const riskIcon = r.risk_level === "critical" ? "\u{1F534}" : r.risk_level === "high" ? "\u{1F7E0}" : r.risk_level === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
|
|
957
|
-
const allowIcon = r.allowed ? "\u2705" : "\u26D4";
|
|
958
|
-
const time = new Date(r.timestamp * 1e3).toLocaleTimeString();
|
|
959
|
-
lines.push(`${allowIcon} ${riskIcon} **${r.tool_name}** \u2014 ${r.action}`);
|
|
960
|
-
if (r.file_path) lines.push(` \u{1F4CD} ${r.file_path}`);
|
|
961
|
-
lines.push(` \u{1F550} ${time} | ${r.duration_ms}ms | ${r.policy_violations} policy violation(s)`);
|
|
962
|
-
lines.push("");
|
|
963
|
-
}
|
|
964
|
-
return lines.join("\n");
|
|
965
|
-
} catch (err) {
|
|
966
|
-
return `Error querying audit: ${err}`;
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
async function auditStats() {
|
|
970
|
-
try {
|
|
971
|
-
await ensureSchema();
|
|
972
|
-
const db = await getDb();
|
|
973
|
-
const total = db.exec("SELECT COUNT(*) as c FROM safety_audit")[0]?.values[0][0] ?? 0;
|
|
974
|
-
const blocked = db.exec("SELECT COUNT(*) as c FROM safety_audit WHERE allowed = 0")[0]?.values[0][0] ?? 0;
|
|
975
|
-
const critical = db.exec("SELECT COUNT(*) as c FROM safety_audit WHERE risk_level IN ('high','critical')")[0]?.values[0][0] ?? 0;
|
|
976
|
-
let topBlocked = [];
|
|
977
|
-
try {
|
|
978
|
-
const stmt = db.prepare("SELECT tool_name, COUNT(*) as cnt FROM safety_audit WHERE allowed = 0 GROUP BY tool_name ORDER BY cnt DESC LIMIT 5");
|
|
979
|
-
while (stmt.step()) {
|
|
980
|
-
topBlocked.push(stmt.getAsObject());
|
|
981
|
-
}
|
|
982
|
-
stmt.free();
|
|
983
|
-
} catch {
|
|
984
|
-
}
|
|
985
|
-
const lines = [
|
|
986
|
-
`\u{1F4CA} **Safety Audit Stats**`,
|
|
987
|
-
`\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`,
|
|
988
|
-
"",
|
|
989
|
-
`\u{1F4DD} Total operations: ${total}`,
|
|
990
|
-
`\u26D4 Blocked: ${blocked} (${total > 0 ? (blocked / total * 100).toFixed(1) : 0}%)`,
|
|
991
|
-
`\u{1F534} High/Critical risk: ${critical}`,
|
|
992
|
-
""
|
|
993
|
-
];
|
|
994
|
-
if (topBlocked.length > 0) {
|
|
995
|
-
lines.push("**Most blocked tools:**");
|
|
996
|
-
for (const t of topBlocked) {
|
|
997
|
-
lines.push(` \u2022 ${t.tool_name}: ${t.cnt}x blocked`);
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
return lines.join("\n");
|
|
1001
|
-
} catch (err) {
|
|
1002
|
-
return `Error getting audit stats: ${err}`;
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
962
|
// src/tools/kumaPolicy.ts
|
|
1007
963
|
import fs4 from "fs";
|
|
1008
964
|
import path4 from "path";
|
|
@@ -1836,6 +1792,11 @@ async function handleSafety(params) {
|
|
|
1836
1792
|
return handleGitignore(params);
|
|
1837
1793
|
case "clean":
|
|
1838
1794
|
return handleClean(params);
|
|
1795
|
+
case "policy":
|
|
1796
|
+
return handlePolicy(params);
|
|
1797
|
+
case "ast":
|
|
1798
|
+
case "validate":
|
|
1799
|
+
return handleAstValidation(params);
|
|
1839
1800
|
default:
|
|
1840
1801
|
return `Unknown action "${action}".`;
|
|
1841
1802
|
}
|
|
@@ -1879,7 +1840,7 @@ async function handleLock(params) {
|
|
|
1879
1840
|
}
|
|
1880
1841
|
async function handleHealth2(_params) {
|
|
1881
1842
|
try {
|
|
1882
|
-
const { computeSafetyScore, formatSafetyScore } = await import("./safetyScore-
|
|
1843
|
+
const { computeSafetyScore, formatSafetyScore } = await import("./safetyScore-GR5N55CU.js");
|
|
1883
1844
|
const score = await computeSafetyScore();
|
|
1884
1845
|
await saveHealthSnapshot(score.score, score.risk, JSON.stringify(score.checks), score.summary);
|
|
1885
1846
|
return formatSafetyScore(score);
|
|
@@ -1983,6 +1944,52 @@ async function handleClean(_params) {
|
|
|
1983
1944
|
return `${result}
|
|
1984
1945
|
\u{1F4A1} Drift warnings have been reset. Any temporary debug artifacts are now cleared.`;
|
|
1985
1946
|
}
|
|
1947
|
+
async function handlePolicy(params) {
|
|
1948
|
+
sessionMemory.recordToolCall("kuma_safety_policy", {});
|
|
1949
|
+
if (params.command) {
|
|
1950
|
+
const { evaluateCommand, evaluateFilePath } = await import("./kumaPolicyEngine-S2PXN3C7.js");
|
|
1951
|
+
const commandVerdict = evaluateCommand(params.command);
|
|
1952
|
+
const lines = [];
|
|
1953
|
+
lines.push(`\u{1F4DC} **Policy Check**: ${commandVerdict.allowed ? "\u2705 Allowed" : "\u26D4 Blocked"}`);
|
|
1954
|
+
lines.push(`\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`);
|
|
1955
|
+
lines.push("");
|
|
1956
|
+
lines.push(`\u{1F4BB} Command: \`${params.command}\``);
|
|
1957
|
+
lines.push(`\u{1F4CB} Result: ${commandVerdict.message}`);
|
|
1958
|
+
if (commandVerdict.blockedBy) {
|
|
1959
|
+
lines.push("");
|
|
1960
|
+
lines.push(`\u{1F534} **Blocked by rule**: ${commandVerdict.blockedBy.description}`);
|
|
1961
|
+
if (commandVerdict.requiresOverride) {
|
|
1962
|
+
lines.push(`\u{1F511} Use kuma_safety({ action: 'override', toolName: 'policy', reason: '...' }) to bypass.`);
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
for (const w of commandVerdict.warnings) {
|
|
1966
|
+
lines.push(`\u{1F7E1} **Warning**: ${w.description}`);
|
|
1967
|
+
}
|
|
1968
|
+
if (params.filePath) {
|
|
1969
|
+
const fileVerdict = evaluateFilePath(params.filePath);
|
|
1970
|
+
if (!fileVerdict.allowed) {
|
|
1971
|
+
lines.push("");
|
|
1972
|
+
lines.push(fileVerdict.message);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
return lines.join("\n");
|
|
1976
|
+
}
|
|
1977
|
+
const { formatPolicyStatus } = await import("./kumaPolicyEngine-S2PXN3C7.js");
|
|
1978
|
+
return formatPolicyStatus();
|
|
1979
|
+
}
|
|
1980
|
+
async function handleAstValidation(params) {
|
|
1981
|
+
sessionMemory.recordToolCall("kuma_safety_ast", { scope: params.scope });
|
|
1982
|
+
const { validateCodeContent, validateFile, formatValidationFindings } = await import("./kumaAstValidator-CNM7FHYA.js");
|
|
1983
|
+
if (params.command) {
|
|
1984
|
+
const findings = validateCodeContent(params.command, params.scope);
|
|
1985
|
+
return formatValidationFindings(findings, params.scope);
|
|
1986
|
+
}
|
|
1987
|
+
if (params.scope) {
|
|
1988
|
+
const findings = validateFile(params.scope);
|
|
1989
|
+
return formatValidationFindings(findings, params.scope);
|
|
1990
|
+
}
|
|
1991
|
+
return "\u26A0\uFE0F Provide a scope (file path) or command (code content) to validate.";
|
|
1992
|
+
}
|
|
1986
1993
|
var _lastVerifyCall = 0;
|
|
1987
1994
|
var VERIFY_COOLDOWN_MS = 3e4;
|
|
1988
1995
|
async function handleVerify(params) {
|
|
@@ -1993,7 +2000,7 @@ async function handleVerify(params) {
|
|
|
1993
2000
|
}
|
|
1994
2001
|
_lastVerifyCall = now;
|
|
1995
2002
|
sessionMemory.recordToolCall("kuma_safety_verify", { scope: params.scope || params.filePath });
|
|
1996
|
-
const { runAutoVerification } = await import("./kumaVerifier-
|
|
2003
|
+
const { runAutoVerification } = await import("./kumaVerifier-ARSGPZAM.js");
|
|
1997
2004
|
return await runAutoVerification({
|
|
1998
2005
|
scope: params.scope || params.filePath,
|
|
1999
2006
|
force: params.force,
|
|
@@ -2007,7 +2014,7 @@ function registerAllTools(server) {
|
|
|
2007
2014
|
"kuma_context",
|
|
2008
2015
|
"**Call FIRST every session.** Understand your project before making changes. Actions: init (load project brief), research (5-step pipeline: cache\u2192staleness\u2192graph\u2192impact\u2192decision), impact (analyze change effects), navigate (trace code flow), changes (view change log), health (project health score 0-100). RESEARCH IS REQUIRED before editing unfamiliar code.",
|
|
2009
2016
|
{
|
|
2010
|
-
action: z.enum(["init", "research", "impact", "navigate", "changes", "health", "rollback", "researches", "sync", "visualize"]).describe("Action: init=project brief, research=5-step research pipeline (REQUIRED before edits), impact=analyze change effects, navigate=trace code flow, changes=view change log, rollback=undo a change by ID, researches=list all cached research, sync=unified batch state, visualize=Mermaid knowledge graph diagram, health=project health score"),
|
|
2017
|
+
action: z.enum(["init", "research", "impact", "navigate", "changes", "health", "rollback", "researches", "sync", "visualize", "digest", "drift"]).describe("Action: init=project brief, research=5-step research pipeline (REQUIRED before edits), impact=analyze change effects, navigate=trace code flow, changes=view change log, rollback=undo a change by ID, researches=list all cached research, sync=unified batch state, visualize=Mermaid knowledge graph diagram, digest=ultra-compact <500 token project briefing (Issue #18), drift=detect memory staleness & code drift (Issue #20), health=project health score"),
|
|
2011
2018
|
scope: z.string().optional().describe("Research scope for research action (e.g. 'auth', 'database', 'api')"),
|
|
2012
2019
|
target: z.string().optional().describe("Target symbol/file for impact/navigate/changes"),
|
|
2013
2020
|
goal: z.string().optional().describe("Current goal (for init/health)"),
|
|
@@ -2034,7 +2041,7 @@ function registerAllTools(server) {
|
|
|
2034
2041
|
"kuma_memory",
|
|
2035
2042
|
"Record and retrieve project knowledge. Actions: decision (ADR-style record/template/suggest), mine (mine historical decisions from git log & code comments), research_save (save research), session (session summary), heal (graph repair), search (search all), changes (change log), todo (persistent todo CRUD), context (inject context notes), benchmark (capture/diff metrics), decision_log (living document with status tracking).",
|
|
2036
2043
|
{
|
|
2037
|
-
action: z.enum(["decision", "mine", "research_save", "session", "heal", "search", "changes", "todo", "context", "benchmark", "decision_log"]).describe("Memory action: decision=ADR, mine=mine git log & comments, research_save=save, session=summary, heal=repair, search=search, changes=log, todo=manage todos, context=inject notes, benchmark=capture/diff, decision_log=manage decisions"),
|
|
2044
|
+
action: z.enum(["decision", "mine", "research_save", "session", "heal", "search", "changes", "todo", "context", "benchmark", "decision_log", "domain_rules", "arch_flow", "gotcha", "layers"]).describe("Memory action: decision=ADR, mine=mine git log & comments, research_save=save, session=summary, heal=repair, search=search, changes=log, todo=manage todos, context=inject notes, benchmark=capture/diff, decision_log=manage decisions, domain_rules=Layer 1 business rules (Issue #17), arch_flow=Layer 2 architecture flow (Issue #17), gotcha=Layer 3 known gotchas (Issue #17/#21), layers=all 3 layers summary"),
|
|
2038
2045
|
scope: z.string().optional().describe("Scope for research_save/search/todo/context/mine"),
|
|
2039
2046
|
query: z.string().optional().describe("Search query for search action"),
|
|
2040
2047
|
content: z.string().optional().describe("Content/notes for research_save / context"),
|
|
@@ -2098,7 +2105,7 @@ function registerAllTools(server) {
|
|
|
2098
2105
|
"kuma_safety",
|
|
2099
2106
|
"Safety checks, policy enforcement, security scanning, integrated auto-verification, and project hygiene. Actions: guard (anti-pattern detection), verify (auto-run scoped tests), check (pre-exec safety), audit (query trail), lock (multi-agent), health (score), security (scan for leaks), gc (garbage collection), doctor (health check), portability (path check), gitignore (auto-config), override (bypass).",
|
|
2100
2107
|
{
|
|
2101
|
-
action: z.enum(["guard", "verify", "check", "audit", "lock", "health", "override", "security", "gc", "doctor", "portability", "gitignore", "clean"]).describe("Safety action: guard=anti-patterns, verify=auto-run scoped tests, check=pre-exec safety, audit=query trail, lock=multi-agent, health=score, security=scan leaks, gc=garbage collect, doctor=health check, portability=paths, gitignore=config, clean=purge scratch dir & drift, override=bypass"),
|
|
2108
|
+
action: z.enum(["guard", "verify", "check", "audit", "lock", "health", "override", "security", "gc", "doctor", "portability", "gitignore", "clean", "policy", "ast", "validate"]).describe("Safety action: guard=anti-patterns, verify=auto-run scoped tests, check=pre-exec safety, audit=query trail, lock=multi-agent, health=score, security=scan leaks, gc=garbage collect, doctor=health check, portability=paths, gitignore=config, clean=purge scratch dir & drift, policy=Policy-as-Code engine (Issue #24), ast/validate=AST-based code validation (Issue #22), override=bypass"),
|
|
2102
2109
|
// Verify params
|
|
2103
2110
|
scope: z.string().optional().describe("Scope for verify or context (e.g. 'auth', file path)"),
|
|
2104
2111
|
// Guard params
|
|
@@ -2192,7 +2199,7 @@ async function main() {
|
|
|
2192
2199
|
console.error("");
|
|
2193
2200
|
let killedCount = 0;
|
|
2194
2201
|
try {
|
|
2195
|
-
const { getRunningVerificationPid } = await import("./kumaVerifier-
|
|
2202
|
+
const { getRunningVerificationPid } = await import("./kumaVerifier-ARSGPZAM.js");
|
|
2196
2203
|
const pid = getRunningVerificationPid();
|
|
2197
2204
|
if (pid) {
|
|
2198
2205
|
try {
|
|
@@ -2434,7 +2441,7 @@ async function main() {
|
|
|
2434
2441
|
console.error(`[${SERVER_NAME}] \u2705 Restored session (${sessionInfo.toolCallCount} previous tool calls)`);
|
|
2435
2442
|
}
|
|
2436
2443
|
try {
|
|
2437
|
-
const { buildFromSessionMemory } = await import("./kumaGraph-
|
|
2444
|
+
const { buildFromSessionMemory } = await import("./kumaGraph-AWP743TJ.js");
|
|
2438
2445
|
const edgeCount = await buildFromSessionMemory();
|
|
2439
2446
|
if (edgeCount > 0) {
|
|
2440
2447
|
console.error(`[${SERVER_NAME}] \u2705 Graph auto-populated with ${edgeCount} entries from session memory`);
|
|
@@ -2454,13 +2461,13 @@ async function main() {
|
|
|
2454
2461
|
console.error(`[${SERVER_NAME}] \u26A0\uFE0F Scratch directory setup: ${err}`);
|
|
2455
2462
|
}
|
|
2456
2463
|
try {
|
|
2457
|
-
const { getDb: getDb2, saveDb
|
|
2464
|
+
const { getDb: getDb2, saveDb } = await import("./kumaDb-6D53ERFP.js");
|
|
2458
2465
|
const db = await getDb2();
|
|
2459
2466
|
db.run(
|
|
2460
2467
|
`INSERT INTO sessions (started_at, goal, tool_calls) VALUES (?, ?, ?)`,
|
|
2461
2468
|
[Math.floor(Date.now() / 1e3), sessionMemory.getSummary().currentGoal || "Session start", sessionInfo.toolCallCount]
|
|
2462
2469
|
);
|
|
2463
|
-
|
|
2470
|
+
saveDb(db);
|
|
2464
2471
|
} catch (err) {
|
|
2465
2472
|
console.error(`[${SERVER_NAME}] \u26A0\uFE0F Session DB record: ${err}`);
|
|
2466
2473
|
}
|
|
@@ -2494,7 +2501,7 @@ fi
|
|
|
2494
2501
|
console.error(`[${SERVER_NAME}] \u26A0\uFE0F Auto-capture hook setup: ${err}`);
|
|
2495
2502
|
}
|
|
2496
2503
|
try {
|
|
2497
|
-
const { buildSearchVectors } = await import("./kumaSearch-
|
|
2504
|
+
const { buildSearchVectors } = await import("./kumaSearch-QGB4QVXS.js");
|
|
2498
2505
|
const vectors = await buildSearchVectors();
|
|
2499
2506
|
if (vectors.length > 0) {
|
|
2500
2507
|
console.error(`[${SERVER_NAME}] \u2705 Search vector cache pre-warmed (${vectors.length} documents)`);
|