@kage-core/kage-graph-mcp 3.2.0 → 3.3.0
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/check.js +612 -0
- package/dist/cli.js +44 -1
- package/dist/index.js +32 -7
- package/dist/kernel.js +372 -79
- package/dist/okf.js +6 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10,11 +10,13 @@ const node_process_1 = require("node:process");
|
|
|
10
10
|
const daemon_js_1 = require("./daemon.js");
|
|
11
11
|
const kernel_js_1 = require("./kernel.js");
|
|
12
12
|
const graph_registry_js_1 = require("./graph-registry.js");
|
|
13
|
+
const check_js_1 = require("./check.js");
|
|
13
14
|
const okf_js_1 = require("./okf.js");
|
|
14
15
|
const CORE_USAGE = `Kage — code-grounded memory for coding agents
|
|
15
16
|
|
|
16
17
|
Core commands:
|
|
17
18
|
kage install [--project <dir>] one-shot: init + index + auto-wire detected agents
|
|
19
|
+
kage check [--project <dir>] verify CLAUDE.md/AGENTS.md/docs claims against the code — counted, not estimated
|
|
18
20
|
kage scan --project <dir> 60-second truth report on any repo (zero setup)
|
|
19
21
|
kage init --project <dir> create repo memory (.agent_memory only)
|
|
20
22
|
kage index --project <dir> [--full] build/refresh code graph + indexes
|
|
@@ -32,6 +34,7 @@ const FULL_USAGE = `Kage — full command reference
|
|
|
32
34
|
|
|
33
35
|
Usage:
|
|
34
36
|
kage index --project <dir>
|
|
37
|
+
kage check [--project <dir>] [--json | --md] [--base <ref>] [--write-baseline] [--init-ci [--force]]
|
|
35
38
|
kage scan --project <dir> [--json] [--scorecard [--out <file>]]
|
|
36
39
|
kage demo [--project <dir>]
|
|
37
40
|
kage install [--project <dir>] [--agents a,b] [--no-agents] [--json]
|
|
@@ -307,6 +310,41 @@ async function main() {
|
|
|
307
310
|
console.log(`Indexes:\n${result.indexes.map((path) => ` - ${path}`).join("\n")}`);
|
|
308
311
|
return;
|
|
309
312
|
}
|
|
313
|
+
if (command === "check") {
|
|
314
|
+
const checkTarget = (0, node_path_1.resolve)(projectArg(args));
|
|
315
|
+
if (args.includes("--init-ci")) {
|
|
316
|
+
const workflowPath = (0, node_path_1.join)(checkTarget, ".github", "workflows", "kage-check.yml");
|
|
317
|
+
if ((0, node_fs_1.existsSync)(workflowPath) && !args.includes("--force")) {
|
|
318
|
+
console.log(`${workflowPath} already exists — rerun with --force to overwrite.`);
|
|
319
|
+
process.exit(2);
|
|
320
|
+
}
|
|
321
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(workflowPath), { recursive: true });
|
|
322
|
+
(0, node_fs_1.writeFileSync)(workflowPath, (0, check_js_1.kageCheckWorkflowYaml)(), "utf8");
|
|
323
|
+
console.log(`Wrote ${workflowPath}`);
|
|
324
|
+
console.log("Every PR now gets a drift check: it comments and fails only when the diff breaks a documented claim.");
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
let report;
|
|
328
|
+
try {
|
|
329
|
+
report = (0, check_js_1.driftCheck)(checkTarget, { base: takeArg(args, "--base") });
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
console.error(`kage check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
333
|
+
process.exit(2);
|
|
334
|
+
}
|
|
335
|
+
if (args.includes("--write-baseline")) {
|
|
336
|
+
const written = (0, check_js_1.writeCheckBaseline)(checkTarget, report);
|
|
337
|
+
console.log(`Baseline written: ${written} (${report.confirmed.length} finding(s) accepted — future runs gate only on new drift)`);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (args.includes("--json"))
|
|
341
|
+
console.log(JSON.stringify(report, null, 2));
|
|
342
|
+
else if (args.includes("--md"))
|
|
343
|
+
console.log((0, check_js_1.checkReportMarkdown)(report));
|
|
344
|
+
else
|
|
345
|
+
console.log((0, check_js_1.formatCheckReport)(report));
|
|
346
|
+
process.exit(report.totals.confirmed > 0 ? 1 : 0);
|
|
347
|
+
}
|
|
310
348
|
if (command === "scan") {
|
|
311
349
|
const scanTarget = (0, node_path_1.resolve)(projectArg(args));
|
|
312
350
|
if (scanTarget === (0, node_os_1.homedir)()) {
|
|
@@ -1577,13 +1615,18 @@ async function main() {
|
|
|
1577
1615
|
const packetId = takeArg(args, "--packet");
|
|
1578
1616
|
if (!packetId)
|
|
1579
1617
|
usage();
|
|
1580
|
-
const result = (0, kernel_js_1.reverifyMemory)(projectArg(args), packetId
|
|
1618
|
+
const result = (0, kernel_js_1.reverifyMemory)(projectArg(args), packetId, {
|
|
1619
|
+
evidence: takeArg(args, "--evidence"),
|
|
1620
|
+
verifiedBy: takeArg(args, "--verified-by"),
|
|
1621
|
+
});
|
|
1581
1622
|
if (args.includes("--json")) {
|
|
1582
1623
|
console.log(JSON.stringify(result, null, 2));
|
|
1583
1624
|
}
|
|
1584
1625
|
else if (result.ok) {
|
|
1585
1626
|
console.log(`Reverified ${result.packet_id}`);
|
|
1586
1627
|
console.log(` grounding refreshed for ${result.refreshed_paths.length} path(s)${result.was_stale ? " · stale flag cleared" : ""}`);
|
|
1628
|
+
if (result.changed_paths.length)
|
|
1629
|
+
console.log(` evidence recorded for changed path(s): ${result.changed_paths.join(", ")}`);
|
|
1587
1630
|
if (result.missing_paths.length)
|
|
1588
1631
|
console.log(` dropped missing path(s): ${result.missing_paths.join(", ")}`);
|
|
1589
1632
|
}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
|
8
8
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
9
9
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
10
10
|
const kernel_js_1 = require("./kernel.js");
|
|
11
|
+
const check_js_1 = require("./check.js");
|
|
11
12
|
const graph_registry_js_1 = require("./graph-registry.js");
|
|
12
13
|
const BASE_URL = "https://raw.githubusercontent.com/kage-core/kage-graph/master";
|
|
13
14
|
async function fetchText(url) {
|
|
@@ -91,6 +92,7 @@ const KAGE_WORKFLOW_TEXT = "Kage memory workflow (this tool performs no action;
|
|
|
91
92
|
// mode (KAGE_TOOLS=full) or via the CLI. Keeping the default small enough that
|
|
92
93
|
// the client always-loads it removes the per-call ToolSearch round-trip.
|
|
93
94
|
exports.CORE_TOOLS = new Set([
|
|
95
|
+
"kage_check",
|
|
94
96
|
"kage_context",
|
|
95
97
|
"kage_learn",
|
|
96
98
|
"kage_supersede",
|
|
@@ -536,6 +538,19 @@ function listTools() {
|
|
|
536
538
|
required: ["project_dir"],
|
|
537
539
|
},
|
|
538
540
|
},
|
|
541
|
+
{
|
|
542
|
+
name: "kage_check",
|
|
543
|
+
description: "Verify the claims in agent-context files (CLAUDE.md, AGENTS.md, .cursor/rules, README, docs) against the code: cited paths, npm scripts, make targets, CLI subcommands. Reports confirmed drift / verified true / unverifiable — every number is a reproducible check, never an estimate. Pass base to gate only drift introduced since that ref.",
|
|
544
|
+
annotations: { title: "Verify agent-context files against the code", readOnlyHint: true },
|
|
545
|
+
inputSchema: {
|
|
546
|
+
type: "object",
|
|
547
|
+
properties: {
|
|
548
|
+
project_dir: { type: "string", description: "Absolute path to the repository root." },
|
|
549
|
+
base: { type: "string", description: "Optional git ref: only report drift attributable to changes since this ref (diff-aware mode for PRs)." },
|
|
550
|
+
},
|
|
551
|
+
required: ["project_dir"],
|
|
552
|
+
},
|
|
553
|
+
},
|
|
539
554
|
{
|
|
540
555
|
name: "kage_memory_reconcile",
|
|
541
556
|
description: "Return agent-owned memory reconciliation work when source files linked to existing memory changed. Agents must update, supersede, or mark stale memory before final handoff.",
|
|
@@ -1097,10 +1112,12 @@ async function callTool(name, args) {
|
|
|
1097
1112
|
reconciliation.unresolved_count ? `\n## Memory Reconciliation\n${reconciliation.agent_instruction}` : "",
|
|
1098
1113
|
`\n_${validationText}_`,
|
|
1099
1114
|
].filter(Boolean).join("");
|
|
1100
|
-
//
|
|
1101
|
-
//
|
|
1115
|
+
// Receipt of counts only: served/withheld are observable events; token or
|
|
1116
|
+
// dollar "savings" were estimates with no counterfactual and do not ship.
|
|
1102
1117
|
const gains = (0, kernel_js_1.valueSummary)(projectDir).today;
|
|
1103
|
-
const gainsLine =
|
|
1118
|
+
const gainsLine = gains.stale_withheld > 0
|
|
1119
|
+
? `\n\n_${gains.stale_withheld} stale memor${gains.stale_withheld === 1 ? "y" : "ies"} withheld today (cited code changed; run \`kage doctor\` to review)._`
|
|
1120
|
+
: "";
|
|
1104
1121
|
// Backstop: per-field clamping + graph dedup keep this compact in practice, but never
|
|
1105
1122
|
// let a pathological repo overflow the MCP response again. ~24k chars ≈ 6k tokens.
|
|
1106
1123
|
const MAX_CONTEXT_CHARS = 24000;
|
|
@@ -1122,11 +1139,11 @@ async function callTool(name, args) {
|
|
|
1122
1139
|
if (docsSection)
|
|
1123
1140
|
result.context_block = `${result.context_block}\n\n${docsSection}`;
|
|
1124
1141
|
}
|
|
1125
|
-
//
|
|
1126
|
-
//
|
|
1142
|
+
// Counts only: stale-withheld is an observable event; estimated token
|
|
1143
|
+
// savings are not a measurement and do not ship.
|
|
1127
1144
|
const receipt = result.value_receipt;
|
|
1128
|
-
const gainsLine = receipt &&
|
|
1129
|
-
? `\n\
|
|
1145
|
+
const gainsLine = receipt && receipt.stale_withheld > 0
|
|
1146
|
+
? `\n\n_${receipt.stale_withheld} stale memor${receipt.stale_withheld === 1 ? "y" : "ies"} withheld by this recall (cited code changed)._`
|
|
1130
1147
|
: "";
|
|
1131
1148
|
return {
|
|
1132
1149
|
content: [{ type: "text", text: args?.json || args?.explain ? JSON.stringify(result, null, 2) : `${result.context_block}${gainsLine}` }],
|
|
@@ -1385,6 +1402,14 @@ async function callTool(name, args) {
|
|
|
1385
1402
|
isError: !result.ok,
|
|
1386
1403
|
};
|
|
1387
1404
|
}
|
|
1405
|
+
if (name === "kage_check") {
|
|
1406
|
+
const report = (0, check_js_1.driftCheck)(String(args?.project_dir ?? ""), {
|
|
1407
|
+
base: typeof args?.base === "string" ? args.base : undefined,
|
|
1408
|
+
});
|
|
1409
|
+
return {
|
|
1410
|
+
content: [{ type: "text", text: (0, check_js_1.formatCheckReport)(report) }],
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1388
1413
|
if (name === "kage_quality") {
|
|
1389
1414
|
const result = (0, kernel_js_1.qualityReport)(String(args?.project_dir ?? ""));
|
|
1390
1415
|
return {
|