@kage-core/kage-graph-mcp 1.1.36 → 1.1.37

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
@@ -34,6 +34,9 @@ Roo Code, Kilo Code, Claude Desktop, Aider, generic MCP (`kage setup list`).
34
34
 
35
35
  - Repo-local memory for decisions, runbooks, bug fixes, gotchas, conventions,
36
36
  and code explanations.
37
+ - Claude Code ambient hooks for prompt-time recall, tool-result observation,
38
+ failure capture, pre-compact/session-end distillation, and stop-time review
39
+ refresh.
37
40
  - A code graph for files, symbols, imports, confidence-scored calls, routes
38
41
  (FastAPI / Flask / Django / Rails / Laravel / Spring / Go / Rust / ASP.NET),
39
42
  tests, and packages.
@@ -42,7 +45,37 @@ Roo Code, Kilo Code, Claude Desktop, Aider, generic MCP (`kage setup list`).
42
45
  ownership silos, module health.
43
46
  - Conservative cleanup review input (unreferenced files, unused exports,
44
47
  internal-looking unused symbols). Never deletes code.
45
- - A local viewer for memory, code graph, risks, review, and metrics.
48
+ - A local viewer for memory, code graph, risks, review, and metrics, served
49
+ with conservative browser security headers.
50
+ - Local memory-access tracking in `.agent_memory/reports/memory-access.json`
51
+ so agents can learn which memories are reused and recommend what to verify,
52
+ ground, or clean up without changing shareable packet files on every recall.
53
+ - Memory lifecycle reporting in `.agent_memory/reports/lifecycle.json` so
54
+ teammates can review healthy, hot, stale, disputed, ungrounded, pending, and
55
+ generated packets with concrete actions.
56
+ - Memory timeline reporting in `.agent_memory/reports/timeline.json` so
57
+ handoffs show recently added, updated, pending, and retired repo knowledge.
58
+ - Memory lineage reporting in `.agent_memory/reports/lineage.json` so
59
+ superseded packets point at the current replacement memory agents should use.
60
+ - Memory audit reporting in `.agent_memory/audit/events.jsonl` and
61
+ `.agent_memory/reports/memory-audit.json` so memory mutations are reviewable.
62
+ - Memory handoff reporting in `.agent_memory/reports/handoff.json` so the next
63
+ teammate or agent gets one queue across inbox, lifecycle, audit, timeline,
64
+ lineage, and distillable session learnings.
65
+ - Project profile reporting in `.agent_memory/reports/profile.json` so agents
66
+ get a compact orientation across repo shape, top concepts, key files,
67
+ commands, memory focus, and next actions.
68
+ - Capability audit reporting in `.agent_memory/reports/capabilities.json` so
69
+ teams can see evidence-backed readiness across memory, collaboration,
70
+ benchmark proof, and dashboard/viewer proof.
71
+ - Pinned context slots in `.agent_memory/slots/slots.json` so teams can review
72
+ tiny always-relevant repo guidance that Kage includes before task-specific
73
+ recall.
74
+ - Session replay digest in `.agent_memory/reports/replay.json` so teams can
75
+ review observed agent timelines, paths, commands, durable candidates, and
76
+ distill actions without exposing raw transcript text.
77
+ - A viewer benchmark proof ledger that shows measured results, thresholds,
78
+ exact commands, and next actions for retrieval, scale, and repo trust gates.
46
79
 
47
80
  No hosted service, external database, or API key is required.
48
81
 
@@ -52,8 +85,24 @@ No hosted service, external database, or API key is required.
52
85
  kage recall "how do I run tests" --project .
53
86
  kage code-graph "auth routes tests" --project .
54
87
  kage risk --project . --targets src/auth.ts --json
88
+ kage profile --project . --json
89
+ kage capabilities --project . --json
90
+ kage slots set --project . --label project_context --content "Always run retry tests after changing retry modules." --paths src/retry.ts --tags retry,tests
91
+ kage slots --project . --json
55
92
  kage learn --project . --learning "Use npm test after parser changes."
93
+ kage sessions --project . # observed sessions and distillation actions
94
+ kage replay --project . # privacy-preserving observed-session timeline
95
+ kage memory-access --project . # hot/cold memories and review actions
96
+ kage memory-audit --project . # auditable memory mutations
97
+ kage handoff --project . # combined teammate/agent handoff queue
98
+ kage lifecycle --project . # memory health, freshness, grounding, and feedback
99
+ kage timeline --project . # recent memory changes for handoff
100
+ kage lineage --project . # current replacements for retired memories
101
+ kage supersede --project . --packet <old-id> --replacement <new-id> --reason "why"
102
+ kage benchmark --memory-quality # coding-memory retrieval proof
103
+ kage benchmark --scale --sizes 240,1000,5000 # large-memory recall proof
56
104
  kage refresh --project .
105
+ kage embeddings build --project . # optional dense local recall
57
106
  kage hook install --project .
58
107
  kage pr check --project .
