@kage-core/kage-graph-mcp 1.1.12 → 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,13 +9,31 @@ This package exposes two surfaces:
9
9
 
10
10
  ## Latest Release
11
11
 
12
- `1.1.12` publishes the launch-ready docs pass:
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
+
23
+ `1.1.13` switches future Kage releases to GPL-3.0-only:
24
+
25
+ - package metadata now advertises `GPL-3.0-only`.
26
+ - the repo includes the official GPLv3 `LICENSE` text.
27
+ - README clarifies that pre-switch releases were MIT, while future releases are
28
+ GPL-3.0-only unless a separate written commercial license says otherwise.
29
+
30
+ `1.1.12` published the launch-ready docs pass:
13
31
 
14
32
  - npm README now includes this explicit release note.
15
33
  - Root README leads with the animated Kage demo GIF.
16
34
  - README links clearly to the website and live viewer.
17
- - Hosted viewer publishes Kage repo graph, code graph, and metrics from GitHub
18
- 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 .`.
19
37
 
20
38
  ## Build
21
39
 
@@ -39,14 +57,18 @@ kage doctor --project /path/to/repo
39
57
  kage index --project /path/to/repo
40
58
  kage refresh --project /path/to/repo
41
59
  kage branch --project /path/to/repo
60
+ kage code-index --project /path/to/repo
42
61
  kage code-graph --project /path/to/repo
43
62
  kage code-graph "createApp routes tests" --project /path/to/repo
44
63
  kage graph --project /path/to/repo
45
64
  kage graph --project /path/to/repo --mermaid
46
65
  kage graph "test command" --project /path/to/repo
66
+ kage graph-registry --project /path/to/repo
47
67
  kage recall "how do I run tests" --project /path/to/repo
48
68
  kage recall "how do I run tests" --project /path/to/repo --explain --json
49
69
  kage quality --project /path/to/repo
70
+ kage audit --project /path/to/repo
71
+ kage inbox --project /path/to/repo
50
72
  kage benchmark --project /path/to/repo
51
73
  kage benchmark --project /path/to/repo --compare --task "how do I run tests"
52
74
  kage viewer --project /path/to/repo
@@ -124,6 +146,12 @@ generic extraction in metrics and file parser coverage. This keeps installation
124
146
  light while allowing teams to plug in the strongest indexer available for their
125
147
  language stack.
126
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
+
127
155
  The memory graph follows the same product direction as temporal context graph
128
156
  systems such as Graphiti: immutable ingestion episodes, derived entities and
129
157
  facts, evidence/provenance on every edge, confidence, branch/commit context, and
@@ -136,12 +164,36 @@ and parser coverage, code graph counts, evidence coverage, approved vs pending
136
164
  memory, validation status, estimated tokens saved per recall, duplicate
137
165
  candidates, average memory quality, and a readiness score.
138
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
+
139
179
  Use `kage benchmark --compare --task "<task>" --project <repo>` or
140
180
  `kage_benchmark_compare` to compare the same task on the same repo with and
141
181
  without Kage. It estimates manual full-file rediscovery tokens/steps, compares
142
182
  them to compact Kage recall plus code graph context, and returns evidence plus
143
183
  caveats for honest marketing proof.
144
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
+
145
197
  Use `kage refresh --project <repo>` or the `kage_refresh` MCP tool after
146
198
  meaningful file changes. Refresh rebuilds indexes, code graph, memory graph,
147
199
  metrics, and stale-memory metadata. Memory is marked stale when status or
@@ -165,13 +217,15 @@ review.
165
217
  clients. It accepts session, prompt, tool, file-change, command, test, and
166
218
  session-end events; deduplicates them; scans for secrets and PII; and stores raw
167
219
  observations locally only. `kage distill` turns useful observations into
168
- repo-local packets with observation session source refs. It never publishes
169
- 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.
170
224
 
171
225
  `kage recall --explain --json` exposes the hybrid scoring explanation used for
172
- ranking: text, graph, path/type/tag, freshness, quality, feedback, and a vector
173
- placeholder for future local or external embedding providers. Current fallback
174
- 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.
175
229
 
176
230
  `kage_context` is the primary MCP entrypoint for agents. It validates repo
177
231
  memory, recalls relevant packets, and returns code/knowledge graph context in
@@ -185,6 +239,7 @@ one call. Agents should use it at task start instead of loading separate
185
239
  - `GET /kage/status`
186
240
  - `GET /kage/metrics`
187
241
  - `GET /kage/quality`
242
+ - `GET /kage/inbox`
188
243
  - `GET /kage/benchmark`
189
244
  - `POST /kage/recall`
190
245
  - `POST /kage/observe`
@@ -200,13 +255,13 @@ and refreshes generated graph/index artifacts after a short debounce.
200
255
  Run `kage viewer --project <repo>` to start the local terminal console. It
201
256
  serves the viewer and the selected repo's `.agent_memory/` files from the same
202
257
  localhost server, then prints a URL that auto-loads memory graph, code graph,
203
- metrics, review artifact, and pending packets when present. Manual JSON selection remains as
204
- 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.
205
260
 
206
261
  The viewer renders nodes and relations in SVG, supports memory/code/combined
207
262
  modes, filters by type and relation, displays metrics, shows packets and pending
208
- quarantine items when present, and marks risks such as low-confidence or
209
- missing-evidence edges.
263
+ quarantine items when present, surfaces the memory inbox, and marks risks such
264
+ as low-confidence or missing-evidence edges.
210
265
 
211
266
  For demos or local docs, the viewer also accepts URL params:
212
267
 
@@ -225,8 +280,12 @@ Local repo tools:
225
280
 
226
281
  - `kage_context`
227
282
  - `kage_recall`
283
+ - `kage_graph_registry`
228
284
  - `kage_code_graph`
285
+ - `kage_code_index`
229
286
  - `kage_metrics`
287
+ - `kage_audit`
288
+ - `kage_inbox`
230
289
  - `kage_refresh`
231
290
  - `kage_pr_summarize`
232
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 {