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
@@ -23,5 +23,8 @@ export { handleProviderCache } from "./routes-cache.js";
23
23
  export { handleMemoryStatus } from "./routes-memory.js";
24
24
  export { handleSetupStatus, handleSetupDetect, handleSetupConfigure } from "./routes-setup.js";
25
25
  export { handleMemoryMap } from "./routes-memory-map.js";
26
+ export { handleRaptorTree } from "./routes-raptor.js";
26
27
  export { handleCacheStripes } from "./routes-cache.js";
27
28
  export { handleContextHealth, handleCachePoison, handleHealthSettings } from "./routes-health.js";
29
+ export { handleEmbedderHealth } from "./routes-embedder-health.js";
30
+ export { handleRagSettings } from "./routes-rag-settings.js";
@@ -44,9 +44,12 @@ import {
44
44
  handleSetupDetect,
45
45
  handleSetupConfigure,
46
46
  handleMemoryMap,
47
+ handleRaptorTree,
47
48
  handleContextHealth,
48
49
  handleCachePoison,
49
50
  handleHealthSettings,
51
+ handleEmbedderHealth,
52
+ handleRagSettings,
50
53
  handleStatic,
51
54
  } from "./routes.js";
52
55
 
@@ -242,9 +245,12 @@ export async function launchDashboardServer(
242
245
  if (handleSetupDetect(req, res, ctx)) return;
243
246
  if (handleSetupConfigure(req, res, ctx)) return;
244
247
  if (handleMemoryMap(req, res, ctx)) return;
248
+ if (handleRaptorTree(req, res, ctx)) return;
245
249
  if (handleContextHealth(req, res, ctx)) return;
246
250
  if (handleCachePoison(req, res, ctx)) return;
247
251
  if (handleHealthSettings(req, res, ctx)) return;
252
+ if (handleEmbedderHealth(req, res, ctx)) return;
253
+ if (handleRagSettings(req, res, ctx)) return;
248
254
  handleStatic(req, res, ctx);
249
255
  });
250
256
 
