@kage-core/kage-graph-mcp 1.1.19 → 1.1.21

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,18 +9,26 @@ This package exposes two surfaces:
9
9
 
10
10
  ## Latest Release
11
11
 
12
- `1.1.18` publishes the end-to-end performance pass:
13
-
14
- - read-only commands reuse current graph artifacts instead of rebuilding them
15
- when inputs are fresh.
16
- - MCP sessions keep an in-process graph cache, so repeated agent calls do not
17
- keep reparsing the same graph JSON.
18
- - `kage refresh` reports lightweight freshness metrics and leaves deep
19
- benchmark/quality work to explicit `kage metrics` and `kage benchmark` calls.
20
- - recall builds graph lookup maps once per query instead of scanning all graph
21
- entities and edges for every memory packet.
22
- - `kage init` remains a packet-only bootstrap path; full graph generation stays
23
- with `kage refresh` and `kage index`.
12
+ `1.1.21` publishes the memory-code graph quality pass:
13
+
14
+ - precise memory-code links now require explicit, non-generic symbol/test
15
+ mentions instead of broad path-only matches.
16
+ - generated memory symbol/route/test entities no longer carry file path aliases
17
+ that can collapse stale graph nodes onto code file hubs.
18
+ - the viewer's `Memory <-> Code only` relation shows actual cross-graph links,
19
+ while path-level memory still appears through capped `affects_code_path`
20
+ bridge edges.
21
+
22
+ `1.1.20` published the large-repo indexing pass:
23
+
24
+ - repeated `kage refresh` calls reuse unchanged code graph artifacts by source
25
+ stat fingerprint, with `kage refresh --full` available for intentional clean
26
+ rebuilds.
27
+ - `kage code-index` prefers SCIP via `scip-typescript` plus the `scip` CLI when
28
+ those tools are installed, then falls back to Kage's built-in LSP-compatible
29
+ symbol index.
30
+ - read-only commands and MCP sessions reuse current graph artifacts instead of
31
+ rebuilding them when inputs are fresh.
24
32
 
25
33
  `1.1.17` publishes content-based graph freshness:
26
34
 
@@ -116,6 +124,7 @@ kage policy --project /path/to/repo
116
124
  kage doctor --project /path/to/repo
117
125
  kage index --project /path/to/repo
118
126
  kage refresh --project /path/to/repo
127
+ kage refresh --project /path/to/repo --full
119
128
  kage branch --project /path/to/repo
120
129
  kage code-index --project /path/to/repo
121
130
  kage code-graph --project /path/to/repo
@@ -170,26 +179,44 @@ The graph builder writes evidence-backed graph artifacts under
170
179
  and memory type entities.
171
180
  - `edges.json`: typed facts such as `contains_memory`, `affects_path`,
172
181
  `mentions_tag`, `uses_package`, `documents_command`, and `defines_command`.
173
- - `graph.json`: the assembled graph with branch, head, and merge-base metadata.
182
+ - `graph.json`: compact graph metadata plus references to the split graph files.
183
+
184
+ In the viewer, path-level memory such as `affects_path: src` is bridged to a
185
+ small representative set of matching code files at render time. This keeps the
186
+ stored graph compact while still making broad repo memories visibly connected
187
+ to the code graph.
174
188
 
175
189
  The code graph builder writes source-derived artifacts under
176
- `.agent_memory/code_graph/`:
177
-
178
- - `files.json`: source, test, config, manifest, and doc files, including
179
- language and parser metadata.
180
- - `symbols.json`: functions, classes, constants, and test cases.
181
- - `imports.json`: local and external import edges.
182
- - `calls.json`: best-effort call edges between discovered symbols.
183
- - `routes.json`: best-effort Node/Express/Next route facts.
184
- - `tests.json`: test-to-symbol/file coverage hints.
185
- - `packages.json`: package scripts and dependencies.
186
- - `graph.json`: the assembled code graph.
190
+ `.agent_memory/code_graph/`. `graph.json` is now a compact compatibility
191
+ artifact: it keeps repo state plus calls, routes, tests, and packages inline, and
192
+ references the canonical structural `files.json`, `symbols.json`, and
193
+ `imports.json` instead of duplicating them.
187
194
 
188
195
  The code graph is multi-language by design. JS/TS/JSX/TSX files use the
