@kage-core/kage-graph-mcp 2.5.5 → 2.5.7
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 +4 -1
- package/dist/kernel.js +45 -45
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,6 @@ const CORE_USAGE = `Kage — code-grounded memory for coding agents
|
|
|
15
15
|
Core commands:
|
|
16
16
|
kage install [--project <dir>] one-shot: init + index + auto-wire detected agents
|
|
17
17
|
kage scan --project <dir> 60-second truth report on any repo (zero setup)
|
|
18
|
-
kage demo watch the reject/withhold loop run in a sandbox
|
|
19
18
|
kage init --project <dir> create repo memory (.agent_memory only)
|
|
20
19
|
kage index --project <dir> [--full] build/refresh code graph + indexes
|
|
21
20
|
kage recall "<query>" --project <dir> grounded recall from repo memory
|
|
@@ -1406,6 +1405,10 @@ async function main() {
|
|
|
1406
1405
|
`~${(0, kernel_js_1.formatTokenCount)(summary.all_time.replay_tokens)} all time ` +
|
|
1407
1406
|
`(discovery cost of served memories vs their compressed read cost)`);
|
|
1408
1407
|
}
|
|
1408
|
+
const usdOverridden = Number.isFinite(Number(process.env.KAGE_USD_PER_MTOK)) && Number(process.env.KAGE_USD_PER_MTOK) > 0;
|
|
1409
|
+
console.log(`\nDollars estimated at $${kernel_js_1.VALUE_DOLLARS_PER_MILLION_TOKENS}/1M input tokens ` +
|
|
1410
|
+
`(${usdOverridden ? "via KAGE_USD_PER_MTOK" : "Sonnet-class default — set KAGE_USD_PER_MTOK for your model"}). ` +
|
|
1411
|
+
`Ledger: .agent_memory/reports/value.json`);
|
|
1409
1412
|
return;
|
|
1410
1413
|
}
|
|
1411
1414
|
if (command === "file-context") {
|
package/dist/kernel.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.PACKET_MERGE_DRIVER_CONFIG = exports.PACKET_MERGE_ATTRIBUTE_LINE = exports.AUTO_DISTILL_SIGNAL_THRESHOLD = exports.AUTO_DISTILL_TAG = exports.SETUP_AGENTS = exports.MEMORY_TYPES = exports.PACKET_SCHEMA_VERSION = void 0;
|
|
36
|
+
exports.PACKET_MERGE_DRIVER_CONFIG = exports.PACKET_MERGE_ATTRIBUTE_LINE = exports.AUTO_DISTILL_SIGNAL_THRESHOLD = exports.AUTO_DISTILL_TAG = exports.VALUE_DOLLARS_PER_MILLION_TOKENS = exports.SETUP_AGENTS = exports.MEMORY_TYPES = exports.PACKET_SCHEMA_VERSION = void 0;
|
|
37
37
|
exports.memoryRoot = memoryRoot;
|
|
38
38
|
exports.packetsDir = packetsDir;
|
|
39
39
|
exports.pendingDir = pendingDir;
|
|
@@ -1017,8 +1017,14 @@ function recordRecallAccess(projectDir, results) {
|
|
|
1017
1017
|
// ---------------------------------------------------------------------------
|
|
1018
1018
|
const VALUE_LEDGER_SCHEMA_VERSION = 1;
|
|
1019
1019
|
const VALUE_LEDGER_EVENT_CAP = 5000;
|
|
1020
|
-
//
|
|
1021
|
-
|
|
1020
|
+
// Input price used for the dollar estimate. Default: Sonnet-class ~$3 per 1M input tokens (the
|
|
1021
|
+
// typical coding-agent tier) — deliberately conservative so the savings figure never overstates.
|
|
1022
|
+
// Override with KAGE_USD_PER_MTOK to match your model (e.g. 15 for Opus, 2.5 for GPT-4o, 0.8 for
|
|
1023
|
+
// Haiku). The old default ($15, Opus pricing) overstated savings ~5x for most users.
|
|
1024
|
+
exports.VALUE_DOLLARS_PER_MILLION_TOKENS = (() => {
|
|
1025
|
+
const raw = Number(process.env.KAGE_USD_PER_MTOK);
|
|
1026
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 3;
|
|
1027
|
+
})();
|
|
1022
1028
|
function valueLedgerPath(projectDir) {
|
|
1023
1029
|
return (0, node_path_1.join)(reportsDir(projectDir), "value.json");
|
|
1024
1030
|
}
|
|
@@ -1112,7 +1118,7 @@ function recordValueEvent(projectDir, event) {
|
|
|
1112
1118
|
recordValueEvents(projectDir, [event]);
|
|
1113
1119
|
}
|
|
1114
1120
|
function estimatedTokenDollars(tokensSaved) {
|
|
1115
|
-
return Number(((tokensSaved / 1_000_000) * VALUE_DOLLARS_PER_MILLION_TOKENS).toFixed(2));
|
|
1121
|
+
return Number(((tokensSaved / 1_000_000) * exports.VALUE_DOLLARS_PER_MILLION_TOKENS).toFixed(2));
|
|
1116
1122
|
}
|
|
1117
1123
|
function summarizeValueWindow(events, cutoff) {
|
|
1118
1124
|
const window = { tokens_saved: 0, replay_tokens: 0, stale_withheld: 0, stale_caught: 0, recalls: 0, caller_answers: 0 };
|
|
@@ -7015,10 +7021,11 @@ function gcProject(projectDir, options = {}) {
|
|
|
7015
7021
|
skipped.push({ id: packet.id, title: packet.title, reason: "already deprecated" });
|
|
7016
7022
|
continue;
|
|
7017
7023
|
}
|
|
7018
|
-
// Serialized transcript / tool-output / file-content dumps
|
|
7019
|
-
//
|
|
7020
|
-
//
|
|
7021
|
-
|
|
7024
|
+
// Serialized transcript / tool-output / file-content dumps and ungrounded conversational
|
|
7025
|
+
// chatter (a path-less rant at the assistant) carry no durable knowledge and bloat recall +
|
|
7026
|
+
// the digest. Always delete them (deprecating would leave the blob on disk) — this also
|
|
7027
|
+
// reclaims legacy junk written before the capture-time guards existed.
|
|
7028
|
+
if (isSerializedDumpTitle(packet.title) || isSerializedDumpBody(packet.body) || isUngroundedConversationalCapture(packet)) {
|
|
7022
7029
|
if (!options.dryRun)
|
|
7023
7030
|
(0, node_fs_1.unlinkSync)(path);
|
|
7024
7031
|
deleted.push({ id: packet.id, title: packet.title });
|
|
@@ -8012,6 +8019,14 @@ function hasRepoGroundingSignal(text) {
|
|
|
8012
8019
|
// punctuation, or one of a curated set of rhetorical / second-person-at-the-assistant
|
|
8013
8020
|
// phrases — so it stays clear of normal declarative learnings (which read as statements, not
|
|
8014
8021
|
// outbursts addressed to "you").
|
|
8022
|
+
// Phrases that rant AT the assistant ("why are you...", "it's your job", "don't stop"). These
|
|
8023
|
+
// never appear in a curated learning, so they mark chatter even when the outburst name-drops a
|
|
8024
|
+
// platform word (github, pr, x, linkedin) that the loose grounding matcher would otherwise
|
|
8025
|
+
// treat as a repo reference. This is the override that closes the leak where a frustrated
|
|
8026
|
+
// message peppered with nouns slipped through and was captured as approved memory.
|
|
8027
|
+
function looksFrustratedAtAssistant(text) {
|
|
8028
|
+
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 ?? "");
|
|
8029
|
+
}
|
|
8015
8030
|
function looksLikeRawUserUtterance(text) {
|
|
8016
8031
|
const t = (text ?? "").trim();
|
|
8017
8032
|
if (!t)
|
|
@@ -8021,18 +8036,21 @@ function looksLikeRawUserUtterance(text) {
|
|
|
8021
8036
|
if (/[!?]{2,}/.test(t))
|
|
8022
8037
|
return true;
|
|
8023
8038
|
// Rhetorical questions / second-person-imperative frustration directed at the assistant.
|
|
8024
|
-
return
|
|
8025
|
-
}
|
|
8026
|
-
// Capture-noise guard for ungrounded chat. A packet trips it
|
|
8027
|
-
//
|
|
8028
|
-
//
|
|
8029
|
-
//
|
|
8030
|
-
//
|
|
8031
|
-
//
|
|
8039
|
+
return looksFrustratedAtAssistant(t);
|
|
8040
|
+
}
|
|
8041
|
+
// Capture-noise guard for ungrounded chat. A packet trips it when it cites zero repo paths and
|
|
8042
|
+
// either (a) it rants at the assistant — which overrides incidental repo-ish words, since the
|
|
8043
|
+
// grounding matcher false-positives on bare platform names — or (b) it reads as a raw outburst
|
|
8044
|
+
// and carries no repo grounding signal at all. The override + conjunction keep it safe: a real
|
|
8045
|
+
// ungrounded decision or convention is declarative (no "why are you.../don't stop") and usually
|
|
8046
|
+
// names a symbol, file, command, or rule, so it is never caught. Such packets route to pending
|
|
8047
|
+
// (not auto-approved) at capture time and are withheld from recall, like serialized dumps.
|
|
8032
8048
|
function isUngroundedConversationalCapture(packet) {
|
|
8033
8049
|
if (packet.paths && packet.paths.length > 0)
|
|
8034
8050
|
return false;
|
|
8035
8051
|
const text = `${packet.title ?? ""}\n${packet.body ?? ""}`;
|
|
8052
|
+
if (looksFrustratedAtAssistant(text))
|
|
8053
|
+
return true;
|
|
8036
8054
|
if (hasRepoGroundingSignal(text))
|
|
8037
8055
|
return false;
|
|
8038
8056
|
return looksLikeRawUserUtterance(text);
|
|
@@ -15615,20 +15633,17 @@ function kageResume(projectDir) {
|
|
|
15615
15633
|
updated_at: packetRecency(packet),
|
|
15616
15634
|
age: humanPacketAge(packetRecency(packet)),
|
|
15617
15635
|
}));
|
|
15618
|
-
|
|
15619
|
-
|
|
15636
|
+
// A new session starts on a fresh task, so SessionStart does NOT replay last session's files,
|
|
15637
|
+
// commands, or a recency-ranked memory list — that was pre-task noise (it fires before the
|
|
15638
|
+
// first prompt, so it can't be task-targeted) and the surface that leaked raw command dumps and
|
|
15639
|
+
// junk packets. Task-relevant memory is pulled on the first prompt via prompt-context; recall
|
|
15640
|
+
// at the moment a file is read via file-context. SessionStart carries only always-on curated
|
|
15641
|
+
// repo facts (the pinned block, below) plus a few actionable open-thread pointers.
|
|
15642
|
+
const hasSessionContent = Boolean(lastChangeMemory || pendingAutoDistilled || reconciliation.unresolved_count);
|
|
15643
|
+
const hasContent = hasSessionContent;
|
|
15620
15644
|
const lines = [];
|
|
15621
|
-
if (
|
|
15622
|
-
lines.push("#
|
|
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
|
-
}
|
|
15645
|
+
if (hasSessionContent) {
|
|
15646
|
+
lines.push("# Open threads (Kage)");
|
|
15632
15647
|
if (lastChangeMemory) {
|
|
15633
15648
|
lines.push(`Change memory: ${lastChangeMemory.title} — ${lastChangeMemory.summary}`);
|
|
15634
15649
|
}
|
|
@@ -15641,22 +15656,7 @@ function kageResume(projectDir) {
|
|
|
15641
15656
|
lines.push(` - ${item.packet_id}: ${item.title}`);
|
|
15642
15657
|
}
|
|
15643
15658
|
}
|
|
15644
|
-
|
|
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
|
-
}
|
|
15659
|
+
const block = lines.slice(0, 12);
|
|
15660
15660
|
// Lead the SessionStart injection with the team's pinned, always-on repo memory (the
|
|
15661
15661
|
// curated high-signal facts), not just the recent-timeline digest — parity with recall's
|
|
15662
15662
|
// context block, so a new session starts already holding the key knowledge, not only a
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kage-core/kage-graph-mcp",
|
|
3
|
-
"version": "2.5.
|
|
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,
|
|
3
|
+
"version": "2.5.7",
|
|
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, no account, no API key.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist/**/*.js",
|