@kage-core/kage-graph-mcp 2.5.5 → 2.5.6

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 +35 -41
  2. package/package.json +1 -1
package/dist/kernel.js CHANGED
@@ -7015,10 +7015,11 @@ function gcProject(projectDir, options = {}) {
7015
7015
  skipped.push({ id: packet.id, title: packet.title, reason: "already deprecated" });
7016
7016
  continue;
7017
7017
  }
7018
- // Serialized transcript / tool-output / file-content dumps carry no durable knowledge
7019
- // and bloat recall + the graph. Always delete them (deprecating would leave the blob on
7020
- // disk) this also reclaims legacy dumps written before the capture-time guard existed.
7021
- if (isSerializedDumpTitle(packet.title) || isSerializedDumpBody(packet.body)) {
7018
+ // Serialized transcript / tool-output / file-content dumps and ungrounded conversational
7019
+ // chatter (a path-less rant at the assistant) carry no durable knowledge and bloat recall +
7020
+ // the digest. Always delete them (deprecating would leave the blob on disk) — this also
7021
+ // reclaims legacy junk written before the capture-time guards existed.
7022
+ if (isSerializedDumpTitle(packet.title) || isSerializedDumpBody(packet.body) || isUngroundedConversationalCapture(packet)) {
7022
7023
  if (!options.dryRun)
7023
7024
  (0, node_fs_1.unlinkSync)(path);
7024
7025
  deleted.push({ id: packet.id, title: packet.title });
@@ -8012,6 +8013,14 @@ function hasRepoGroundingSignal(text) {
8012
8013
  // punctuation, or one of a curated set of rhetorical / second-person-at-the-assistant
8013
8014
  // phrases — so it stays clear of normal declarative learnings (which read as statements, not
8014
8015
  // outbursts addressed to "you").
8016
+ // Phrases that rant AT the assistant ("why are you...", "it's your job", "don't stop"). These
8017
+ // never appear in a curated learning, so they mark chatter even when the outburst name-drops a
8018
+ // platform word (github, pr, x, linkedin) that the loose grounding matcher would otherwise
8019
+ // treat as a repo reference. This is the override that closes the leak where a frustrated
8020
+ // message peppered with nouns slipped through and was captured as approved memory.
8021
+ function looksFrustratedAtAssistant(text) {
8022
+ return /\b(why are you|why did you|why would you|why aren'?t you|are you (kidding|serious|even|really)|it'?s your job|that'?s your job|do your job|don'?t stop|stop asking|stop before you|keep going|hurry up|just do it|figure it out yourself|i (already )?told you)\b/i.test(text ?? "");
8023
+ }
8015
8024
  function looksLikeRawUserUtterance(text) {
8016
8025
  const t = (text ?? "").trim();
8017
8026
  if (!t)
@@ -8021,18 +8030,21 @@ function looksLikeRawUserUtterance(text) {
8021
8030
  if (/[!?]{2,}/.test(t))
8022
8031
  return true;
8023
8032
  // Rhetorical questions / second-person-imperative frustration directed at the assistant.
8024
- return /\b(why are you|why did you|why would you|why aren'?t you|are you (kidding|serious|even|really)|it'?s your job|that'?s your job|do your job|don'?t stop|stop asking|stop before you|keep going|hurry up|just do it|figure it out yourself|i (already )?told you)\b/i.test(t);
8025
- }
8026
- // Capture-noise guard for ungrounded chat. A packet trips it only when ALL hold: it cites zero
8027
- // repo paths, its text carries no repo grounding signal (no path/file/identifier/command), and
8028
- // it reads as a raw conversational user utterance. The conjunction is what keeps it safe — a
8029
- // real ungrounded decision or convention names a symbol, file, command, or rule and so is never
8030
- // caught. Such packets are routed to pending (not auto-approved) at capture time and withheld
8031
- // from recall, mirroring how serialized dumps are gated.
8033
+ return looksFrustratedAtAssistant(t);
8034
+ }
8035
+ // Capture-noise guard for ungrounded chat. A packet trips it when it cites zero repo paths and
8036
+ // either (a) it rants at the assistant which overrides incidental repo-ish words, since the
8037
+ // grounding matcher false-positives on bare platform names or (b) it reads as a raw outburst
8038
+ // and carries no repo grounding signal at all. The override + conjunction keep it safe: a real
8039
+ // ungrounded decision or convention is declarative (no "why are you.../don't stop") and usually
8040
+ // names a symbol, file, command, or rule, so it is never caught. Such packets route to pending
8041
+ // (not auto-approved) at capture time and are withheld from recall, like serialized dumps.
8032
8042
  function isUngroundedConversationalCapture(packet) {
8033
8043
  if (packet.paths && packet.paths.length > 0)
8034
8044
  return false;
8035
8045
  const text = `${packet.title ?? ""}\n${packet.body ?? ""}`;
8046
+ if (looksFrustratedAtAssistant(text))
8047
+ return true;
8036
8048
  if (hasRepoGroundingSignal(text))
8037
8049
  return false;
8038
8050
  return looksLikeRawUserUtterance(text);
@@ -15615,20 +15627,17 @@ function kageResume(projectDir) {
15615
15627
  updated_at: packetRecency(packet),
15616
15628
  age: humanPacketAge(packetRecency(packet)),
15617
15629
  }));
15618
- const hasSessionContent = Boolean(lastSession || lastChangeMemory || pendingAutoDistilled || reconciliation.unresolved_count);
15619
- const hasContent = hasSessionContent || recentMemory.length > 0;
15630
+ // A new session starts on a fresh task, so SessionStart does NOT replay last session's files,
15631
+ // commands, or a recency-ranked memory list — that was pre-task noise (it fires before the
15632
+ // first prompt, so it can't be task-targeted) and the surface that leaked raw command dumps and
15633
+ // junk packets. Task-relevant memory is pulled on the first prompt via prompt-context; recall
15634
+ // at the moment a file is read via file-context. SessionStart carries only always-on curated
15635
+ // repo facts (the pinned block, below) plus a few actionable open-thread pointers.
15636
+ const hasSessionContent = Boolean(lastChangeMemory || pendingAutoDistilled || reconciliation.unresolved_count);
15637
+ const hasContent = hasSessionContent;
15620
15638
  const lines = [];
15621
- if (hasContent) {
15622
- lines.push("# Previously (Kage)");
15623
- if (lastSession) {
15624
- lines.push(`Last session ${lastSession.session_id} (${lastSession.observations} observation${lastSession.observations === 1 ? "" : "s"}, ended ${lastSession.last_at}).`);
15625
- if (lastSession.paths.length)
15626
- lines.push(`Worked on: ${lastSession.paths.join(", ")}`);
15627
- if (lastSession.commands.length)
15628
- lines.push(`Commands: ${lastSession.commands.join("; ")}`);
15629
- if (lastSession.distilled_titles.length)
15630
- lines.push(`Learned: ${lastSession.distilled_titles.join("; ")}`);
15631
- }
15639
+ if (hasSessionContent) {
15640
+ lines.push("# Open threads (Kage)");
15632
15641
  if (lastChangeMemory) {
15633
15642
  lines.push(`Change memory: ${lastChangeMemory.title} — ${lastChangeMemory.summary}`);
15634
15643
  }
@@ -15641,22 +15650,7 @@ function kageResume(projectDir) {
15641
15650
  lines.push(` - ${item.packet_id}: ${item.title}`);
15642
15651
  }
15643
15652
  }
15644
- // Compact timeline index: one line per recent packet, full detail (summary)
15645
- // only for the newest few, hard-capped to the resume token budget.
15646
- const block = lines.slice(0, 15);
15647
- if (recentPackets.length) {
15648
- block.push("", "## Recent memory");
15649
- recentPackets.forEach((packet, position) => {
15650
- const entry = `[${packet.id.slice(0, 12)}] ${packet.type} ${packet.title} (${humanPacketAge(packetRecency(packet))})`;
15651
- const candidate = [entry];
15652
- if (position < RESUME_TIMELINE_DETAILED && packet.summary) {
15653
- const summary = packet.summary.replace(/\s+/g, " ").trim();
15654
- candidate.push(` ${summary.length > 160 ? `${summary.slice(0, 157)}...` : summary}`);
15655
- }
15656
- if (estimateTokens([...block, ...candidate].join("\n")) <= RESUME_CONTEXT_TOKEN_BUDGET)
15657
- block.push(...candidate);
15658
- });
15659
- }
15653
+ const block = lines.slice(0, 12);
15660
15654
  // Lead the SessionStart injection with the team's pinned, always-on repo memory (the
15661
15655
  // curated high-signal facts), not just the recent-timeline digest — parity with recall's
15662
15656
  // context block, so a new session starts already holding the key knowledge, not only a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kage-core/kage-graph-mcp",
3
- "version": "2.5.5",
3
+ "version": "2.5.6",
4
4
  "description": "Team memory for coding agents: captures the decisions, runbooks, and bug fixes that get lost, verified against your code and shared via git. MCP server, zero deps, no account.",
5
5
  "main": "dist/index.js",
6
6
  "files": [