@kage-core/kage-graph-mcp 1.1.3 → 1.1.4

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.
Files changed (2) hide show
  1. package/dist/kernel.js +61 -12
  2. package/package.json +1 -1
package/dist/kernel.js CHANGED
@@ -180,11 +180,23 @@ Keep captures concise and future-facing. Do not store raw transcripts.
180
180
 
181
181
  ## End-Of-Task Proposal
182
182
 
183
- Before finishing a task that changed files, call \`kage_propose_from_diff\`.
183
+ After meaningful file changes, call \`kage_refresh\` so indexes, code graph,
184
+ memory graph, metrics, and stale-memory checks are current.
184
185
 
185
- This writes a branch review summary and a repo-local change-memory packet. It
186
- should capture what changed, why it matters, how to verify it, and what future
187
- agents should know. Git or PR review is the repo-level review boundary.
186
+ Before finishing a task that changed files, call \`kage_pr_summarize\` or
187
+ \`kage_propose_from_diff\`, then call \`kage_pr_check\`.
188
+
189
+ \`kage_pr_summarize\` writes a branch review summary and a repo-local
190
+ change-memory packet. \`kage_pr_check\` verifies validation, graph freshness,
191
+ stale packets, and whether repo memory changed with the branch. If the check
192
+ fails, explain the required actions instead of hiding the failure. Git or PR
193
+ review is the repo-level review boundary.
194
+
195
+ ## Package Updates
196
+
197
+ If the user asks to update Kage, run \`kage upgrade\`, then verify setup with
198
+ \`kage setup verify-agent --agent <agent> --project <repo>\`. Tell the user to
199
+ restart the agent when MCP tools need to reload.
188
200
 
189
201
  ## Feedback
190
202
 
@@ -210,7 +222,9 @@ For normal coding tasks:
210
222
  4. \`kage_graph\` for remembered decisions, bugs, workflows, and conventions
211
223
  5. Work on the task
212
224
  6. \`kage_learn\` for concrete learnings
213
- 7. \`kage_propose_from_diff\` before the final response to create repo-local change memory
225
+ 7. \`kage_refresh\` after meaningful file changes
226
+ 8. \`kage_pr_summarize\` or \`kage_propose_from_diff\` before the final response to create repo-local change memory
227
+ 9. \`kage_pr_check\` before final handoff or merge readiness claims
214
228
 
215
229
  For quick factual questions, \`kage_recall\` alone is enough. For status or demo requests, call \`kage_metrics\`.
216
230
  ${AGENTS_POLICY_END}
@@ -3414,22 +3428,42 @@ Before making code changes or answering implementation questions:
3414
3428
  3. Call kage_code_graph for file, symbol, route, test, or dependency questions.
3415
3429
  4. Call kage_graph for decisions, bugs, workflows, and conventions.
3416
3430
  When you learn something reusable: kage_learn.
3417
- Before finishing a task that changed files: kage_propose_from_diff.
3431
+ After meaningful file changes: kage_refresh.
3432
+ Before finishing a task that changed files: kage_pr_summarize or kage_propose_from_diff, then kage_pr_check.
3418
3433
  If recalled memory helped: kage_feedback helpful. If wrong or stale: kage_feedback wrong or stale."
3419
3434
  fi
3420
3435
 
3421
3436
  KAGE_MSG="$POLICY" python3 -c "import json,os; print(json.dumps({'systemMessage': os.environ['KAGE_MSG']}))"
3437
+ `;
3438
+ const stopHookScript = `#!/usr/bin/env bash
3439
+ # Kage Stop hook — best-effort repo memory refresh before Claude Code finishes.
3440
+ # Silent if Kage is not initialized in the current project or no git changes exist.
3441
+ set -euo pipefail
3442
+
3443
+ PAYLOAD="$(cat || true)"
3444
+ CWD="$(printf "%s" "$PAYLOAD" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('cwd',''))" 2>/dev/null || echo "")"
3445
+
3446
+ [[ -d "$CWD/.agent_memory" ]] || exit 0
3447
+ command -v kage >/dev/null 2>&1 || exit 0
3448
+
3449
+ if git -C "$CWD" status --porcelain -uall >/dev/null 2>&1 && [[ -n "$(git -C "$CWD" status --porcelain -uall)" ]]; then
3450
+ kage refresh --project "$CWD" --json >/dev/null 2>&1 || true
3451
+ kage pr summarize --project "$CWD" --json >/dev/null 2>&1 || true
3452
+ fi
3453
+
3454
+ exit 0
3422
3455
  `;
3423
3456
  const settingsPath = (0, node_path_1.join)(home, ".claude", "settings.json");
