@kage-core/kage-graph-mcp 2.1.0 → 2.2.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 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 result = (0, kernel_js_1.learn)({
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("Repo-local memory is written immediately. Promotion to org/global still requires explicit review.");
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 {