189
196
  TypeScript compiler API for AST-backed symbols, imports, and call hints. Python,
190
197
  Go, Rust, Java, Kotlin, Ruby, PHP, C#, C/C++, and Swift use deterministic generic
191
198
  static extractors so every repo gets a useful graph immediately.
192
199
 
200
+ For large repos, refresh also writes a complete structural index under
201
+ `.agent_memory/structural/`:
202
+
203
+ - `files.json`: every supported source/config/doc file, including files the
204
+ code graph represents as metadata-only because they are too large to parse.
205
+ - `symbols.json`: extracted functions, classes, constants, routes, and tests.
206
+ - `edges.json`: file-to-symbol and file-to-import edges with confidence labels.
207
+ - `manifest.json`: mtime/hash entries, cache hits/misses, ignored files, and
208
+ deleted-file tracking.
209
+ - `file-cache.json`: packed per-file structural facts keyed by source content
210
+ hash. Refresh migrates older `.agent_memory/structural/file-cache/*.json`
211
+ layouts and removes stale per-file cache entries.
212
+ - `report.md`: a compact language/concept coverage report.
213
+
214
+ This follows the same shape as fast graph indexers such as Graphify: discover
215
+ files, skip generated/vendor paths, use a per-file content cache, parallelize
216
+ extraction on large repos, rebuild only changed files, and keep generated
217
+ structural facts separate from learned memory. Use `.kageignore` for
218
+ repo-specific excludes.
219
+
193
220
  Kage also consumes external industry indexer artifacts when present:
194
221
 
195
222
  - `.agent_memory/code_index/tree-sitter.json`
@@ -206,11 +233,13 @@ generic extraction in metrics and file parser coverage. This keeps installation
206
233
  light while allowing teams to plug in the strongest indexer available for their
207
234
  language stack.
208
235
 
209
- `kage code-index --project <repo>` writes `.agent_memory/code_index/lsp-symbols.json`
210
- in an LSP document-symbol-compatible shape using Kage's local parser. The CI,
236
+ `kage code-index --project <repo>` now tries the best external indexer first for
237
+ the common JS/TS case: if `scip-typescript` and the `scip` CLI are on the repo or
238
+ shell path, it writes `.agent_memory/code_index/scip.json` from the generated
239
+ SCIP index. If those tools are unavailable, it writes
240
+ `.agent_memory/code_index/lsp-symbols.json` using Kage's local parser. The CI,
211
241
  PR, and sync workflows run it before refresh so the code graph has a committed
212
- precise-index slot while teams can still replace or augment it with SCIP/LSIF
213
- artifacts from their preferred toolchain.
242
+ precise-index slot without making first-run setup depend on external binaries.
214
243
 
215
244
  The memory graph follows the same product direction as temporal context graph
216
245
  systems such as Graphiti: immutable ingestion episodes, derived entities and
@@ -258,7 +287,9 @@ Use `kage refresh --project <repo>` or the `kage_refresh` MCP tool after
258
287
  meaningful file/content changes. Refresh rebuilds indexes, code graph, memory
259
288
  graph, metrics, and stale-memory metadata. Memory is marked stale when status or
260
289
  feedback says it is stale, its TTL expires, or grounded paths disappear. Pushes
261
- and empty/same-tree commits do not need another refresh.
290
+ and empty/same-tree commits do not need another refresh. Use `--full` or
291
+ `kage_refresh` with `full: true` only when you intentionally want to bypass
292
+ unchanged-graph reuse and rebuild the code graph from scratch.
262
293
 
263
294
  Use `kage gc --project <repo> --dry-run` to preview stale packet cleanup.
264
295
  `kage gc --project <repo>` marks stale repo packets deprecated, rebuilds
package/dist/cli.js CHANGED
@@ -24,7 +24,7 @@ Usage:
24
24
  kage daemon status --project <dir> [--json]
25
25
  kage daemon doctor --project <dir> [--json]
26
26
  kage viewer --project <dir> [--port 3113]
27
- kage refresh --project <dir> [--json]
27
+ kage refresh --project <dir> [--full] [--json]
28
28
  kage gc --project <dir> [--dry-run] [--force] [--json]
29
29
  kage pr summarize --project <dir> [--json]
30
30
  kage pr check --project <dir> [--json]
@@ -39,6 +39,7 @@ Usage:
39
39
  kage code-graph --project <dir> [--json]
