@kage-core/kage-graph-mcp 1.1.13 → 1.1.14

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 CHANGED
@@ -9,6 +9,17 @@ This package exposes two surfaces:
9
9
 
10
10
  ## Latest Release
11
11
 
12
+ `1.1.14` publishes the memory/code graph trust and retrieval pass:
13
+
14
+ - recall now uses vectorless BM25 lexical ranking with graph, path/type/tag,
15
+ intent, freshness, quality, and feedback boosts.
16
+ - `kage audit`, `kage inbox`, `kage code-index`, and `kage graph-registry`
17
+ are documented as first-class CLI and MCP surfaces.
18
+ - the viewer coalesces memory graph code entities with code graph nodes and
19
+ highlights memory-code links.
20
+ - README and the website now report the current 79-test proof state and BM25
21
+ retrieval behavior.
22
+
12
23
  `1.1.13` switches future Kage releases to GPL-3.0-only:
13
24
 
14
25
  - package metadata now advertises `GPL-3.0-only`.
@@ -21,8 +32,8 @@ This package exposes two surfaces:
21
32
  - npm README now includes this explicit release note.
22
33
  - Root README leads with the animated Kage demo GIF.
23
34
  - README links clearly to the website and live viewer.
24
- - Hosted viewer publishes Kage repo graph, code graph, and metrics from GitHub
25
- Pages while local repos still use `kage viewer --project .`.
35
+ - Hosted viewer publishes Kage repo graph, code graph, metrics, and inbox from
36
+ GitHub Pages while local repos still use `kage viewer --project .`.
26
37
 
27
38
  ## Build
28
39
 
@@ -46,14 +57,18 @@ kage doctor --project /path/to/repo
46
57
  kage index --project /path/to/repo
47
58
  kage refresh --project /path/to/repo
48
59
  kage branch --project /path/to/repo
60
+ kage code-index --project /path/to/repo
49
61
  kage code-graph --project /path/to/repo
50
62
  kage code-graph "createApp routes tests" --project /path/to/repo
51
63
  kage graph --project /path/to/repo
52
64
  kage graph --project /path/to/repo --mermaid
53
65
  kage graph "test command" --project /path/to/repo
66
+ kage graph-registry --project /path/to/repo
54
67
  kage recall "how do I run tests" --project /path/to/repo
55
68
  kage recall "how do I run tests" --project /path/to/repo --explain --json
56
69
  kage quality --project /path/to/repo
70
+ kage audit --project /path/to/repo
71
+ kage inbox --project /path/to/repo
57
72
  kage benchmark --project /path/to/repo
58
73
  kage benchmark --project /path/to/repo --compare --task "how do I run tests"
59
74
  kage viewer --project /path/to/repo
@@ -131,6 +146,12 @@ generic extraction in metrics and file parser coverage. This keeps installation
131
146
  light while allowing teams to plug in the strongest indexer available for their
132
147
  language stack.
133
148
 
149
+ `kage code-index --project <repo>` writes `.agent_memory/code_index/lsp-symbols.json`
150
+ in an LSP document-symbol-compatible shape using Kage's local parser. The CI,
151
+ PR, and sync workflows run it before refresh so the code graph has a committed
152
+ precise-index slot while teams can still replace or augment it with SCIP/LSIF
153
+ artifacts from their preferred toolchain.
154
+
134
155
  The memory graph follows the same product direction as temporal context graph
135
156
  systems such as Graphiti: immutable ingestion episodes, derived entities and
136
157
  facts, evidence/provenance on every edge, confidence, branch/commit context, and
@@ -143,12 +164,36 @@ and parser coverage, code graph counts, evidence coverage, approved vs pending
143
164
  memory, validation status, estimated tokens saved per recall, duplicate
144
165
  candidates, average memory quality, and a readiness score.
145
166
 
167
+ Use `kage audit --project <repo>` or the `kage_audit` MCP tool before relying
168
+ on repo memory for agent work. Audit reports validation, pending memory inbox
169
+ size, structured context coverage, stale/duplicate risk, memory-to-code graph
170
+ links, precise code index coverage, and concrete recommendations such as
171
+ extending SCIP/LSIF/LSP coverage or adding structured
172
+ `why`/`verification`/`risk_if_forgotten` fields to high-value packets.
173
+
174
+ Use `kage inbox --project <repo>` or the `kage_inbox` MCP tool for the
175
+ actionable review queue. It consolidates pending packets, stale packets,
176
+ duplicates, missing structured context, validation warnings/errors, and concrete
177
+ actions into one report that the viewer also loads.
178
+
146
179
  Use `kage benchmark --compare --task "<task>" --project <repo>` or