59
108
  kage viewer --project .
@@ -62,6 +111,14 @@ kage viewer --project .
62
111
  MCP agents should start with `kage_context`. When the query or target list
63
112
  mentions file paths, it also includes risk and dependency-path context.
64
113
 
114
+ Normal recall is local and dependency-free. For repos that need denser semantic
115
+ matching, install `@xenova/transformers` in the same Node environment as Kage,
116
+ then run `kage embeddings build --project .`. The default lexical layer is
117
+ Unicode-aware and adds CJK bigrams for memory written without spaces. Dense
118
+ embeddings write an optional rebuildable
119
+ `.agent_memory/indexes/embeddings-local.json` artifact, and
120
+ `kage recall "query" --project . --embeddings --explain` uses it.
121
+
65
122
  For stale or wrong memory:
66
123
 
67
124
  ```bash
@@ -79,6 +136,46 @@ kage setup claude-code --project . --write
79
136
  kage setup generic-mcp --project .
80
137
  ```
81
138
 
139
+ `kage setup claude-code --write` installs the MCP server plus SessionStart,
140
+ UserPromptSubmit, PostToolUse, PostToolUseFailure, PreCompact, Stop, and
141
+ SessionEnd hooks. The hooks observe reusable work signals, inject relevant
142
+ repo memory on new prompts, and distill durable learnings before compaction or
143
+ handoff.
144
+
145
+ `kage setup verify-agent --agent claude-code --project .` checks those hooks,
146
+ not only the MCP config. If a teammate has the server configured but missing
147
+ ambient hooks, verification reports the missing events and tells them to rerun
148
+ setup.
149
+
150
+ `kage setup doctor --project . --json` also includes the Claude hook summary,
151
+ so teams can audit partial installs before relying on automatic capture.
152
+ MCP agents can call `kage_setup_doctor` for the same audit without shelling out.
153
+
154
+ ## REST daemon
155
+
156
+ HTTP-only agents can use the same memory system through the local daemon:
157
+
158
+ ```bash
159
+ kage daemon start --project .
160
+ curl -X POST http://127.0.0.1:3111/kage/context \
161
+ -H 'content-type: application/json' \
162
+ -d '{"query":"how does auth work?","limit":5}'
163
+ ```
164
+
165
+ Useful endpoints:
166
+
167
+ - `POST /kage/context` - combined recall, graph facts, validation, risk, and dependency context.
168
+ - `POST /kage/recall` - repo memory recall.
169
+ - `POST /kage/capture` and `POST /kage/learn` - write durable repo memory.
170
+ - `POST /kage/feedback` - mark recalled memory helpful, wrong, or stale.
171
+ - `POST /kage/observe` and `POST /kage/distill` - session observation and durable learning distillation.
172
+ - `GET /kage/replay` - privacy-preserving session replay digest without raw transcript text.
173
+ - `GET /kage/setup-doctor` - supported-agent setup and Claude hook readiness.
174
+ - `GET /kage/profile` - compact project profile for agent orientation.
175
+ - `GET /kage/capabilities` - evidence-backed memory system readiness across memory, collaboration, benchmarks, and viewer proof.
176
+ - `GET /kage/context-slots`, `POST /kage/context-slots`, `DELETE /kage/context-slots/:label` - pinned repo context slots.
177
+ - `GET /kage/metrics`, `/kage/quality`, `/kage/inbox`, `/kage/benchmark`, `/kage/handoff`, `/kage/lifecycle`, `/kage/timeline`, `/kage/lineage`, `/kage/memory-audit` - human and agent review reports.
178
+
82
179
  ## Storage
83
180
 
84
181
  Kage writes to `.agent_memory/`. Packets are durable repo memory; everything
@@ -90,7 +187,9 @@ else is rebuildable with `kage refresh`.
90
187
  | `.agent_memory/graph/` | memory graph (rebuildable) |
91
188
  | `.agent_memory/code_graph/` | source-derived code facts (rebuildable) |
92
189
  | `.agent_memory/structural/` | files, symbols, imports |
93
- | `.agent_memory/reports/` | risk, contributors, decisions, module health, workspace, quality, benchmark |
190
+ | `.agent_memory/slots/` | pinned repo context slots |
191
+ | `.agent_memory/indexes/` | recall indexes, including optional embeddings |
192
+ | `.agent_memory/reports/` | profile, capabilities, context-slots, replay, risk, contributors, decisions, module health, workspace, quality, benchmark, handoff, lifecycle, timeline, lineage |
94
193
 
95
194
  Repo-local packets are git-visible and reviewable. Generated indexes and
96
195
  graphs are rebuildable.
package/dist/cli.js CHANGED
@@ -34,7 +34,20 @@ Usage:
34
34
  kage upgrade [--dry-run]
35
35
  kage branch --project <dir> [--json]
36
36
  kage metrics --project <dir> [--json]
