@kage-core/kage-graph-mcp 1.1.4 → 1.1.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.
- package/README.md +20 -8
- package/dist/cli.js +41 -0
- package/dist/index.js +57 -1
- package/dist/kernel.js +128 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ kage recall "how do I run tests" --project /path/to/repo
|
|
|
38
38
|
kage recall "how do I run tests" --project /path/to/repo --explain --json
|
|
39
39
|
kage quality --project /path/to/repo
|
|
40
40
|
kage benchmark --project /path/to/repo
|
|
41
|
+
kage benchmark --project /path/to/repo --compare --task "how do I run tests"
|
|
41
42
|
kage viewer --project /path/to/repo
|
|
42
43
|
kage daemon start --project /path/to/repo
|
|
43
44
|
kage observe --project /path/to/repo --event '{"type":"command_result","session_id":"s1","command":"npm test","exit_code":0}'
|
|
@@ -125,6 +126,12 @@ and parser coverage, code graph counts, evidence coverage, approved vs pending
|
|
|
125
126
|
memory, validation status, estimated tokens saved per recall, duplicate
|
|
126
127
|
candidates, average memory quality, and a readiness score.
|
|
127
128
|
|
|
129
|
+
Use `kage benchmark --compare --task "<task>" --project <repo>` or
|
|
130
|
+
`kage_benchmark_compare` to compare the same task on the same repo with and
|
|
131
|
+
without Kage. It estimates manual full-file rediscovery tokens/steps, compares
|
|
132
|
+
them to compact Kage recall plus code graph context, and returns evidence plus
|
|
133
|
+
caveats for honest marketing proof.
|
|
134
|
+
|
|
128
135
|
Use `kage refresh --project <repo>` or the `kage_refresh` MCP tool after
|
|
129
136
|
meaningful file changes. Refresh rebuilds indexes, code graph, memory graph,
|
|
130
137
|
metrics, and stale-memory metadata. Memory is marked stale when status or
|
|
@@ -151,6 +158,11 @@ ranking: text, graph, path/type/tag, freshness, quality, feedback, and a vector
|
|
|
151
158
|
placeholder for future local or external embedding providers. Current fallback
|
|
152
159
|
is deterministic text plus graph retrieval.
|
|
153
160
|
|
|
161
|
+
`kage_context` is the primary MCP entrypoint for agents. It validates repo
|
|
162
|
+
memory, recalls relevant packets, and returns code/knowledge graph context in
|
|
163
|
+
one call. Agents should use it at task start instead of loading separate
|
|
164
|
+
`kage_validate`, `kage_recall`, `kage_code_graph`, and `kage_graph` schemas.
|
|
165
|
+
|
|
154
166
|
`kage daemon start` exposes the optional local REST runtime on
|
|
155
167
|
`127.0.0.1:3111`:
|
|
156
168
|
|
|
@@ -196,6 +208,7 @@ confidence, and token-savings metrics connect.
|
|
|
196
208
|
|
|
197
209
|
Local repo tools:
|
|
198
210
|
|
|
211
|
+
- `kage_context`
|
|
199
212
|
- `kage_recall`
|
|
200
213
|
- `kage_code_graph`
|
|
201
214
|
- `kage_metrics`
|
|
@@ -204,6 +217,7 @@ Local repo tools:
|
|
|
204
217
|
- `kage_pr_check`
|
|
205
218
|
- `kage_quality`
|
|
206
219
|
- `kage_benchmark`
|
|
220
|
+
- `kage_benchmark_compare`
|
|
207
221
|
- `kage_setup_agent`
|
|
208
222
|
- `kage_graph`
|
|
209
223
|
- `kage_graph_visual`
|
|
@@ -280,14 +294,12 @@ Minimum policy:
|
|
|
280
294
|
|
|
281
295
|
```md
|
|
282
296
|
Before code changes or repo-specific answers:
|
|
283
|
-
1. Call `
|
|
284
|
-
2.
|
|
285
|
-
3.
|
|
286
|
-
4.
|
|
287
|
-
5.
|
|
288
|
-
6.
|
|
289
|
-
7. Before merge, call `kage_pr_check`.
|
|
290
|
-
8. Never publish or promote org/global memory automatically.
|
|
297
|
+
1. Call `kage_context` with `project_dir` and the user task as `query`.
|
|
298
|
+
2. Capture reusable learnings with `kage_learn` or `kage_capture`.
|
|
299
|
+
3. After meaningful file changes, call `kage_refresh`.
|
|
300
|
+
4. Before finishing changed-file tasks, call `kage_propose_from_diff` or `kage_pr_summarize`.
|
|
301
|
+
5. Before merge, call `kage_pr_check`.
|
|
302
|
+
6. Never publish or promote org/global memory automatically.
|
|
291
303
|
```
|
|
292
304
|
|
|
293
305
|
Run `kage setup verify-agent --agent codex --project <repo>` after setup. The
|
package/dist/cli.js
CHANGED
|
@@ -31,6 +31,7 @@ Usage:
|
|
|
31
31
|
kage metrics --project <dir> [--json]
|
|
32
32
|
kage quality --project <dir> [--json]
|
|
33
33
|
kage benchmark --project <dir> [--json]
|
|
34
|
+
kage benchmark --project <dir> --compare --task <task> [--json]
|
|
34
35
|
kage code-graph --project <dir> [--json]
|
|
35
36
|
kage code-graph "<query>" --project <dir> [--json]
|
|
36
37
|
kage graph --project <dir> [--json]
|
|
@@ -533,6 +534,46 @@ async function main() {
|
|
|
533
534
|
return;
|
|
534
535
|
}
|
|
535
536
|
if (command === "benchmark") {
|
|
537
|
+
if (args.includes("--compare")) {
|
|
538
|
+
const result = (0, kernel_js_1.benchmarkTaskComparison)(projectArg(args), takeArg(args, "--task") ?? firstPositional(args) ?? "how do I run tests");
|
|
539
|
+
if (args.includes("--json")) {
|
|
540
|
+
console.log(JSON.stringify(result, null, 2));
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
console.log(`Kage A/B Benchmark: ${result.project_dir}`);
|
|
544
|
+
console.log(`Task: ${result.task}`);
|
|
545
|
+
console.log("");
|
|
546
|
+
console.log("Without Kage:");
|
|
547
|
+
console.log(` Files examined: ${result.baseline_without_kage.files_examined}`);
|
|
548
|
+
console.log(` Full-file tokens: ${result.baseline_without_kage.full_file_tokens}`);
|
|
549
|
+
console.log(` Steps: ${result.baseline_without_kage.steps}`);
|
|
550
|
+
console.log(` Estimated time: ${result.baseline_without_kage.estimated_time_seconds}s`);
|
|
551
|
+
console.log("");
|
|
552
|
+
console.log("With Kage:");
|
|
553
|
+
console.log(` Memory packets: ${result.with_kage.memory_packets_used}`);
|
|
554
|
+
console.log(` Code facts: ${result.with_kage.code_files_returned + result.with_kage.code_symbols_returned + result.with_kage.code_routes_returned + result.with_kage.code_tests_returned}`);
|
|
555
|
+
console.log(` Context tokens: ${result.with_kage.context_tokens}`);
|
|
556
|
+
console.log(` Steps: ${result.with_kage.steps}`);
|
|
557
|
+
console.log(` Estimated time: ${result.with_kage.estimated_time_seconds}s`);
|
|
558
|
+
console.log("");
|
|
559
|
+
console.log("Delta:");
|
|
560
|
+
console.log(` Estimated tokens saved: ${result.delta.estimated_tokens_saved}`);
|
|
561
|
+
console.log(` Context reduction: ${result.delta.context_reduction_percent}%`);
|
|
562
|
+
console.log(` Rediscovery steps saved: ${result.delta.rediscovery_steps_saved}`);
|
|
563
|
+
console.log(` Estimated time saved: ${result.delta.estimated_time_saved_seconds}s`);
|
|
564
|
+
console.log(` Full-file reads avoided: ${result.delta.full_file_reads_avoided}`);
|
|
565
|
+
console.log(` Recall hit: ${result.delta.recall_hit ? "yes" : "no"}`);
|
|
566
|
+
console.log(` Code graph hit: ${result.delta.code_graph_hit ? "yes" : "no"}`);
|
|
567
|
+
console.log("");
|
|
568
|
+
console.log("Baseline files:");
|
|
569
|
+
for (const file of result.evidence.baseline_files.slice(0, 8))
|
|
570
|
+
console.log(` - ${file.path} (${file.tokens} tokens): ${file.why}`);
|
|
571
|
+
console.log("");
|
|
572
|
+
console.log("Kage memory:");
|
|
573
|
+
for (const packet of result.evidence.kage_memory.slice(0, 5))
|
|
574
|
+
console.log(` - ${packet.title} (${packet.type}, score ${packet.score})`);
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
536
577
|
const result = (0, kernel_js_1.benchmarkProject)(projectArg(args));
|
|
537
578
|
if (args.includes("--json")) {
|
|
538
579
|
console.log(JSON.stringify(result, null, 2));
|
package/dist/index.js
CHANGED
|
@@ -54,9 +54,25 @@ 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.
|
|
57
|
+
const server = new index_js_1.Server({ name: "kage-graph", version: "1.1.6" }, { capabilities: { tools: {} } });
|
|
58
58
|
function listTools() {
|
|
59
59
|
return [
|
|
60
|
+
{
|
|
61
|
+
// Combined entry-point tool: validate + recall + code_graph + graph in one call.
|
|
62
|
+
// Agents should load this schema first (one ToolSearch) instead of loading four
|
|
63
|
+
// separate deferred schemas. Cuts session start from 4 schema loads to 1.
|
|
64
|
+
name: "kage_context",
|
|
65
|
+
description: "Primary kage entry point. Validates memory health, recalls relevant packets, and queries both the code graph and knowledge graph — all in one call. Call this at the start of every task instead of calling kage_validate, kage_recall, kage_code_graph, and kage_graph separately.",
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: "object",
|
|
68
|
+
properties: {
|
|
69
|
+
project_dir: { type: "string", description: "Absolute path to the project root" },
|
|
70
|
+
query: { type: "string", description: "The task or question — used for both memory recall and code graph search" },
|
|
71
|
+
limit: { type: "number", description: "Max memory packets to return (default 5)" },
|
|
72
|
+
},
|
|
73
|
+
required: ["project_dir", "query"],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
60
76
|
{
|
|
61
77
|
name: "kage_search",
|
|
62
78
|
description: "Search the kage community knowledge graph for gotchas, patterns, configs, and architectural decisions across auth, database, payments, deployment, frontend, testing, and more. Returns node summaries ranked by relevance.",
|
|
@@ -209,6 +225,18 @@ function listTools() {
|
|
|
209
225
|
required: ["project_dir"],
|
|
210
226
|
},
|
|
211
227
|
},
|
|
228
|
+
{
|
|
229
|
+
name: "kage_benchmark_compare",
|
|
230
|
+
description: "Compare the same task on the same repo with and without Kage. Reports estimated baseline discovery tokens/steps versus Kage recall/code-graph context, with evidence and caveats.",
|
|
231
|
+
inputSchema: {
|
|
232
|
+
type: "object",
|
|
233
|
+
properties: {
|
|
234
|
+
project_dir: { type: "string" },
|
|
235
|
+
task: { type: "string" },
|
|
236
|
+
},
|
|
237
|
+
required: ["project_dir", "task"],
|
|
238
|
+
},
|
|
239
|
+
},
|
|
212
240
|
{
|
|
213
241
|
name: "kage_setup_agent",
|
|
214
242
|
description: "Generate MCP/setup instructions for Codex, Claude Code, Cursor, Windsurf, Gemini CLI, OpenCode, Cline, Goose, Roo Code, Kilo Code, Claude Desktop, Aider, or generic MCP.",
|
|
@@ -596,6 +624,28 @@ async function callTool(name, args) {
|
|
|
596
624
|
content: [{ type: "text", text: content }],
|
|
597
625
|
};
|
|
598
626
|
}
|
|
627
|
+
if (name === "kage_context") {
|
|
628
|
+
const projectDir = String(args?.project_dir ?? "");
|
|
629
|
+
const query = String(args?.query ?? "");
|
|
630
|
+
const limit = Number(args?.limit ?? 5);
|
|
631
|
+
// validate
|
|
632
|
+
const validation = (0, kernel_js_1.validateProject)(projectDir);
|
|
633
|
+
const validationText = validation.ok
|
|
634
|
+
? "Memory healthy."
|
|
635
|
+
: `Warnings: ${validation.warnings.join("; ")}`;
|
|
636
|
+
// recall (memory + code graph + knowledge graph combined)
|
|
637
|
+
const recallResult = (0, kernel_js_1.recall)(projectDir, query, limit, false);
|
|
638
|
+
// graph facts on top of recall
|
|
639
|
+
const graphResult = (0, kernel_js_1.queryGraph)(projectDir, query, 5);
|
|
640
|
+
const sections = [
|
|
641
|
+
recallResult.context_block,
|
|
642
|
+
graphResult.context_block ? `\n## Graph Facts\n${graphResult.context_block}` : "",
|
|
643
|
+
`\n_${validationText}_`,
|
|
644
|
+
].filter(Boolean).join("");
|
|
645
|
+
return {
|
|
646
|
+
content: [{ type: "text", text: sections }],
|
|
647
|
+
};
|
|
648
|
+
}
|
|
599
649
|
if (name === "kage_recall") {
|
|
600
650
|
const result = (0, kernel_js_1.recall)(String(args?.project_dir ?? ""), String(args?.query ?? ""), Number(args?.limit ?? 5), Boolean(args?.explain));
|
|
601
651
|
return {
|
|
@@ -661,6 +711,12 @@ async function callTool(name, args) {
|
|
|
661
711
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
662
712
|
};
|
|
663
713
|
}
|
|
714
|
+
if (name === "kage_benchmark_compare") {
|
|
715
|
+
const result = (0, kernel_js_1.benchmarkTaskComparison)(String(args?.project_dir ?? ""), String(args?.task ?? ""));
|
|
716
|
+
return {
|
|
717
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
718
|
+
};
|
|
719
|
+
}
|
|
664
720
|
if (name === "kage_setup_agent") {
|
|
665
721
|
const result = (0, kernel_js_1.setupAgent)(String(args?.agent ?? ""), String(args?.project_dir ?? ""), { write: Boolean(args?.write) });
|
|
666
722
|
return {
|
package/dist/kernel.js
CHANGED
|
@@ -75,6 +75,7 @@ exports.graphMermaid = graphMermaid;
|
|
|
75
75
|
exports.kageMetrics = kageMetrics;
|
|
76
76
|
exports.qualityReport = qualityReport;
|
|
77
77
|
exports.benchmarkProject = benchmarkProject;
|
|
78
|
+
exports.benchmarkTaskComparison = benchmarkTaskComparison;
|
|
78
79
|
exports.learn = learn;
|
|
79
80
|
exports.capture = capture;
|
|
80
81
|
exports.createPublicCandidate = createPublicCandidate;
|
|
@@ -150,12 +151,11 @@ This repo uses Kage as an automatic memory harness for coding agents.
|
|
|
150
151
|
|
|
151
152
|
Before making code changes, answering repo-specific implementation questions, debugging failures, or proposing architecture:
|
|
152
153
|
|
|
153
|
-
1. Call \`
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
6. Prefer repo memory over public/community memory when they conflict.
|
|
154
|
+
1. Call \`kage_context\` with \`project_dir\` and the task as \`query\`.
|
|
155
|
+
This validates memory, recalls relevant packets, and queries both the code graph
|
|
156
|
+
and knowledge graph in one call — replacing the old four-step validate/recall/code_graph/graph sequence.
|
|
157
|
+
2. Use returned memory only when it is relevant, source-backed, and not stale.
|
|
158
|
+
3. Prefer repo memory over public/community memory when they conflict.
|
|
159
159
|
|
|
160
160
|
Do this without waiting for the user to ask. Kage should feel like ambient repo memory, not a manual search command.
|
|
161
161
|
|
|
@@ -216,17 +216,13 @@ If recalled memory materially helped, call \`kage_feedback\` with \`helpful\`.
|
|
|
216
216
|
|
|
217
217
|
For normal coding tasks:
|
|
218
218
|
|
|
219
|
-
1. \`
|
|
220
|
-
2.
|
|
221
|
-
3. \`
|
|
222
|
-
4. \`
|
|
223
|
-
5.
|
|
224
|
-
6. \`kage_learn\` for concrete learnings
|
|
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
|
|
219
|
+
1. \`kage_context\` — validate + recall + code graph + knowledge graph in one call
|
|
220
|
+
2. Work on the task
|
|
221
|
+
3. \`kage_learn\` for concrete learnings
|
|
222
|
+
4. \`kage_refresh\` after meaningful file changes
|
|
223
|
+
5. \`kage_propose_from_diff\` before the final response to create repo-local change memory
|
|
228
224
|
|
|
229
|
-
For quick factual questions, \`
|
|
225
|
+
For quick factual questions, \`kage_context\` alone is enough. For status or demo requests, call \`kage_metrics\`.
|
|
230
226
|
${AGENTS_POLICY_END}
|
|
231
227
|
`;
|
|
232
228
|
const STOPWORDS = new Set([
|
|
@@ -579,7 +575,9 @@ function evaluateMemoryQuality(projectDir, packet) {
|
|
|
579
575
|
risks,
|
|
580
576
|
duplicate_candidates: duplicates,
|
|
581
577
|
stale_reasons: staleReasons,
|
|
582
|
-
|
|
578
|
+
// Tokens an agent saves by reading this packet instead of the files it references.
|
|
579
|
+
// Approximated as the token size of the files it grounds to (or the packet body if no paths).
|
|
580
|
+
estimated_tokens_saved: Math.max(20, estimateTokens(packet.body)),
|
|
583
581
|
};
|
|
584
582
|
}
|
|
585
583
|
function evaluateMemoryAdmission(projectDir, packet) {
|
|
@@ -2905,8 +2903,13 @@ function kageMetrics(projectDir) {
|
|
|
2905
2903
|
const duplicatePairs = allPackets.reduce((sum, packet) => sum + duplicateCandidates(projectDir, packet).length, 0);
|
|
2906
2904
|
const indexedSourceTokens = Math.ceil(sourceFiles.reduce((sum, file) => sum + file.size_bytes, 0) / 4);
|
|
2907
2905
|
const memoryTokens = allPackets.reduce((sum, packet) => sum + estimateTokens(packetText(packet)), 0);
|
|
2906
|
+
// Estimated size of a typical recall response: structured packet summaries + code graph
|
|
2907
|
+
// slice, capped at ~1 800 tokens. This is what actually reaches the agent per recall call.
|
|
2908
2908
|
const recallContextTokens = Math.max(250, Math.min(1800, codeGraph.symbols.length * 12 + codeGraph.routes.length * 10 + knowledgeGraph.edges.length * 14 + 180));
|
|
2909
|
-
|
|
2909
|
+
// Honest saving: tokens an agent would spend reading all source files minus tokens a
|
|
2910
|
+
// targeted recall costs. Only meaningful when an agent would otherwise read everything.
|
|
2911
|
+
// memoryTokens is storage cost, not context sent — excluded from this calculation.
|
|
2912
|
+
const tokensSaved = Math.max(0, indexedSourceTokens - recallContextTokens);
|
|
2910
2913
|
const readinessScore = Math.max(0, Math.min(100, Math.round(coverage * 0.35 +
|
|
2911
2914
|
percent(evidenceBackedEdges, knowledgeGraph.edges.length) * 0.25 +
|
|
2912
2915
|
(approvedPackets > 0 ? 20 : 0) +
|
|
@@ -3064,6 +3067,110 @@ function benchmarkProject(projectDir) {
|
|
|
3064
3067
|
},
|
|
3065
3068
|
};
|
|
3066
3069
|
}
|
|
3070
|
+
function baselineDiscoveryFiles(projectDir, task) {
|
|
3071
|
+
const terms = tokenize(task);
|
|
3072
|
+
const graph = buildCodeGraph(projectDir);
|
|
3073
|
+
const candidatePaths = unique([
|
|
3074
|
+
"README.md",
|
|
3075
|
+
"AGENTS.md",
|
|
3076
|
+
"CLAUDE.md",
|
|
3077
|
+
"package.json",
|
|
3078
|
+
...graph.files.map((file) => file.path),
|
|
3079
|
+
]).filter((path) => path && !shouldSkipRepoMemoryPath(path));
|
|
3080
|
+
return candidatePaths
|
|
3081
|
+
.map((path) => {
|
|
3082
|
+
const absolute = (0, node_path_1.join)(projectDir, path);
|
|
3083
|
+
if (!(0, node_fs_1.existsSync)(absolute))
|
|
3084
|
+
return null;
|
|
3085
|
+
const stats = (0, node_fs_1.statSync)(absolute);
|
|
3086
|
+
if (!stats.isFile() || stats.size > 240_000)
|
|
3087
|
+
return null;
|
|
3088
|
+
const text = (0, node_fs_1.readFileSync)(absolute, "utf8");
|
|
3089
|
+
const score = scoreText(terms, `${path}\n${text.slice(0, 8000)}`, [path]);
|
|
3090
|
+
const alwaysUseful = ["README.md", "AGENTS.md", "CLAUDE.md", "package.json"].includes(path);
|
|
3091
|
+
if (score <= 0 && !alwaysUseful)
|
|
3092
|
+
return null;
|
|
3093
|
+
return {
|
|
3094
|
+
path,
|
|
3095
|
+
tokens: Math.max(1, Math.ceil(stats.size / 4)),
|
|
3096
|
+
why: score > 0 ? "task terms matched path or file content" : "standard repo orientation file",
|
|
3097
|
+
score: score + (alwaysUseful ? 1 : 0),
|
|
3098
|
+
};
|
|
3099
|
+
})
|
|
3100
|
+
.filter((entry) => Boolean(entry))
|
|
3101
|
+
.sort((a, b) => b.score - a.score || b.tokens - a.tokens || a.path.localeCompare(b.path))
|
|
3102
|
+
.slice(0, 10);
|
|
3103
|
+
}
|
|
3104
|
+
function benchmarkTaskComparison(projectDir, task) {
|
|
3105
|
+
ensureMemoryDirs(projectDir);
|
|
3106
|
+
const query = task.trim() || "how do I run tests";
|
|
3107
|
+
const baselineFiles = baselineDiscoveryFiles(projectDir, query);
|
|
3108
|
+
const baselineTokens = baselineFiles.reduce((sum, file) => sum + file.tokens, 0);
|
|
3109
|
+
const recallResult = recall(projectDir, query, 5, true);
|
|
3110
|
+
const codeResult = queryCodeGraph(projectDir, query, 10);
|
|
3111
|
+
const kageContext = `${recallResult.context_block}\n\n${codeResult.context_block}`;
|
|
3112
|
+
const kageTokens = estimateTokens(kageContext);
|
|
3113
|
+
const codeFactLines = [
|
|
3114
|
+
...codeResult.routes.map((route) => `[route] ${route.method} ${route.path} in ${route.file_path}:${route.line}`),
|
|
3115
|
+
...codeResult.symbols.map((symbol) => `[symbol] ${symbol.kind} ${symbol.name} in ${symbol.path}:${symbol.line}`),
|
|
3116
|
+
...codeResult.tests.map((test) => `[test] ${test.title} in ${test.test_path}:${test.line}`),
|
|
3117
|
+
...codeResult.files.slice(0, 5).map((file) => `[file] ${file.path} (${file.kind}, ${file.language}, ${file.parser})`),
|
|
3118
|
+
];
|
|
3119
|
+
const baselineSteps = Math.max(3, baselineFiles.length + 2);
|
|
3120
|
+
const kageSteps = 3;
|
|
3121
|
+
const tokensSaved = Math.max(0, baselineTokens - kageTokens);
|
|
3122
|
+
const contextReduction = baselineTokens > 0 ? percent(tokensSaved, baselineTokens) : 0;
|
|
3123
|
+
const timeSaved = Math.max(0, baselineSteps * 45 - kageSteps * 12);
|
|
3124
|
+
return {
|
|
3125
|
+
schema_version: 1,
|
|
3126
|
+
project_dir: projectDir,
|
|
3127
|
+
task: query,
|
|
3128
|
+
generated_at: nowIso(),
|
|
3129
|
+
baseline_without_kage: {
|
|
3130
|
+
strategy: "manual_repo_discovery_estimate",
|
|
3131
|
+
files_examined: baselineFiles.length,
|
|
3132
|
+
full_file_tokens: baselineTokens,
|
|
3133
|
+
steps: baselineSteps,
|
|
3134
|
+
estimated_time_seconds: baselineSteps * 45,
|
|
3135
|
+
},
|
|
3136
|
+
with_kage: {
|
|
3137
|
+
strategy: "recall_plus_code_graph",
|
|
3138
|
+
recall_results: recallResult.results.length,
|
|
3139
|
+
memory_packets_used: recallResult.results.length,
|
|
3140
|
+
code_files_returned: codeResult.files.length,
|
|
3141
|
+
code_symbols_returned: codeResult.symbols.length,
|
|
3142
|
+
code_routes_returned: codeResult.routes.length,
|
|
3143
|
+
code_tests_returned: codeResult.tests.length,
|
|
3144
|
+
context_tokens: kageTokens,
|
|
3145
|
+
steps: kageSteps,
|
|
3146
|
+
estimated_time_seconds: kageSteps * 12,
|
|
3147
|
+
},
|
|
3148
|
+
delta: {
|
|
3149
|
+
estimated_tokens_saved: tokensSaved,
|
|
3150
|
+
context_reduction_percent: contextReduction,
|
|
3151
|
+
rediscovery_steps_saved: Math.max(0, baselineSteps - kageSteps),
|
|
3152
|
+
estimated_time_saved_seconds: timeSaved,
|
|
3153
|
+
full_file_reads_avoided: Math.max(0, baselineFiles.length - codeResult.files.length),
|
|
3154
|
+
recall_hit: recallResult.results.length > 0,
|
|
3155
|
+
code_graph_hit: codeFactLines.length > 0,
|
|
3156
|
+
},
|
|
3157
|
+
evidence: {
|
|
3158
|
+
baseline_files: baselineFiles.map(({ path, tokens, why }) => ({ path, tokens, why })),
|
|
3159
|
+
kage_memory: recallResult.results.map((entry) => ({
|
|
3160
|
+
id: entry.packet.id,
|
|
3161
|
+
title: entry.packet.title,
|
|
3162
|
+
type: entry.packet.type,
|
|
3163
|
+
score: entry.score,
|
|
3164
|
+
})),
|
|
3165
|
+
kage_code_facts: codeFactLines.slice(0, 12),
|
|
3166
|
+
},
|
|
3167
|
+
caveats: [
|
|
3168
|
+
"Baseline is a deterministic manual-discovery estimate, not a live human or agent timing trace.",
|
|
3169
|
+
"Token savings estimate full-file reads avoided versus compact Kage recall/code-graph context.",
|
|
3170
|
+
"Use this for relative proof on the same repo/task, not cross-repo absolute claims.",
|
|
3171
|
+
],
|
|
3172
|
+
};
|
|
3173
|
+
}
|
|
3067
3174
|
function kageMetricsShallow(projectDir) {
|
|
3068
3175
|
const codeGraph = buildCodeGraph(projectDir);
|
|
3069
3176
|
const knowledgeGraph = buildKnowledgeGraph(projectDir);
|
|
@@ -3108,7 +3215,7 @@ function kageMetricsShallow(projectDir) {
|
|
|
3108
3215
|
estimated_indexed_source_tokens: indexedSourceTokens,
|
|
3109
3216
|
estimated_memory_tokens: memoryTokens,
|
|
3110
3217
|
estimated_recall_context_tokens: recallContextTokens,
|
|
3111
|
-
estimated_tokens_saved_per_recall: Math.max(0, indexedSourceTokens
|
|
3218
|
+
estimated_tokens_saved_per_recall: Math.max(0, indexedSourceTokens - recallContextTokens),
|
|
3112
3219
|
},
|
|
3113
3220
|
harness: {
|
|
3114
3221
|
policy_installed: (0, node_fs_1.existsSync)((0, node_path_1.join)(projectDir, "AGENTS.md")),
|
|
@@ -3423,10 +3530,8 @@ fi
|
|
|
3423
3530
|
if [[ -z "$POLICY" ]]; then
|
|
3424
3531
|
POLICY="This repo uses Kage as an automatic memory harness for coding agents.
|
|
3425
3532
|
Before making code changes or answering implementation questions:
|
|
3426
|
-
1. Call
|
|
3427
|
-
2.
|
|
3428
|
-
3. Call kage_code_graph for file, symbol, route, test, or dependency questions.
|
|
3429
|
-
4. Call kage_graph for decisions, bugs, workflows, and conventions.
|
|
3533
|
+
1. Call kage_context with project_dir and the user task as query.
|
|
3534
|
+
2. Use returned memory only when it is relevant, source-backed, and not stale.
|
|
3430
3535
|
When you learn something reusable: kage_learn.
|
|
3431
3536
|
After meaningful file changes: kage_refresh.
|
|
3432
3537
|
Before finishing a task that changed files: kage_pr_summarize or kage_propose_from_diff, then kage_pr_check.
|