@kage-core/kage-graph-mcp 1.1.6 → 1.1.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 CHANGED
@@ -137,6 +137,11 @@ meaningful file changes. Refresh rebuilds indexes, code graph, memory graph,
137
137
  metrics, and stale-memory metadata. Memory is marked stale when status or
138
138
  feedback says it is stale, its TTL expires, or grounded paths disappear.
139
139
 
140
+ Use `kage gc --project <repo> --dry-run` to preview stale packet cleanup.
141
+ `kage gc --project <repo>` marks stale repo packets deprecated, rebuilds
142
+ indexes/graphs/metrics, and keeps helpful-voted memories unless `--force` is
143
+ used.
144
+
140
145
  Use `kage pr summarize --project <repo>` / `kage_pr_summarize` before handoff to
141
146
  write branch review metadata and repo-local change memory from the git diff.
142
147
  Use `kage pr check --project <repo>` / `kage_pr_check` before merge to verify
package/dist/cli.js CHANGED
@@ -24,6 +24,7 @@ Usage:
24
24
  kage daemon doctor --project <dir> [--json]
25
25
  kage viewer --project <dir> [--port 3113]
26
26
  kage refresh --project <dir> [--json]
27
+ kage gc --project <dir> [--dry-run] [--force] [--json]
27
28
  kage pr summarize --project <dir> [--json]
28
29
  kage pr check --project <dir> [--json]
29
30
  kage upgrade [--dry-run]
@@ -302,6 +303,32 @@ async function main() {
302
303
  await (0, daemon_js_1.startViewer)(projectArg(args), { port: numberArg(args, "--port", 3113) });
303
304
  return;
304
305
  }