37
+ kage memory-access --project <dir> [--json]
38
+ kage memory-audit --project <dir> [--limit <n>] [--json]
39
+ kage slots --project <dir> [--json]
40
+ kage slots set --project <dir> --label <label> --content <text> [--description <text>] [--paths a,b] [--tags a,b] [--size-limit <n>] [--unpinned] [--json]
41
+ kage slots delete --project <dir> --label <label> [--json]
42
+ kage handoff --project <dir> [--json]
43
+ kage lifecycle --project <dir> [--json]
44
+ kage reconcile --project <dir> [--session <id>] [--json]
45
+ kage timeline --project <dir> [--days <n>] [--json]
46
+ kage lineage --project <dir> [--json]
47
+ kage supersede --project <dir> --packet <old-id> --replacement <new-id> [--reason <text>] [--json]
37
48
  kage contributors --project <dir> [--json]
49
+ kage profile --project <dir> [--json]
50
+ kage capabilities --project <dir> [--json]
38
51
  kage decisions --project <dir> [--json]
39
52
  kage module-health --project <dir> [--json]
40
53
  kage graph-insights --project <dir> [--json]
@@ -44,6 +57,8 @@ Usage:
44
57
  kage inbox --project <dir> [--json]
45
58
  kage quality --project <dir> [--json]
46
59
  kage benchmark --project <dir> [--json]
60
+ kage benchmark --memory-quality [--json]
61
+ kage benchmark --scale [--sizes 240,1000,5000] [--json]
47
62
  kage benchmark --project <dir> --compare --task <task> [--json]
48
63
  kage code-graph --project <dir> [--json]
49
64
  kage code-graph "<query>" --project <dir> [--json]
@@ -57,8 +72,11 @@ Usage:
57
72
  kage graph --project <dir> --mermaid
58
73
  kage graph "<query>" --project <dir> [--json]
59
74
  kage graph-registry --project <dir> [--json]
60
- kage recall "<query>" --project <dir> [--json] [--explain]
75
+ kage embeddings build --project <dir> [--model Xenova/all-MiniLM-L6-v2] [--json]
76
+ kage recall "<query>" --project <dir> [--json] [--explain] [--embeddings]
61
77
  kage observe --project <dir> --event <json>
78
+ kage sessions --project <dir> [--json]
79
+ kage replay --project <dir> [--session <id>] [--limit <n>] [--json]
62
80
  kage distill --project <dir> --session <id>
63
81
  kage learn --project <dir> --learning <text> [--title <title>] [--type <type>] [--evidence <text>] [--verified-by <text>] [--tags a,b] [--paths a,b]
64
82
  kage feedback --project <dir> --packet <packet-id> --kind helpful|wrong|stale
@@ -220,7 +238,10 @@ async function main() {
220
238
  }
221
239
  console.log("Kage setup doctor");
222
240
  for (const item of result) {
223
- console.log(`- ${item.agent}: ${item.configured ? "configured" : "not detected"}${item.config_path ? ` (${item.config_path})` : ""}`);
241
+ const hookStatus = item.hook_summary
242
+ ? item.hook_summary.ready ? " hooks: installed" : ` hooks: missing ${item.hook_summary.missing.join(", ")}`
243
+ : "";
244
+ console.log(`- ${item.agent}: ${item.configured ? "configured" : "not detected"}${hookStatus}${item.config_path ? ` (${item.config_path})` : ""}`);
224
245
  }
225
246
  return;
226
247
  }