40
40
  kage code-graph "<query>" --project <dir> [--json]
41
41
  kage code-index --project <dir> [--json]
42
+ kage structural-index --project <dir> [--json]
42
43
  kage graph --project <dir> [--json]
43
44
  kage graph --project <dir> --mermaid
44
45
  kage graph "<query>" --project <dir> [--json]
@@ -335,7 +336,7 @@ async function main() {
335
336
  return;
336
337
  }
337
338
  if (command === "refresh") {
338
- const result = (0, kernel_js_1.refreshProject)(projectArg(args));
339
+ const result = (0, kernel_js_1.refreshProject)(projectArg(args), { full: args.includes("--full") });
339
340
  if (args.includes("--json")) {
340
341
  console.log(JSON.stringify(result, null, 2));
341
342
  if (!result.ok)
@@ -506,7 +507,7 @@ async function main() {
506
507
  return;
507
508
  }
508
509
  if (command === "code-index") {
509
- const result = (0, kernel_js_1.writeLspSymbolIndex)(projectArg(args));
510
+ const result = (0, kernel_js_1.writeCodeIndex)(projectArg(args));
510
511
  if (args.includes("--json")) {
511
512
  console.log(JSON.stringify(result, null, 2));
512
513
  return;
@@ -516,6 +517,11 @@ async function main() {
516
517
  console.log(`Path: ${result.path}`);
517
518
  console.log(`Documents: ${result.documents}`);
518
519
  console.log(`Symbols: ${result.symbols}`);
520
+ if (result.warnings.length) {
521
+ console.log("\nWarnings:");
522
+ for (const warning of result.warnings)
523
+ console.log(` - ${warning}`);
524
+ }
519
525
  if (result.errors.length) {
520
526
  console.log("\nErrors:");
521
527
  for (const error of result.errors)
@@ -524,6 +530,22 @@ async function main() {
524
530
  }
525
531
  return;
526
532
  }
533
+ if (command === "structural-index") {
534
+ const result = (0, kernel_js_1.buildStructuralIndex)(projectArg(args));
535
+ if (args.includes("--json")) {
536
+ console.log(JSON.stringify(result, null, 2));
537
+ return;
538
+ }
539
+ console.log(`Kage Structural Index: ${result.manifest.project_dir}`);
540
+ console.log(`Files: ${result.files.length}`);
541
+ console.log(`Symbols: ${result.symbols.length}`);
542
+ console.log(`Edges: ${result.edges.length}`);
543
+ console.log(`Metadata-only files: ${result.manifest.files.metadata_only}`);
544
+ console.log(`Cache: ${result.manifest.cache.hits} hits, ${result.manifest.cache.misses} misses`);
545
+ console.log(`Workers: ${result.manifest.worker_count}`);
546
+ console.log(`Path: .agent_memory/structural`);
547
+ return;
548
+ }
527
549
  if (command === "branch") {
528
550
  const result = (0, kernel_js_1.buildBranchOverlay)(projectArg(args));
529
551
  if (args.includes("--json"))
@@ -557,6 +579,13 @@ async function main() {
557
579
  console.log(` Indexer coverage: ${result.code_graph.indexer_coverage_percent}%`);
558
580
  console.log(` Languages: ${Object.entries(result.code_graph.languages).map(([name, count]) => `${name}=${count}`).join(", ") || "(none)"}`);
559
581
  console.log(` Parsers: ${Object.entries(result.code_graph.parsers).map(([name, count]) => `${name}=${count}`).join(", ") || "(none)"}`);
582
+ console.log("\nStructural index:");
583
+ console.log(` Files: ${result.structural_index.files}`);
584
+ console.log(` Symbols: ${result.structural_index.symbols}`);
585
+ console.log(` Edges: ${result.structural_index.edges}`);
586
+ console.log(` Metadata-only files: ${result.structural_index.metadata_only_files}`);
587
+ console.log(` Workers: ${result.structural_index.worker_count}`);
588
+ console.log(` Cache: ${result.structural_index.cache_hits} hits, ${result.structural_index.cache_misses} misses`);
560
589
  console.log("\nMemory graph:");
561
590
  console.log(` Approved packets: ${result.memory_graph.approved_packets}`);
562
591
  console.log(` Pending packets: ${result.memory_graph.pending_packets}`);
@@ -599,7 +628,7 @@ async function main() {
599
628
  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
629
  console.log(`Structured memory: ${result.checks.structured_memory.structured_packets}/${result.checks.structured_memory.total_packets} (${result.checks.structured_memory.coverage_percent}%)`);
601
630
  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}`);
631
+ console.log(`Memory-code graph edges: ${result.checks.graph_links.memory_code_edges} (${result.checks.graph_links.precise_memory_code_edges} precise, ${result.checks.graph_links.path_memory_code_edges} path)`);
603
632
  if (result.recommendations.length) {
604
633
  console.log("\nRecommendations:");
605
634
  for (const recommendation of result.recommendations)
package/dist/daemon.js CHANGED
@@ -249,12 +249,15 @@ async function startViewer(projectDir, options = {}) {
249
249
  catch {
250
250
  // non-fatal: viewer will show 404 for reports if generation fails
251
251
  }
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)}`;
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)}&view=code`;
253
253
  const server = (0, node_http_1.createServer)((req, res) => {
254
254
  const requestUrl = new URL(req.url ?? "/", `http://${host}:${port}`);
255
255
  let filePath = null;
256
256
  if (requestUrl.pathname === "/" || requestUrl.pathname === "/viewer") {
257
- filePath = (0, node_path_1.join)(viewerDir, "index.html");
257
+ const viewerSearch = requestUrl.search || new URL(url).search;
258
+ res.writeHead(302, { location: `/viewer/index.html${viewerSearch}` });
259
+ res.end();
260
+ return;
258
261
  }
259
262
  else if (requestUrl.pathname.startsWith("/viewer/")) {
260
263
  filePath = (0, node_path_1.join)(viewerDir, (0, node_path_1.normalize)(requestUrl.pathname.replace(/^\/viewer\//, "")));
package/dist/index.js CHANGED
@@ -153,6 +153,7 @@ function listTools() {
153
153
  type: "object",
154
154
  properties: {
155
155
  project_dir: { type: "string" },
156
+ full: { type: "boolean", description: "Force a full code graph rebuild instead of reusing unchanged graph artifacts." },
156
157
  },
157
158
  required: ["project_dir"],
158
159
  },
@@ -173,7 +174,18 @@ function listTools() {
173
174
  },
174
175
  {
175
176
  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
+ description: "Write external code index artifacts consumed by the code graph. Prefers SCIP when scip-typescript and scip are installed, then falls back to the built-in LSP-compatible symbol index.",
178
+ inputSchema: {
179
+ type: "object",
180
+ properties: {
181
+ project_dir: { type: "string" },
182
+ },
183
+ required: ["project_dir"],
184
+ },
185
+ },
186
+ {
187
+ name: "kage_structural_index",
188
+ description: "Build the complete cache-backed structural index for large repos. This covers all supported source/config/doc files and writes .agent_memory/structural artifacts separate from learned memory.",
177
189
  inputSchema: {
178
190
  type: "object",
179
191
  properties: {
@@ -725,12 +737,18 @@ async function callTool(name, args) {
725
737
  };
726
738
  }
727
739
  if (name === "kage_code_index") {
728
- const result = (0, kernel_js_1.writeLspSymbolIndex)(String(args?.project_dir ?? ""));
740
+ const result = (0, kernel_js_1.writeCodeIndex)(String(args?.project_dir ?? ""));
729
741
  return {
730
742
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
731
743
  isError: !result.ok,
732
744
  };
733
745
  }
746
+ if (name === "kage_structural_index") {
747
+ const result = (0, kernel_js_1.buildStructuralIndex)(String(args?.project_dir ?? ""));
748
+ return {
749
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
750
+ };
751
+ }
734
752
  if (name === "kage_metrics") {
735
753
  const result = (0, kernel_js_1.kageMetrics)(String(args?.project_dir ?? ""));
736
754
  return {
@@ -752,7 +770,7 @@ async function callTool(name, args) {
752
770
  };
753
771
  }
754
772
  if (name === "kage_refresh") {
755
- const result = (0, kernel_js_1.refreshProject)(String(args?.project_dir ?? ""));
773
+ const result = (0, kernel_js_1.refreshProject)(String(args?.project_dir ?? ""), { full: Boolean(args?.full) });
756
774
  return {
757
775
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
758
776
  isError: !result.ok,