306
+ if (command === "gc") {
307
+ const project = projectArg(args);
308
+ const dryRun = args.includes("--dry-run");
309
+ const force = args.includes("--force");
310
+ const result = (0, kernel_js_1.gcProject)(project, { dryRun, force });
311
+ if (args.includes("--json")) {
312
+ console.log(JSON.stringify(result, null, 2));
313
+ return;
314
+ }
315
+ const label = dryRun ? " [dry-run]" : "";
316
+ console.log(`Kage GC${label} — scanned ${result.total_scanned} packets`);
317
+ if (result.deprecated.length) {
318
+ console.log(`\nDeprecated (${result.deprecated.length}):`);
319
+ for (const p of result.deprecated)
320
+ console.log(` ✗ ${p.title} — ${p.reason}`);
321
+ }
322
+ if (result.deleted.length) {
323
+ console.log(`\nDeleted (${result.deleted.length}):`);
324
+ for (const p of result.deleted)
325
+ console.log(` 🗑 ${p.title}`);
326
+ }
327
+ if (!result.deprecated.length && !result.deleted.length) {
328
+ console.log("No stale packets found — memory is clean.");
329
+ }
330
+ return;
331
+ }
305
332
  if (command === "refresh") {
306
333
  const result = (0, kernel_js_1.refreshProject)(projectArg(args));
307
334
  if (args.includes("--json")) {
package/dist/index.js CHANGED
@@ -54,7 +54,7 @@ function arrayArg(value) {
54
54
  return value.split(",").map((item) => item.trim()).filter(Boolean);
55
55
  return [];
56
56
  }
57
- const server = new index_js_1.Server({ name: "kage-graph", version: "1.1.6" }, { capabilities: { tools: {} } });
57
+ const server = new index_js_1.Server({ name: "kage-graph", version: "1.1.7" }, { capabilities: { tools: {} } });
58
58
  function listTools() {
59
59
  return [
60
60
  {
package/dist/kernel.js CHANGED
@@ -67,6 +67,7 @@ exports.buildKnowledgeGraph = buildKnowledgeGraph;
67
67
  exports.buildIndexes = buildIndexes;
68
68
  exports.indexProject = indexProject;
69
69
  exports.refreshProject = refreshProject;
70
+ exports.gcProject = gcProject;
70
71
  exports.installAgentPolicy = installAgentPolicy;
71
72
  exports.recall = recall;
72
73
  exports.queryCodeGraph = queryCodeGraph;
@@ -335,6 +336,9 @@ function repoKey(projectDir) {
335
336
  }
336
337
  return slugify((0, node_path_1.basename)(projectDir));
337
338
  }
339
+ function repoDisplayName(projectDir) {
340
+ return (0, node_path_1.basename)((0, node_path_1.resolve)(projectDir));
341
+ }
338
342
  function makePacketId(projectDir, type, title, suffix) {
339
343
  const raw = suffix ? `${title}-${suffix}` : title;
340
344
  return `repo:${repoKey(projectDir)}:${type}:${slugify(raw)}`;
@@ -931,14 +935,14 @@ function createRepoOverviewPacket(projectDir) {
931
935
  const readmePath = (0, node_path_1.join)(projectDir, "README.md");
932
936
  if (!(0, node_fs_1.existsSync)(packagePath) && !(0, node_fs_1.existsSync)(readmePath))
933
937
  return null;
934
- let title = `${(0, node_path_1.basename)(projectDir)} repo overview`;
938
+ let title = `${repoDisplayName(projectDir)} repo overview`;
935
939
  const tags = ["repo", "overview"];
936
940
  const bodyParts = [];
937
941
  const paths = ["root"];
938
942
  const stack = [];
939
943
  if ((0, node_fs_1.existsSync)(packagePath)) {
940
944
  const pkg = readJson(packagePath);
941
- title = `${String(pkg.name ?? (0, node_path_1.basename)(projectDir))} repo overview`;
945
+ title = `${String(pkg.name ?? repoDisplayName(projectDir))} repo overview`;
942
946
  const scripts = pkg.scripts && typeof pkg.scripts === "object" ? Object.keys(pkg.scripts) : [];
943
947
  const deps = {
944
948
  ...pkg.dependencies,
@@ -1050,8 +1054,8 @@ function createRepoStructurePacket(projectDir) {
1050
1054
  ].filter(Boolean).join("\n");
1051
1055
  return {
1052
1056
  schema_version: exports.PACKET_SCHEMA_VERSION,
1053
- id: makePacketId(projectDir, "repo_map", `${(0, node_path_1.basename)(projectDir)} repo structure`, "auto-structure"),
1054
- title: `${(0, node_path_1.basename)(projectDir)} repo structure`,
1057
+ id: makePacketId(projectDir, "repo_map", `${repoDisplayName(projectDir)} repo structure`, "auto-structure"),
1058
+ title: `${repoDisplayName(projectDir)} repo structure`,
1055
1059
  summary: summarize(body),
1056
1060
  body,
1057
1061
  type: "repo_map",
@@ -1083,7 +1087,18 @@ function createRepoStructurePacket(projectDir) {
1083
1087
  }
1084
1088
  function upsertGeneratedPacket(projectDir, packet) {
1085
1089
  const dir = packetsDir(projectDir);
1086
- const existing = loadPacketsFromDir(dir).find((candidate) => candidate.id === packet.id);
1090
+ const entries = loadPacketEntriesFromDir(dir);
1091
+ const generatedKind = packet.tags.includes("overview") ? "overview" : packet.tags.includes("structure") ? "structure" : null;
1092
+ for (const entry of entries) {
1093
+ if (generatedKind &&
1094
+ entry.packet.id !== packet.id &&
1095
+ entry.packet.type === packet.type &&
1096
+ entry.packet.quality?.reviewer === "kage-indexer" &&
1097
+ entry.packet.tags.includes(generatedKind)) {
1098
+ (0, node_fs_1.unlinkSync)(entry.path);
1099
+ }
1100
+ }
1101
+ const existing = entries.find((entry) => entry.packet.id === packet.id)?.packet;
1087
1102
  if (existing && existing.quality?.reviewer !== "kage-indexer")
1088
1103
  return;
1089
1104
  if (existing) {
@@ -2502,6 +2517,57 @@ function refreshProject(projectDir) {
2502
2517
  next_actions: nextActions,
2503
2518
  };
2504
2519
  }
2520
+ function gcProject(projectDir, options = {}) {
2521
+ ensureMemoryDirs(projectDir);
2522
+ const packetEntries = loadPacketEntriesFromDir(packetsDir(projectDir));
2523
+ const deprecated = [];
2524
+ const deleted = [];
2525
+ const skipped = [];
2526
+ for (const { path, packet } of packetEntries) {
2527
+ if (packet.status === "deprecated") {
2528
+ skipped.push({ id: packet.id, title: packet.title, reason: "already deprecated" });
2529
+ continue;
2530
+ }
2531
+ const reasons = staleMemoryReasons(projectDir, packet);
2532
+ if (!reasons.length) {
2533
+ skipped.push({ id: packet.id, title: packet.title, reason: "healthy" });
2534
+ continue;
2535
+ }
2536
+ const quality = packet.quality;
2537
+ const hasHelpfulVotes = Number(quality?.votes_up ?? 0) > 0;
2538
+ if (hasHelpfulVotes && !options.force) {
2539
+ skipped.push({ id: packet.id, title: packet.title, reason: `stale but has helpful votes (use --force to override)` });
2540
+ continue;
2541
+ }
2542
+ // Mark as deprecated (or hard-delete if --force)
2543
+ if (options.force && !hasHelpfulVotes) {
2544
+ if (!options.dryRun) {
2545
+ (0, node_fs_1.unlinkSync)(path);
2546
+ }
2547
+ deleted.push({ id: packet.id, title: packet.title });
2548
+ }
2549
+ else {
2550
+ if (!options.dryRun) {
2551
+ const updated = { ...packet, status: "deprecated", updated_at: nowIso() };
2552
+ writeJson(path, updated);
2553
+ }
2554
+ deprecated.push({ id: packet.id, title: packet.title, reason: reasons[0] });
2555
+ }
2556
+ }
2557
+ if (!options.dryRun && (deprecated.length || deleted.length)) {
2558
+ buildIndexes(projectDir);
2559
+ buildKnowledgeGraph(projectDir);
2560
+ writeJson((0, node_path_1.join)(memoryRoot(projectDir), "metrics.json"), kageMetrics(projectDir));
2561
+ }
2562
+ return {
2563
+ ok: true,
2564
+ project_dir: projectDir,
2565
+ deprecated,
2566
+ deleted,
2567
+ skipped,
2568
+ total_scanned: packetEntries.length,
2569
+ };
2570
+ }
2505
2571
  function installAgentPolicy(projectDir) {
2506
2572
  const agentsPath = (0, node_path_1.join)(projectDir, "AGENTS.md");
2507
2573
  const claudePath = (0, node_path_1.join)(projectDir, "CLAUDE.md");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kage-core/kage-graph-mcp",
3
- "version": "1.1.6",
3
+ "version": "1.1.8",
4
4
  "description": "Local-first repo memory, code graph, and recall MCP server for coding agents",
5
5
  "main": "dist/index.js",
6
6
  "files": [