147
180
  `kage_benchmark_compare` to compare the same task on the same repo with and
148
181
  without Kage. It estimates manual full-file rediscovery tokens/steps, compares
149
182
  them to compact Kage recall plus code graph context, and returns evidence plus
150
183
  caveats for honest marketing proof.
151
184
 
185
+ Plain `kage benchmark --project <repo>` now includes explicit gates and an
186
+ overall score for recall hit rate, evidence coverage, useful memory ratio, and
187
+ code-flow coverage, so benchmark output has pass/fail criteria instead of loose
188
+ claims.
189
+
190
+ Use `kage graph-registry --project <repo>` or `kage_graph_registry` to write
191
+ `.agent_memory/graph_registry/manifest.json`. The manifest is signed with the
192
+ same canonical JSON scheme as registry bundles and records memory/code graph
193
+ artifact hashes, generated index/report paths, source packet IDs and packet
194
+ hashes, git state, audit trust, inbox counts, and metrics readiness. CI, PR, and
195
+ sync workflows build it after refresh.
196
+
152
197
  Use `kage refresh --project <repo>` or the `kage_refresh` MCP tool after
153
198
  meaningful file changes. Refresh rebuilds indexes, code graph, memory graph,
154
199
  metrics, and stale-memory metadata. Memory is marked stale when status or
@@ -172,13 +217,15 @@ review.
172
217
  clients. It accepts session, prompt, tool, file-change, command, test, and
173
218
  session-end events; deduplicates them; scans for secrets and PII; and stores raw
174
219
  observations locally only. `kage distill` turns useful observations into
175
- repo-local packets with observation session source refs. It never publishes
176
- memory.
220
+ repo-local packets with observation session source refs. Distillation is not
221
+ limited to action-changing instructions: durable rationale, bug causes, issue
222
+ state, decisions, and code explanations are valid memory when source-backed. It
223
+ never publishes memory.
177
224
 
178
225
  `kage recall --explain --json` exposes the hybrid scoring explanation used for
179
- ranking: text, graph, path/type/tag, freshness, quality, feedback, and a vector
180
- placeholder for future local or external embedding providers. Current fallback
181
- is deterministic text plus graph retrieval.
226
+ ranking: BM25 lexical score, graph, path/type/tag, intent, freshness, quality,
227
+ feedback, and a vector placeholder for future local or external embedding providers.
228
+ Current fallback is vectorless BM25 plus graph retrieval.
182
229
 
183
230
  `kage_context` is the primary MCP entrypoint for agents. It validates repo
184
231
  memory, recalls relevant packets, and returns code/knowledge graph context in
@@ -192,6 +239,7 @@ one call. Agents should use it at task start instead of loading separate
192
239
  - `GET /kage/status`
193
240
  - `GET /kage/metrics`
194
241
  - `GET /kage/quality`
242
+ - `GET /kage/inbox`
195
243
  - `GET /kage/benchmark`
196
244
  - `POST /kage/recall`
197
245
  - `POST /kage/observe`
@@ -207,13 +255,13 @@ and refreshes generated graph/index artifacts after a short debounce.
207
255
  Run `kage viewer --project <repo>` to start the local terminal console. It
208
256
  serves the viewer and the selected repo's `.agent_memory/` files from the same
209
257
  localhost server, then prints a URL that auto-loads memory graph, code graph,
210
- metrics, review artifact, and pending packets when present. Manual JSON selection remains as
211
- a fallback, not the main workflow.
258
+ metrics, memory inbox, review artifact, and pending packets when present.
259
+ Manual JSON selection remains as a fallback, not the main workflow.
212
260
 
213
261
  The viewer renders nodes and relations in SVG, supports memory/code/combined
214
262
  modes, filters by type and relation, displays metrics, shows packets and pending
215
- quarantine items when present, and marks risks such as low-confidence or
216
- missing-evidence edges.
263
+ quarantine items when present, surfaces the memory inbox, and marks risks such
264
+ as low-confidence or missing-evidence edges.
217
265
 
