@kage-core/kage-graph-mcp 2.1.0 → 2.2.1
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 +123 -6
- package/dist/index.js +28 -2
- package/dist/kernel.js +1377 -24
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -51,7 +51,8 @@ Usage:
|
|
|
51
51
|
kage hook install --project <dir> [--json]
|
|
52
52
|
kage hook status --project <dir> [--json]
|
|
53
53
|
kage hook uninstall --project <dir> [--json]
|
|
54
|
-
kage refresh --project <dir> [--full] [--json]
|
|
54
|
+
kage refresh --project <dir> [--full] [--force] [--json]
|
|
55
|
+
kage merge-packet <ours> <base> <theirs> git merge driver for .agent_memory/packets/*.json
|
|
55
56
|
kage gc --project <dir> [--dry-run] [--force] [--json]
|
|
56
57
|
kage compact --project <dir> [--dry-run] [--json]
|
|
57
58
|
kage verify --project <dir> [--id <packet-id>] [--json]
|
|
@@ -85,6 +86,7 @@ Usage:
|
|
|
85
86
|
kage workspace --project <workspace-dir> [--json]
|
|
86
87
|
kage workspace recall "<query>" --project <workspace-dir> [--json]
|
|
87
88
|
kage audit --project <dir> [--json]
|
|
89
|
+
kage audit-claude-mem [--store <path>] [--project <dir>] [--json]
|
|
88
90
|
kage inbox --project <dir> [--json]
|
|
89
91
|
kage quality --project <dir> [--json]
|
|
90
92
|
kage benchmark --project <dir> [--json]
|
|
@@ -106,12 +108,16 @@ Usage:
|
|
|
106
108
|
kage graph-registry --project <dir> [--json]
|
|
107
109
|
kage embeddings build --project <dir> [--model Xenova/all-MiniLM-L6-v2] [--json]
|
|
108
110
|
kage recall "<query>" --project <dir> [--json] [--explain] [--embeddings] [--max-context-tokens <n>] [--structural-hops <n>]
|
|
111
|
+
kage file-context --project <dir> --path <file> [--json]
|
|
109
112
|
kage observe --project <dir> --event <json>
|
|
110
113
|
kage sessions --project <dir> [--json]
|
|
111
114
|
kage replay --project <dir> [--session <id>] [--limit <n>] [--json]
|
|
112
115
|
kage distill --project <dir> --session <id> [--auto] [--json]
|
|
113
116
|
kage resume --project <dir> [--json]
|
|
114
|
-
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]
|
|
117
|
+
kage learn --project <dir> --learning <text> [--personal] [--title <title>] [--type <type>] [--evidence <text>] [--verified-by <text>] [--tags a,b] [--paths a,b] [--graph-nodes a,b] [--discovery-tokens <n>] [--allow-missing-paths]
|
|
118
|
+
kage sync setup --remote <git-url> init ~/.kage/memory as a git repo wired to your private remote
|
|
119
|
+
kage sync [--json] commit + pull --rebase + push personal memory (newest-wins conflicts)
|
|
120
|
+
kage sync --status [--json] ahead/behind/dirty for the personal store (fetch only)
|
|
115
121
|
kage feedback --project <dir> --packet <packet-id> --kind helpful|wrong|stale
|
|
116
122
|
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]
|
|
117
123
|
kage propose --project <dir> --from-diff
|
|
@@ -207,6 +213,74 @@ async function main() {
|
|
|
207
213
|
console.log(args.includes("--all") ? FULL_USAGE : CORE_USAGE);
|
|
208
214
|
return;
|
|
209
215
|
}
|
|
216
|
+
if (command === "merge-packet") {
|
|
217
|
+
// Git merge driver (%A %O %B): runs before any heavy setup — merge drivers
|
|
218
|
+
// must be fast and dependency-free. Exit 0 = merged, 1 = leave conflict.
|
|
219
|
+
const [ours, base, theirs] = [args[1], args[2], args[3]];
|
|
220
|
+
if (!ours || !base || !theirs) {
|
|
221
|
+
console.error("Usage: kage merge-packet <ours> <base> <theirs>");
|
|
222
|
+
console.error(`Enable once per clone: ${kernel_js_1.PACKET_MERGE_DRIVER_CONFIG}`);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
const result = (0, kernel_js_1.mergePacketFiles)(ours, base, theirs);
|
|
226
|
+
console.error(result.detail);
|
|
227
|
+
process.exit(result.ok ? 0 : 1);
|
|
228
|
+
}
|
|
229
|
+
if (command === "sync") {
|
|
230
|
+
// Personal-store sync (docs/CLOUD.md v1): plain git under the hood, no
|
|
231
|
+
// tree-sitter or repo indexes needed, so it runs before the heavy setup.
|
|
232
|
+
if (args[1] === "setup") {
|
|
233
|
+
const remote = takeArg(args, "--remote");
|
|
234
|
+
if (!remote) {
|
|
235
|
+
console.error("Usage: kage sync setup --remote <git-url>");
|
|
236
|
+
process.exit(2);
|
|
237
|
+
}
|
|
238
|
+
const result = (0, kernel_js_1.syncSetup)(remote);
|
|
239
|
+
if (args.includes("--json")) {
|
|
240
|
+
console.log(JSON.stringify(result, null, 2));
|
|
241
|
+
process.exit(result.ok ? 0 : 2);
|
|
242
|
+
}
|
|
243
|
+
if (!result.ok) {
|
|
244
|
+
console.error(`kage sync setup failed:\n${result.errors.map((error) => ` - ${error}`).join("\n")}`);
|
|
245
|
+
process.exit(2);
|
|
246
|
+
}
|
|
247
|
+
console.log(`Personal memory store: ${result.memory_dir}${result.initialized ? " (new git repo)" : ""}`);
|
|
248
|
+
console.log(`Remote: ${result.remote}${result.remote_updated ? " (updated)" : ""}`);
|
|
249
|
+
console.log(`Pushed ${result.branch ?? "HEAD"} to origin. Run \`kage sync\` on any machine to stay in sync.`);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (args.includes("--status")) {
|
|
253
|
+
const result = (0, kernel_js_1.syncStatus)();
|
|
254
|
+
if (args.includes("--json")) {
|
|
255
|
+
console.log(JSON.stringify(result, null, 2));
|
|
256
|
+
process.exit(result.ok ? 0 : 2);
|
|
257
|
+
}
|
|
258
|
+
if (!result.ok) {
|
|
259
|
+
console.error(`kage sync status failed:\n${result.errors.map((error) => ` - ${error}`).join("\n")}`);
|
|
260
|
+
process.exit(2);
|
|
261
|
+
}
|
|
262
|
+
console.log(`Personal memory store: ${result.memory_dir}`);
|
|
263
|
+
console.log(`Remote: ${result.remote} (branch ${result.branch ?? "unknown"})`);
|
|
264
|
+
console.log(`Ahead ${result.ahead}, behind ${result.behind}, ${result.dirty ? "uncommitted local changes" : "clean"}`);
|
|
265
|
+
for (const warning of result.warnings)
|
|
266
|
+
console.log(`Warning: ${warning}`);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const result = (0, kernel_js_1.syncPersonal)();
|
|
270
|
+
if (args.includes("--json")) {
|
|
271
|
+
console.log(JSON.stringify(result, null, 2));
|
|
272
|
+
process.exit(result.ok ? 0 : 2);
|
|
273
|
+
}
|
|
274
|
+
if (!result.ok) {
|
|
275
|
+
console.error(`kage sync failed:\n${result.errors.map((error) => ` - ${error}`).join("\n")}`);
|
|
276
|
+
process.exit(2);
|
|
277
|
+
}
|
|
278
|
+
console.log(`kage sync: pushed ${result.pushed}, pulled ${result.pulled}, resolved ${result.resolved}`);
|
|
279
|
+
if (result.conflict_backups.length) {
|
|
280
|
+
console.log(`Conflict losers preserved:\n${result.conflict_backups.map((path) => ` - ${path}`).join("\n")}`);
|
|
281
|
+
}
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
210
284
|
await (0, kernel_js_1.ensureTreeSitterLanguages)();
|
|
211
285
|
if (command === "index") {
|
|
212
286
|
const result = (0, kernel_js_1.indexProject)(projectArg(args));
|
|
@@ -290,6 +364,7 @@ async function main() {
|
|
|
290
364
|
console.log(`Initialized Kage memory for ${result.index.projectDir}`);
|
|
291
365
|
console.log("\nCreated:");
|
|
292
366
|
console.log(" .agent_memory/ memory packets + indexes (only directory Kage owns)");
|
|
367
|
+
console.log(` .gitattributes kage-packet merge driver for packet JSON${result.gitAttributes.changed ? "" : " (already current)"}`);
|
|
293
368
|
if (result.policyInstalled) {
|
|
294
369
|
console.log(" AGENTS.md, CLAUDE.md agent policy (requested via --with-policy)");
|
|
295
370
|
console.log(" .claude/settings.json allowed kage tools (requested via --with-policy)");
|
|
@@ -305,6 +380,8 @@ async function main() {
|
|
|
305
380
|
console.log("\nTip — version control:");
|
|
306
381
|
console.log(" commit .agent_memory/packets/ (your team's reviewed memory)");
|
|
307
382
|
console.log(" ignore .agent_memory/indexes/ .agent_memory/reports/ (regenerated)");
|
|
383
|
+
console.log("\nEnable the packet merge driver once per clone:");
|
|
384
|
+
console.log(` ${kernel_js_1.PACKET_MERGE_DRIVER_CONFIG}`);
|
|
308
385
|
if (!result.policyInstalled) {
|
|
309
386
|
console.log("\nNot written (opt-in): agent policy files. Add them with `kage policy --project .`");
|
|
310
387
|
console.log("or rerun `kage init --with-policy` when you're ready to commit them.");
|
|
@@ -378,6 +455,8 @@ async function main() {
|
|
|
378
455
|
console.log(" kage scan --project . 60-second Truth Report on this repo");
|
|
379
456
|
console.log(" kage viewer --project . local dashboard (gains, packets, graph)");
|
|
380
457
|
console.log("\nVersion control: commit .agent_memory/packets/, ignore .agent_memory/indexes/ and reports/.");
|
|
458
|
+
console.log("Enable the packet merge driver once per clone:");
|
|
459
|
+
console.log(` ${kernel_js_1.PACKET_MERGE_DRIVER_CONFIG}`);
|
|
381
460
|
if (!init.validation.ok)
|
|
382
461
|
process.exit(2);
|
|
383
462
|
return;
|
|
@@ -698,7 +777,7 @@ async function main() {
|
|
|
698
777
|
return;
|
|
699
778
|
}
|
|
700
779
|
if (command === "refresh") {
|
|
701
|
-
const result = (0, kernel_js_1.refreshProject)(projectArg(args), { full: args.includes("--full") });
|
|
780
|
+
const result = (0, kernel_js_1.refreshProject)(projectArg(args), { full: args.includes("--full"), force: args.includes("--force") });
|
|
702
781
|
if (args.includes("--json")) {
|
|
703
782
|
console.log(JSON.stringify(result, null, 2));
|
|
704
783
|
if (!result.ok)
|
|
@@ -706,6 +785,8 @@ async function main() {
|
|
|
706
785
|
return;
|
|
707
786
|
}
|
|
708
787
|
console.log(`Refreshed ${result.project_dir}`);
|
|
788
|
+
if (result.quiet_refresh)
|
|
789
|
+
console.log("Quiet refresh (non-default branch): packet metadata not rewritten on disk; use --force to persist.");
|
|
709
790
|
console.log(`Packets indexed: ${result.index.packets}`);
|
|
710
791
|
console.log(`Packet metadata updated: ${result.updated_packets}`);
|
|
711
792
|
console.log(`Code graph: ${result.code_graph.files} files, ${result.code_graph.symbols} symbols, ${result.code_graph.imports} imports, ${result.code_graph.calls} calls`);
|
|
@@ -1187,6 +1268,23 @@ async function main() {
|
|
|
1187
1268
|
`${window.caller_answers} caller ${plural(window.caller_answers, "answer", "answers")}`;
|
|
1188
1269
|
console.log(windowLine("Today: ", summary.today));
|
|
1189
1270
|
console.log(windowLine("All time:", summary.all_time));
|
|
1271
|
+
if (summary.all_time.replay_tokens > 0) {
|
|
1272
|
+
console.log(`Knowledge replay value: ~${(0, kernel_js_1.formatTokenCount)(week.replay_tokens)} tokens this week · ` +
|
|
1273
|
+
`~${(0, kernel_js_1.formatTokenCount)(summary.all_time.replay_tokens)} all time ` +
|
|
1274
|
+
`(discovery cost of served memories vs their compressed read cost)`);
|
|
1275
|
+
}
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
if (command === "file-context") {
|
|
1279
|
+
const path = takeArg(args, "--path");
|
|
1280
|
+
if (!path)
|
|
1281
|
+
usage();
|
|
1282
|
+
const result = (0, kernel_js_1.kageFileContext)(projectArg(args), path);
|
|
1283
|
+
if (args.includes("--json"))
|
|
1284
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1285
|
+
else if (result.context_block)
|
|
1286
|
+
console.log(result.context_block);
|
|
1287
|
+
// No verified packets cite this file: print nothing so hooks can gate on empty output.
|
|
1190
1288
|
return;
|
|
1191
1289
|
}
|
|
1192
1290
|
if (command === "memory-access") {
|
|
@@ -1534,6 +1632,21 @@ async function main() {
|
|
|
1534
1632
|
console.log(`Warnings:\n${result.warnings.map((warning) => ` - ${warning}`).join("\n")}`);
|
|
1535
1633
|
return;
|
|
1536
1634
|
}
|
|
1635
|
+
if (command === "audit-claude-mem") {
|
|
1636
|
+
const projectDir = projectArg(args);
|
|
1637
|
+
const storePath = takeArg(args, "--store") ?? (0, kernel_js_1.defaultClaudeMemStorePath)();
|
|
1638
|
+
const result = (0, kernel_js_1.auditClaudeMemStore)(projectDir, { storePath });
|
|
1639
|
+
if (!result.ok) {
|
|
1640
|
+
console.error(result.error);
|
|
1641
|
+
process.exit(2);
|
|
1642
|
+
}
|
|
1643
|
+
if (args.includes("--json")) {
|
|
1644
|
+
console.log(JSON.stringify(result.report, null, 2));
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
console.log((0, kernel_js_1.renderClaudeMemAuditReceipt)(result.report));
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1537
1650
|
if (command === "audit") {
|
|
1538
1651
|
const result = (0, kernel_js_1.auditProject)(projectArg(args));
|
|
1539
1652
|
if (args.includes("--json")) {
|
|
@@ -1731,7 +1844,8 @@ async function main() {
|
|
|
1731
1844
|
const learning = takeArg(args, "--learning");
|
|
1732
1845
|
if (!learning)
|
|
1733
1846
|
usage();
|
|
1734
|
-
const
|
|
1847
|
+
const personal = args.includes("--personal");
|
|
1848
|
+
const result = (personal ? kernel_js_1.learnPersonal : kernel_js_1.learn)({
|
|
1735
1849
|
projectDir: projectArg(args),
|
|
1736
1850
|
learning,
|
|
1737
1851
|
title: takeArg(args, "--title"),
|
|
@@ -1744,15 +1858,18 @@ async function main() {
|
|
|
1744
1858
|
graphNodes: listArg(takeArg(args, "--graph-nodes")),
|
|
1745
1859
|
allowMissingPaths: args.includes("--allow-missing-paths"),
|
|
1746
1860
|
strictCitations: true,
|
|
1861
|
+
discoveryTokens: args.includes("--discovery-tokens") ? numberArg(args, "--discovery-tokens", 0) : undefined,
|
|
1747
1862
|
});
|
|
1748
1863
|
if (!result.ok) {
|
|
1749
1864
|
console.error(`Learning capture blocked:\n${result.errors.map((error) => ` - ${error}`).join("\n")}`);
|
|
1750
1865
|
process.exit(2);
|
|
1751
1866
|
}
|
|
1752
|
-
console.log(`Captured session learning: ${result.path}`);
|
|
1867
|
+
console.log(`Captured ${personal ? "personal" : "session"} learning: ${result.path}`);
|
|
1753
1868
|
if (result.warnings?.length)
|
|
1754
1869
|
console.log(`Warnings:\n${result.warnings.map((warning) => ` - ${warning}`).join("\n")}`);
|
|
1755
|
-
console.log(
|
|
1870
|
+
console.log(personal
|
|
1871
|
+
? "Personal memory is recalled with lower trust and never enters repo review flows. Sync it across machines with `kage sync`."
|
|
1872
|
+
: "Repo-local memory is written immediately. Promotion to org/global still requires explicit review.");
|
|
1756
1873
|
return;
|
|
1757
1874
|
}
|
|
1758
1875
|
if (command === "propose") {
|
package/dist/index.js
CHANGED
|
@@ -75,6 +75,15 @@ function riskContextBlock(result) {
|
|
|
75
75
|
return `\n## Risk Signals\n${lines.join("\n")}`;
|
|
76
76
|
}
|
|
77
77
|
const server = new index_js_1.Server({ name: "kage-graph", version: "2.0.0" }, { capabilities: { tools: {} } });
|
|
78
|
+
// Workflow pseudo-tool: the description itself is the documentation, so agents
|
|
79
|
+
// absorb the loop just by listing tools. The handler returns the same text.
|
|
80
|
+
const KAGE_WORKFLOW_TEXT = "Kage memory workflow (this tool performs no action; it returns this loop). " +
|
|
81
|
+
"1) Start every task with kage_context (project_dir + the task as query): it validates memory, recalls relevant packets, and queries the code and knowledge graphs in one call. " +
|
|
82
|
+
"2) Do the work, preferring repo memory over public context. " +
|
|
83
|
+
"3) Capture reusable learnings with kage_learn — bug causes and verified fixes, conventions, decisions, gotchas, run/test/build commands. Wrap anything that must never leave the repo in <private>...</private> tags; private spans are stripped before sharing. " +
|
|
84
|
+
"4) After meaningful file changes, call kage_refresh so indexes, graphs, and stale-memory checks stay current. " +
|
|
85
|
+
"5) Before finishing a branch, call kage_pr_summarize then kage_pr_check. " +
|
|
86
|
+
"Recall receipts show estimated tokens saved versus rediscovery; report memory quality with kage_feedback (helpful/wrong/stale).";
|
|
78
87
|
function listTools() {
|
|
79
88
|
return [
|
|
80
89
|
{
|
|
@@ -457,15 +466,25 @@ function listTools() {
|
|
|
457
466
|
},
|
|
458
467
|
{
|
|
459
468
|
name: "kage_refresh",
|
|
460
|
-
description: "Rebuild repo indexes, code graph, memory graph, metrics, and stale-memory metadata. Agents should run this after meaningful file/content changes before PR checks; push-only or same-tree commits do not need another refresh.",
|
|
469
|
+
description: "Rebuild repo indexes, code graph, memory graph, metrics, and stale-memory metadata. Agents should run this after meaningful file/content changes before PR checks; push-only or same-tree commits do not need another refresh. On non-default git branches metadata-only packet rewrites are skipped (quiet refresh) to avoid merge conflicts; pass force to persist them anyway.",
|
|
461
470
|
inputSchema: {
|
|
462
471
|
type: "object",
|
|
463
472
|
properties: {
|
|
464
473
|
project_dir: { type: "string" },
|
|
474
|
+
force: { type: "boolean", description: "Persist packet metadata rewrites even on a non-default branch" },
|
|
465
475
|
},
|
|
466
476
|
required: ["project_dir"],
|
|
467
477
|
},
|
|
468
478
|
},
|
|
479
|
+
{
|
|
480
|
+
name: "kage_workflow",
|
|
481
|
+
description: KAGE_WORKFLOW_TEXT,
|
|
482
|
+
inputSchema: {
|
|
483
|
+
type: "object",
|
|
484
|
+
properties: {},
|
|
485
|
+
required: [],
|
|
486
|
+
},
|
|
487
|
+
},
|
|
469
488
|
{
|
|
470
489
|
name: "kage_pr_summarize",
|
|
471
490
|
description: "Create a PR/branch memory summary from local git diff metadata and write repo-local change memory. Use when a branch is ready to hand off.",
|
|
@@ -685,6 +704,7 @@ function listTools() {
|
|
|
685
704
|
stack: { type: "array", items: { type: "string" } },
|
|
686
705
|
graph_nodes: { type: "array", items: { type: "string" } },
|
|
687
706
|
allow_missing_paths: { type: "boolean" },
|
|
707
|
+
discovery_tokens: { type: "number", description: "Approximate token cost of producing this knowledge (exploration + reasoning). Stored on the packet so recall receipts can report replay value; a conservative per-type default is estimated when omitted." },
|
|
688
708
|
},
|
|
689
709
|
required: ["project_dir", "learning"],
|
|
690
710
|
},
|
|
@@ -1243,12 +1263,17 @@ async function callTool(name, args) {
|
|
|
1243
1263
|
};
|
|
1244
1264
|
}
|
|
1245
1265
|
if (name === "kage_refresh") {
|
|
1246
|
-
const result = (0, kernel_js_1.refreshProject)(String(args?.project_dir ?? ""), { full: Boolean(args?.full) });
|
|
1266
|
+
const result = (0, kernel_js_1.refreshProject)(String(args?.project_dir ?? ""), { full: Boolean(args?.full), force: Boolean(args?.force) });
|
|
1247
1267
|
return {
|
|
1248
1268
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
1249
1269
|
isError: !result.ok,
|
|
1250
1270
|
};
|
|
1251
1271
|
}
|
|
1272
|
+
if (name === "kage_workflow") {
|
|
1273
|
+
return {
|
|
1274
|
+
content: [{ type: "text", text: KAGE_WORKFLOW_TEXT }],
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1252
1277
|
if (name === "kage_pr_summarize") {
|
|
1253
1278
|
const result = (0, kernel_js_1.prSummarize)(String(args?.project_dir ?? ""));
|
|
1254
1279
|
return {
|
|
@@ -1349,6 +1374,7 @@ async function callTool(name, args) {
|
|
|
1349
1374
|
graphNodes: arrayArg(args?.graph_nodes),
|
|
1350
1375
|
allowMissingPaths: Boolean(args?.allow_missing_paths),
|
|
1351
1376
|
strictCitations: true,
|
|
1377
|
+
discoveryTokens: args?.discovery_tokens === undefined ? undefined : Number(args.discovery_tokens),
|
|
1352
1378
|
});
|
|
1353
1379
|
const learnWarnings = result.warnings?.length ? `\nWarnings:\n${result.warnings.map((warning) => `- ${warning}`).join("\n")}` : "";
|
|
1354
1380
|
return {
|