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

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,31 @@ This package exposes two surfaces:
9
9
 
10
10
  ## Latest Release
11
11
 
12
+ `1.1.15` hardens the npm release path and memory-only review flow:
13
+
14
+ - `npm run release:npm:dry-run` runs the guarded release checks without
15
+ publishing.
16
+ - `npm run release:npm` builds the release helper, requires a clean worktree,
17
+ fetches the remote branch, verifies local `HEAD` contains `origin/<branch>`,
18
+ runs tests and `npm pack --dry-run`, pushes the branch before publishing,
19
+ publishes with `--access public`, verifies npm registry metadata, and performs
20
+ a smoke install.
21
+ - all git steps run with `GIT_EDITOR=true` so agent sessions cannot get stuck in
22
+ an interactive commit or rebase editor.
23
+ - `kage propose --from-diff` now includes repo memory packet-only changes from
24
+ `.agent_memory/packets/*.json` and `.agent_memory/pending/*.json`.
25
+
26
+ `1.1.14` publishes the memory/code graph trust and retrieval pass:
27
+
28
+ - recall now uses vectorless BM25 lexical ranking with graph, path/type/tag,
29
+ intent, freshness, quality, and feedback boosts.
30
+ - `kage audit`, `kage inbox`, `kage code-index`, and `kage graph-registry`
31
+ are documented as first-class CLI and MCP surfaces.
32
+ - the viewer coalesces memory graph code entities with code graph nodes and
33
+ highlights memory-code links.
34
+ - README and the website now report the current 79-test proof state and BM25
35
+ retrieval behavior.
36
+
12
37
  `1.1.13` switches future Kage releases to GPL-3.0-only:
13
38
 
14
39
  - package metadata now advertises `GPL-3.0-only`.
@@ -21,16 +46,28 @@ This package exposes two surfaces:
21
46
  - npm README now includes this explicit release note.
22
47
  - Root README leads with the animated Kage demo GIF.
23
48
  - 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 .`.
49
+ - Hosted viewer publishes Kage repo graph, code graph, metrics, and inbox from
50
+ GitHub Pages while local repos still use `kage viewer --project .`.
26
51
 
27
52
  ## Build
28
53
 
29
54
  ```bash
30
55
  npm install
31
56
  npm run build
57
+ npm run release:npm:dry-run
58
+ ```
59
+
60
+ Publishing from the repo should use the guarded release script after the release
61
+ commit is ready:
62
+
63
+ ```bash
64
+ npm run release:npm
32
65
  ```
33
66
 
67
+ The script fetches the current branch and blocks if the remote branch is not an
68
+ ancestor of local `HEAD`, which prevents publishing an npm version from a branch
69
+ that cannot be pushed cleanly.
70
+
34
71
  ## CLI
35
72
 
36
73
  ```bash
@@ -46,14 +83,18 @@ kage doctor --project /path/to/repo
46
83
  kage index --project /path/to/repo
47
84
  kage refresh --project /path/to/repo
48
85
  kage branch --project /path/to/repo
86
+ kage code-index --project /path/to/repo
49
87
  kage code-graph --project /path/to/repo
50
88
  kage code-graph "createApp routes tests" --project /path/to/repo
51
89
  kage graph --project /path/to/repo
52
90
  kage graph --project /path/to/repo --mermaid
53
91
  kage graph "test command" --project /path/to/repo
92
+ kage graph-registry --project /path/to/repo
54
93
  kage recall "how do I run tests" --project /path/to/repo
55
94
  kage recall "how do I run tests" --project /path/to/repo --explain --json
56
95
  kage quality --project /path/to/repo
96
+ kage audit --project /path/to/repo
97
+ kage inbox --project /path/to/repo
57
98
  kage benchmark --project /path/to/repo
58
99
  kage benchmark --project /path/to/repo --compare --task "how do I run tests"
59
100
  kage viewer --project /path/to/repo
@@ -131,6 +172,12 @@ generic extraction in metrics and file parser coverage. This keeps installation
131
172
  light while allowing teams to plug in the strongest indexer available for their
132
173
  language stack.
133
174
 
175
+ `kage code-index --project <repo>` writes `.agent_memory/code_index/lsp-symbols.json`
176
+ in an LSP document-symbol-compatible shape using Kage's local parser. The CI,
177
+ PR, and sync workflows run it before refresh so the code graph has a committed
178
+ precise-index slot while teams can still replace or augment it with SCIP/LSIF
179
+ artifacts from their preferred toolchain.
180
+
134
181
  The memory graph follows the same product direction as temporal context graph
135
182
  systems such as Graphiti: immutable ingestion episodes, derived entities and
136
183
  facts, evidence/provenance on every edge, confidence, branch/commit context, and
@@ -143,12 +190,36 @@ and parser coverage, code graph counts, evidence coverage, approved vs pending
143
190
  memory, validation status, estimated tokens saved per recall, duplicate
