pi-mega-compact 0.13.1 → 0.13.3

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.
Files changed (212) hide show
  1. package/dist/extensions/dashboard-server/api-contracts/embedder-health.js +11 -0
  2. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +238 -0
  3. package/dist/extensions/dashboard-server/api-contracts/endpoints/types.js +1 -0
  4. package/dist/extensions/dashboard-server/api-contracts/endpoints.js +5 -224
  5. package/dist/extensions/dashboard-server/api-contracts/rag-settings.js +10 -0
  6. package/dist/extensions/dashboard-server/api-contracts/raptor.js +8 -0
  7. package/dist/extensions/dashboard-server/api-contracts.test/_helpers.js +32 -0
  8. package/dist/extensions/dashboard-server/routes-cache.test/_helpers.js +48 -0
  9. package/dist/extensions/dashboard-server/routes-embedder-health.js +67 -0
  10. package/dist/extensions/dashboard-server/routes-rag-settings.js +169 -0
  11. package/dist/extensions/dashboard-server/routes-raptor.js +88 -0
  12. package/dist/extensions/dashboard-server/routes-setup.js +1 -1
  13. package/dist/extensions/dashboard-server/routes.js +3 -0
  14. package/dist/extensions/dashboard-server/server.js +7 -1
  15. package/dist/extensions/mega-cache-replay.test/_helpers.js +175 -0
  16. package/dist/extensions/mega-commands/dataCommands.js +151 -0
  17. package/dist/extensions/mega-commands/helpers.js +61 -0
  18. package/dist/extensions/mega-commands/historyCommands.js +97 -0
  19. package/dist/extensions/mega-commands/setupCommand.js +200 -0
  20. package/dist/extensions/mega-commands.js +14 -499
  21. package/dist/extensions/mega-compact-s38.test/_helpers.js +194 -0
  22. package/dist/extensions/mega-compact.test/_helpers.js +225 -0
  23. package/dist/extensions/mega-events/agent-handlers/agentEndHandler.js +211 -0
  24. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/cacheStripe.js +49 -0
  25. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/contextHealth.js +33 -0
  26. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/errorRetry.js +387 -0
  27. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/event.js +7 -0
  28. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/gameScoring.js +55 -0
  29. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/lengthStop.js +12 -0
  30. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/memoryReview.js +22 -0
  31. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/recordTurnRow.js +38 -0
  32. package/dist/extensions/mega-events/agent-handlers/turnEndHandler.js +36 -0
  33. package/dist/extensions/mega-events/agent-handlers.js +4 -799
  34. package/dist/extensions/mega-events/context-handler/afterCompact.js +163 -0
  35. package/dist/extensions/mega-events/context-handler/messageText.js +12 -0
  36. package/dist/extensions/mega-events/context-handler/tailResult.js +46 -0
  37. package/dist/extensions/mega-events/context-handler.js +11 -198
  38. package/dist/extensions/mega-events/separated-prompt.test/_helpers.js +25 -0
  39. package/dist/src/config.js +14 -5
  40. package/dist/src/dedup-engine.test/_helpers.js +55 -0
  41. package/dist/src/e2e.test/_helpers.js +52 -0
  42. package/dist/src/embedder.js +1 -0
  43. package/dist/src/httpEmbedder.js +6 -0
  44. package/dist/src/hyde.js +146 -0
  45. package/dist/src/importance.test/_helpers.js +5 -0
  46. package/dist/src/memoryGraph/sources/checkpoints.js +78 -0
  47. package/dist/src/memoryGraph/sources/edges.js +17 -0
  48. package/dist/src/memoryGraph/sources/flags.js +22 -0
  49. package/dist/src/memoryGraph/sources/helpers.js +14 -0
  50. package/dist/src/memoryGraph/sources/memories.js +88 -0
  51. package/dist/src/memoryGraph/sources/raptor.js +26 -0
  52. package/dist/src/memoryGraph/sources/turns.js +176 -0
  53. package/dist/src/memoryGraph/sources.js +15 -441
  54. package/dist/src/memoryGraph-gates.test/_helpers.js +120 -0
  55. package/dist/src/ratio.bench.test/_helpers.js +198 -0
  56. package/dist/src/recall/async.js +112 -0
  57. package/dist/src/recall/format.js +149 -0
  58. package/dist/src/recall/memory.js +62 -0
  59. package/dist/src/recall/reformulate.js +82 -0
  60. package/dist/src/recall/sync.js +170 -0
  61. package/dist/src/recall/types.js +1 -0
  62. package/dist/src/recall.js +13 -530
  63. package/dist/src/store/sqlite/schema/core.js +232 -0
  64. package/dist/src/store/sqlite/schema/game.js +65 -0
  65. package/dist/src/store/sqlite/schema/plan-v2.js +107 -0
  66. package/dist/src/store/sqlite/schema/turns.js +59 -0
  67. package/dist/src/store/sqlite/schema.js +8 -441
  68. package/dist/src/store/turns/contract-compliance.test/_helpers.js +21 -0
  69. package/dist/src/store/turns/sqlite-store/admin.js +171 -0
  70. package/dist/src/store/turns/sqlite-store/ctx.js +1 -0
  71. package/dist/src/store/turns/sqlite-store/read.js +111 -0
  72. package/dist/src/store/turns/sqlite-store/rows.js +42 -0
  73. package/dist/src/store/turns/sqlite-store/write.js +102 -0
  74. package/dist/src/store/turns/sqlite-store.js +31 -367
  75. package/dist/src/vectorStore/class.js +356 -0
  76. package/dist/src/vectorStore/hash.js +10 -0
  77. package/dist/src/vectorStore/types.js +2 -0
  78. package/dist/src/vectorStore.js +8 -359
  79. package/dist/src/vectorStore.test/_helpers.js +17 -0
  80. package/extensions/dashboard-client/dist/assets/{CacheTab-8HRroK9K.js → CacheTab-Cqnc7lMg.js} +2 -2
  81. package/extensions/dashboard-client/dist/assets/{CacheTab-8HRroK9K.js.map → CacheTab-Cqnc7lMg.js.map} +1 -1
  82. package/extensions/dashboard-client/dist/assets/{EventsTab-ncobZw-I.js → EventsTab-tYk3VFAp.js} +2 -2
  83. package/extensions/dashboard-client/dist/assets/{EventsTab-ncobZw-I.js.map → EventsTab-tYk3VFAp.js.map} +1 -1
  84. package/extensions/dashboard-client/dist/assets/{HealthTab-C6BI1EZG.js → HealthTab-D2_kjgxw.js} +2 -2
  85. package/extensions/dashboard-client/dist/assets/{HealthTab-C6BI1EZG.js.map → HealthTab-D2_kjgxw.js.map} +1 -1
  86. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js +2 -0
  87. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js.map +1 -0
  88. package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js +2 -0
  89. package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js.map +1 -0
  90. package/extensions/dashboard-client/dist/assets/{MetricsTab-B88XTCMk.js → MetricsTab-DT_XfL96.js} +2 -2
  91. package/extensions/dashboard-client/dist/assets/{MetricsTab-B88XTCMk.js.map → MetricsTab-DT_XfL96.js.map} +1 -1
  92. package/extensions/dashboard-client/dist/assets/{OverviewTab-CGZrSia-.js → OverviewTab-BY6KZCme.js} +2 -2
  93. package/extensions/dashboard-client/dist/assets/{OverviewTab-CGZrSia-.js.map → OverviewTab-BY6KZCme.js.map} +1 -1
  94. package/extensions/dashboard-client/dist/assets/{ReposTab-BZo5cNS1.js → ReposTab-CeS-tpDM.js} +2 -2
  95. package/extensions/dashboard-client/dist/assets/{ReposTab-BZo5cNS1.js.map → ReposTab-CeS-tpDM.js.map} +1 -1
  96. package/extensions/dashboard-client/dist/assets/{SessionsTab-C2RokJcw.js → SessionsTab-C30AwyoF.js} +2 -2
  97. package/extensions/dashboard-client/dist/assets/{SessionsTab-C2RokJcw.js.map → SessionsTab-C30AwyoF.js.map} +1 -1
  98. package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js +2 -0
  99. package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js.map +1 -0
  100. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CewYB2aA.js → TimeSavedCard-p55K1tFP.js} +2 -2
  101. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CewYB2aA.js.map → TimeSavedCard-p55K1tFP.js.map} +1 -1
  102. package/extensions/dashboard-client/dist/assets/{TopicsTab-DpVNIuaL.js → TopicsTab-D8FqyAbK.js} +2 -2
  103. package/extensions/dashboard-client/dist/assets/{TopicsTab-DpVNIuaL.js.map → TopicsTab-D8FqyAbK.js.map} +1 -1
  104. package/extensions/dashboard-client/dist/assets/{TurnsTab-KeuKKVC9.js → TurnsTab-ju-nXDys.js} +2 -2
  105. package/extensions/dashboard-client/dist/assets/{TurnsTab-KeuKKVC9.js.map → TurnsTab-ju-nXDys.js.map} +1 -1
  106. package/extensions/dashboard-client/dist/assets/{index-Cucgohga.js → index-BEj1Zahy.js} +9 -9
  107. package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js.map +1 -0
  108. package/extensions/dashboard-client/dist/assets/{useSSE-DJsqdPXC.js → useSSE-p1pOI_-P.js} +2 -2
  109. package/extensions/dashboard-client/dist/assets/{useSSE-DJsqdPXC.js.map → useSSE-p1pOI_-P.js.map} +1 -1
  110. package/extensions/dashboard-client/dist/index.html +1 -1
  111. package/extensions/dashboard-client/src/api/client.ts +33 -0
  112. package/extensions/dashboard-client/src/tabs/MaintenanceTab/ActionsCard.tsx +178 -0
  113. package/extensions/dashboard-client/src/tabs/MaintenanceTab/DbStatsCard.tsx +140 -0
  114. package/extensions/dashboard-client/src/tabs/MaintenanceTab/DebugBundleCard.tsx +109 -0
  115. package/extensions/dashboard-client/src/tabs/MaintenanceTab/HealthMitigationCard.tsx +98 -0
  116. package/extensions/dashboard-client/src/tabs/MaintenanceTab/SchemaHealthCard.tsx +108 -0
  117. package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +12 -598
  118. package/extensions/dashboard-client/src/tabs/MemoryMapTab/MemoryMapView.tsx +476 -0
  119. package/extensions/dashboard-client/src/tabs/MemoryMapTab/RaptorTreeView.tsx +163 -0
  120. package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +56 -466
  121. package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderHealthCard.tsx +109 -0
  122. package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +470 -0
  123. package/extensions/dashboard-client/src/tabs/SetupTab/RagSettingsCard.tsx +160 -0
  124. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +13 -483
  125. package/extensions/dashboard-server/api-contracts/embedder-health.ts +32 -0
  126. package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +383 -0
  127. package/extensions/dashboard-server/api-contracts/endpoints/types.ts +350 -0
  128. package/extensions/dashboard-server/api-contracts/endpoints.ts +27 -648
  129. package/extensions/dashboard-server/api-contracts/index.ts +14 -0
  130. package/extensions/dashboard-server/api-contracts/rag-settings.ts +42 -0
  131. package/extensions/dashboard-server/api-contracts/raptor.ts +49 -0
  132. package/extensions/dashboard-server/api-contracts.test/_helpers.ts +47 -0
  133. package/extensions/dashboard-server/routes-cache.test/_helpers.ts +94 -0
  134. package/extensions/dashboard-server/routes-embedder-health.ts +77 -0
  135. package/extensions/dashboard-server/routes-rag-settings.ts +207 -0
  136. package/extensions/dashboard-server/routes-raptor.ts +128 -0
  137. package/extensions/dashboard-server/routes-setup.ts +1 -1
  138. package/extensions/dashboard-server/routes.ts +3 -0
  139. package/extensions/dashboard-server/server.ts +6 -0
  140. package/extensions/mega-cache-replay.test/_helpers.ts +188 -0
  141. package/extensions/mega-commands/dataCommands.ts +169 -0
  142. package/extensions/mega-commands/helpers.ts +62 -0
  143. package/extensions/mega-commands/historyCommands.ts +117 -0
  144. package/extensions/mega-commands/setupCommand.ts +235 -0
  145. package/extensions/mega-commands.ts +25 -538
  146. package/extensions/mega-compact-s38.test/_helpers.ts +201 -0
  147. package/extensions/mega-compact.test/_helpers.ts +237 -0
  148. package/extensions/mega-events/agent-handlers/agentEndHandler.ts +238 -0
  149. package/extensions/mega-events/agent-handlers/turnEndHandler/cacheStripe.ts +74 -0
  150. package/extensions/mega-events/agent-handlers/turnEndHandler/contextHealth.ts +50 -0
  151. package/extensions/mega-events/agent-handlers/turnEndHandler/errorRetry.ts +421 -0
  152. package/extensions/mega-events/agent-handlers/turnEndHandler/event.ts +16 -0
  153. package/extensions/mega-events/agent-handlers/turnEndHandler/gameScoring.ts +73 -0
  154. package/extensions/mega-events/agent-handlers/turnEndHandler/lengthStop.ts +29 -0
  155. package/extensions/mega-events/agent-handlers/turnEndHandler/memoryReview.ts +42 -0
  156. package/extensions/mega-events/agent-handlers/turnEndHandler/recordTurnRow.ts +61 -0
  157. package/extensions/mega-events/agent-handlers/turnEndHandler.ts +64 -0
  158. package/extensions/mega-events/agent-handlers.ts +15 -861
  159. package/extensions/mega-events/context-handler/afterCompact.ts +213 -0
  160. package/extensions/mega-events/context-handler/messageText.ts +20 -0
  161. package/extensions/mega-events/context-handler/tailResult.ts +63 -0
  162. package/extensions/mega-events/context-handler.ts +17 -235
  163. package/extensions/mega-events/separated-prompt.test/_helpers.ts +35 -0
  164. package/package.json +1 -1
  165. package/src/config.ts +17 -5
  166. package/src/dedup-engine.test/_helpers.ts +79 -0
  167. package/src/e2e.test/_helpers.ts +59 -0
  168. package/src/embedder.ts +4 -0
  169. package/src/httpEmbedder.ts +7 -0
  170. package/src/hyde.ts +162 -0
  171. package/src/importance.test/_helpers.ts +5 -0
  172. package/src/memoryGraph/sources/checkpoints.ts +99 -0
  173. package/src/memoryGraph/sources/edges.ts +23 -0
  174. package/src/memoryGraph/sources/flags.ts +26 -0
  175. package/src/memoryGraph/sources/helpers.ts +13 -0
  176. package/src/memoryGraph/sources/memories.ts +108 -0
  177. package/src/memoryGraph/sources/raptor.ts +37 -0
  178. package/src/memoryGraph/sources/turns.ts +226 -0
  179. package/src/memoryGraph/sources.ts +19 -544
  180. package/src/memoryGraph-gates.test/_helpers.ts +164 -0
  181. package/src/ratio.bench.test/_helpers.ts +268 -0
  182. package/src/recall/async.ts +142 -0
  183. package/src/recall/format.ts +173 -0
  184. package/src/recall/memory.ts +90 -0
  185. package/src/recall/reformulate.ts +111 -0
  186. package/src/recall/sync.ts +197 -0
  187. package/src/recall/types.ts +63 -0
  188. package/src/recall.ts +25 -712
  189. package/src/store/sqlite/schema/core.ts +233 -0
  190. package/src/store/sqlite/schema/game.ts +66 -0
  191. package/src/store/sqlite/schema/plan-v2.ts +108 -0
  192. package/src/store/sqlite/schema/turns.ts +60 -0
  193. package/src/store/sqlite/schema.ts +13 -441
  194. package/src/store/turns/contract-compliance.test/_helpers.ts +38 -0
  195. package/src/store/turns/sqlite-store/admin.ts +249 -0
  196. package/src/store/turns/sqlite-store/ctx.ts +14 -0
  197. package/src/store/turns/sqlite-store/read.ts +174 -0
  198. package/src/store/turns/sqlite-store/rows.ts +55 -0
  199. package/src/store/turns/sqlite-store/write.ts +193 -0
  200. package/src/store/turns/sqlite-store.ts +33 -514
  201. package/src/vectorStore/class.ts +433 -0
  202. package/src/vectorStore/hash.ts +11 -0
  203. package/src/vectorStore/types.ts +58 -0
  204. package/src/vectorStore.test/_helpers.ts +20 -0
  205. package/src/vectorStore.ts +13 -489
  206. package/extensions/dashboard-client/dist/assets/MaintenanceTab-DZi1MnZI.js +0 -2
  207. package/extensions/dashboard-client/dist/assets/MaintenanceTab-DZi1MnZI.js.map +0 -1
  208. package/extensions/dashboard-client/dist/assets/MemoryMapTab-CjUa9zzw.js +0 -2
  209. package/extensions/dashboard-client/dist/assets/MemoryMapTab-CjUa9zzw.js.map +0 -1
  210. package/extensions/dashboard-client/dist/assets/SetupTab-C_BwmebC.js +0 -2
  211. package/extensions/dashboard-client/dist/assets/SetupTab-C_BwmebC.js.map +0 -1
  212. package/extensions/dashboard-client/dist/assets/index-Cucgohga.js.map +0 -1
