@kage-core/kage-graph-mcp 1.1.38 → 1.3.0
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/cli.js +137 -4
- package/dist/daemon.js +5 -1
- package/dist/index.js +85 -14
- package/dist/kernel.js +537 -15
- package/package.json +1 -1
- package/viewer/app.js +93 -4
- package/viewer/index.html +8 -6
- package/viewer/styles.css +99 -2
package/dist/cli.js
CHANGED
|
@@ -12,6 +12,7 @@ function usage() {
|
|
|
12
12
|
|
|
13
13
|
Usage:
|
|
14
14
|
kage index --project <dir>
|
|
15
|
+
kage demo [--project <dir>]
|
|
15
16
|
kage init --project <dir>
|
|
16
17
|
kage policy --project <dir>
|
|
17
18
|
kage doctor --project <dir>
|
|
@@ -29,6 +30,9 @@ Usage:
|
|
|
29
30
|
kage hook uninstall --project <dir> [--json]
|
|
30
31
|
kage refresh --project <dir> [--full] [--json]
|
|
31
32
|
kage gc --project <dir> [--dry-run] [--force] [--json]
|
|
33
|
+
kage compact --project <dir> [--dry-run] [--json]
|
|
34
|
+
kage verify --project <dir> [--id <packet-id>] [--json]
|
|
35
|
+
kage suppressed --project <dir> [--json]
|
|
32
36
|
kage pr summarize --project <dir> [--json]
|
|
33
37
|
kage pr check --project <dir> [--json]
|
|
34
38
|
kage upgrade [--dry-run]
|
|
@@ -58,6 +62,7 @@ Usage:
|
|
|
58
62
|
kage inbox --project <dir> [--json]
|
|
59
63
|
kage quality --project <dir> [--json]
|
|
60
64
|
kage benchmark --project <dir> [--json]
|
|
65
|
+
kage benchmark --trust --project <dir> [--json]
|
|
61
66
|
kage benchmark --memory-quality [--json]
|
|
62
67
|
kage benchmark --scale [--sizes 240,1000,5000] [--json]
|
|
63
68
|
kage benchmark --project <dir> --compare --task <task> [--json]
|
|
@@ -74,14 +79,14 @@ Usage:
|
|
|
74
79
|
kage graph "<query>" --project <dir> [--json]
|
|
75
80
|
kage graph-registry --project <dir> [--json]
|
|
76
81
|
kage embeddings build --project <dir> [--model Xenova/all-MiniLM-L6-v2] [--json]
|
|
77
|
-
kage recall "<query>" --project <dir> [--json] [--explain] [--embeddings]
|
|
82
|
+
kage recall "<query>" --project <dir> [--json] [--explain] [--embeddings] [--max-context-tokens <n>] [--structural-hops <n>]
|
|
78
83
|
kage observe --project <dir> --event <json>
|
|
79
84
|
kage sessions --project <dir> [--json]
|
|
80
85
|
kage replay --project <dir> [--session <id>] [--limit <n>] [--json]
|
|
81
86
|
kage distill --project <dir> --session <id>
|
|
82
|
-
kage learn --project <dir> --learning <text> [--title <title>] [--type <type>] [--evidence <text>] [--verified-by <text>] [--tags a,b] [--paths a,b]
|
|
87
|
+
kage learn --project <dir> --learning <text> [--title <title>] [--type <type>] [--evidence <text>] [--verified-by <text>] [--tags a,b] [--paths a,b] [--graph-nodes a,b] [--allow-missing-paths]
|
|
83
88
|
kage feedback --project <dir> --packet <packet-id> --kind helpful|wrong|stale
|
|
84
|
-
kage capture --project <dir> --title <title> --body <body> [--type <type>] [--summary <summary>] [--tags a,b] [--paths a,b] [--stack a,b]
|
|
89
|
+
kage capture --project <dir> --title <title> --body <body> [--type <type>] [--summary <summary>] [--tags a,b] [--paths a,b] [--stack a,b] [--graph-nodes a,b] [--allow-missing-paths]
|
|
85
90
|
kage propose --project <dir> --from-diff
|
|
86
91
|
kage review-artifact --project <dir>
|
|
87
92
|
kage promote --project <dir> --public <packet-id>
|
|
@@ -174,6 +179,30 @@ async function main() {
|
|
|
174
179
|
console.log(`Indexes:\n${result.indexes.map((path) => ` - ${path}`).join("\n")}`);
|
|
175
180
|
return;
|
|
176
181
|
}
|
|
182
|
+
if (command === "demo") {
|
|
183
|
+
const demoDir = takeArg(args, "--project") ?? `${process.cwd()}/kage-demo`;
|
|
184
|
+
const result = (0, kernel_js_1.runDemo)(demoDir);
|
|
185
|
+
if (args.includes("--json")) {
|
|
186
|
+
console.log(JSON.stringify(result, null, 2));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
console.log("Kage demo — can you trust your agent's memory?\n");
|
|
190
|
+
console.log(`Seeded ${result.captured.length} grounded memories in ${result.project_dir}\n`);
|
|
191
|
+
console.log("1. Hallucinated citation — REJECTED on write:");
|
|
192
|
+
if (result.rejected_hallucination) {
|
|
193
|
+
console.log(` ✗ "${result.rejected_hallucination.title}"`);
|
|
194
|
+
console.log(` ${result.rejected_hallucination.error}\n`);
|
|
195
|
+
}
|
|
196
|
+
console.log("2. Stale memory (cited file deleted) — WITHHELD from recall:");
|
|
197
|
+
for (const w of result.withheld)
|
|
198
|
+
console.log(` ⊘ ${w.title}\n ${w.reason}`);
|
|
199
|
+
console.log("\n3. Recall returns only grounded, current memory:");
|
|
200
|
+
for (const t of result.recalled)
|
|
201
|
+
console.log(` ✓ ${t}`);
|
|
202
|
+
console.log(`\nTrust score: ${result.trust_score}/100`);
|
|
203
|
+
console.log(`\nSee it in the viewer: ${result.viewer_command}`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
177
206
|
if (command === "init") {
|
|
178
207
|
const result = (0, kernel_js_1.initProject)(projectArg(args));
|
|
179
208
|
console.log(`Initialized Kage memory for ${result.index.projectDir}`);
|
|
@@ -404,6 +433,80 @@ async function main() {
|
|
|
404
433
|
}
|
|
405
434
|
return;
|
|
406
435
|
}
|
|
436
|
+
if (command === "compact") {
|
|
437
|
+
const project = projectArg(args);
|
|
438
|
+
const dryRun = args.includes("--dry-run");
|
|
439
|
+
const result = (0, kernel_js_1.compactProject)(project, { dryRun });
|
|
440
|
+
if (args.includes("--json")) {
|
|
441
|
+
console.log(JSON.stringify(result, null, 2));
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const label = dryRun ? " [dry-run]" : "";
|
|
445
|
+
console.log(`Kage compact${label} — scanned ${result.total_scanned} packets`);
|
|
446
|
+
if (result.pruned_citations.length) {
|
|
447
|
+
console.log(`\nPruned dead citations (${result.pruned_citations.length}):`);
|
|
448
|
+
for (const p of result.pruned_citations)
|
|
449
|
+
console.log(` ✂ ${p.title} — removed ${p.removed_paths.join(", ")}`);
|
|
450
|
+
}
|
|
451
|
+
if (result.deprecated.length) {
|
|
452
|
+
console.log(`\nDeprecated stale (${result.deprecated.length}):`);
|
|
453
|
+
for (const p of result.deprecated)
|
|
454
|
+
console.log(` ✗ ${p.title} — ${p.reason}`);
|
|
455
|
+
}
|
|
456
|
+
if (result.duplicate_clusters.length) {
|
|
457
|
+
console.log(`\nDuplicate clusters to merge (${result.duplicate_clusters.length}) — review with kage_compact / kage supersede:`);
|
|
458
|
+
for (const cluster of result.duplicate_clusters) {
|
|
459
|
+
console.log(` ~${cluster.score} similarity:`);
|
|
460
|
+
for (const member of cluster.packets)
|
|
461
|
+
console.log(` • ${member.title} (${member.id})`);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (!result.pruned_citations.length && !result.deprecated.length && !result.duplicate_clusters.length) {
|
|
465
|
+
console.log("Nothing to compact — memory is clean.");
|
|
466
|
+
}
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (command === "verify") {
|
|
470
|
+
const project = projectArg(args);
|
|
471
|
+
const idFlag = args.indexOf("--id");
|
|
472
|
+
const id = idFlag >= 0 ? args[idFlag + 1] : undefined;
|
|
473
|
+
const result = (0, kernel_js_1.verifyCitations)(project, { id });
|
|
474
|
+
if (args.includes("--json")) {
|
|
475
|
+
console.log(JSON.stringify(result, null, 2));
|
|
476
|
+
if (!result.ok)
|
|
477
|
+
process.exit(2);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (!result.ok) {
|
|
481
|
+
console.log(`Verification failed:\n${result.errors.map((error) => ` - ${error}`).join("\n")}`);
|
|
482
|
+
process.exit(2);
|
|
483
|
+
}
|
|
484
|
+
console.log(`Kage verify — ${result.checked} packet(s): ${result.valid} valid, ${result.stale} stale, ${result.ungrounded} ungrounded`);
|
|
485
|
+
for (const entry of result.packets.filter((p) => p.stale || !p.grounded)) {
|
|
486
|
+
const flags = [entry.stale ? `stale:${entry.stale_severity}` : "", entry.grounded ? "" : "ungrounded"].filter(Boolean).join(", ");
|
|
487
|
+
console.log(` ⚠ ${entry.title} [${flags}]`);
|
|
488
|
+
if (entry.missing_paths.length)
|
|
489
|
+
console.log(` missing: ${entry.missing_paths.join(", ")}`);
|
|
490
|
+
for (const reason of entry.stale_reasons)
|
|
491
|
+
console.log(` - ${reason}`);
|
|
492
|
+
}
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (command === "suppressed") {
|
|
496
|
+
const result = (0, kernel_js_1.kageSuppressedMemory)(projectArg(args));
|
|
497
|
+
if (args.includes("--json")) {
|
|
498
|
+
console.log(JSON.stringify(result, null, 2));
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
console.log(`Kage suppressed memory — ${result.count} packet(s) currently withheld from recall`);
|
|
502
|
+
for (const item of result.items) {
|
|
503
|
+
console.log(` ⊘ ${item.title}`);
|
|
504
|
+
console.log(` ${item.reason}`);
|
|
505
|
+
}
|
|
506
|
+
if (!result.count)
|
|
507
|
+
console.log(" (none — all recallable memory is grounded and current)");
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
407
510
|
if (command === "refresh") {
|
|
408
511
|
const result = (0, kernel_js_1.refreshProject)(projectArg(args), { full: args.includes("--full") });
|
|
409
512
|
if (args.includes("--json")) {
|
|
@@ -1258,6 +1361,24 @@ async function main() {
|
|
|
1258
1361
|
return;
|
|
1259
1362
|
}
|
|
1260
1363
|
if (command === "benchmark") {
|
|
1364
|
+
if (args.includes("--trust")) {
|
|
1365
|
+
const result = (0, kernel_js_1.benchmarkTrust)(projectArg(args));
|
|
1366
|
+
if (args.includes("--json")) {
|
|
1367
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1368
|
+
if (!result.ok)
|
|
1369
|
+
process.exitCode = 1;
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
console.log("Kage Trust Benchmark — can this memory be trusted?");
|
|
1373
|
+
console.log(`Trust score: ${result.trust_score}/100 (${result.ok ? "PASS" : "REVIEW"})`);
|
|
1374
|
+
console.log(` Hallucinated-citation rejection: ${result.metrics.hallucinated_citation_rejection_rate}% (${result.detail.hallucination.rejected}/${result.detail.hallucination.attempted})`);
|
|
1375
|
+
console.log(` Stale-memory exclusion: ${result.metrics.stale_memory_exclusion_rate}% (${result.detail.staleness.excluded_after}/${result.detail.staleness.recallable_before})`);
|
|
1376
|
+
console.log(` Live grounding rate: ${result.metrics.live_grounding_rate}% (${result.detail.live_memory.grounded}/${result.detail.live_memory.checked} packets)`);
|
|
1377
|
+
console.log(` Wrong-advice prevented: ${result.metrics.wrong_advice_prevented_rate}%`);
|
|
1378
|
+
if (!result.ok)
|
|
1379
|
+
process.exitCode = 1;
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1261
1382
|
if (args.includes("--memory-quality")) {
|
|
1262
1383
|
const result = (0, kernel_js_1.benchmarkCodingMemoryQuality)({
|
|
1263
1384
|
topK: Number(takeArg(args, "--top-k") ?? 10),
|
|
@@ -1377,12 +1498,17 @@ async function main() {
|
|
|
1377
1498
|
tags: listArg(takeArg(args, "--tags")),
|
|
1378
1499
|
paths: listArg(takeArg(args, "--paths")),
|
|
1379
1500
|
stack: listArg(takeArg(args, "--stack")),
|
|
1501
|
+
graphNodes: listArg(takeArg(args, "--graph-nodes")),
|
|
1502
|
+
allowMissingPaths: args.includes("--allow-missing-paths"),
|
|
1503
|
+
strictCitations: true,
|
|
1380
1504
|
});
|
|
1381
1505
|
if (!result.ok) {
|
|
1382
1506
|
console.error(`Learning capture blocked:\n${result.errors.map((error) => ` - ${error}`).join("\n")}`);
|
|
1383
1507
|
process.exit(2);
|
|
1384
1508
|
}
|
|
1385
1509
|
console.log(`Captured session learning: ${result.path}`);
|
|
1510
|
+
if (result.warnings?.length)
|
|
1511
|
+
console.log(`Warnings:\n${result.warnings.map((warning) => ` - ${warning}`).join("\n")}`);
|
|
1386
1512
|
console.log("Repo-local memory is written immediately. Promotion to org/global still requires explicit review.");
|
|
1387
1513
|
return;
|
|
1388
1514
|
}
|
|
@@ -1565,9 +1691,11 @@ async function main() {
|
|
|
1565
1691
|
const query = firstPositional(args);
|
|
1566
1692
|
if (!query)
|
|
1567
1693
|
usage();
|
|
1694
|
+
const maxContextTokens = args.includes("--max-context-tokens") ? numberArg(args, "--max-context-tokens", 0) : undefined;
|
|
1695
|
+
const structuralHops = args.includes("--structural-hops") ? numberArg(args, "--structural-hops", 2) : undefined;
|
|
1568
1696
|
const result = args.includes("--embeddings")
|
|
1569
1697
|
? await (0, kernel_js_1.recallWithEmbeddings)(projectArg(args), query, 5, args.includes("--explain"))
|
|
1570
|
-
: (0, kernel_js_1.recall)(projectArg(args), query, 5, args.includes("--explain"));
|
|
1698
|
+
: (0, kernel_js_1.recall)(projectArg(args), query, 5, args.includes("--explain"), { maxContextTokens, structuralHops });
|
|
1571
1699
|
if (args.includes("--json"))
|
|
1572
1700
|
console.log(JSON.stringify(result, null, 2));
|
|
1573
1701
|
else
|
|
@@ -1711,6 +1839,9 @@ async function main() {
|
|
|
1711
1839
|
tags: listArg(takeArg(args, "--tags")),
|
|
1712
1840
|
paths: listArg(takeArg(args, "--paths")),
|
|
1713
1841
|
stack: listArg(takeArg(args, "--stack")),
|
|
1842
|
+
graphNodes: listArg(takeArg(args, "--graph-nodes")),
|
|
1843
|
+
allowMissingPaths: args.includes("--allow-missing-paths"),
|
|
1844
|
+
strictCitations: true,
|
|
1714
1845
|
};
|
|
1715
1846
|
const result = (0, kernel_js_1.capture)(input);
|
|
1716
1847
|
if (!result.ok) {
|
|
@@ -1718,6 +1849,8 @@ async function main() {
|
|
|
1718
1849
|
process.exit(2);
|
|
1719
1850
|
}
|
|
1720
1851
|
console.log(`Captured repo-local packet: ${result.path}`);
|
|
1852
|
+
if (result.warnings?.length)
|
|
1853
|
+
console.log(`Warnings:\n${result.warnings.map((warning) => ` - ${warning}`).join("\n")}`);
|
|
1721
1854
|
console.log("Repo-local memory is written immediately. Promotion to org/global still requires explicit review.");
|
|
1722
1855
|
return;
|
|
1723
1856
|
}
|
package/dist/daemon.js
CHANGED
|
@@ -573,6 +573,8 @@ async function startViewer(projectDir, options = {}) {
|
|
|
573
573
|
const timelinePath = (0, node_path_1.join)(reportsDir, "timeline.json");
|
|
574
574
|
const lineagePath = (0, node_path_1.join)(reportsDir, "lineage.json");
|
|
575
575
|
const setupPath = (0, node_path_1.join)(reportsDir, "setup.json");
|
|
576
|
+
const trustPath = (0, node_path_1.join)(reportsDir, "trust.json");
|
|
577
|
+
const suppressedPath = (0, node_path_1.join)(reportsDir, "suppressed.json");
|
|
576
578
|
// Pre-generate lightweight JSON reports so the viewer can load them directly.
|
|
577
579
|
try {
|
|
578
580
|
(0, node_fs_1.mkdirSync)(reportsDir, { recursive: true });
|
|
@@ -601,11 +603,13 @@ async function startViewer(projectDir, options = {}) {
|
|
|
601
603
|
(0, node_fs_1.writeFileSync)(timelinePath, JSON.stringify((0, kernel_js_1.kageMemoryTimeline)(projectDir), null, 2));
|
|
602
604
|
(0, node_fs_1.writeFileSync)(lineagePath, JSON.stringify((0, kernel_js_1.kageMemoryLineage)(projectDir), null, 2));
|
|
603
605
|
(0, node_fs_1.writeFileSync)(setupPath, JSON.stringify((0, kernel_js_1.setupDoctor)(projectDir), null, 2));
|
|
606
|
+
(0, node_fs_1.writeFileSync)(trustPath, JSON.stringify((0, kernel_js_1.benchmarkTrust)(projectDir), null, 2));
|
|
607
|
+
(0, node_fs_1.writeFileSync)(suppressedPath, JSON.stringify((0, kernel_js_1.kageSuppressedMemory)(projectDir), null, 2));
|
|
604
608
|
}
|
|
605
609
|
catch {
|
|
606
610
|
// non-fatal: viewer will show 404 for reports if generation fails
|
|
607
611
|
}
|
|
608
|
-
const url = `http://${host}:${port}/viewer/index.html?graph=${encodeURIComponent(graphPath)}&code=${encodeURIComponent(codePath)}&metrics=${encodeURIComponent(metricsPath)}&inbox=${encodeURIComponent(inboxPath)}&review=${encodeURIComponent(reviewPath)}&pending=${encodeURIComponent(pendingDir)}&quality=${encodeURIComponent(qualityPath)}&benchmark=${encodeURIComponent(benchmarkPath)}&contributors=${encodeURIComponent(contributorsPath)}&profile=${encodeURIComponent(profilePath)}&xray=${encodeURIComponent(xrayPath)}&capabilities=${encodeURIComponent(capabilitiesPath)}&slots=${encodeURIComponent(slotsPath)}&decisions=${encodeURIComponent(decisionsPath)}&risk=${encodeURIComponent(riskPath)}&moduleHealth=${encodeURIComponent(moduleHealthPath)}&graphInsights=${encodeURIComponent(graphInsightsPath)}&workspace=${encodeURIComponent(workspacePath)}&sessions=${encodeURIComponent(sessionsPath)}&replay=${encodeURIComponent(replayPath)}&memoryAccess=${encodeURIComponent(memoryAccessPath)}&memoryAudit=${encodeURIComponent(memoryAuditPath)}&handoff=${encodeURIComponent(handoffPath)}&lifecycle=${encodeURIComponent(lifecyclePath)}&timeline=${encodeURIComponent(timelinePath)}&lineage=${encodeURIComponent(lineagePath)}&setup=${encodeURIComponent(setupPath)}&view=code`;
|
|
612
|
+
const url = `http://${host}:${port}/viewer/index.html?graph=${encodeURIComponent(graphPath)}&code=${encodeURIComponent(codePath)}&metrics=${encodeURIComponent(metricsPath)}&inbox=${encodeURIComponent(inboxPath)}&review=${encodeURIComponent(reviewPath)}&pending=${encodeURIComponent(pendingDir)}&quality=${encodeURIComponent(qualityPath)}&benchmark=${encodeURIComponent(benchmarkPath)}&contributors=${encodeURIComponent(contributorsPath)}&profile=${encodeURIComponent(profilePath)}&xray=${encodeURIComponent(xrayPath)}&capabilities=${encodeURIComponent(capabilitiesPath)}&slots=${encodeURIComponent(slotsPath)}&decisions=${encodeURIComponent(decisionsPath)}&risk=${encodeURIComponent(riskPath)}&moduleHealth=${encodeURIComponent(moduleHealthPath)}&graphInsights=${encodeURIComponent(graphInsightsPath)}&workspace=${encodeURIComponent(workspacePath)}&sessions=${encodeURIComponent(sessionsPath)}&replay=${encodeURIComponent(replayPath)}&memoryAccess=${encodeURIComponent(memoryAccessPath)}&memoryAudit=${encodeURIComponent(memoryAuditPath)}&handoff=${encodeURIComponent(handoffPath)}&lifecycle=${encodeURIComponent(lifecyclePath)}&timeline=${encodeURIComponent(timelinePath)}&lineage=${encodeURIComponent(lineagePath)}&setup=${encodeURIComponent(setupPath)}&trust=${encodeURIComponent(trustPath)}&suppressed=${encodeURIComponent(suppressedPath)}&view=code`;
|
|
609
613
|
const server = (0, node_http_1.createServer)((req, res) => {
|
|
610
614
|
const requestUrl = new URL(req.url ?? "/", `http://${host}:${port}`);
|
|
611
615
|
let filePath = null;
|
package/dist/index.js
CHANGED
|
@@ -152,6 +152,8 @@ function listTools() {
|
|
|
152
152
|
explain: { type: "boolean" },
|
|
153
153
|
embeddings: { type: "boolean" },
|
|
154
154
|
json: { type: "boolean" },
|
|
155
|
+
max_context_tokens: { type: "number" },
|
|
156
|
+
structural_hops: { type: "number", description: "If >0, append a bounded N-hop code-graph blast radius seeded from the recalled memory's files." },
|
|
155
157
|
},
|
|
156
158
|
required: ["query", "project_dir"],
|
|
157
159
|
},
|
|
@@ -588,7 +590,7 @@ function listTools() {
|
|
|
588
590
|
type: "object",
|
|
589
591
|
properties: {
|
|
590
592
|
project_dir: { type: "string" },
|
|
591
|
-
mode: { type: "string", enum: ["project", "memory_quality", "memory_scale"] },
|
|
593
|
+
mode: { type: "string", enum: ["project", "trust", "memory_quality", "memory_scale"] },
|
|
592
594
|
sizes: { type: "array", items: { type: "number" } },
|
|
593
595
|
top_k: { type: "number" },
|
|
594
596
|
},
|
|
@@ -668,7 +670,7 @@ function listTools() {
|
|
|
668
670
|
},
|
|
669
671
|
{
|
|
670
672
|
name: "kage_learn",
|
|
671
|
-
description: "Capture an actual reusable learning from the current session as repo-local memory. Prefer this over diff proposal when the agent knows what was learned.",
|
|
673
|
+
description: "Capture an actual reusable learning from the current session as repo-local memory. Prefer this over diff proposal when the agent knows what was learned. Capture is rejected if every referenced path is missing from the repo; set allow_missing_paths to record anyway (e.g. a file you are about to create).",
|
|
672
674
|
inputSchema: {
|
|
673
675
|
type: "object",
|
|
674
676
|
properties: {
|
|
@@ -681,13 +683,15 @@ function listTools() {
|
|
|
681
683
|
tags: { type: "array", items: { type: "string" } },
|
|
682
684
|
paths: { type: "array", items: { type: "string" } },
|
|
683
685
|
stack: { type: "array", items: { type: "string" } },
|
|
686
|
+
graph_nodes: { type: "array", items: { type: "string" } },
|
|
687
|
+
allow_missing_paths: { type: "boolean" },
|
|
684
688
|
},
|
|
685
689
|
required: ["project_dir", "learning"],
|
|
686
690
|
},
|
|
687
691
|
},
|
|
688
692
|
{
|
|
689
693
|
name: "kage_capture",
|
|
690
|
-
description: "Create a repo-local Kage memory packet immediately. Org/global promotion still requires explicit human review.",
|
|
694
|
+
description: "Create a repo-local Kage memory packet immediately. Org/global promotion still requires explicit human review. Capture is rejected if every referenced path is missing from the repo; set allow_missing_paths to record anyway.",
|
|
691
695
|
inputSchema: {
|
|
692
696
|
type: "object",
|
|
693
697
|
properties: {
|
|
@@ -699,10 +703,36 @@ function listTools() {
|
|
|
699
703
|
tags: { type: "array", items: { type: "string" } },
|
|
700
704
|
paths: { type: "array", items: { type: "string" } },
|
|
701
705
|
stack: { type: "array", items: { type: "string" } },
|
|
706
|
+
graph_nodes: { type: "array", items: { type: "string" }, description: "Code-graph node references (symbol/route/file) this memory is about." },
|
|
707
|
+
allow_missing_paths: { type: "boolean" },
|
|
702
708
|
},
|
|
703
709
|
required: ["project_dir", "title", "body"],
|
|
704
710
|
},
|
|
705
711
|
},
|
|
712
|
+
{
|
|
713
|
+
name: "kage_verify_citations",
|
|
714
|
+
description: "Verify that a memory packet's cited file paths still exist and that the memory is not stale, before trusting it. Pass an id to check one packet, or omit to audit all approved repo memory. Returns grounding and staleness for each.",
|
|
715
|
+
inputSchema: {
|
|
716
|
+
type: "object",
|
|
717
|
+
properties: {
|
|
718
|
+
project_dir: { type: "string" },
|
|
719
|
+
id: { type: "string" },
|
|
720
|
+
},
|
|
721
|
+
required: ["project_dir"],
|
|
722
|
+
},
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
name: "kage_compact",
|
|
726
|
+
description: "Consolidate repo memory: prune dead citations, deprecate hard-stale packets, and surface near-duplicate clusters to merge (via kage_supersede). Defaults to a dry run; pass dry_run=false to apply pruning/deprecation. Duplicate merging stays an agent decision — no hosted LLM is used.",
|
|
727
|
+
inputSchema: {
|
|
728
|
+
type: "object",
|
|
729
|
+
properties: {
|
|
730
|
+
project_dir: { type: "string" },
|
|
731
|
+
dry_run: { type: "boolean" },
|
|
732
|
+
},
|
|
733
|
+
required: ["project_dir"],
|
|
734
|
+
},
|
|
735
|
+
},
|
|
706
736
|
{
|
|
707
737
|
name: "kage_observe",
|
|
708
738
|
description: "Store an automatic local observation event from an agent session. Observations are privacy-scanned, deduplicated, and never published automatically.",
|
|
@@ -1092,9 +1122,11 @@ async function callTool(name, args) {
|
|
|
1092
1122
|
};
|
|
1093
1123
|
}
|
|
1094
1124
|
if (name === "kage_recall") {
|
|
1125
|
+
const maxContextTokens = typeof args?.max_context_tokens === "number" ? args.max_context_tokens : undefined;
|
|
1126
|
+
const structuralHops = typeof args?.structural_hops === "number" ? args.structural_hops : undefined;
|
|
1095
1127
|
const result = args?.embeddings
|
|
1096
1128
|
? await (0, kernel_js_1.recallWithEmbeddings)(String(args?.project_dir ?? ""), String(args?.query ?? ""), Number(args?.limit ?? 5), Boolean(args?.explain))
|
|
1097
|
-
: (0, kernel_js_1.recall)(String(args?.project_dir ?? ""), String(args?.query ?? ""), Number(args?.limit ?? 5), Boolean(args?.explain));
|
|
1129
|
+
: (0, kernel_js_1.recall)(String(args?.project_dir ?? ""), String(args?.query ?? ""), Number(args?.limit ?? 5), Boolean(args?.explain), { maxContextTokens, structuralHops });
|
|
1098
1130
|
return {
|
|
1099
1131
|
content: [{ type: "text", text: args?.json || args?.explain ? JSON.stringify(result, null, 2) : result.context_block }],
|
|
1100
1132
|
};
|
|
@@ -1344,14 +1376,16 @@ async function callTool(name, args) {
|
|
|
1344
1376
|
}
|
|
1345
1377
|
if (name === "kage_benchmark") {
|
|
1346
1378
|
const mode = String(args?.mode ?? "project");
|
|
1347
|
-
const result = mode === "
|
|
1348
|
-
? (0, kernel_js_1.
|
|
1349
|
-
: mode === "
|
|
1350
|
-
? (0, kernel_js_1.
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1379
|
+
const result = mode === "trust"
|
|
1380
|
+
? (0, kernel_js_1.benchmarkTrust)(String(args?.project_dir ?? ""))
|
|
1381
|
+
: mode === "memory_quality"
|
|
1382
|
+
? (0, kernel_js_1.benchmarkCodingMemoryQuality)({ topK: Number(args?.top_k ?? 10) })
|
|
1383
|
+
: mode === "memory_scale"
|
|
1384
|
+
? (0, kernel_js_1.benchmarkMemoryScale)({
|
|
1385
|
+
sizes: Array.isArray(args?.sizes) ? args.sizes.map(Number) : undefined,
|
|
1386
|
+
topK: Number(args?.top_k ?? 10),
|
|
1387
|
+
})
|
|
1388
|
+
: (0, kernel_js_1.benchmarkProject)(String(args?.project_dir ?? ""));
|
|
1355
1389
|
return {
|
|
1356
1390
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
1357
1391
|
};
|
|
@@ -1403,13 +1437,17 @@ async function callTool(name, args) {
|
|
|
1403
1437
|
tags: arrayArg(args?.tags),
|
|
1404
1438
|
paths: arrayArg(args?.paths),
|
|
1405
1439
|
stack: arrayArg(args?.stack),
|
|
1440
|
+
graphNodes: arrayArg(args?.graph_nodes),
|
|
1441
|
+
allowMissingPaths: Boolean(args?.allow_missing_paths),
|
|
1442
|
+
strictCitations: true,
|
|
1406
1443
|
});
|
|
1444
|
+
const learnWarnings = result.warnings?.length ? `\nWarnings:\n${result.warnings.map((warning) => `- ${warning}`).join("\n")}` : "";
|
|
1407
1445
|
return {
|
|
1408
1446
|
content: [
|
|
1409
1447
|
{
|
|
1410
1448
|
type: "text",
|
|
1411
1449
|
text: result.ok
|
|
1412
|
-
? `Captured session learning: ${result.path}\nRepo-local memory is written immediately. Org/global promotion still requires explicit review
|
|
1450
|
+
? `Captured session learning: ${result.path}\nRepo-local memory is written immediately. Org/global promotion still requires explicit review.${learnWarnings}`
|
|
1413
1451
|
: `Learning capture blocked:\n${result.errors.map((error) => `- ${error}`).join("\n")}`,
|
|
1414
1452
|
},
|
|
1415
1453
|
],
|
|
@@ -1426,19 +1464,41 @@ async function callTool(name, args) {
|
|
|
1426
1464
|
tags: arrayArg(args?.tags),
|
|
1427
1465
|
paths: arrayArg(args?.paths),
|
|
1428
1466
|
stack: arrayArg(args?.stack),
|
|
1467
|
+
graphNodes: arrayArg(args?.graph_nodes),
|
|
1468
|
+
allowMissingPaths: Boolean(args?.allow_missing_paths),
|
|
1469
|
+
strictCitations: true,
|
|
1429
1470
|
});
|
|
1471
|
+
const captureWarnings = result.warnings?.length ? `\nWarnings:\n${result.warnings.map((warning) => `- ${warning}`).join("\n")}` : "";
|
|
1430
1472
|
return {
|
|
1431
1473
|
content: [
|
|
1432
1474
|
{
|
|
1433
1475
|
type: "text",
|
|
1434
1476
|
text: result.ok
|
|
1435
|
-
? `Captured repo-local packet: ${result.path}\nOrg/global promotion still requires explicit review
|
|
1477
|
+
? `Captured repo-local packet: ${result.path}\nOrg/global promotion still requires explicit review.${captureWarnings}`
|
|
1436
1478
|
: `Capture blocked:\n${result.errors.map((error) => `- ${error}`).join("\n")}`,
|
|
1437
1479
|
},
|
|
1438
1480
|
],
|
|
1439
1481
|
isError: !result.ok,
|
|
1440
1482
|
};
|
|
1441
1483
|
}
|
|
1484
|
+
if (name === "kage_verify_citations") {
|
|
1485
|
+
const result = (0, kernel_js_1.verifyCitations)(String(args?.project_dir ?? ""), {
|
|
1486
|
+
id: args?.id ? String(args.id) : undefined,
|
|
1487
|
+
});
|
|
1488
|
+
return {
|
|
1489
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
1490
|
+
isError: !result.ok,
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
if (name === "kage_compact") {
|
|
1494
|
+
const result = (0, kernel_js_1.compactProject)(String(args?.project_dir ?? ""), {
|
|
1495
|
+
dryRun: args?.dry_run === undefined ? true : Boolean(args.dry_run),
|
|
1496
|
+
});
|
|
1497
|
+
return {
|
|
1498
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
1499
|
+
isError: !result.ok,
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1442
1502
|
if (name === "kage_observe") {
|
|
1443
1503
|
const projectDir = String(args?.project_dir ?? "");
|
|
1444
1504
|
const event = { ...args };
|
|
@@ -1634,5 +1694,16 @@ async function main() {
|
|
|
1634
1694
|
await server.connect(transport);
|
|
1635
1695
|
}
|
|
1636
1696
|
if (require.main === module) {
|
|
1697
|
+
const firstArg = process.argv[2];
|
|
1698
|
+
if (firstArg && !firstArg.startsWith("-")) {
|
|
1699
|
+
// A positional subcommand (demo, init, recall, ...) means the user wants the
|
|
1700
|
+
// kage CLI, not the MCP stdio server. Delegate so a single
|
|
1701
|
+
// `npx @kage-core/kage-graph-mcp <command>` works like the `kage` binary.
|
|
1702
|
+
// MCP clients launch with no args (or flags), which falls through to the server.
|
|
1703
|
+
const { spawnSync } = require("node:child_process");
|
|
1704
|
+
const { join } = require("node:path");
|
|
1705
|
+
const result = spawnSync(process.execPath, [join(__dirname, "cli.js"), ...process.argv.slice(2)], { stdio: "inherit" });
|
|
1706
|
+
process.exit(result.status ?? 0);
|
|
1707
|
+
}
|
|
1637
1708
|
main().catch(console.error);
|
|
1638
1709
|
}
|