@kage-core/kage-graph-mcp 1.1.20 → 1.1.22

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,25 @@ 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.22` fixes viewer inspector scrolling:
13
+
14
+ - selecting high-degree nodes no longer expands the page or pushes the canvas
15
+ out of view.
16
+ - selected-node details, connected relations, and memory-code evidence scroll
17
+ inside bounded inspector regions.
18
+ - long summaries and relation bodies are capped so dense nodes stay readable.
19
+
20
+ `1.1.21` published the memory-code graph quality pass:
21
+
22
+ - precise memory-code links now require explicit, non-generic symbol/test
23
+ mentions instead of broad path-only matches.
24
+ - generated memory symbol/route/test entities no longer carry file path aliases
25
+ that can collapse stale graph nodes onto code file hubs.
26
+ - the viewer's `Memory <-> Code only` relation shows actual cross-graph links,
27
+ while path-level memory still appears through capped `affects_code_path`
28
+ bridge edges.
29
+
30
+ `1.1.20` published the large-repo indexing pass:
13
31
 
14
32
  - repeated `kage refresh` calls reuse unchanged code graph artifacts by source
15
33
  stat fingerprint, with `kage refresh --full` available for intentional clean
@@ -169,26 +187,44 @@ The graph builder writes evidence-backed graph artifacts under
169
187
  and memory type entities.
170
188
  - `edges.json`: typed facts such as `contains_memory`, `affects_path`,
171
189
  `mentions_tag`, `uses_package`, `documents_command`, and `defines_command`.
172
- - `graph.json`: the assembled graph with branch, head, and merge-base metadata.
190
+ - `graph.json`: compact graph metadata plus references to the split graph files.
191
+
192
+ In the viewer, path-level memory such as `affects_path: src` is bridged to a
193
+ small representative set of matching code files at render time. This keeps the
194
+ stored graph compact while still making broad repo memories visibly connected
195
+ to the code graph.
173
196
 
174
197
  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.
198
+ `.agent_memory/code_graph/`. `graph.json` is now a compact compatibility
199
+ artifact: it keeps repo state plus calls, routes, tests, and packages inline, and
200
+ references the canonical structural `files.json`, `symbols.json`, and
201
+ `imports.json` instead of duplicating them.
186
202
 
187
203
  The code graph is multi-language by design. JS/TS/JSX/TSX files use the
188
204
  TypeScript compiler API for AST-backed symbols, imports, and call hints. Python,
189
205
  Go, Rust, Java, Kotlin, Ruby, PHP, C#, C/C++, and Swift use deterministic generic
190
206
  static extractors so every repo gets a useful graph immediately.
191
207
 
208
+ For large repos, refresh also writes a complete structural index under
209
+ `.agent_memory/structural/`:
210
+
211
+ - `files.json`: every supported source/config/doc file, including files the
212
+ code graph represents as metadata-only because they are too large to parse.
213
+ - `symbols.json`: extracted functions, classes, constants, routes, and tests.
214
+ - `edges.json`: file-to-symbol and file-to-import edges with confidence labels.
215
+ - `manifest.json`: mtime/hash entries, cache hits/misses, ignored files, and
216
+ deleted-file tracking.
217
+ - `file-cache.json`: packed per-file structural facts keyed by source content
218
+ hash. Refresh migrates older `.agent_memory/structural/file-cache/*.json`
219
+ layouts and removes stale per-file cache entries.
220
+ - `report.md`: a compact language/concept coverage report.
221
+
222
+ This follows the same shape as fast graph indexers such as Graphify: discover
223
+ files, skip generated/vendor paths, use a per-file content cache, parallelize
224
+ extraction on large repos, rebuild only changed files, and keep generated
225
+ structural facts separate from learned memory. Use `.kageignore` for
226
+ repo-specific excludes.
227
+
192
228
  Kage also consumes external industry indexer artifacts when present:
193
229
 
194
230
  - `.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 {