@kage-core/kage-graph-mcp 1.1.20 → 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,7 +9,17 @@ This package exposes two surfaces:
9
9
 
10
10
  ## Latest Release
11
11
 
12
- `1.1.20` publishes the large-repo indexing pass:
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:
13
23
 
14
24
  - repeated `kage refresh` calls reuse unchanged code graph artifacts by source
15
25
  stat fingerprint, with `kage refresh --full` available for intentional clean
@@ -169,26 +179,44 @@ The graph builder writes evidence-backed graph artifacts under
169
179
  and memory type entities.
170
180
  - `edges.json`: typed facts such as `contains_memory`, `affects_path`,
171
181
  `mentions_tag`, `uses_package`, `documents_command`, and `defines_command`.
172
- - `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.
173
188
 
174
189
  The code graph builder writes source-derived artifacts under
175
- `.agent_memory/code_graph/`:
176
-
177
- - `files.json`: source, test, config, manifest, and doc files, including
178
- language and parser metadata.
179
- - `symbols.json`: functions, classes, constants, and test cases.
180
- - `imports.json`: local and external import edges.
181
- - `calls.json`: best-effort call edges between discovered symbols.
182
- - `routes.json`: best-effort Node/Express/Next route facts.
183
- - `tests.json`: test-to-symbol/file coverage hints.
184
- - `packages.json`: package scripts and dependencies.
185
- - `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.
186
194
 
187
195
  The code graph is multi-language by design. JS/TS/JSX/TSX files use the
188
196
  TypeScript compiler API for AST-backed symbols, imports, and call hints. Python,
189
197
  Go, Rust, Java, Kotlin, Ruby, PHP, C#, C/C++, and Swift use deterministic generic
190
198
  static extractors so every repo gets a useful graph immediately.
191
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
+
192
220
  Kage also consumes external industry indexer artifacts when present:
193
221
 
194
222
  - `.agent_memory/code_index/tree-sitter.json`
package/dist/cli.js CHANGED
@@ -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]
@@ -529,6 +530,22 @@ async function main() {
529
530
  }
530
531
  return;
531
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
+ }
532
549
  if (command === "branch") {
533
550
  const result = (0, kernel_js_1.buildBranchOverlay)(projectArg(args));
534
551
  if (args.includes("--json"))
@@ -562,6 +579,13 @@ async function main() {
562
579
  console.log(` Indexer coverage: ${result.code_graph.indexer_coverage_percent}%`);
563
580
  console.log(` Languages: ${Object.entries(result.code_graph.languages).map(([name, count]) => `${name}=${count}`).join(", ") || "(none)"}`);
564
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`);
565
589
  console.log("\nMemory graph:");
566
590
  console.log(` Approved packets: ${result.memory_graph.approved_packets}`);
567
591
  console.log(` Pending packets: ${result.memory_graph.pending_packets}`);
@@ -604,7 +628,7 @@ async function main() {
604
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`);
605
629
  console.log(`Structured memory: ${result.checks.structured_memory.structured_packets}/${result.checks.structured_memory.total_packets} (${result.checks.structured_memory.coverage_percent}%)`);
606
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`);
607
- 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)`);
608
632
  if (result.recommendations.length) {
609
633
  console.log("\nRecommendations:");
610
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
@@ -183,6 +183,17 @@ function listTools() {
183
183
  required: ["project_dir"],
184
184
  },
185
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.",
189
+ inputSchema: {
190
+ type: "object",
191
+ properties: {
192
+ project_dir: { type: "string" },
193
+ },
194
+ required: ["project_dir"],
195
+ },
196
+ },
186
197
  {
187
198
  name: "kage_metrics",
188
199
  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.",
@@ -732,6 +743,12 @@ async function callTool(name, args) {
732
743
  isError: !result.ok,
733
744
  };
734
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
+ }
735
752
  if (name === "kage_metrics") {
736
753
  const result = (0, kernel_js_1.kageMetrics)(String(args?.project_dir ?? ""));
737
754
  return {