@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 +60 -29
- package/dist/cli.js +33 -4
- package/dist/daemon.js +5 -2
- package/dist/index.js +21 -3
- package/dist/kernel.js +1299 -184
- package/dist/structural-worker.js +30 -0
- package/package.json +1 -1
- package/viewer/app.js +540 -31
- package/viewer/index.html +2 -2
package/README.md
CHANGED
|
@@ -9,18 +9,26 @@ This package exposes two surfaces:
|
|
|
9
9
|
|
|
10
10
|
## Latest Release
|
|
11
11
|
|
|
12
|
-
`1.1.
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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`:
|
|
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
|
-
|
|
179
|
-
|
|
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>`
|
|
210
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
|
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.
|
|
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,
|