144
191
  candidates, average memory quality, and a readiness score.
145
192
 
193
+ Use `kage audit --project <repo>` or the `kage_audit` MCP tool before relying
194
+ on repo memory for agent work. Audit reports validation, pending memory inbox
195
+ size, structured context coverage, stale/duplicate risk, memory-to-code graph
196
+ links, precise code index coverage, and concrete recommendations such as
197
+ extending SCIP/LSIF/LSP coverage or adding structured
198
+ `why`/`verification`/`risk_if_forgotten` fields to high-value packets.
199
+
200
+ Use `kage inbox --project <repo>` or the `kage_inbox` MCP tool for the
201
+ actionable review queue. It consolidates pending packets, stale packets,
202
+ duplicates, missing structured context, validation warnings/errors, and concrete
203
+ actions into one report that the viewer also loads.
204
+
146
205
  Use `kage benchmark --compare --task "<task>" --project <repo>` or
147
206
  `kage_benchmark_compare` to compare the same task on the same repo with and
148
207
  without Kage. It estimates manual full-file rediscovery tokens/steps, compares
149
208
  them to compact Kage recall plus code graph context, and returns evidence plus
150
209
  caveats for honest marketing proof.
151
210
 
211
+ Plain `kage benchmark --project <repo>` now includes explicit gates and an
212
+ overall score for recall hit rate, evidence coverage, useful memory ratio, and
213
+ code-flow coverage, so benchmark output has pass/fail criteria instead of loose
214
+ claims.
215
+
216
+ Use `kage graph-registry --project <repo>` or `kage_graph_registry` to write
217
+ `.agent_memory/graph_registry/manifest.json`. The manifest is signed with the
218
+ same canonical JSON scheme as registry bundles and records memory/code graph
219
+ artifact hashes, generated index/report paths, source packet IDs and packet
220
+ hashes, git state, audit trust, inbox counts, and metrics readiness. CI, PR, and
221
+ sync workflows build it after refresh.
222
+
152
223
  Use `kage refresh --project <repo>` or the `kage_refresh` MCP tool after
153
224
  meaningful file changes. Refresh rebuilds indexes, code graph, memory graph,
154
225
  metrics, and stale-memory metadata. Memory is marked stale when status or
@@ -172,13 +243,15 @@ review.
172
243
  clients. It accepts session, prompt, tool, file-change, command, test, and
173
244
  session-end events; deduplicates them; scans for secrets and PII; and stores raw
174
245
  observations locally only. `kage distill` turns useful observations into
175
- repo-local packets with observation session source refs. It never publishes
176
- memory.
246
+ repo-local packets with observation session source refs. Distillation is not
247
+ limited to action-changing instructions: durable rationale, bug causes, issue
248
+ state, decisions, and code explanations are valid memory when source-backed. It
249
+ never publishes memory.
177
250
 
178
251
  `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.
252
+ ranking: BM25 lexical score, graph, path/type/tag, intent, freshness, quality,
253
+ feedback, and a vector placeholder for future local or external embedding providers.
254
+ Current fallback is vectorless BM25 plus graph retrieval.
182
255
 
183
256
  `kage_context` is the primary MCP entrypoint for agents. It validates repo
184
257
  memory, recalls relevant packets, and returns code/knowledge graph context in
@@ -192,6 +265,7 @@ one call. Agents should use it at task start instead of loading separate
192
265
  - `GET /kage/status`
193
266
  - `GET /kage/metrics`
194
267
  - `GET /kage/quality`
268
+ - `GET /kage/inbox`
195
269
  - `GET /kage/benchmark`
196
270
  - `POST /kage/recall`
197
271
  - `POST /kage/observe`
@@ -207,13 +281,13 @@ and refreshes generated graph/index artifacts after a short debounce.
207
281
  Run `kage viewer --project <repo>` to start the local terminal console. It
208
282
  serves the viewer and the selected repo's `.agent_memory/` files from the same
209
283
  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.
284
+ metrics, memory inbox, review artifact, and pending packets when present.
285
+ Manual JSON selection remains as a fallback, not the main workflow.
212
286
 
213
287
  The viewer renders nodes and relations in SVG, supports memory/code/combined
214
288
  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.
289
+ quarantine items when present, surfaces the memory inbox, and marks risks such
290
+ as low-confidence or missing-evidence edges.
217
291
 
218
292
  For demos or local docs, the viewer also accepts URL params:
219
293
 
@@ -232,8 +306,12 @@ Local repo tools:
232
306
 
233
307
  - `kage_context`
234
308
  - `kage_recall`
309
+ - `kage_graph_registry`
235
310
  - `kage_code_graph`
311
+ - `kage_code_index`
236
312
  - `kage_metrics`
313
+ - `kage_audit`
314
+ - `kage_inbox`
237
315
  - `kage_refresh`
238
316
  - `kage_pr_summarize`
239
317
  - `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 {