3424
3457
  const hookEntry = {
3425
3458
  hooks: {
3426
3459
  SessionStart: [{ matcher: "", hooks: [{ type: "command", command: "bash ~/.claude/kage/hooks/session-start.sh", timeout: 5 }] }],
3460
+ Stop: [{ matcher: "", hooks: [{ type: "command", command: "bash ~/.claude/kage/hooks/stop.sh", timeout: 20 }] }],
3427
3461
  },
3428
3462
  };
3429
3463
  setSnippet(path, JSON.stringify({ mcpServers: { kage: server } }, null, 2), [
3430
3464
  "Add the MCP server to ~/.claude.json, then restart Claude Code.",
3431
3465
  "alwaysLoad: true makes Kage tools immediately visible without requiring ToolSearch.",
3432
- `Also create ${hookDir}/session-start.sh with the hook script and add the SessionStart hook to ~/.claude/settings.json.`,
3466
+ `Also create ${hookDir}/session-start.sh and ${hookDir}/stop.sh with the hook scripts and add SessionStart/Stop hooks to ~/.claude/settings.json.`,
3433
3467
  "Run `kage init --project <repo>` inside each repo to install the ambient memory policy.",
3434
3468
  ], true);
3435
3469
  if (options.write) {
@@ -3437,6 +3471,7 @@ KAGE_MSG="$POLICY" python3 -c "import json,os; print(json.dumps({'systemMessage'
3437
3471
  // Install the ambient session-start hook
3438
3472
  (0, node_fs_1.mkdirSync)(hookDir, { recursive: true });
3439
3473
  (0, node_fs_1.writeFileSync)((0, node_path_1.join)(hookDir, "session-start.sh"), hookScript, { mode: 0o755 });
3474
+ (0, node_fs_1.writeFileSync)((0, node_path_1.join)(hookDir, "stop.sh"), stopHookScript, { mode: 0o755 });
3440
3475
  upsertJsonSettings(settingsPath, hookEntry);
3441
3476
  result.wrote = true;
3442
3477
  }
@@ -3862,11 +3897,25 @@ function distillSession(projectDir, sessionId) {
3862
3897
  function createDiffChangeMemory(projectDir, summary) {
3863
3898
  const branch = summary.branch ?? "detached";
3864
3899
  const head = summary.head ?? "unknown";
3865
- const fingerprint = (0, node_crypto_1.createHash)("sha256")
3866
- .update(`${branch}\n${head}\n${summary.changed_files.join("\n")}\n${summary.diff_stat}`)
3867
- .digest("hex")
3868
- .slice(0, 10);
3869
3900
  const title = `Change memory: ${branch}`;
3901
+ // Remove any stale change-memory packets for this branch so propose_from_diff
3902
+ // replaces rather than accumulates. The stable ID (branch-only, no fingerprint)
3903
+ // makes writePacket idempotent going forward; this sweep handles packets that
3904
+ // were written with the old fingerprint-based ID.
3905
+ const stalePrefix = `workflow-${slugify(title)}-`;
3906
+ const stableId = makePacketId(projectDir, "workflow", title);
3907
+ const stableFileName = `${stalePrefix}${(0, node_crypto_1.createHash)("sha256").update(stableId).digest("hex").slice(0, 8)}.json`;
3908
+ try {
3909
+ const existing = (0, node_fs_1.readdirSync)(packetsDir(projectDir)).filter((name) => name.startsWith(stalePrefix) && name !== stableFileName);
3910
+ for (const name of existing) {
3911
+ const stale = (0, node_path_1.join)(packetsDir(projectDir), name);
3912
+ const stalePacket = readJson(stale);
3913
+ if (stalePacket?.type === "workflow" && stalePacket?.title === title) {
3914
+ (0, node_fs_1.unlinkSync)(stale);
3915
+ }
3916
+ }
3917
+ }
3918
+ catch { /* non-fatal */ }
3870
3919
  const verifyCommands = npmScriptCommands(projectDir)
3871
3920
  .filter((command) => /(test|check|lint|build|type|verify)/i.test(command))
3872
3921
  .slice(0, 8);
@@ -3900,7 +3949,7 @@ function createDiffChangeMemory(projectDir, summary) {
3900
3949
  const now = nowIso();
3901
3950
  const packet = {
3902
3951
  schema_version: exports.PACKET_SCHEMA_VERSION,
3903
- id: makePacketId(projectDir, "workflow", title, fingerprint),
3952
+ id: stableId,
3904
3953
  title,
3905
3954
  summary: `Repo-local context for ${summary.changed_files.length} changed repo path${summary.changed_files.length === 1 ? "" : "s"} on ${branch}.`,
3906
3955
  body,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kage-core/kage-graph-mcp",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
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": [