@@ -240,6 +261,9 @@ async function main() {
240
261
  console.log(`Indexes: ${result.checks.indexes_present ? "present" : "missing"}`);
241
262
  console.log(`Recall: ${result.checks.recall_works ? "ok" : "failed"} (${result.recall_preview})`);
242
263
  console.log(`Code graph: ${result.checks.code_graph_works ? "ok" : "failed"} (${result.code_graph_summary})`);
264
+ if (result.hook_summary) {
265
+ console.log(`Ambient hooks: ${result.checks.ambient_hooks_present ? "installed" : `missing ${result.hook_summary.missing.join(", ")}`}`);
266
+ }
243
267
  console.log(`Active MCP tool: ${result.checks.mcp_tool_reachable ? "reachable" : "not verified from CLI"}`);
244
268
  if (result.warnings.length)
245
269
  console.log(`Warnings:\n${result.warnings.map((warning) => ` - ${warning}`).join("\n")}`);
@@ -641,6 +665,33 @@ async function main() {
641
665
  console.log(`Warnings:\n${result.warnings.map((warning) => ` - ${warning}`).join("\n")}`);
642
666
  return;
643
667
  }
668
+ if (command === "profile") {
669
+ const result = (0, kernel_js_1.kageProjectProfile)(projectArg(args));
670
+ if (args.includes("--json")) {
671
+ console.log(JSON.stringify(result, null, 2));
672
+ return;
673
+ }
674
+ console.log(`Kage project profile: ${result.summary}`);
675
+ console.log(`Files: ${result.totals.files} (${result.totals.source_files} source, ${result.totals.test_files} test), symbols: ${result.totals.symbols}`);
676
+ console.log(`Memory: ${result.totals.approved_memory} packets, ${result.totals.memory_code_coverage_percent}% memory-code coverage`);
677
+ if (result.top_concepts.length)
678
+ console.log(`Top concepts: ${result.top_concepts.slice(0, 6).map((item) => `${item.concept} (${item.count})`).join(", ")}`);
679
+ if (result.key_files.length) {
680
+ console.log("Key files:");
681
+ for (const file of result.key_files.slice(0, 8))
682
+ console.log(`- ${file.path}: ${file.why.slice(0, 3).join("; ")}`);
683
+ }
684
+ if (result.run_commands.length) {
685
+ console.log("Commands:");
686
+ for (const commandItem of result.run_commands.slice(0, 6))
687
+ console.log(`- ${commandItem.name}: ${commandItem.command}`);
688
+ }
689
+ if (result.next_actions.length)
690
+ console.log(`Next: ${result.next_actions[0]}`);
691
+ if (result.warnings.length)
692
+ console.log(`Warnings:\n${result.warnings.map((warning) => ` - ${warning}`).join("\n")}`);
693
+ return;
694
+ }
644
695
  if (command === "decisions") {
645
696
  const result = (0, kernel_js_1.kageDecisionIntelligence)(projectArg(args));
646
697
  if (args.includes("--json")) {
@@ -775,6 +826,256 @@ async function main() {
775
826
  console.log(` Estimated tokens saved: ${result.pain.estimated_tokens_saved}`);
776
827
  console.log(` Time to first use: ${result.pain.time_to_first_use_seconds}s`);
777
828
  }
829
+ if (result.memory_access) {
830
+ console.log("\nMemory access:");
831
+ console.log(` Tracked packets: ${result.memory_access.tracked_packets}`);
832
+ console.log(` Uses in 30d: ${result.memory_access.uses_30d}`);
833
+ console.log(` Hot / cold packets: ${result.memory_access.hot_packets} / ${result.memory_access.cold_packets}`);
834
+ }
835
+ return;
836
+ }
837
+ if (command === "memory-access") {
838
+ const result = (0, kernel_js_1.kageMemoryAccess)(projectArg(args));
839
+ if (args.includes("--json")) {
840
+ console.log(JSON.stringify(result, null, 2));
841
+ return;
842
+ }
843
+ console.log(`Kage memory access: ${result.totals.tracked_packets} tracked packet${result.totals.tracked_packets === 1 ? "" : "s"}`);
844
+ console.log(`Recent uses: ${result.totals.uses_30d} in ${result.window_days} days`);
845
+ console.log(`Hot / cold: ${result.totals.hot_packets} / ${result.totals.cold_packets}`);
846
+ if (result.recommendations.length) {
847
+ console.log("\nRecommended review:");
848
+ for (const item of result.recommendations.slice(0, 5)) {
849
+ console.log(`- ${item.summary}`);
850
+ console.log(` ${item.action}`);
851
+ }
852
+ }
853
+ console.log("\nTop recalled packets:");
854
+ for (const entry of result.entries.filter((item) => !(item.tags.includes("change-memory") && item.tags.includes("diff-proposal"))).slice(0, 10)) {
855
+ if (!entry.total_uses)
856
+ continue;
857
+ console.log(`- ${entry.title}: ${entry.uses_30d} recent, ${entry.total_uses} total${entry.best_rank ? `, best rank ${entry.best_rank}` : ""}`);
858
+ }
859
+ return;
860
+ }
861
+ if (command === "lifecycle" || command === "memory-lifecycle") {
862
+ const result = (0, kernel_js_1.kageMemoryLifecycle)(projectArg(args));
863
+ if (args.includes("--json")) {
864
+ console.log(JSON.stringify(result, null, 2));
865
+ return;
866
+ }
867
+ console.log(`Kage memory lifecycle: ${result.totals.approved} approved, ${result.totals.pending} pending`);
868
+ console.log(`Healthy / hot / stale: ${result.totals.healthy} / ${result.totals.hot} / ${result.totals.stale}`);
869
+ console.log(`Ungrounded / disputed / generated: ${result.totals.ungrounded} / ${result.totals.disputed} / ${result.totals.generated}`);
870
+ if (result.recommendations.length) {
871
+ console.log("\nRecommended actions:");
872
+ for (const item of result.recommendations.slice(0, 6)) {
873
+ console.log(`- ${item.title ? `${item.title}: ` : ""}${item.summary}`);
874
+ console.log(` ${item.action}`);
875
+ }
876
+ }
877
+ return;
878
+ }
879
+ if (command === "reconcile" || command === "memory-reconcile" || command === "memory-reconciliation") {
880
+ const result = (0, kernel_js_1.kageMemoryReconciliation)(projectArg(args), {
881
+ sessionId: takeArg(args, "--session"),
882
+ limit: numberArg(args, "--limit", 25),
883
+ });
884
+ if (args.includes("--json")) {
885
+ console.log(JSON.stringify(result, null, 2));
886
+ }
887
+ else {
888
+ console.log(result.agent_instruction);
889
+ if (result.items.length) {
890
+ console.log("\nItems:");
891
+ for (const item of result.items) {
892
+ console.log(`- ${item.packet_id}: ${item.title}`);
893
+ console.log(` Paths: ${item.changed_paths.join(", ") || item.paths.join(", ")}`);
894
+ console.log(` Action: ${item.next_action}`);
895
+ }
896
+ }
897
+ }
898
+ if (!result.ok)
899
+ process.exitCode = 2;
900
+ return;
901
+ }
902
+ if (command === "memory-audit" || command === "audit-log") {
903
+ const result = (0, kernel_js_1.kageMemoryAudit)(projectArg(args), numberArg(args, "--limit", 100));
904
+ if (args.includes("--json")) {
905
+ console.log(JSON.stringify(result, null, 2));
906
+ return;
907
+ }
908
+ console.log(`Kage memory audit: ${result.totals.total} mutation${result.totals.total === 1 ? "" : "s"}`);
909
+ console.log(`Capture / feedback / supersede: ${result.totals.capture} / ${result.totals.feedback} / ${result.totals.supersede}`);
910
+ for (const entry of result.entries.slice(0, 12)) {
911
+ console.log(`- ${entry.operation}: ${entry.packet_titles.join(", ") || entry.packet_ids.join(", ")} (${entry.timestamp.slice(0, 19)})`);
912
+ }
913
+ if (!result.entries.length)
914
+ console.log("No memory mutations have been audited yet.");
915
+ return;
916
+ }
917
+ if (command === "capabilities" || command === "capability-audit" || command === "readiness") {
918
+ const result = (0, kernel_js_1.kageCapabilityAudit)(projectArg(args));
919
+ if (args.includes("--json")) {
920
+ console.log(JSON.stringify(result, null, 2));
921
+ return;
922
+ }
923
+ console.log(`Kage capability audit: ${result.overall_score}/100 (${result.status})`);
924
+ console.log(result.summary);
925
+ for (const pillar of result.pillars) {
926
+ console.log(`\n${pillar.label}: ${pillar.score}/100 (${pillar.status})`);
927
+ for (const item of pillar.evidence.slice(0, 4))
928
+ console.log(` - ${item.label}: ${item.value}`);
929
+ if (pillar.gaps.length)
930
+ console.log(` Gap: ${pillar.gaps[0]}`);
931
+ if (pillar.actions.length)
932
+ console.log(` Action: ${pillar.actions[0]}`);
933
+ }
934
+ return;
935
+ }
936
+ if (command === "slots" || command === "context-slots") {
937
+ const action = args[1] && !args[1].startsWith("--") ? args[1] : undefined;
938
+ if (!action || action === "list") {
939
+ const result = (0, kernel_js_1.kageContextSlots)(projectArg(args));
940
+ if (args.includes("--json")) {
941
+ console.log(JSON.stringify(result, null, 2));
942
+ return;
943
+ }
944
+ console.log(`Kage pinned context slots: ${result.summary}`);
945
+ for (const slot of result.slots) {
946
+ console.log(`- ${slot.label}${slot.pinned ? " [pinned]" : ""}: ${slot.description || "(no description)"}`);
947
+ console.log(` ${slot.content.slice(0, 160)}${slot.content.length > 160 ? "..." : ""}`);
948
+ }
949
+ if (!result.slots.length)
950
+ console.log("No slots yet. Add one with `kage slots set --label project_context --content \"...\" --project .`.");
951
+ if (result.warnings.length)
952
+ console.log(`Warnings:\n${result.warnings.map((warning) => ` - ${warning}`).join("\n")}`);
953
+ return;
954
+ }
955
+ if (action === "set") {
956
+ const label = takeArg(args, "--label");
957
+ const content = takeArg(args, "--content");
958
+ if (!label || !content)
959
+ usage();
960
+ const result = (0, kernel_js_1.setContextSlot)(projectArg(args), {
961
+ label,
962
+ content,
963
+ description: takeArg(args, "--description"),
964
+ pinned: !args.includes("--unpinned"),
965
+ size_limit: numberArg(args, "--size-limit", 2000),
966
+ paths: listArg(takeArg(args, "--paths")),
967
+ tags: listArg(takeArg(args, "--tags")),
968
+ });
969
+ if (args.includes("--json")) {
970
+ console.log(JSON.stringify(result, null, 2));
971
+ if (!result.ok)
972
+ process.exit(2);
973
+ return;
974
+ }
975
+ if (!result.ok) {
976
+ console.error(`Context slot not saved:\n${result.errors.map((error) => ` - ${error}`).join("\n")}`);
977
+ process.exit(2);
978
+ }
979
+ console.log(`Saved context slot: ${result.slot?.label}`);
980
+ return;
981
+ }
982
+ if (action === "delete") {
983
+ const label = takeArg(args, "--label");
984
+ if (!label)
985
+ usage();
986
+ const result = (0, kernel_js_1.deleteContextSlot)(projectArg(args), label);
987
+ if (args.includes("--json")) {
988
+ console.log(JSON.stringify(result, null, 2));
989
+ if (!result.ok)
990
+ process.exit(2);
991
+ return;
992
+ }
993
+ if (!result.ok) {
994
+ console.error(`Context slot not deleted:\n${result.errors.map((error) => ` - ${error}`).join("\n")}`);
995
+ process.exit(2);
996
+ }
997
+ console.log(`Deleted context slot: ${result.deleted?.label}`);
998
+ return;
999
+ }
1000
+ usage();
1001
+ }
1002
+ if (command === "handoff" || command === "memory-handoff") {
1003
+ const result = (0, kernel_js_1.kageMemoryHandoff)(projectArg(args));
1004
+ if (args.includes("--json")) {
1005
+ console.log(JSON.stringify(result, null, 2));
1006
+ return;
1007
+ }
1008
+ console.log(`Kage memory handoff: ${result.totals.open_items} open item${result.totals.open_items === 1 ? "" : "s"}, ${result.totals.distillable_sessions} distillable session${result.totals.distillable_sessions === 1 ? "" : "s"}, ${result.totals.recent_mutations} recent mutation${result.totals.recent_mutations === 1 ? "" : "s"}`);
1009
+ console.log(result.summary);
1010
+ console.log(`Primary action: ${result.primary_action.label} — ${result.primary_action.action}`);
1011
+ if (result.items.length) {
1012
+ console.log("\nNext actions:");
1013
+ for (const item of result.items.slice(0, 10)) {
1014
+ console.log(`- [${item.severity}] ${item.title}: ${item.summary}`);
1015
+ console.log(` ${item.action}`);
1016
+ }
1017
+ }
1018
+ if (result.recommendations.length) {
1019
+ console.log("\nRecommendations:");
1020
+ for (const item of result.recommendations.slice(0, 5))
1021
+ console.log(`- ${item}`);
1022
+ }
1023
+ return;
1024
+ }
1025
+ if (command === "timeline" || command === "memory-timeline") {
1026
+ const result = (0, kernel_js_1.kageMemoryTimeline)(projectArg(args), numberArg(args, "--days", 14));
1027
+ if (args.includes("--json")) {
1028
+ console.log(JSON.stringify(result, null, 2));
1029
+ return;
1030
+ }
1031
+ console.log(`Kage memory timeline: last ${result.days} day${result.days === 1 ? "" : "s"} — ${result.totals.total} event${result.totals.total === 1 ? "" : "s"}`);
1032
+ console.log(`Added / updated / pending / deprecated: ${result.totals.added} / ${result.totals.updated} / ${result.totals.pending} / ${result.totals.deprecated}`);
1033
+ for (const entry of result.entries.slice(0, 12)) {
1034
+ const prefix = entry.kind === "added" ? "+" : entry.kind === "updated" ? "~" : entry.kind === "pending" ? "?" : "-";
1035
+ console.log(` ${prefix} [${entry.type}] ${entry.title} (${entry.date.slice(0, 10)})`);
1036
+ }
1037
+ if (!result.entries.length)
1038
+ console.log("No memory activity in this period.");
1039
+ return;
1040
+ }
1041
+ if (command === "lineage" || command === "memory-lineage") {
1042
+ const result = (0, kernel_js_1.kageMemoryLineage)(projectArg(args));
1043
+ if (args.includes("--json")) {
1044
+ console.log(JSON.stringify(result, null, 2));
1045
+ return;
1046
+ }
1047
+ console.log(`Kage memory lineage: ${result.totals.chains} replacement chain${result.totals.chains === 1 ? "" : "s"}, ${result.totals.orphans} orphan${result.totals.orphans === 1 ? "" : "s"}`);
1048
+ for (const chain of result.chains.slice(0, 10)) {
1049
+ console.log(`- ${chain.current_title}: replaces ${chain.superseded_packet_ids.length} packet${chain.superseded_packet_ids.length === 1 ? "" : "s"}`);
1050
+ console.log(` ${chain.action}`);
1051
+ }
1052
+ if (result.orphans.length) {
1053
+ console.log("\nNeeds repair:");
1054
+ for (const orphan of result.orphans.slice(0, 10))
1055
+ console.log(`- ${orphan.title}: ${orphan.action}`);
1056
+ }
1057
+ if (!result.chains.length && !result.orphans.length)
1058
+ console.log("No superseded memory chains yet.");
1059
+ return;
1060
+ }
1061
+ if (command === "supersede") {
1062
+ const oldId = takeArg(args, "--packet");
1063
+ const replacementId = takeArg(args, "--replacement");
1064
+ if (!oldId || !replacementId)
1065
+ usage();
1066
+ const result = (0, kernel_js_1.supersedeMemory)(projectArg(args), oldId, replacementId, takeArg(args, "--reason") ?? "");
1067
+ if (args.includes("--json")) {
1068
+ console.log(JSON.stringify(result, null, 2));
1069
+ return;
1070
+ }
1071
+ if (!result.ok) {
1072
+ console.error(`Failed to supersede memory: ${result.errors.join("; ")}`);
1073
+ process.exit(1);
1074
+ }
1075
+ console.log(`Superseded memory: ${result.old_packet_id}`);
1076
+ console.log(`Replacement: ${result.replacement_packet_id}`);
1077
+ if (result.warnings.length)
1078
+ console.log(`Warnings:\n${result.warnings.map((warning) => ` - ${warning}`).join("\n")}`);
778
1079
  return;
779
1080
  }
780
1081
  if (command === "module-health") {
@@ -935,6 +1236,55 @@ async function main() {
935
1236
  return;
936
1237
  }
937
1238
  if (command === "benchmark") {
1239
+ if (args.includes("--memory-quality")) {
1240
+ const result = (0, kernel_js_1.benchmarkCodingMemoryQuality)({
1241
+ topK: Number(takeArg(args, "--top-k") ?? 10),
1242
+ packetsPerTopic: Number(takeArg(args, "--packets-per-topic") ?? 5),
1243
+ distractorsPerTopic: Number(takeArg(args, "--distractors-per-topic") ?? 7),
1244
+ keep: args.includes("--keep"),
1245
+ });
1246
+ if (args.includes("--json")) {
1247
+ console.log(JSON.stringify(result, null, 2));
1248
+ return;
1249
+ }
1250
+ console.log("Kage Coding Memory Quality Benchmark");
1251
+ console.log(`Packets: ${result.summary.packets}`);
1252
+ console.log(`Queries: ${result.summary.queries}`);
1253
+ console.log(`Refresh/index: ${result.summary.refresh_ms}ms`);
1254
+ console.log(`R@5: ${result.summary.recall_at_5_percent ?? "n/a"}%`);
1255
+ console.log(`R@10: ${result.summary.recall_at_10_percent ?? "n/a"}%`);
1256
+ console.log(`NDCG@10: ${result.summary.ndcg_at_10}`);
1257
+ console.log(`MRR: ${result.summary.mrr}`);
1258
+ console.log(`Median recall: ${result.summary.median_latency_ms}ms`);
1259
+ console.log(`Context reduction: ${result.summary.context_reduction_percent}%`);
1260
+ return;
1261
+ }
1262
+ if (args.includes("--scale")) {
1263
+ const sizes = String(takeArg(args, "--sizes") ?? "240,1000,5000")
1264
+ .split(",")
1265
+ .map((value) => Number(value.trim()))
1266
+ .filter((value) => Number.isFinite(value) && value > 0);
1267
+ const result = (0, kernel_js_1.benchmarkMemoryScale)({
1268
+ sizes,
1269
+ topK: Number(takeArg(args, "--top-k") ?? 10),
1270
+ keep: args.includes("--keep"),
1271
+ });
1272
+ if (args.includes("--json")) {
1273
+ console.log(JSON.stringify(result, null, 2));
1274
+ return;
1275
+ }
1276
+ console.log("Kage Memory Scale Benchmark");
1277
+ console.log(`Sizes: ${result.sizes.join(", ")}`);
1278
+ console.log(`Top K: ${result.top_k}`);
1279
+ console.log(`Largest corpus: ${result.summary.largest_packets} packets`);
1280
+ console.log(`Hit rate: ${result.summary.largest_hit_rate_percent}%`);
1281
+ console.log(`Median recall: ${result.summary.largest_median_recall_latency_ms}ms`);
1282
+ console.log(`Context reduction: ${result.summary.largest_context_reduction_percent}%`);
1283
+ for (const row of result.results) {
1284
+ console.log(`- ${row.packets} packets: ${row.recall_hit_rate_percent}% hit, ${row.median_recall_latency_ms}ms median, ${row.context_reduction_percent}% context reduction`);
1285
+ }
1286
+ return;
1287
+ }
938
1288
  if (args.includes("--compare")) {
939
1289
  const result = (0, kernel_js_1.benchmarkTaskComparison)(projectArg(args), takeArg(args, "--task") ?? firstPositional(args) ?? "how do I run tests");
940
1290
  if (args.includes("--json")) {
@@ -1193,13 +1543,36 @@ async function main() {
1193
1543
  const query = firstPositional(args);
1194
1544
  if (!query)
1195
1545
  usage();
1196
- const result = (0, kernel_js_1.recall)(projectArg(args), query, 5, args.includes("--explain"));
1546
+ const result = args.includes("--embeddings")
1547
+ ? await (0, kernel_js_1.recallWithEmbeddings)(projectArg(args), query, 5, args.includes("--explain"))
1548
+ : (0, kernel_js_1.recall)(projectArg(args), query, 5, args.includes("--explain"));
1197
1549
  if (args.includes("--json"))
1198
1550
  console.log(JSON.stringify(result, null, 2));
1199
1551
  else
1200
1552
  console.log(result.context_block);
1201
1553
  return;
1202
1554
  }
1555
+ if (command === "embeddings") {
1556
+ const action = firstPositional(args);
1557
+ if (action !== "build")
1558
+ usage();
1559
+ const result = await (0, kernel_js_1.buildEmbeddingIndex)(projectArg(args), { model: takeArg(args, "--model") });
1560
+ if (args.includes("--json")) {
1561
+ console.log(JSON.stringify(result, null, 2));
1562
+ if (!result.ok)
1563
+ process.exitCode = 2;
1564
+ return;
1565
+ }
1566
+ if (!result.ok) {
1567
+ console.error(`Embedding index failed:\n${result.errors.map((error) => ` - ${error}`).join("\n")}`);
1568
+ process.exit(2);
1569
+ }
1570
+ console.log(`Embedding index: ${result.path}`);
1571
+ console.log(`Provider: ${result.provider}`);
1572
+ console.log(`Model: ${result.model}`);
1573
+ console.log(`Packets: ${result.packet_count}`);
1574
+ return;
1575
+ }
1203
1576
  if (command === "observe") {
1204
1577
  const event = takeArg(args, "--event");
1205
1578
  if (!event)
@@ -1217,6 +1590,59 @@ async function main() {
1217
1590
  }
1218
1591
  return;
1219
1592
  }
1593
+ if (command === "sessions") {
1594
+ const result = (0, kernel_js_1.kageSessionCaptureReport)(projectArg(args));
1595
+ if (args.includes("--json")) {
1596
+ console.log(JSON.stringify(result, null, 2));
1597
+ return;
1598
+ }
1599
+ console.log(`Sessions: ${result.totals.sessions}`);
1600
+ console.log(`Observations: ${result.totals.observations}`);
1601
+ console.log(`Distillable observations: ${result.totals.durable_observations}`);
1602
+ for (const session of result.sessions.slice(0, 10)) {
1603
+ console.log(`\n${session.session_id} — ${session.observations} observation${session.observations === 1 ? "" : "s"}, ${session.durable_observations} distillable`);
1604
+ console.log(` ${session.first_at || "unknown"} → ${session.last_at || "unknown"}`);
1605
+ if (session.candidate_types.length)
1606
+ console.log(` Candidates: ${session.candidate_types.join(", ")}`);
1607
+ console.log(` Next: ${session.next_action}`);
1608
+ }
1609
+ if (!result.sessions.length)
1610
+ console.log("No local observation sessions recorded yet.");
1611
+ return;
1612
+ }
1613
+ if (command === "replay" || command === "session-replay") {
1614
+ const result = (0, kernel_js_1.kageSessionReplay)(projectArg(args), {
1615
+ sessionId: takeArg(args, "--session"),
1616
+ limit: Number(takeArg(args, "--limit") ?? 200),
1617
+ });
1618
+ if (args.includes("--json")) {
1619
+ console.log(JSON.stringify(result, null, 2));
1620
+ return;
1621
+ }
1622
+ console.log(`Session replay digest: ${result.totals.sessions} session${result.totals.sessions === 1 ? "" : "s"}, ${result.totals.events} event${result.totals.events === 1 ? "" : "s"}`);
1623
+ console.log(`Durable candidates: ${result.totals.durable_candidates}`);
1624
+ for (const session of result.sessions.slice(0, 8)) {
1625
+ console.log(`\n${session.session_id} — ${session.events} event${session.events === 1 ? "" : "s"}, ${session.durable_candidates} durable candidate${session.durable_candidates === 1 ? "" : "s"}`);
1626
+ console.log(` ${session.first_at || "unknown"} → ${session.last_at || "unknown"}`);
1627
+ if (session.paths.length)
1628
+ console.log(` Paths: ${session.paths.slice(0, 4).join(", ")}`);
1629
+ if (session.commands.length)
1630
+ console.log(` Commands: ${session.commands.slice(0, 3).join(", ")}`);
1631
+ if (session.durable_candidates)
1632
+ console.log(` Next: ${session.distill_command}`);
1633
+ }
1634
+ if (result.events.length) {
1635
+ console.log("\nTimeline:");
1636
+ for (const event of result.events.slice(0, 20)) {
1637
+ const durable = event.durable_candidate ? ` [${event.candidate_type ?? "durable"}]` : "";
1638
+ console.log(` ${event.timestamp} ${event.label}${durable}: ${event.summary}`);
1639
+ }
1640
+ }
1641
+ else {
1642
+ console.log("No local observation events recorded yet.");
1643
+ }
1644
+ return;
1645
+ }
1220
1646
  if (command === "distill") {
1221
1647
  const sessionId = takeArg(args, "--session");
1222
1648
  if (!sessionId)