@@ -0,0 +1,188 @@
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
+ import type { AgentMessage } from "@earendil-works/pi-agent-core";
10
+
11
+ export const baseTmp = mkdtempSync(join(tmpdir(), "mc-cache-"));
12
+
13
+ let counter = 0;
14
+
15
+ export function setupEnv(): void {
16
+ process.env.MEGACOMPACT_INDEX_DIR = join(baseTmp, "index");
17
+ process.env.MEGACOMPACT_PGLITE_DISABLED = "true";
18
+ }
19
+
20
+ export function harness() {
21
+ const stateDir = join(baseTmp, `run-${counter++}`);
22
+ process.env.MEGACOMPACT_STATE_DIR = stateDir;
23
+ process.env.MEGACOMPACT_DEBUG = "true";
24
+ process.env.MEGACOMPACT_THRESHOLD_TOKENS = "50";
25
+ process.env.MEGACOMPACT_FAST_GATE_PCT = "1";
26
+ process.env.MEGACOMPACT_ANCHOR_USER_MESSAGES = "1";
27
+ process.env.MEGACOMPACT_DURABLE_TRIM_FLOOR = "0";
28
+ process.env.MEGACOMPACT_MEMORY_AUTO_REVIEW = "false";
29
+ process.env.MEGACOMPACT_RAPTOR_ENABLED = "false";
30
+ process.env.MEGACOMPACT_L1_ENABLED = "false";
31
+ process.env.MEGACOMPACT_L2_ENABLED = "false";
32
+ delete process.env.MEGACOMPACT_LEGACY_DURABLE_TRIM;
33
+
34
+ const usage = {
35
+ tokens: 200000,
36
+ contextWindow: 200000,
37
+ percent: 100 as number | null,
38
+ };
39
+
40
+ const handlers: Record<string, Function[]> = {};
41
+ const compactCalls: any[] = [];
42
+
43
+ function msg(role: string, text: string, toolName?: string): AgentMessage {
44
+ if (role === "assistant" && toolName) {
45
+ return {
46
+ role: "assistant",
47
+ content: [
48
+ { type: "toolCall", name: toolName, id: "c1", arguments: {} },
49
+ ],
50
+ api: "anthropic-messages",
51
+ provider: "anthropic",
52
+ model: "m",
53
+ usage: {
54
+ inputTokens: 1,
55
+ outputTokens: 1,
56
+ cacheReadTokens: 0,
57
+ cacheWriteTokens: 0,
58
+ },
59
+ stopReason: "tool_use",
60
+ timestamp: 0,
61
+ } as unknown as AgentMessage;
62
+ }
63
+ if (role === "toolResult" && toolName) {
64
+ return {
65
+ role: "toolResult",
66
+ content: [{ type: "text", text }],
67
+ toolCallId: "c1",
68
+ toolName,
69
+ isError: false,
70
+ timestamp: 0,
71
+ } as unknown as AgentMessage;
72
+ }
73
+ return {
74
+ role: "user",
75
+ content: text,
76
+ timestamp: 0,
77
+ } as unknown as AgentMessage;
78
+ }
79
+
80
+ function buildSession(tag: string, n: number): AgentMessage[] {
81
+ const s: AgentMessage[] = [];
82
+ for (let i = 0; i < n; i++) {
83
+ s.push(
84
+ msg("user", `[${tag}] we decided to use approach ${i} for module ${i}`),
85
+ );
86
+ s.push(msg("assistant", `[${tag}] edited module ${i}`, "Edit"));
87
+ s.push(msg("toolResult", `[${tag}] edited module ${i}`, "Edit"));
88
+ }
89
+ return s;
90
+ }
91
+
92
+ const toEntry = (m: AgentMessage, i: number): any => ({
93
+ type: "message",
94
+ id: `e${i}`,
95
+ parentId: null,
96
+ timestamp: String(i),
97
+ message: m,
98
+ });
99
+ const sessionManager = {
100
+ getSessionId: () => "sess_cache_001",
101
+ getEntries: () => buildSession("A", 14).map(toEntry),
102
+ getBranch: () => buildSession("A", 14).map(toEntry),
103
+ };
104
+
105
+ function makeCtx(over: Partial<any> = {}) {
106
+ return {
107
+ ui: {
108
+ setStatus: () => {},
109
+ notify: () => {},
110
+ select: () => {},
111
+ confirm: async () => true,
112
+ input: async () => "",
113
+ setWidget: () => {},
114
+ },
115
+ mode: "tui" as any,
116
+ hasUI: true,
117
+ cwd: stateDir,
118
+ sessionManager,
119
+ modelRegistry: {} as any,
120
+ model: undefined,
121
+ isIdle: () => true,
122
+ isProjectTrusted: () => true,
123
+ signal: undefined,
124
+ abort: () => {},
125
+ hasPendingMessages: () => false,
126
+ shutdown: () => {},
127
+ getContextUsage: () => ({ ...usage }),
128
+ compact: (opts?: any) => {
129
+ compactCalls.push(opts);
130
+ return undefined;
131
+ },
132
+ getSystemPrompt: () => "system base",
133
+ ...over,
134
+ } as any;
135
+ }
136
+
137
+ const pi = {
138
+ on: (ev: string, h: Function) => {
139
+ if (!handlers[ev]) handlers[ev] = [];
140
+ handlers[ev].push(h);
141
+ },
142
+ registerCommand: () => {},
143
+ registerTool: () => {},
144
+ registerShortcut: () => {},
145
+ registerFlag: () => {},
146
+ getFlag: () => undefined,
147
+ registerMessageRenderer: () => {},
148
+ registerEntryRenderer: () => {},
149
+ sendMessage: () => {},
150
+ sendUserMessage: () => {},
151
+ appendEntry: () => {},
152
+ setSessionName: () => {},
153
+ getSessionName: () => undefined,
154
+ setLabel: () => {},
155
+ exec: async () => ({ stdout: "", stderr: "", code: 0 }),
156
+ getActiveTools: () => [],
157
+ getAllTools: () => [],
158
+ setActiveTools: () => {},
159
+ getCommands: () => [],
160
+ setModel: async () => false,
161
+ getThinkingLevel: () => "off" as any,
162
+ setThinkingLevel: () => {},
163
+ } as any;
164
+
165
+ const require = createRequire(import.meta.url);
166
+ const mod = require("../mega-compact.js") as { default: (p: any) => void };
167
+ mod.default(pi);
168
+ const { lastRuntime } = require("../mega-events.js") as { lastRuntime: any };
169
+
170
+ const fire = async (ev: string, event: any, ctx: any) => {
171
+ let r: any;
172
+ for (const h of handlers[ev] || []) r = await h(event, ctx);
173
+ return r;
174
+ };
175
+ return {
176
+ stateDir,
177
+ handlers,
178
+ compactCalls,
179
+ fire,
180
+ ctx: makeCtx,
181
+ usage,
182
+ buildSession,
183
+ runtime: lastRuntime,
184
+ clearDebounce: () => {
185
+ if (lastRuntime) lastRuntime.debounceUntil = 0;
186
+ },
187
+ };
188
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * mega-commands/dataCommands.ts — the data/inspection slash commands (data group).
3
+ *
4
+ * Extracted from mega-commands.ts (delegate-shell split). Registers
5
+ * /mega-compact, /mega-recall, and /mega-status.
6
+ */
7
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
8
+ import { sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
9
+ import { normalizeSessionId } from "../../src/store.js";
10
+ import { latestModelSnapshot, countInjectedGlobal, listRepoRegistry } from "../../src/store/sqlite.js";
11
+ import { loadMetrics, fpRate, p95, defaultMetricsPath } from "../../src/monitoring.js";
12
+ import { type MegaRuntime, C, recentUserQuery } from "../mega-runtime.js";
13
+ import { runCompact, doRecall, doRecallAsync } from "../mega-pipeline.js";
14
+ import { vectorStats, vectorRepoStats, vectorDataInvariant } from "../../src/vectorStore.js";
15
+ import type { MegaConfig } from "../mega-config.js";
16
+
17
+ /** Register the data/inspection commands (data group). */
18
+ export function registerDataCommands(
19
+ pi: ExtensionAPI,
20
+ runtime: MegaRuntime,
21
+ config: MegaConfig,
22
+ ): void {
23
+ pi.registerCommand("mega-compact", {
24
+ description: "Compress current session context into the local vector store.",
25
+ handler: async (args: string, ctx: ExtensionContext) => {
26
+ try {
27
+ const sessionEntries = ctx.sessionManager.getEntries();
28
+ // Project entries (branch-aware) into the message view.
29
+ const messages = sessionEntries.flatMap((e) => sessionEntryToContextMessages(e));
30
+ const summaryArg = args.trim();
31
+ const ran = runCompact(pi, runtime, config, ctx, messages, summaryArg ? { summary: summaryArg } : {});
32
+ if ("skipped" in ran && ran.skipped) {
33
+ ctx.ui.notify("[mega-compact] Nothing to compact (session too small).");
34
+ return;
35
+ }
36
+ const r = (ran as { result: { deduped: boolean; checkpointId?: string; tokenEstimate: number } }).result;
37
+ ctx.ui.notify(
38
+ `[mega-compact] ${r.deduped ? "region already compacted (deduped)" : `persisted ${r.checkpointId}`} · ` +
39
+ `${r.tokenEstimate} tok · ${runtime.currentStateDir}`,
40
+ );
41
+ } catch (e) {
42
+ ctx.ui.notify(`[mega-compact] /mega-compact failed: ${String(e)}`);
43
+ }
44
+ },
45
+ });
46
+
47
+ pi.registerCommand("mega-recall", {
48
+ description: "Recall relevant compacted context from the vector store and inline it. Use --cross-repo to search all repos.",
49
+ handler: async (args: string, ctx: ExtensionContext) => {
50
+ try {
51
+ // S17: --cross-repo (or --cross repo) runs the async path over every repo's
52
+ // PGlite HNSW index (stricter cosine floor + source labels).
53
+ const crossRepo = /--cross[- ]repo\b/.test(args);
54
+ const query = args.replace(/--cross[- ]repo\b/, "").trim() || recentUserQuery(ctx);
55
+ if (!query) {
56
+ ctx.ui.notify("[mega-compact] /mega-recall needs a query or a prior user message.");
57
+ return;
58
+ }
59
+ const r = crossRepo
60
+ ? await doRecallAsync(runtime, config, ctx, query, "command", { crossRepo: true })
61
+ : doRecall(runtime, config, ctx, query, "command");
62
+ if (r.empty) {
63
+ runtime.logger.info("recall-empty", { query, crossRepo });
64
+ ctx.ui.notify(`[mega-compact] recall found nothing new for "${query}".`);
65
+ return;
66
+ }
67
+ // Stage the block so the next before_agent_start prepends it (actual
68
+ // injection). Report what was selected now for immediate feedback.
69
+ runtime.pendingRecallBlock = r.block;
70
+ const list = r.report.map((l) => l).join("\n");
71
+ runtime.logger.info("recall", { query, crossRepo, injected: r.toInject.map((h) => h.checkpoint.checkpointId) });
72
+ runtime.setStatus(ctx, `mega-compact: recalled ${r.toInject.length} chkpt${crossRepo ? " (cross-repo)" : ""}`);
73
+ ctx.ui.notify(
74
+ `[mega-compact] recall staged ${r.toInject.length} checkpoint(s) for "${query}"${crossRepo ? " (cross-repo)" : ""}:\n${list}\n` +
75
+ `(injected at the tail of the next turn's context)`,
76
+ );
77
+ } catch (e) {
78
+ ctx.ui.notify(`[mega-compact] /mega-recall failed: ${String(e)}`);
79
+ }
80
+ },
81
+ });
82
+
83
+ pi.registerCommand("mega-status", {
84
+ description: "Show mega-compact config, context usage, and the data-safety invariant.",
85
+ handler: async (_args: string, ctx: ExtensionContext) => {
86
+ try {
87
+ runtime.bindRepo(ctx.cwd);
88
+ const usage = ctx.getContextUsage();
89
+ const pct = usage?.percent != null ? `${usage.percent}%` : "n/a";
90
+ const tokens = usage?.tokens != null ? `${usage.tokens} tok` : "n/a";
91
+ const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
92
+ const st = vectorStats(runtime.store, sid);
93
+ const repo = vectorRepoStats(runtime.store);
94
+ const di = vectorDataInvariant(runtime.store);
95
+ const fmtB = (b: number) =>
96
+ b >= 1_048_576 ? `${(b / 1_048_576).toFixed(1)} MiB` :
97
+ b >= 1024 ? `${(b / 1024).toFixed(1)} KiB` : `${b} B`;
98
+ // Real cost: tokens saved × the captured model's input rate (USD/token),
99
+ // read from the model_snapshots table (Phase 5b schema). Falls back to 0
100
+ // when no model has been captured yet. contextWindow ÷ savedRate = context
101
+ // windows extended (how much "extra" conversation the freed space buys).
102
+ const model = latestModelSnapshot(runtime.currentStateDir);
103
+ const rate = model?.inputRate ?? 0;
104
+ const usd = ((repo.tokensSaved ?? 0) * rate).toFixed(4);
105
+ const ctxWindow = usage?.contextWindow ?? 0;
106
+ const daysExtended = ctxWindow > 0 && repo.tokensSaved > 0
107
+ ? (repo.tokensSaved / ctxWindow).toFixed(1)
108
+ : "0";
109
+ // Identified model/provider (captured on model_select / session_start).
110
+ // Shows the human model name + provider so the user knows WHICH model's
111
+ // pricing drives the cost figure. Falls back when none captured yet.
112
+ const modelStr = model
113
+ ? `${model.modelName ?? model.modelId ?? "?"} · ${model.providerName ?? model.provider ?? "?"}`
114
+ : "unknown (no model captured)";
115
+ const costStr = `≈ $${usd} saved · ${daysExtended} context-windows extended`;
116
+ // Recall-quality badge (Phase 4): trust score from monitoring metrics.
117
+ // H1 fix: loadMetrics expects a *file* path (dashboard.json), not the
118
+ // state dir — passing the dir made existsSync() true (dirs exist) then
119
+ // readFileSync() threw EISDIR, silently caught → metrics always zero.
120
+ const m = loadMetrics(defaultMetricsPath(runtime.currentStateDir));
121
+ const fp = fpRate(m, "L2");
122
+ const p95L2 = p95(m.latency.L2 ?? []);
123
+ const relPct = (st.dedupHitRate * 100).toFixed(0);
124
+ const qualityStr = `recall ${relPct}% relevant · FP ${(fp * 100).toFixed(1)}% · L2 p95 ${p95L2.toFixed(0)}ms`;
125
+ // S18: cross-repo stats from the machine-wide index (best-effort; the
126
+ // index dir may be unset → 0/empty, never throws).
127
+ let crossRepoInjections = 0;
128
+ let repoCount = 0;
129
+ try {
130
+ crossRepoInjections = countInjectedGlobal(process.env.MEGACOMPACT_INDEX_DIR);
131
+ repoCount = listRepoRegistry(process.env.MEGACOMPACT_INDEX_DIR).length;
132
+ } catch { /* non-fatal */ }
133
+ const crossRepoStr = `${crossRepoInjections} cross-repo injections recorded · ${repoCount} repos indexed`;
134
+ // Effective compaction threshold = tierPct × model context window (kept
135
+ // BELOW pi's native ~80% auto-compact for any model size). Falls back to
136
+ // the boot token value when the window is unknown (custom tier / pre-
137
+ // model-select). Display matches the dashboard's percentage-based view.
138
+ const effThreshold = config.tierPct != null && ctxWindow > 0
139
+ ? Math.round(config.tierPct * ctxWindow)
140
+ : config.thresholdTokens;
141
+ const winStr = ctxWindow > 0
142
+ ? (ctxWindow >= 1_000_000 ? `${Math.round(ctxWindow / 1_000_000)}M` : `${Math.round(ctxWindow / 1_000)}k`)
143
+ : "?";
144
+ const tierPctStr = config.tierPct != null ? `${Math.round(config.tierPct * 100)}%` : "n/a";
145
+ ctx.ui.notify(
146
+ `[mega-compact] pct=${pct} tokens=${tokens} tier=${runtime.pressureBand} (live) preset=${config.tier} ` +
147
+ `pressure=${Math.round(runtime.pressure * 100)}% fastGate=${config.fastGatePct}% ` +
148
+ `threshold=${effThreshold.toLocaleString()} (${tierPctStr} of ${winStr} window) tierPct=${config.tierPct != null ? config.tierPct.toFixed(2) : "n/a"} auto=${config.auto} autoInline=${config.autoInline}\n` +
149
+ `[mega-compact] store: ${st.checkpointCount} chkpt · ` +
150
+ `${st.totalTokenEstimate} tok · last=${st.lastCheckpointId ?? "—"} · ` +
151
+ `injected=${st.injectedCount} · dedup=${(st.dedupHitRate * 100).toFixed(0)}%\n` +
152
+ `[mega-compact] anchor=${config.anchorUserMessages} preserveRecent=${config.preserveRecent} ` +
153
+ `autoInlineK=${config.autoInlineK} dedupSim=${config.dedupSim} debug=${config.debug}\n` +
154
+ `[mega-compact] 🛡 data-safe: ${di.regionsRetained} regions retained ` +
155
+ `(${fmtB(di.compressedOriginalBytes)} compressed-original) · ` +
156
+ `${di.duplicatesCollapsed} dedup-duplicates collapsed · ` +
157
+ `${C.green}0 bytes permanently deleted${C.reset}\n` +
158
+ `[mega-compact] 💰 ${costStr}\n` +
159
+ `[mega-compact] 🤖 model: ${modelStr}\n` +
160
+ `[mega-compact] 🎯 ${qualityStr}\n` +
161
+ `[mega-compact] 🌐 ${crossRepoStr}\n` +
162
+ `[mega-compact] stateDir=${runtime.currentStateDir}`,
163
+ );
164
+ } catch (e) {
165
+ ctx.ui.notify(`[mega-compact] /mega-status error: ${String(e)}`);
166
+ }
167
+ },
168
+ });
169
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * mega-commands/helpers.ts — shared helpers for the data/inspection commands.
3
+ *
4
+ * Extracted from mega-commands.ts (delegate-shell split). findCheckpoint
5
+ * resolves a checkpoint by id (or "recent"/"last"); checkRecallQuality peeks at
6
+ * recent events.log / mega-compact.log for low recall-quality signals.
7
+ */
8
+ import type { MegaRuntime } from "../mega-runtime.js";
9
+ import { listCheckpoints } from "../../src/store/sqlite.js";
10
+ import { defaultEventsPath } from "../../src/monitoring.js";
11
+ import { existsSync, readFileSync } from "node:fs";
12
+ import path from "node:path";
13
+
14
+ /** Resolve a checkpoint by id (or "recent"/"last") from this session's store. */
15
+ export function findCheckpoint(runtime: MegaRuntime, sid: string, ref: string) {
16
+ const all = listCheckpoints(sid, runtime.currentStateDir);
17
+ if (all.length === 0) return undefined;
18
+ if (!ref || ref === "recent" || ref === "last") return all[all.length - 1];
19
+ return all.find((c) => c.checkpointId === ref) ?? all.find((c) => c.checkpointId.endsWith(ref));
20
+ }
21
+
22
+ /**
23
+ * Try to peek at recent events.log and mega-compact.log for low recall quality signals.
24
+ * Best-effort, non-fatal — returns true if a low-quality signal was found.
25
+ */
26
+ export function checkRecallQuality(stateDir: string): boolean {
27
+ const eventPaths = [
28
+ defaultEventsPath(stateDir),
29
+ path.join(stateDir, "mega-compact.log"),
30
+ ];
31
+ for (const fp of eventPaths) {
32
+ try {
33
+ if (!existsSync(fp)) continue;
34
+ const buf = readFileSync(fp, { encoding: "utf-8" });
35
+ // Only scan last 64 KiB of the file
36
+ const tail = buf.length > 65536 ? buf.slice(buf.length - 65536) : buf;
37
+ const lines = tail.split("\n").filter(Boolean);
38
+ for (const line of lines) {
39
+ try {
40
+ // guardrails-allow PREVENT-001: JSON.parse with null check
41
+ const parsed = JSON.parse(line);
42
+ if (typeof parsed !== "object" || parsed === null) continue;
43
+ // Check for recall_metrics_low_quality event (latest format)
44
+ if (parsed.event === "recall_metrics_low_quality" && parsed.score !== undefined) {
45
+ if (typeof parsed.score === "number" && parsed.score < 0.4) return true;
46
+ }
47
+ // Check for recall_metrics with low relevanceScore
48
+ if (parsed.event === "recall_metrics" && parsed.relevanceScore !== undefined) {
49
+ if (typeof parsed.relevanceScore === "number" && parsed.relevanceScore < 0.4) return true;
50
+ }
51
+ // Check for RecallQualityEvent format from monitoring.ts
52
+ if (parsed.score !== undefined && typeof parsed.score === "number" && parsed.score < 0.4) return true;
53
+ } catch {
54
+ // skip unparseable lines
55
+ }
56
+ }
57
+ } catch {
58
+ // non-fatal: skip if can't read
59
+ }
60
+ }
61
+ return false;
62
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * mega-commands/historyCommands.ts — the checkpoint history/inspection commands.
3
+ *
4
+ * Extracted from mega-commands.ts (delegate-shell split). Registers
5
+ * /mega-restore, /mega-history, /mega-view, and /mega-help.
6
+ */
7
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
8
+ import { normalizeSessionId } from "../../src/store.js";
9
+ import { listCheckpoints } from "../../src/store/sqlite.js";
10
+ import { decompressSmart } from "../../src/store/compression.js";
11
+ import { type MegaRuntime, C } from "../mega-runtime.js";
12
+ import { findCheckpoint } from "./helpers.js";
13
+
14
+ /** Register the checkpoint history/inspection commands. */
15
+ export function registerHistoryCommands(
16
+ pi: ExtensionAPI,
17
+ runtime: MegaRuntime,
18
+ ): void {
19
+ pi.registerCommand("mega-restore", {
20
+ description: "Re-inject a checkpoint's verbatim original region into context. Usage: /mega-restore <chkpt|recent>",
21
+ handler: async (args: string, ctx: ExtensionContext) => {
22
+ try {
23
+ runtime.bindRepo(ctx.cwd);
24
+ const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
25
+ const cp = findCheckpoint(runtime, sid, args.trim());
26
+ if (!cp) {
27
+ ctx.ui.notify(`[mega-compact] no checkpoint found${args.trim() ? ` for "${args.trim()}"` : ""} in this session. Try /mega-history.`);
28
+ return;
29
+ }
30
+ if (!cp.compressedOriginal) {
31
+ ctx.ui.notify(`[mega-compact] ${cp.checkpointId} has no recoverable original (pre-blob or direct add). Cannot restore verbatim.`);
32
+ return;
33
+ }
34
+ const original = decompressSmart(cp.compressedOriginal).toString("utf-8");
35
+ // Re-inject verbatim via before_agent_start (PREVENT-PI-003) — never
36
+ // touches live messages, only prepends the restored region to systemPrompt.
37
+ runtime.pendingRecallBlock = `The following compacted context was RESTORED from checkpoint ${cp.checkpointId} (verbatim original region):\n\n${original}`;
38
+ const files = cp.filesModified?.length ? cp.filesModified.join(", ") : "(no files captured)";
39
+ ctx.ui.notify(
40
+ `[mega-compact] ♻ restored ${cp.checkpointId} — ${original.length} chars re-injected on next turn.\n` +
41
+ `[mega-compact] files: ${files}`,
42
+ );
43
+ runtime.dashboard.event("restore", { checkpointId: cp.checkpointId, chars: original.length });
44
+ } catch (e) {
45
+ ctx.ui.notify(`[mega-compact] /mega-restore failed (checkpoint may be corrupt): ${String(e)}`);
46
+ }
47
+ },
48
+ });
49
+
50
+ pi.registerCommand("mega-history", {
51
+ description: "List this session's checkpoints (id, date, files, tokens). Usage: /mega-history",
52
+ handler: async (_args: string, ctx: ExtensionContext) => {
53
+ runtime.bindRepo(ctx.cwd);
54
+ const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
55
+ const all = listCheckpoints(sid, runtime.currentStateDir);
56
+ if (all.length === 0) {
57
+ ctx.ui.notify("[mega-compact] no checkpoints in this session yet.");
58
+ return;
59
+ }
60
+ const rows = all.map((c) => {
61
+ const when = c.timestamp ? new Date(c.timestamp).toISOString().slice(0, 16).replace("T", " ") : "—";
62
+ const files = c.filesModified?.length ? c.filesModified.map((f) => f.split("/").pop() ?? f).join(", ") : "—";
63
+ const orig = c.originalTokenEstimate ?? 0;
64
+ const stored = c.tokenEstimate ?? 0;
65
+ const saved = Math.max(0, orig - stored);
66
+ return ` ${c.checkpointId} ${when} ${C.cyan}${saved}t saved${C.reset} ${files}`;
67
+ });
68
+ ctx.ui.notify(
69
+ `[mega-compact] ${all.length} checkpoint(s) in this session:\n` + rows.join("\n") +
70
+ `\n[mega-compact] /mega-view <chkpt> to see the original region · /mega-restore <chkpt> to re-inject it`,
71
+ );
72
+ },
73
+ });
74
+
75
+ pi.registerCommand("mega-view", {
76
+ description: "Show a checkpoint's verbatim original region. Usage: /mega-view <chkpt|recent>",
77
+ handler: async (args: string, ctx: ExtensionContext) => {
78
+ try {
79
+ runtime.bindRepo(ctx.cwd);
80
+ const sid = normalizeSessionId(ctx.sessionManager.getSessionId());
81
+ const cp = findCheckpoint(runtime, sid, args.trim());
82
+ if (!cp) {
83
+ ctx.ui.notify(`[mega-compact] no checkpoint found${args.trim() ? ` for "${args.trim()}"` : ""}. Try /mega-history.`);
84
+ return;
85
+ }
86
+ if (!cp.compressedOriginal) {
87
+ ctx.ui.notify(`[mega-compact] ${cp.checkpointId} summary:\n${cp.summary.slice(0, 500)}${cp.summary.length > 500 ? "…" : ""}\n(no verbatim original stored)`);
88
+ return;
89
+ }
90
+ const original = decompressSmart(cp.compressedOriginal).toString("utf-8");
91
+ ctx.ui.notify(
92
+ `[mega-compact] ${cp.checkpointId} — original region (${original.length} chars):\n` +
93
+ `${original.slice(0, 1500)}${original.length > 1500 ? "\n…(truncated)" : ""}`,
94
+ );
95
+ } catch (e) {
96
+ ctx.ui.notify(`[mega-compact] /mega-view failed (checkpoint may be corrupt): ${String(e)}`);
97
+ }
98
+ },
99
+ });
100
+
101
+ pi.registerCommand("mega-help", {
102
+ description: "Plain-language glossary of what mega-compact's stats mean.",
103
+ handler: async (_args: string, ctx: ExtensionContext) => {
104
+ ctx.ui.notify(
105
+ `[mega-compact] glossary — what the numbers mean:\n` +
106
+ `• token — a chunk of text (~4 chars). Context window = how much text fits in memory at once.\n` +
107
+ `• space freed — how much conversation we've compressed away to make room (the win).\n` +
108
+ `• memory held — how much compact summary we're currently keeping as your 'notes'.\n` +
109
+ `• saved checkpoint — a compact summary of an old conversation chunk we stored.\n` +
110
+ `• repeat-skipped — how often new text matched something we already had, so we didn't store a duplicate.\n` +
111
+ `• injected — times we pasted an old saved note back into the chat because it was relevant.\n` +
112
+ `• recall relevance — of those, how often the note was actually on-topic.\n` +
113
+ `• data safety — every compressed region is kept verbatim; nothing is permanently deleted. /mega-restore brings any of it back.`,
114
+ );
115
+ },
116
+ });
117
+ }