@@ -0,0 +1,169 @@
1
+ /**
2
+ * dashboard-server/routes-rag-settings.ts — RAG Settings route handler.
3
+ *
4
+ * GET /api/rag-settings — Returns the state of all RAG feature flags (B1–B5).
5
+ * POST /api/rag-settings — Toggles flags by writing MEGACOMPACT_*_DISABLED
6
+ * lines to the per-repo .mega-compact.env file.
7
+ *
8
+ * Guardrails: PREVENT-PI-004 (loopback-only), PREVENT-001 (null-safe JSON),
9
+ * PREVENT-011 (no `any`). Each JSON write carries a guardrails-allow annotation.
10
+ */
11
+ import { readFileSync, existsSync, writeFileSync, mkdirSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { detectCurrentEmbedder } from "./routes-setup.js";
14
+ // ---------------------------------------------------------------------------
15
+ // RAG_FLAGS — the five feature flags surfaced by this panel.
16
+ // ---------------------------------------------------------------------------
17
+ const RAG_FLAGS = [
18
+ {
19
+ key: "MEGACOMPACT_QUERY_REFORMULATION",
20
+ label: "Query Reformulation",
21
+ description: "TF-IDF keyword expansion for vague recall queries (TrigramEmbedder path)",
22
+ requiresLlm: false,
23
+ },
24
+ {
25
+ key: "MEGACOMPACT_TIERED_ROUTER",
26
+ label: "Tiered Recall Router",
27
+ description: "L0 cache → L1 FTS5 → L2 HNSW routing for faster recall",
28
+ requiresLlm: false,
29
+ },
30
+ {
31
+ key: "MEGACOMPACT_RECALL_METRICS",
32
+ label: "Recall Quality Metrics",
33
+ description: "Precision/recall scoring and logging for recall evaluation",
34
+ requiresLlm: false,
35
+ },
36
+ {
37
+ key: "MEGACOMPACT_MEMORY_GRAPH",
38
+ label: "Memory Graph",
39
+ description: "Dashboard-oriented memory graph traversal across sessions",
40
+ requiresLlm: false,
41
+ },
42
+ {
43
+ key: "MEGACOMPACT_HYDE",
44
+ label: "HyDE (Hypothetical Document Embeddings)",
45
+ description: "Generate hypothetical answer via LLM, embed it, RRF-fuse with raw-query results",
46
+ requiresLlm: true,
47
+ },
48
+ ];
49
+ /** Strip any MEGACOMPACT_*_DISABLED assignment lines from env file content. */
50
+ const DISABLED_LINE = /^export\s+MEGACOMPACT_\w+_DISABLED=/;
51
+ function isDisabled(key) {
52
+ const v = process.env[key + "_DISABLED"];
53
+ return v === "true" || v === "1";
54
+ }
55
+ function readJsonBody(req, cb) {
56
+ let body = "";
57
+ let tooBig = false;
58
+ req.on("data", (chunk) => {
59
+ if (body.length > 65536) {
60
+ tooBig = true;
61
+ return;
62
+ }
63
+ body += chunk.toString();
64
+ });
65
+ req.on("end", () => {
66
+ if (tooBig)
67
+ return cb({ ok: false, error: "body_too_large" });
68
+ try {
69
+ const v = body ? JSON.parse(body) : {}; // PREVENT-001: parsed value type-checked below
70
+ if (typeof v !== "object" || v === null || Array.isArray(v)) {
71
+ return cb({ ok: false, error: "invalid_object" });
72
+ }
73
+ cb({ ok: true, value: v });
74
+ }
75
+ catch {
76
+ cb({ ok: false, error: "invalid_json" });
77
+ }
78
+ });
79
+ req.on("error", () => cb({ ok: false, error: "read_error" }));
80
+ }
81
+ // ---------------------------------------------------------------------------
82
+ // handleRagSettings — "/api/rag-settings"
83
+ // ---------------------------------------------------------------------------
84
+ export function handleRagSettings(req, res, ctx) {
85
+ if (req.url !== "/api/rag-settings")
86
+ return false;
87
+ if (req.method === "GET") {
88
+ const flags = RAG_FLAGS.map((f) => ({
89
+ key: f.key,
90
+ label: f.label,
91
+ description: f.description,
92
+ enabled: !isDisabled(f.key),
93
+ requiresLlm: f.requiresLlm,
94
+ }));
95
+ const body = {
96
+ flags,
97
+ llmActive: detectCurrentEmbedder() === "http",
98
+ };
99
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
100
+ res.writeHead(200, { "Content-Type": "application/json" });
101
+ res.end(JSON.stringify(body));
102
+ return true;
103
+ }
104
+ if (req.method === "POST") {
105
+ readJsonBody(req, (parsed) => {
106
+ if (!parsed.ok) {
107
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
108
+ res.writeHead(400, { "Content-Type": "application/json" });
109
+ res.end(JSON.stringify({ error: parsed.error }));
110
+ return;
111
+ }
112
+ const body = parsed.value;
113
+ const desired = body.flags;
114
+ if (typeof desired !== "object" || desired === null || Array.isArray(desired)) {
115
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
116
+ res.writeHead(400, { "Content-Type": "application/json" });
117
+ res.end(JSON.stringify({ error: "invalid_flags" }));
118
+ return;
119
+ }
120
+ // Only accept known RAG flag keys.
121
+ const known = new Set(RAG_FLAGS.map((f) => f.key));
122
+ for (const key of Object.keys(desired)) {
123
+ if (!known.has(key)) {
124
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
125
+ res.writeHead(400, { "Content-Type": "application/json" });
126
+ res.end(JSON.stringify({ error: `unknown_flag: ${key}` }));
127
+ return;
128
+ }
129
+ }
130
+ const envPath = join(ctx.stateDir, ".mega-compact.env");
131
+ let lines = [];
132
+ if (existsSync(envPath)) {
133
+ const content = readFileSync(envPath, "utf-8");
134
+ lines = content.split("\n").filter((line) => !DISABLED_LINE.test(line));
135
+ }
136
+ for (const key of Object.keys(desired)) {
137
+ if (desired[key] === false) {
138
+ lines.push(`export ${key}_DISABLED="true"`);
139
+ }
140
+ }
141
+ if (lines.length > 0 && lines[lines.length - 1] !== "")
142
+ lines.push("");
143
+ try {
144
+ mkdirSync(ctx.stateDir, { recursive: true });
145
+ writeFileSync(envPath, lines.join("\n"), "utf-8");
146
+ }
147
+ catch (e) {
148
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
149
+ res.writeHead(500, { "Content-Type": "application/json" });
150
+ res.end(JSON.stringify({
151
+ error: `write_failed: ${e instanceof Error ? e.message : String(e)}`,
152
+ }));
153
+ return;
154
+ }
155
+ const resp = {
156
+ envPath,
157
+ restartRequired: true,
158
+ };
159
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
160
+ res.writeHead(200, { "Content-Type": "application/json" });
161
+ res.end(JSON.stringify(resp));
162
+ });
163
+ return true;
164
+ }
165
+ // guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
166
+ res.writeHead(405, { "Content-Type": "application/json" });
167
+ res.end(JSON.stringify({ error: "method_not_allowed" }));
168
+ return true;
169
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * routes-raptor.ts — GET /api/raptor-tree route handler (Part B).
3
+ *
4
+ * Returns the hierarchical RAPTOR tree (summary nodes by level) for a session.
5
+ * When no sessionId is given, resolves to the most recent session that has
6
+ * raptor nodes. Reads only from the local SQLite store (PREVENT-PI-004 OK).
7
+ * Uses an inline require to the pi-agnostic src/store/sqlite/raptor.ts reader.
8
+ */
9
+ import { createRequire } from "node:module";
10
+ import { parse as parseUrl } from "node:url";
11
+ import { openStore } from "../../src/store/sqlite.js";
12
+ const _req = createRequire(import.meta.url);
13
+ /** Find the most recent sessionId that has raptor nodes (else null). */
14
+ function latestRaptorSession(stateDir) {
15
+ try {
16
+ const db = openStore(stateDir);
17
+ const row = db
18
+ .prepare("SELECT DISTINCT session_id FROM raptor_nodes ORDER BY built_at DESC LIMIT 1")
19
+ .get();
20
+ return row?.session_id ?? null;
21
+ }
22
+ catch {
23
+ // no raptor_nodes table yet (fresh DB) — treat as empty
24
+ return null;
25
+ }
26
+ }
27
+ function toDTO(node) {
28
+ return {
29
+ id: node.id,
30
+ sessionId: node.sessionId,
31
+ level: node.level,
32
+ parentId: node.parentId,
33
+ children: node.children,
34
+ summary: node.summary,
35
+ qualityMarker: node.qualityMarker,
36
+ tokenEstimate: node.tokenEstimate,
37
+ builtAt: node.builtAt,
38
+ };
39
+ }
40
+ function emptyResponse() {
41
+ return { nodes: [], levels: 0, rootId: null, builtAt: null, empty: true };
42
+ }
43
+ export function handleRaptorTree(req, res, ctx) {
44
+ if (req.method !== "GET")
45
+ return false;
46
+ const parsed = parseUrl(req.url ?? "", true);
47
+ if (parsed.pathname !== "/api/raptor-tree")
48
+ return false;
49
+ try {
50
+ const { listRaptorNodes } = _req("../../src/store/sqlite/raptor.js");
51
+ let sessionId = typeof parsed.query.sessionId === "string" ? parsed.query.sessionId : "";
52
+ if (!sessionId) {
53
+ sessionId = latestRaptorSession(ctx.stateDir) ?? "";
54
+ if (!sessionId) {
55
+ const body = emptyResponse();
56
+ res.writeHead(200, { "Content-Type": "application/json" });
57
+ res.end(JSON.stringify(body));
58
+ return true;
59
+ }
60
+ }
61
+ const nodes = listRaptorNodes(sessionId, ctx.stateDir);
62
+ if (nodes.length === 0) {
63
+ const body = emptyResponse();
64
+ res.writeHead(200, { "Content-Type": "application/json" });
65
+ res.end(JSON.stringify(body));
66
+ return true;
67
+ }
68
+ const dtos = nodes.map(toDTO);
69
+ const levels = dtos.reduce((m, n) => Math.max(m, n.level), 0);
70
+ const root = dtos.find((n) => n.parentId === null);
71
+ const builtAt = dtos.reduce((m, n) => Math.max(m, n.builtAt), 0);
72
+ const body = {
73
+ nodes: dtos,
74
+ levels,
75
+ rootId: root?.id ?? null,
76
+ builtAt,
77
+ empty: false,
78
+ };
79
+ res.writeHead(200, { "Content-Type": "application/json" });
80
+ res.end(JSON.stringify(body));
81
+ return true;
82
+ }
83
+ catch (e) {
84
+ res.writeHead(500, { "Content-Type": "application/json" });
85
+ res.end(JSON.stringify({ error: String(e) }));
86
+ return true;
87
+ }
88
+ }
@@ -15,7 +15,7 @@ import { join } from "node:path";
15
15
  // ---------------------------------------------------------------------------
16
16
  // handleSetupStatus — "/api/setup-status"
17
17
  // ---------------------------------------------------------------------------
18
- function detectCurrentEmbedder() {
18
+ export function detectCurrentEmbedder() {
19
19
  const url = process.env["MEGACOMPACT_EMBEDDING_URL"];
20
20
  const minilm = process.env["MEGACOMPACT_MINILM"];
21
21
  if (url && url.trim().length > 0)
@@ -15,5 +15,8 @@ export { handleProviderCache } from "./routes-cache.js";
15
15
  export { handleMemoryStatus } from "./routes-memory.js";
16
16
  export { handleSetupStatus, handleSetupDetect, handleSetupConfigure } from "./routes-setup.js";
17
17
  export { handleMemoryMap } from "./routes-memory-map.js";
18
+ export { handleRaptorTree } from "./routes-raptor.js";
18
19
  export { handleCacheStripes } from "./routes-cache.js";
19
20
  export { handleContextHealth, handleCachePoison, handleHealthSettings } from "./routes-health.js";
21
+ export { handleEmbedderHealth } from "./routes-embedder-health.js";
22
+ export { handleRagSettings } from "./routes-rag-settings.js";
@@ -12,7 +12,7 @@ import { join, dirname } from "node:path";
12
12
  import { fileURLToPath } from "node:url";
13
13
  import { createRequire } from "node:module";
14
14
  import { log, setLogPath, setDashboardServerVersion } from "./state.js";
15
- import { buildRouteContext, handleIndex, handleRepoIndex, handleEvents, handleGameState, handleGameScores, handlePerf, handleAchievements, handleSessions, handleTopics, handleTurns, handleMaintenance, handleProviderCache, handleCacheStripes, handleMemoryStatus, handleSetupStatus, handleSetupDetect, handleSetupConfigure, handleMemoryMap, handleContextHealth, handleCachePoison, handleHealthSettings, handleStatic, } from "./routes.js";
15
+ import { buildRouteContext, handleIndex, handleRepoIndex, handleEvents, handleGameState, handleGameScores, handlePerf, handleAchievements, handleSessions, handleTopics, handleTurns, handleMaintenance, handleProviderCache, handleCacheStripes, handleMemoryStatus, handleSetupStatus, handleSetupDetect, handleSetupConfigure, handleMemoryMap, handleRaptorTree, handleContextHealth, handleCachePoison, handleHealthSettings, handleEmbedderHealth, handleRagSettings, handleStatic, } from "./routes.js";
16
16
  export async function launchDashboardServer(stateDir) {
17
17
  // Our own package version — exposed at /api/version so the launcher can
18
18
  // detect a stale server (started by an older build) and replace it on
@@ -207,12 +207,18 @@ export async function launchDashboardServer(stateDir) {
207
207
  return;
208
208
  if (handleMemoryMap(req, res, ctx))
209
209
  return;
210
+ if (handleRaptorTree(req, res, ctx))
211
+ return;
210
212
  if (handleContextHealth(req, res, ctx))
211
213
  return;
212
214
  if (handleCachePoison(req, res, ctx))
213
215
  return;
214
216
  if (handleHealthSettings(req, res, ctx))
215
217
  return;
218
+ if (handleEmbedderHealth(req, res, ctx))
219
+ return;
220
+ if (handleRagSettings(req, res, ctx))
221
+ return;
216
222
  handleStatic(req, res, ctx);
217
223
  });
218
224
  // Bind base + range are env-configurable so tests can use a private,
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Shared helpers for the mega-cache-replay.test split files.
3
+ * Extracted from extensions/mega-cache-replay.test.ts: baseTmp, env, harness().
4
+ */
5
+ import { mkdtempSync } from "node:fs";
6
+ import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
8
+ import { createRequire } from "node:module";
9
+ export const baseTmp = mkdtempSync(join(tmpdir(), "mc-cache-"));
10
+ let counter = 0;
11
+ export function setupEnv() {
12
+ process.env.MEGACOMPACT_INDEX_DIR = join(baseTmp, "index");
13
+ process.env.MEGACOMPACT_PGLITE_DISABLED = "true";
14
+ }
15
+ export function harness() {
16
+ const stateDir = join(baseTmp, `run-${counter++}`);
17
+ process.env.MEGACOMPACT_STATE_DIR = stateDir;
18
+ process.env.MEGACOMPACT_DEBUG = "true";
19
+ process.env.MEGACOMPACT_THRESHOLD_TOKENS = "50";
20
+ process.env.MEGACOMPACT_FAST_GATE_PCT = "1";
21
+ process.env.MEGACOMPACT_ANCHOR_USER_MESSAGES = "1";
22
+ process.env.MEGACOMPACT_DURABLE_TRIM_FLOOR = "0";
23
+ process.env.MEGACOMPACT_MEMORY_AUTO_REVIEW = "false";
24
+ process.env.MEGACOMPACT_RAPTOR_ENABLED = "false";
25
+ process.env.MEGACOMPACT_L1_ENABLED = "false";
26
+ process.env.MEGACOMPACT_L2_ENABLED = "false";
27
+ delete process.env.MEGACOMPACT_LEGACY_DURABLE_TRIM;
28
+ const usage = {
29
+ tokens: 200000,
30
+ contextWindow: 200000,
31
+ percent: 100,
32
+ };
33
+ const handlers = {};
34
+ const compactCalls = [];
35
+ function msg(role, text, toolName) {
36
+ if (role === "assistant" && toolName) {
37
+ return {
38
+ role: "assistant",
39
+ content: [
40
+ { type: "toolCall", name: toolName, id: "c1", arguments: {} },
41
+ ],
42
+ api: "anthropic-messages",
43
+ provider: "anthropic",
44
+ model: "m",
45
+ usage: {
46
+ inputTokens: 1,
47
+ outputTokens: 1,
48
+ cacheReadTokens: 0,
49
+ cacheWriteTokens: 0,
50
+ },
51
+ stopReason: "tool_use",
52
+ timestamp: 0,
53
+ };
54
+ }
55
+ if (role === "toolResult" && toolName) {
56
+ return {
57
+ role: "toolResult",
58
+ content: [{ type: "text", text }],
59
+ toolCallId: "c1",
60
+ toolName,
61
+ isError: false,
62
+ timestamp: 0,
63
+ };
64
+ }
65
+ return {
66
+ role: "user",
67
+ content: text,
68
+ timestamp: 0,
69
+ };
70
+ }
71
+ function buildSession(tag, n) {
72
+ const s = [];
73
+ for (let i = 0; i < n; i++) {
74
+ s.push(msg("user", `[${tag}] we decided to use approach ${i} for module ${i}`));
75
+ s.push(msg("assistant", `[${tag}] edited module ${i}`, "Edit"));
76
+ s.push(msg("toolResult", `[${tag}] edited module ${i}`, "Edit"));
77
+ }
78
+ return s;
79
+ }
80
+ const toEntry = (m, i) => ({
81
+ type: "message",
82
+ id: `e${i}`,
83
+ parentId: null,
84
+ timestamp: String(i),
85
+ message: m,
86
+ });
87
+ const sessionManager = {
88
+ getSessionId: () => "sess_cache_001",
89
+ getEntries: () => buildSession("A", 14).map(toEntry),
90
+ getBranch: () => buildSession("A", 14).map(toEntry),
91
+ };
92
+ function makeCtx(over = {}) {
93
+ return {
94
+ ui: {
95
+ setStatus: () => { },
96
+ notify: () => { },
97
+ select: () => { },
98
+ confirm: async () => true,
99
+ input: async () => "",
100
+ setWidget: () => { },
101
+ },
102
+ mode: "tui",
103
+ hasUI: true,
104
+ cwd: stateDir,
105
+ sessionManager,
106
+ modelRegistry: {},
107
+ model: undefined,
108
+ isIdle: () => true,
109
+ isProjectTrusted: () => true,
110
+ signal: undefined,
111
+ abort: () => { },
112
+ hasPendingMessages: () => false,
113
+ shutdown: () => { },
114
+ getContextUsage: () => ({ ...usage }),
115
+ compact: (opts) => {
116
+ compactCalls.push(opts);
117
+ return undefined;
118
+ },
119
+ getSystemPrompt: () => "system base",
120
+ ...over,
121
+ };
122
+ }
123
+ const pi = {
124
+ on: (ev, h) => {
125
+ if (!handlers[ev])
126
+ handlers[ev] = [];
127
+ handlers[ev].push(h);
128
+ },
129
+ registerCommand: () => { },
130
+ registerTool: () => { },
131
+ registerShortcut: () => { },
132
+ registerFlag: () => { },
133
+ getFlag: () => undefined,
134
+ registerMessageRenderer: () => { },
135
+ registerEntryRenderer: () => { },
136
+ sendMessage: () => { },
137
+ sendUserMessage: () => { },
138
+ appendEntry: () => { },
139
+ setSessionName: () => { },
140
+ getSessionName: () => undefined,
141
+ setLabel: () => { },
142
+ exec: async () => ({ stdout: "", stderr: "", code: 0 }),
143
+ getActiveTools: () => [],
144
+ getAllTools: () => [],
145
+ setActiveTools: () => { },
146
+ getCommands: () => [],
147
+ setModel: async () => false,
148
+ getThinkingLevel: () => "off",
149
+ setThinkingLevel: () => { },
150
+ };
151
+ const require = createRequire(import.meta.url);
152
+ const mod = require("../mega-compact.js");
153
+ mod.default(pi);
154
+ const { lastRuntime } = require("../mega-events.js");
155
+ const fire = async (ev, event, ctx) => {
156
+ let r;
157
+ for (const h of handlers[ev] || [])
158
+ r = await h(event, ctx);
159
+ return r;
160
+ };
161
+ return {
162
+ stateDir,
163
+ handlers,
164
+ compactCalls,
165
+ fire,
166
+ ctx: makeCtx,
167
+ usage,
168
+ buildSession,
169
+ runtime: lastRuntime,
170
+ clearDebounce: () => {
171
+ if (lastRuntime)
172
+ lastRuntime.debounceUntil = 0;
173
+ },
174
+ };
175
+ }
@@ -0,0 +1,151 @@
1
+ import { sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
2
+ import { normalizeSessionId } from "../../src/store.js";
3
+ import { latestModelSnapshot, countInjectedGlobal, listRepoRegistry } from "../../src/store/sqlite.js";
4
+ import { loadMetrics, fpRate, p95, defaultMetricsPath } from "../../src/monitoring.js";
5
+ import { C, recentUserQuery } from "../mega-runtime.js";
6
+ import { runCompact, doRecall, doRecallAsync } from "../mega-pipeline.js";
7
+ import { vectorStats, vectorRepoStats, vectorDataInvariant } from "../../src/vectorStore.js";
8
+ /** Register the data/inspection commands (data group). */
9
+ export function registerDataCommands(pi, runtime, config) {
10
+ pi.registerCommand("mega-compact", {
11
+ description: "Compress current session context into the local vector store.",
12
+ handler: async (args, ctx) => {
13
+ try {
14
+ const sessionEntries = ctx.sessionManager.getEntries();
15
+ // Project entries (branch-aware) into the message view.
16
+ const messages = sessionEntries.flatMap((e) => sessionEntryToContextMessages(e));
17
+ const summaryArg = args.trim();
18
+ const ran = runCompact(pi, runtime, config, ctx, messages, summaryArg ? { summary: summaryArg } : {});
19
+ if ("skipped" in ran && ran.skipped) {
20
+ ctx.ui.notify("[mega-compact] Nothing to compact (session too small).");
21
+ return;
22
+ }
23
+ const r = ran.result;
24
+ ctx.ui.notify(`[mega-compact] ${r.deduped ? "region already compacted (deduped)" : `persisted ${r.checkpointId}`} · ` +
25
+ `${r.tokenEstimate} tok · ${runtime.currentStateDir}`);
26
+ }
27
+ catch (e) {
28
+ ctx.ui.notify(`[mega-compact] /mega-compact failed: ${String(e)}`);
29
+ }
30
+ },
31
+ });
32
+ pi.registerCommand("mega-recall", {
33
+ description: "Recall relevant compacted context from the vector store and inline it. Use --cross-repo to search all repos.",
34
+ handler: async (args, ctx) => {
35
+ try {
36
+ // S17: --cross-repo (or --cross repo) runs the async path over every repo's
37
+ // PGlite HNSW index (stricter cosine floor + source labels).
38
+ const crossRepo = /--cross[- ]repo\b/.test(args);
39
+ const query = args.replace(/--cross[- ]repo\b/, "").trim() || recentUserQuery(ctx);
40
+ if (!query) {
41
+ ctx.ui.notify("[mega-compact] /mega-recall needs a query or a prior user message.");
42
+ return;
43
+ }
44
+ const r = crossRepo
45
+ ? await doRecallAsync(runtime, config, ctx, query, "command", { crossRepo: true })
46
+ : doRecall(runtime, config, ctx, query, "command");
47
+ if (r.empty) {
48
+ runtime.logger.info("recall-empty", { query, crossRepo });
49
+ ctx.ui.notify(`[mega-compact] recall found nothing new for "${query}".`);
50
+ return;
51
+ }
52
+ // Stage the block so the next before_agent_start prepends it (actual
53
+ // injection). Report what was selected now for immediate feedback.
54
+ runtime.pendingRecallBlock = r.block;
55
+ const list = r.report.map((l) => l).join("\n");
56
+ runtime.logger.info("recall", { query, crossRepo, injected: r.toInject.map((h) => h.checkpoint.checkpointId) });
57
+ runtime.setStatus(ctx, `mega-compact: recalled ${r.toInject.length} chkpt${crossRepo ? " (cross-repo)" : ""}`);
58
+ ctx.ui.notify(`[mega-compact] recall staged ${r.toInject.length} checkpoint(s) for "${query}"${crossRepo ? " (cross-repo)" : ""}:\n${list}\n` +
59
+ `(injected at the tail of the next turn's context)`);
60
+ }
61
+ catch (e) {
62
+ ctx.ui.notify(`[mega-compact] /mega-recall failed: ${String(e)}`);
63
+ }
64
+ },
65
+ });
66
+ pi.registerCommand("mega-status", {
67
+ description: "Show mega-compact config, context usage, and the data-safety invariant.",
68
+ handler: async (_args, ctx) => {
69
+ try {
70
+ runtime.bindRepo(ctx.cwd);
71
+ const usage = ctx.getContextUsage();
72
+ const pct = usage?.percent != null ? `${usage.percent}%` : "n/a";
73
+ const tokens = usage?.tokens != null ? `${usage.tokens} tok` : "n/a";
74
+ const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
75
+ const st = vectorStats(runtime.store, sid);
76
+ const repo = vectorRepoStats(runtime.store);
77
+ const di = vectorDataInvariant(runtime.store);
78
+ const fmtB = (b) => b >= 1_048_576 ? `${(b / 1_048_576).toFixed(1)} MiB` :
79
+ b >= 1024 ? `${(b / 1024).toFixed(1)} KiB` : `${b} B`;
80
+ // Real cost: tokens saved × the captured model's input rate (USD/token),
81
+ // read from the model_snapshots table (Phase 5b schema). Falls back to 0
82
+ // when no model has been captured yet. contextWindow ÷ savedRate = context
83
+ // windows extended (how much "extra" conversation the freed space buys).
84
+ const model = latestModelSnapshot(runtime.currentStateDir);
85
+ const rate = model?.inputRate ?? 0;
86
+ const usd = ((repo.tokensSaved ?? 0) * rate).toFixed(4);
87
+ const ctxWindow = usage?.contextWindow ?? 0;
88
+ const daysExtended = ctxWindow > 0 && repo.tokensSaved > 0
89
+ ? (repo.tokensSaved / ctxWindow).toFixed(1)
90
+ : "0";
91
+ // Identified model/provider (captured on model_select / session_start).
92
+ // Shows the human model name + provider so the user knows WHICH model's
93
+ // pricing drives the cost figure. Falls back when none captured yet.
94
+ const modelStr = model
95
+ ? `${model.modelName ?? model.modelId ?? "?"} · ${model.providerName ?? model.provider ?? "?"}`
96
+ : "unknown (no model captured)";
97
+ const costStr = `≈ $${usd} saved · ${daysExtended} context-windows extended`;
98
+ // Recall-quality badge (Phase 4): trust score from monitoring metrics.
99
+ // H1 fix: loadMetrics expects a *file* path (dashboard.json), not the
100
+ // state dir — passing the dir made existsSync() true (dirs exist) then
101
+ // readFileSync() threw EISDIR, silently caught → metrics always zero.
102
+ const m = loadMetrics(defaultMetricsPath(runtime.currentStateDir));
103
+ const fp = fpRate(m, "L2");
104
+ const p95L2 = p95(m.latency.L2 ?? []);
105
+ const relPct = (st.dedupHitRate * 100).toFixed(0);
106
+ const qualityStr = `recall ${relPct}% relevant · FP ${(fp * 100).toFixed(1)}% · L2 p95 ${p95L2.toFixed(0)}ms`;
107
+ // S18: cross-repo stats from the machine-wide index (best-effort; the
108
+ // index dir may be unset → 0/empty, never throws).
109
+ let crossRepoInjections = 0;
110
+ let repoCount = 0;
111
+ try {
112
+ crossRepoInjections = countInjectedGlobal(process.env.MEGACOMPACT_INDEX_DIR);
113
+ repoCount = listRepoRegistry(process.env.MEGACOMPACT_INDEX_DIR).length;
114
+ }
115
+ catch { /* non-fatal */ }
116
+ const crossRepoStr = `${crossRepoInjections} cross-repo injections recorded · ${repoCount} repos indexed`;
117
+ // Effective compaction threshold = tierPct × model context window (kept
118
+ // BELOW pi's native ~80% auto-compact for any model size). Falls back to
119
+ // the boot token value when the window is unknown (custom tier / pre-
120
+ // model-select). Display matches the dashboard's percentage-based view.
121
+ const effThreshold = config.tierPct != null && ctxWindow > 0
122
+ ? Math.round(config.tierPct * ctxWindow)
123
+ : config.thresholdTokens;
124
+ const winStr = ctxWindow > 0
125
+ ? (ctxWindow >= 1_000_000 ? `${Math.round(ctxWindow / 1_000_000)}M` : `${Math.round(ctxWindow / 1_000)}k`)
126
+ : "?";
127
+ const tierPctStr = config.tierPct != null ? `${Math.round(config.tierPct * 100)}%` : "n/a";
128
+ ctx.ui.notify(`[mega-compact] pct=${pct} tokens=${tokens} tier=${runtime.pressureBand} (live) preset=${config.tier} ` +
129
+ `pressure=${Math.round(runtime.pressure * 100)}% fastGate=${config.fastGatePct}% ` +
130
+ `threshold=${effThreshold.toLocaleString()} (${tierPctStr} of ${winStr} window) tierPct=${config.tierPct != null ? config.tierPct.toFixed(2) : "n/a"} auto=${config.auto} autoInline=${config.autoInline}\n` +
131
+ `[mega-compact] store: ${st.checkpointCount} chkpt · ` +
132
+ `${st.totalTokenEstimate} tok · last=${st.lastCheckpointId ?? "—"} · ` +
133
+ `injected=${st.injectedCount} · dedup=${(st.dedupHitRate * 100).toFixed(0)}%\n` +
134
+ `[mega-compact] anchor=${config.anchorUserMessages} preserveRecent=${config.preserveRecent} ` +
135
+ `autoInlineK=${config.autoInlineK} dedupSim=${config.dedupSim} debug=${config.debug}\n` +
136
+ `[mega-compact] 🛡 data-safe: ${di.regionsRetained} regions retained ` +
137
+ `(${fmtB(di.compressedOriginalBytes)} compressed-original) · ` +
138
+ `${di.duplicatesCollapsed} dedup-duplicates collapsed · ` +
139
+ `${C.green}0 bytes permanently deleted${C.reset}\n` +
140
+ `[mega-compact] 💰 ${costStr}\n` +
141
+ `[mega-compact] 🤖 model: ${modelStr}\n` +
142
+ `[mega-compact] 🎯 ${qualityStr}\n` +
143
+ `[mega-compact] 🌐 ${crossRepoStr}\n` +
144
+ `[mega-compact] stateDir=${runtime.currentStateDir}`);
145
+ }
146
+ catch (e) {
147
+ ctx.ui.notify(`[mega-compact] /mega-status error: ${String(e)}`);
148
+ }
149
+ },
150
+ });
151
+ }