218
266
  For demos or local docs, the viewer also accepts URL params:
219
267
 
@@ -232,8 +280,12 @@ Local repo tools:
232
280
 
233
281
  - `kage_context`
234
282
  - `kage_recall`
283
+ - `kage_graph_registry`
235
284
  - `kage_code_graph`
285
+ - `kage_code_index`
236
286
  - `kage_metrics`
287
+ - `kage_audit`
288
+ - `kage_inbox`
237
289
  - `kage_refresh`
238
290
  - `kage_pr_summarize`
239
291
  - `kage_pr_check`
package/dist/cli.js CHANGED
@@ -6,6 +6,7 @@ const promises_1 = require("node:readline/promises");
6
6
  const node_process_1 = require("node:process");
7
7
  const daemon_js_1 = require("./daemon.js");
8
8
  const kernel_js_1 = require("./kernel.js");
9
+ const graph_registry_js_1 = require("./graph-registry.js");
9
10
  function usage() {
10
11
  console.log(`Kage repo memory and code graph
11
12
 
@@ -30,14 +31,18 @@ Usage:
30
31
  kage upgrade [--dry-run]
31
32
  kage branch --project <dir> [--json]
32
33
  kage metrics --project <dir> [--json]
34
+ kage audit --project <dir> [--json]
35
+ kage inbox --project <dir> [--json]
33
36
  kage quality --project <dir> [--json]
34
37
  kage benchmark --project <dir> [--json]
35
38
  kage benchmark --project <dir> --compare --task <task> [--json]
36
39
  kage code-graph --project <dir> [--json]
37
40
  kage code-graph "<query>" --project <dir> [--json]
41
+ kage code-index --project <dir> [--json]
38
42
  kage graph --project <dir> [--json]
39
43
  kage graph --project <dir> --mermaid
40
44
  kage graph "<query>" --project <dir> [--json]
45
+ kage graph-registry --project <dir> [--json]
41
46
  kage recall "<query>" --project <dir> [--json] [--explain]
42
47
  kage observe --project <dir> --event <json>
43
48
  kage distill --project <dir> --session <id>
@@ -452,6 +457,25 @@ async function main() {
452
457
  console.log(`- ${edge.fact}`);
453
458
  return;
454
459
  }
460
+ if (command === "graph-registry") {
461
+ const result = (0, graph_registry_js_1.buildGraphRegistryManifest)(projectArg(args));
462
+ if (args.includes("--json")) {
463
+ console.log(JSON.stringify(result, null, 2));
464
+ return;
465
+ }
466
+ console.log(`Kage Graph Registry: ${result.project_dir}`);
467
+ console.log(`Manifest: ${result.path}`);
468
+ console.log(`Artifacts: ${result.artifacts.length}`);
469
+ console.log(`Packets: ${result.manifest.payload.sources.packet_count}`);
470
+ console.log(`Signature: ${result.manifest.signature.payload_sha256}`);
471
+ if (result.errors.length) {
472
+ console.log("\nErrors:");
473
+ for (const error of result.errors)
474
+ console.log(` - ${error}`);
475
+ process.exitCode = 2;
476
+ }
477
+ return;
478
+ }
455
479
  if (command === "code-graph") {
456
480
  const query = firstPositional(args);
457
481
  if (query) {
@@ -481,6 +505,25 @@ async function main() {
481
505
  console.log(`- ${symbol.kind} ${symbol.name} (${symbol.path}:${symbol.line})`);
482
506
  return;
483
507
  }
508
+ if (command === "code-index") {
509
+ const result = (0, kernel_js_1.writeLspSymbolIndex)(projectArg(args));
510
+ if (args.includes("--json")) {
511
+ console.log(JSON.stringify(result, null, 2));
512
+ return;
513
+ }
514
+ console.log(`Kage Code Index: ${result.project_dir}`);
515
+ console.log(`Parser: ${result.parser}`);
516
+ console.log(`Path: ${result.path}`);
517
+ console.log(`Documents: ${result.documents}`);
518
+ console.log(`Symbols: ${result.symbols}`);
519
+ if (result.errors.length) {
520
+ console.log("\nErrors:");
521
+ for (const error of result.errors)
522
+ console.log(` - ${error}`);
523
+ process.exitCode = 2;
524
+ }
525
+ return;
526
+ }
484
527
  if (command === "branch") {
485
528
  const result = (0, kernel_js_1.buildBranchOverlay)(projectArg(args));
486
529
  if (args.includes("--json"))
@@ -544,6 +587,59 @@ async function main() {
544
587
  }
545
588
  return;
546
589
  }
590
+ if (command === "audit") {
591
+ const result = (0, kernel_js_1.auditProject)(projectArg(args));
592
+ if (args.includes("--json")) {
593
+ console.log(JSON.stringify(result, null, 2));
594
+ return;
595
+ }
596
+ console.log(`Kage Audit: ${result.project_dir}`);
597
+ console.log(`Trust score: ${result.trust_score}/100`);
598
+ console.log(`Validation: ${result.checks.validation.ok ? "passed" : "failed"}`);
599
+ console.log(`Memory inbox: ${result.checks.memory_inbox.approved_packets} approved, ${result.checks.memory_inbox.pending_packets} pending, ${result.checks.memory_inbox.stale_packets} stale`);
600
+ console.log(`Structured memory: ${result.checks.structured_memory.structured_packets}/${result.checks.structured_memory.total_packets} (${result.checks.structured_memory.coverage_percent}%)`);
601
+ console.log(`Code graph precision: ${result.checks.code_graph.precise_files}/${result.checks.code_graph.files} precise (${result.checks.code_graph.precise_coverage_percent}%), ${result.checks.code_graph.ast_files} AST, ${result.checks.code_graph.fallback_files} fallback`);
602
+ console.log(`Memory-code graph edges: ${result.checks.graph_links.memory_code_edges}`);
603
+ if (result.recommendations.length) {
604
+ console.log("\nRecommendations:");
605
+ for (const recommendation of result.recommendations)
606
+ console.log(` - ${recommendation}`);
607
+ }
608
+ if (!result.ok)
609
+ process.exitCode = 2;
610
+ return;
611
+ }
612
+ if (command === "inbox") {
613
+ const result = (0, kernel_js_1.memoryInbox)(projectArg(args));
614
+ if (args.includes("--json")) {
615
+ console.log(JSON.stringify(result, null, 2));
616
+ return;
617
+ }
618
+ console.log(`Kage Memory Inbox: ${result.project_dir}`);
619
+ console.log(`Approved: ${result.counts.approved}`);
620
+ console.log(`Pending: ${result.counts.pending}`);
621
+ console.log(`Stale: ${result.counts.stale}`);
622
+ console.log(`Duplicates: ${result.counts.duplicates}`);
623
+ console.log(`Missing structured context: ${result.counts.missing_context}`);
624
+ console.log(`Validation: ${result.counts.validation_errors} errors, ${result.counts.validation_warnings} warnings`);
625
+ if (result.items.length) {
626
+ console.log("\nInbox items:");
627
+ for (const item of result.items.slice(0, 30)) {
628
+ console.log(` - [${item.severity}] ${item.kind}: ${item.title ?? item.summary}`);
629
+ console.log(` Action: ${item.action}`);
630
+ }
631
+ if (result.items.length > 30)
632
+ console.log(` ... ${result.items.length - 30} more item(s)`);
633
+ }
634
+ if (result.recommendations.length) {
635
+ console.log("\nRecommendations:");
636
+ for (const recommendation of result.recommendations)
637
+ console.log(` - ${recommendation}`);
638
+ }
639
+ if (!result.ok)
640
+ process.exitCode = 2;
641
+ return;
642
+ }
547
643
  if (command === "quality") {
548
644
  const result = (0, kernel_js_1.qualityReport)(projectArg(args));
549
645
  if (args.includes("--json")) {
@@ -607,6 +703,12 @@ async function main() {
607
703
  return;
608
704
  }
609
705
  console.log(`Kage Benchmark: ${result.project_dir}`);
706
+ console.log(`OK: ${result.ok ? "yes" : "no"}`);
707
+ console.log(`Overall score: ${result.overall_score}/100`);
708
+ console.log("Gates:");
709
+ for (const gate of result.gates)
710
+ console.log(` - ${gate.name}: ${gate.actual}${gate.unit === "percent" ? "%" : ""} / target ${gate.target}${gate.unit === "percent" ? "%" : ""} (${gate.pass ? "pass" : "fail"})`);
711
+ console.log("Pain metrics:");
610
712
  for (const [name, value] of Object.entries(result.pain_metrics))
611
713
  console.log(`${name}: ${value}`);
612
714
  return;
package/dist/daemon.js CHANGED
@@ -98,6 +98,7 @@ function daemonDoctor(projectDir) {
98
98
  `POST http://${DEFAULT_HOST}:${restPort}/kage/distill`,
99
99
  `GET http://${DEFAULT_HOST}:${restPort}/kage/metrics`,
100
100
  `GET http://${DEFAULT_HOST}:${restPort}/kage/quality`,
101
+ `GET http://${DEFAULT_HOST}:${restPort}/kage/inbox`,
101
102
  `GET http://${DEFAULT_HOST}:${restPort}/kage/benchmark`,
102
103
  ],
103
104
  warnings,
@@ -186,6 +187,10 @@ async function startDaemon(projectDir, options = {}) {
186
187
  json(res, 200, (0, kernel_js_1.qualityReport)(projectDir));
187
188
  return;
188
189
  }
190
+ if (req.method === "GET" && url.pathname === "/kage/inbox") {
191
+ json(res, 200, (0, kernel_js_1.memoryInbox)(projectDir));
192
+ return;
193
+ }
189
194
  if (req.method === "GET" && url.pathname === "/kage/benchmark") {
190
195
  json(res, 200, (0, kernel_js_1.benchmarkProject)(projectDir));
191
196
  return;
@@ -231,17 +236,20 @@ async function startViewer(projectDir, options = {}) {
231
236
  const graphPath = (0, node_path_1.join)(projectRoot, ".agent_memory", "graph", "graph.json");
232
237
  const codePath = (0, node_path_1.join)(projectRoot, ".agent_memory", "code_graph", "graph.json");
233
238
  const metricsPath = (0, node_path_1.join)(projectRoot, ".agent_memory", "metrics.json");
239
+ const inboxPath = (0, node_path_1.join)(projectRoot, ".agent_memory", "inbox.json");
234
240
  const reviewPath = (0, node_path_1.join)(projectRoot, ".agent_memory", "review", "memory-review.md");
235
241
  const pendingDir = (0, node_path_1.join)(projectRoot, ".agent_memory", "pending");
236
- // Pre-generate metrics.json so the viewer can load it
242
+ // Pre-generate lightweight JSON reports so the viewer can load them directly.
237
243
  try {
238
244
  const metrics = (0, kernel_js_1.kageMetrics)(projectDir);
239
245
  (0, node_fs_1.writeFileSync)(metricsPath, JSON.stringify(metrics, null, 2));
246
+ const inbox = (0, kernel_js_1.memoryInbox)(projectDir);
247
+ (0, node_fs_1.writeFileSync)(inboxPath, JSON.stringify(inbox, null, 2));
240
248
  }
241
249
  catch {
242
- // non-fatal: viewer will show 404 for metrics if generation fails
250
+ // non-fatal: viewer will show 404 for reports if generation fails
243
251
  }
244
- const url = `http://${host}:${port}/viewer/index.html?graph=${encodeURIComponent(graphPath)}&code=${encodeURIComponent(codePath)}&metrics=${encodeURIComponent(metricsPath)}&review=${encodeURIComponent(reviewPath)}&pending=${encodeURIComponent(pendingDir)}`;
252
+ const url = `http://${host}:${port}/viewer/index.html?graph=${encodeURIComponent(graphPath)}&code=${encodeURIComponent(codePath)}&metrics=${encodeURIComponent(metricsPath)}&inbox=${encodeURIComponent(inboxPath)}&review=${encodeURIComponent(reviewPath)}&pending=${encodeURIComponent(pendingDir)}`;
245
253
  const server = (0, node_http_1.createServer)((req, res) => {
246
254
  const requestUrl = new URL(req.url ?? "/", `http://${host}:${port}`);
247
255
  let filePath = null;
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildGraphRegistryManifest = buildGraphRegistryManifest;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const node_child_process_1 = require("node:child_process");
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
8
+ const index_js_1 = require("./registry/index.js");
9
+ const kernel_js_1 = require("./kernel.js");
10
+ function nowIso() {
11
+ return new Date().toISOString();
12
+ }
13
+ function ensureDir(path) {
14
+ if (!(0, node_fs_1.existsSync)(path)) {
15
+ (0, node_fs_1.mkdirSync)(path, { recursive: true });
16
+ }
17
+ }
18
+ function writeJson(path, value) {
19
+ const dir = (0, node_path_1.dirname)(path);
20
+ if (!(0, node_fs_1.existsSync)(dir)) {
21
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
22
+ }
23
+ (0, node_fs_1.writeFileSync)(path, `${JSON.stringify(value, null, 2)}\n`, "utf8");
24
+ }
25
+ function readGit(projectDir, args) {
26
+ try {
27
+ return (0, node_child_process_1.execFileSync)("git", args, { cwd: projectDir, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim() || null;
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ function gitBranch(projectDir) {
34
+ return readGit(projectDir, ["rev-parse", "--abbrev-ref", "HEAD"]);
35
+ }
36
+ function gitHead(projectDir) {
37
+ return readGit(projectDir, ["rev-parse", "HEAD"]);
38
+ }
39
+ function gitMergeBase(projectDir) {
40
+ return readGit(projectDir, ["merge-base", "HEAD", "origin/HEAD"]) ?? gitHead(projectDir);
41
+ }
42
+ function repoKey(projectDir) {
43
+ return (readGit(projectDir, ["config", "--get", "remote.origin.url"]) ?? projectDir)
44
+ .toLowerCase()
45
+ .replace(/[^a-z0-9]+/g, "-")
46
+ .replace(/^-+|-+$/g, "")
47
+ .slice(0, 120) || "local-repo";
48
+ }
49
+ function canonicalPacketText(packet) {
50
+ return JSON.stringify({
51
+ title: packet.title,
52
+ summary: packet.summary,
53
+ body: packet.body,
54
+ type: packet.type,
55
+ tags: packet.tags,
56
+ paths: packet.paths,
57
+ });
58
+ }
59
+ function graphRegistryArtifact(projectDir, path, name, kind) {
60
+ const absolute = (0, node_path_1.join)(projectDir, path);
61
+ if (!(0, node_fs_1.existsSync)(absolute))
62
+ return null;
63
+ const bytes = (0, node_fs_1.readFileSync)(absolute);
64
+ let schemaVersion = null;
65
+ try {
66
+ const parsed = JSON.parse(bytes.toString("utf8"));
67
+ schemaVersion = typeof parsed.schema_version === "number" ? parsed.schema_version : null;
68
+ }
69
+ catch {
70
+ schemaVersion = null;
71
+ }
72
+ return {
73
+ name,
74
+ kind,
75
+ path,
76
+ schema_version: schemaVersion,
77
+ sha256: (0, node_crypto_1.createHash)("sha256").update(bytes).digest("hex"),
78
+ bytes: (0, node_fs_1.statSync)(absolute).size,
79
+ };
80
+ }
81
+ function buildGraphRegistryManifest(projectDir) {
82
+ (0, kernel_js_1.ensureMemoryDirs)(projectDir);
83
+ ensureDir((0, kernel_js_1.graphRegistryDir)(projectDir));
84
+ (0, kernel_js_1.buildIndexes)(projectDir);
85
+ (0, kernel_js_1.buildCodeGraph)(projectDir);
86
+ (0, kernel_js_1.buildKnowledgeGraph)(projectDir);
87
+ const metrics = (0, kernel_js_1.kageMetrics)(projectDir);
88
+ const audit = (0, kernel_js_1.auditProject)(projectDir);
89
+ const inbox = (0, kernel_js_1.memoryInbox)(projectDir);
90
+ const metricsPath = ".agent_memory/metrics.json";
91
+ const auditPath = ".agent_memory/audit.json";
92
+ const inboxPath = ".agent_memory/inbox.json";
93
+ writeJson((0, node_path_1.join)(projectDir, metricsPath), metrics);
94
+ writeJson((0, node_path_1.join)(projectDir, auditPath), audit);
95
+ writeJson((0, node_path_1.join)(projectDir, inboxPath), inbox);
96
+ const artifacts = [
97
+ graphRegistryArtifact(projectDir, ".agent_memory/graph/graph.json", "memory graph", "memory_graph"),
98
+ graphRegistryArtifact(projectDir, ".agent_memory/code_graph/graph.json", "code graph", "code_graph"),
99
+ graphRegistryArtifact(projectDir, ".agent_memory/indexes/catalog.json", "packet catalog", "indexes"),
100
+ graphRegistryArtifact(projectDir, ".agent_memory/indexes/graph.json", "memory graph index", "indexes"),
101
+ graphRegistryArtifact(projectDir, ".agent_memory/indexes/code-graph.json", "code graph index", "indexes"),
102
+ graphRegistryArtifact(projectDir, metricsPath, "metrics report", "metrics"),
103
+ graphRegistryArtifact(projectDir, auditPath, "audit report", "audit"),
104
+ graphRegistryArtifact(projectDir, inboxPath, "memory inbox report", "inbox"),
105
+ ].filter((artifact) => Boolean(artifact));
106
+ const packets = (0, kernel_js_1.loadApprovedPackets)(projectDir).sort((a, b) => a.id.localeCompare(b.id));
107
+ const payload = {
108
+ schema_version: 1,
109
+ repo_key: repoKey(projectDir),
110
+ project_dir: projectDir,
111
+ generated_at: nowIso(),
112
+ repo_state: {
113
+ branch: gitBranch(projectDir),
114
+ head: gitHead(projectDir),
115
+ merge_base: gitMergeBase(projectDir),
116
+ },
117
+ artifacts,
118
+ sources: {
119
+ packet_schema_version: kernel_js_1.PACKET_SCHEMA_VERSION,
120
+ packet_count: packets.length,
121
+ packets: packets.map((packet) => ({
122
+ id: packet.id,
123
+ title: packet.title,
124
+ type: packet.type,
125
+ status: packet.status,
126
+ updated_at: packet.updated_at,
127
+ content_sha256: (0, node_crypto_1.createHash)("sha256").update(canonicalPacketText(packet)).digest("hex"),
128
+ })),
129
+ },
130
+ reports: {
131
+ metrics: {
132
+ path: metricsPath,
133
+ readiness_score: metrics.harness.readiness_score,
134
+ evidence_coverage_percent: metrics.memory_graph.evidence_coverage_percent,
135
+ },
136
+ audit: {
137
+ path: auditPath,
138
+ ok: audit.ok,
139
+ trust_score: audit.trust_score,
140
+ structured_coverage_percent: audit.checks.structured_memory.coverage_percent,
141
+ precise_coverage_percent: audit.checks.code_graph.precise_coverage_percent,
142
+ },
143
+ inbox: {
144
+ path: inboxPath,
145
+ ok: inbox.ok,
146
+ pending: inbox.counts.pending,
147
+ stale: inbox.counts.stale,
148
+ duplicates: inbox.counts.duplicates,
149
+ missing_context: inbox.counts.missing_context,
150
+ },
151
+ },
152
+ };
153
+ const manifest = (0, index_js_1.createSignedManifest)({
154
+ kind: "graph_registry",
155
+ name: `${repoKey(projectDir)} graph registry`,
156
+ version: payload.repo_state.head?.slice(0, 12) ?? payload.generated_at.slice(0, 10),
157
+ keyId: `${repoKey(projectDir)}-local`,
158
+ payload,
159
+ });
160
+ const path = (0, node_path_1.join)((0, kernel_js_1.graphRegistryDir)(projectDir), "manifest.json");
161
+ writeJson(path, manifest);
162
+ const errors = [
163
+ ...(!artifacts.some((artifact) => artifact.kind === "memory_graph") ? ["memory graph artifact missing"] : []),
164
+ ...(!artifacts.some((artifact) => artifact.kind === "code_graph") ? ["code graph artifact missing"] : []),
165
+ ];
166
+ return { ok: errors.length === 0, project_dir: projectDir, path, manifest, artifacts, errors };
167
+ }
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
7
7
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
8
8
  const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
9
9
  const kernel_js_1 = require("./kernel.js");
10
+ const graph_registry_js_1 = require("./graph-registry.js");
10
11
  const BASE_URL = "https://raw.githubusercontent.com/kage-core/kage-graph/master";
11
12
  async function fetchText(url) {
12
13
  const res = await fetch(url);
@@ -145,6 +146,17 @@ function listTools() {
145
146
  required: ["project_dir", "query"],
146
147
  },
147
148
  },
149
+ {
150
+ name: "kage_graph_registry",
151
+ description: "Build a signed graph-registry manifest for generated memory graph, code graph, indexes, metrics, audit, inbox, source packet IDs, packet hashes, and repo git state.",
152
+ inputSchema: {
153
+ type: "object",
154
+ properties: {
155
+ project_dir: { type: "string" },
156
+ },
157
+ required: ["project_dir"],
158
+ },
159
+ },
148
160
  {
149
161
  name: "kage_code_graph",
150
162
  description: "Query the source-derived codebase graph: files, symbols, imports, calls, routes, tests, package scripts. This is generated from code, not learned memory.",
@@ -159,6 +171,17 @@ function listTools() {
159
171
  required: ["project_dir"],
160
172
  },
161
173
  },
174
+ {
175
+ name: "kage_code_index",
176
+ description: "Write .agent_memory/code_index/lsp-symbols.json, an LSP-compatible symbol artifact consumed by the code graph for higher parser coverage.",
177
+ inputSchema: {
178
+ type: "object",
179
+ properties: {
180
+ project_dir: { type: "string" },
181
+ },
182
+ required: ["project_dir"],
183
+ },
184
+ },
162
185
  {
163
186
  name: "kage_metrics",
164
187
  description: "Return concise Kage adoption and quality metrics: code graph counts, language/parser coverage, memory graph evidence coverage, pending/approved packets, validation state, and readiness score.",
@@ -170,6 +193,28 @@ function listTools() {
170
193
  required: ["project_dir"],
171
194
  },
172
195
  },
196
+ {
197
+ name: "kage_audit",
198
+ description: "Audit whether repo memory and code intelligence are trustworthy: validation, memory inbox, structured context coverage, code graph precision, graph links, and concrete recommendations.",
199
+ inputSchema: {
200
+ type: "object",
201
+ properties: {
202
+ project_dir: { type: "string" },
203
+ },
204
+ required: ["project_dir"],
205
+ },
206
+ },
207
+ {
208
+ name: "kage_inbox",
209
+ description: "Return an actionable memory review inbox: pending packets, stale packets, duplicates, missing structured context, validation issues, and recommended actions.",
210
+ inputSchema: {
211
+ type: "object",
212
+ properties: {
213
+ project_dir: { type: "string" },
214
+ },
215
+ required: ["project_dir"],
216
+ },
217
+ },
173
218
  {
174
219
  name: "kage_refresh",
175
220
  description: "Rebuild repo indexes, code graph, memory graph, metrics, and stale-memory metadata. Agents should run this after meaningful file changes and before PR checks.",
@@ -658,6 +703,13 @@ async function callTool(name, args) {
658
703
  content: [{ type: "text", text: result.context_block }],
659
704
  };
660
705
  }
706
+ if (name === "kage_graph_registry") {
707
+ const result = (0, graph_registry_js_1.buildGraphRegistryManifest)(String(args?.project_dir ?? ""));
708
+ return {
709
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
710
+ isError: !result.ok,
711
+ };
712
+ }
661
713
  if (name === "kage_code_graph") {
662
714
  const projectDir = String(args?.project_dir ?? "");
663
715
  const query = typeof args?.query === "string" ? args.query : "";
@@ -672,12 +724,33 @@ async function callTool(name, args) {
672
724
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
673
725
  };
674
726
  }
727
+ if (name === "kage_code_index") {
728
+ const result = (0, kernel_js_1.writeLspSymbolIndex)(String(args?.project_dir ?? ""));
729
+ return {
730
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
731
+ isError: !result.ok,
732
+ };
733
+ }
675
734
  if (name === "kage_metrics") {
676
735
  const result = (0, kernel_js_1.kageMetrics)(String(args?.project_dir ?? ""));
677
736
  return {
678
737
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
679
738
  };
680
739
  }
740
+ if (name === "kage_audit") {
741
+ const result = (0, kernel_js_1.auditProject)(String(args?.project_dir ?? ""));
742
+ return {
743
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
744
+ isError: !result.ok,
745
+ };
746
+ }
747
+ if (name === "kage_inbox") {
748
+ const result = (0, kernel_js_1.memoryInbox)(String(args?.project_dir ?? ""));
749
+ return {
750
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
751
+ isError: !result.ok,
752
+ };
753
+ }
681
754
  if (name === "kage_refresh") {
682
755
  const result = (0, kernel_js_1.refreshProject)(String(args?.project_dir ?? ""));
683
756
  return {