pi-mega-compact 0.11.3 → 0.11.5
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/dist/extensions/dashboard-server/api-contracts/endpoints.js +19 -0
- package/dist/extensions/dashboard-server/api-contracts/memory.js +8 -0
- package/dist/extensions/dashboard-server/api-contracts/provider-cache.js +1 -0
- package/dist/extensions/dashboard-server/api-contracts/setup.js +10 -0
- package/dist/extensions/dashboard-server/index-reader.js +6 -2
- package/dist/extensions/dashboard-server/routes-cache.js +115 -55
- package/dist/extensions/dashboard-server/routes-memory.js +51 -0
- package/dist/extensions/dashboard-server/routes-repo.js +2 -2
- package/dist/extensions/dashboard-server/routes-setup.js +162 -0
- package/dist/extensions/dashboard-server/routes.js +2 -0
- package/dist/extensions/dashboard-server/server.js +7 -1
- package/dist/extensions/mega-commands.js +189 -1
- package/dist/extensions/mega-config.js +3 -0
- package/dist/extensions/mega-events/agent-handlers.js +41 -6
- package/dist/extensions/mega-events/compact-handlers.js +1 -0
- package/dist/extensions/mega-events/context-handler.js +37 -92
- package/dist/extensions/mega-events/context-hwm.js +51 -0
- package/dist/extensions/mega-events/error-classifier.js +118 -128
- package/dist/extensions/mega-events/mirror-append.js +107 -0
- package/dist/extensions/mega-events/outage-advisor.js +59 -0
- package/dist/extensions/mega-events/perf-handler.js +51 -1
- package/dist/extensions/mega-events/recall-tail.js +59 -0
- package/dist/extensions/mega-events/session-handlers.js +15 -8
- package/dist/extensions/mega-runtime/reset-runtime.js +6 -0
- package/dist/extensions/mega-runtime/runtime.js +7 -0
- package/dist/src/embedder.js +41 -2
- package/dist/src/memoryStats.js +75 -0
- package/dist/src/prefix-break.js +43 -0
- package/dist/src/pricing.js +1 -1
- package/dist/src/store/sqlite/perf-samples.js +144 -16
- package/dist/src/store/turns/memory-store.js +8 -0
- package/dist/src/store/turns/sqlite-store.js +14 -3
- package/dist/src/store/turns/types.js +18 -1
- package/dist/src/store/vectorIndex.js +26 -5
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js → AchievementTiles-BoL7qBOJ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-vEo2MtE2.js.map → AchievementTiles-BoL7qBOJ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/AchievementsTab-BFDE3HYc.js +2 -0
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-DjxfYrDc.js.map → AchievementsTab-BFDE3HYc.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-eKVc-NV1.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js → ConfigTab-DDFE-ckA.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ConfigTab-Cm6ymbmx.js.map → ConfigTab-DDFE-ckA.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js → EventsTab-B6UxZ7PM.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-DXWl_YzI.js.map → EventsTab-B6UxZ7PM.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js → GameTab-DehUX-KE.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{GameTab-BLDudcO5.js.map → GameTab-DehUX-KE.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js → MaintenanceTab-0GWRt4wn.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-DLkKCztn.js.map → MaintenanceTab-0GWRt4wn.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js → MetricsTab-C3rwMVsN.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-Cq4u-rZF.js.map → MetricsTab-C3rwMVsN.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-39O9_x5j.js +2 -0
- package/extensions/dashboard-client/dist/assets/{OverviewTab-D4kGvsiQ.js.map → OverviewTab-39O9_x5j.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js +2 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-Cfj6Q5sH.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js → SessionsTab-DXDTCi3r.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-DZC2-GCn.js.map → SessionsTab-DXDTCi3r.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-mMlfunJa.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js +2 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-Cw1dJ4e9.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js → TopicsTab-BAw972BV.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TopicsTab-01G71hv1.js.map → TopicsTab-BAw972BV.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js → TurnsTab-Cf5mGIdl.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-DLRg0LZT.js.map → TurnsTab-Cf5mGIdl.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js +2 -0
- package/extensions/dashboard-client/dist/assets/format-COjDIVGj.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{index-BX0bcgLu.js → index-4gQ7auad.js} +10 -10
- package/extensions/dashboard-client/dist/assets/index-4gQ7auad.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js +2 -0
- package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js → useSSE-DNgMuyP6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-BBYt5UPB.js.map → useSSE-DNgMuyP6.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/App.tsx +4 -0
- package/extensions/dashboard-client/src/api/client.ts +14 -0
- package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +21 -12
- package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +56 -0
- package/extensions/dashboard-client/src/components/SavingsByModelTable.tsx +38 -57
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +1 -0
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +355 -0
- package/extensions/dashboard-client/tsconfig.json +3 -2
- package/extensions/dashboard-client/vite.config.ts +2 -0
- package/extensions/dashboard-server/api-contracts/endpoints.ts +36 -3
- package/extensions/dashboard-server/api-contracts/index.ts +7 -0
- package/extensions/dashboard-server/api-contracts/memory.ts +27 -0
- package/extensions/dashboard-server/api-contracts/multi-repo.ts +231 -231
- package/extensions/dashboard-server/api-contracts/provider-cache.ts +37 -0
- package/extensions/dashboard-server/api-contracts/setup.ts +58 -0
- package/extensions/dashboard-server/index-reader.ts +138 -121
- package/extensions/dashboard-server/routes-cache.ts +161 -85
- package/extensions/dashboard-server/routes-memory.ts +63 -0
- package/extensions/dashboard-server/routes-repo.ts +36 -36
- package/extensions/dashboard-server/routes-setup.ts +181 -0
- package/extensions/dashboard-server/routes.ts +2 -0
- package/extensions/dashboard-server/server.ts +6 -0
- package/extensions/mega-commands.ts +211 -1
- package/extensions/mega-config.ts +18 -0
- package/extensions/mega-events/agent-handlers.ts +44 -5
- package/extensions/mega-events/compact-handlers.ts +1 -0
- package/extensions/mega-events/context-handler.ts +45 -110
- package/extensions/mega-events/context-hwm.ts +85 -0
- package/extensions/mega-events/error-classifier.ts +156 -124
- package/extensions/mega-events/mirror-append.ts +155 -0
- package/extensions/mega-events/outage-advisor.ts +79 -0
- package/extensions/mega-events/perf-handler.ts +79 -5
- package/extensions/mega-events/recall-tail.ts +88 -0
- package/extensions/mega-events/session-handlers.ts +14 -7
- package/extensions/mega-runtime/helpers.ts +14 -0
- package/extensions/mega-runtime/reset-runtime.ts +6 -0
- package/extensions/mega-runtime/runtime.ts +7 -0
- package/package.json +5 -2
- package/src/embedder.ts +42 -2
- package/src/memoryStats.ts +107 -0
- package/src/prefix-break.ts +83 -0
- package/src/pricing.ts +2 -2
- package/src/store/sqlite/perf-samples.ts +215 -22
- package/src/store/turns/memory-store.ts +10 -1
- package/src/store/turns/sqlite-store.ts +27 -15
- package/src/store/turns/types.ts +21 -0
- package/src/store/vectorIndex.ts +33 -4
- package/dist/extensions/conflict-scan.test.js +0 -115
- package/dist/extensions/dashboard-server/api-contracts.test.js +0 -884
- package/dist/extensions/dashboard-server/html.test.js +0 -52
- package/dist/extensions/dashboard-server/perf-server.test.js +0 -80
- package/dist/extensions/dashboard-server/routes-cache.test.js +0 -248
- package/dist/extensions/dashboard-server/server.test.js +0 -120
- package/dist/extensions/dashboard-server-s32.test.js +0 -181
- package/dist/extensions/dashboard-server.test.js +0 -339
- package/dist/extensions/mega-cache-replay.test.js +0 -400
- package/dist/extensions/mega-compact-s38.test.js +0 -820
- package/dist/extensions/mega-compact.test.js +0 -1112
- package/dist/extensions/mega-events.test.js +0 -47
- package/dist/extensions/mega-game-cmds.test.js +0 -163
- package/dist/extensions/mega-runtime/snapshot.test.js +0 -127
- package/dist/extensions/mega-runtime/state.test.js +0 -266
- package/dist/extensions/mega-runtime/widget.test.js +0 -343
- package/dist/extensions/mega-shutdown-widget.test.js +0 -121
- package/dist/extensions/mega-teamrun.test.js +0 -156
- package/dist/extensions/mega-trim.test.js +0 -58
- package/dist/extensions/mega-turn-store.test.js +0 -68
- package/dist/src/boundary.test.js +0 -170
- package/dist/src/compact.test.js +0 -78
- package/dist/src/config/themes.test.js +0 -94
- package/dist/src/dedup/dedup.test.js +0 -41
- package/dist/src/dedup/l1.test.js +0 -50
- package/dist/src/dedup/raptor/buildHistory.test.js +0 -292
- package/dist/src/dedup/raptor/multilevel-serve.test.js +0 -229
- package/dist/src/dedup/raptor/multilevel.test.js +0 -238
- package/dist/src/dedup/raptor/promote.test.js +0 -69
- package/dist/src/dedup/raptor/raptor.test.js +0 -248
- package/dist/src/dedup/raptor/retrieval.test.js +0 -95
- package/dist/src/dedup/raptor/serve-gate.test.js +0 -298
- package/dist/src/dedup/sprint12.test.js +0 -219
- package/dist/src/dedup-engine.test.js +0 -472
- package/dist/src/driftDetection.test.js +0 -87
- package/dist/src/e2e.test.js +0 -698
- package/dist/src/engine.test.js +0 -111
- package/dist/src/extractive.test.js +0 -147
- package/dist/src/fork.test.js +0 -81
- package/dist/src/game/scoring.test.js +0 -98
- package/dist/src/httpEmbedder.test.js +0 -277
- package/dist/src/importance.test.js +0 -372
- package/dist/src/intent.test.js +0 -78
- package/dist/src/log.test.js +0 -42
- package/dist/src/mechanical-fix.test.js +0 -65
- package/dist/src/memory.test.js +0 -70
- package/dist/src/memoryConsolidate.test.js +0 -38
- package/dist/src/memoryOps.test.js +0 -129
- package/dist/src/memoryRecall.test.js +0 -171
- package/dist/src/memoryRoundtrip.test.js +0 -137
- package/dist/src/metrics/turns.test.js +0 -152
- package/dist/src/mirror/mirror.test.js +0 -185
- package/dist/src/raptor-inject-summaries.test.js +0 -162
- package/dist/src/ratio.bench.test.js +0 -897
- package/dist/src/recall.integration.test.js +0 -77
- package/dist/src/recall.test.js +0 -379
- package/dist/src/sprint14.test.js +0 -219
- package/dist/src/sprint4x-rag-verification.test.js +0 -93
- package/dist/src/store/compression.test.js +0 -139
- package/dist/src/store/memoryIndex.test.js +0 -51
- package/dist/src/store/migrate.test.js +0 -139
- package/dist/src/store/pgOpenGuard.test.js +0 -74
- package/dist/src/store/phase01.test.js +0 -81
- package/dist/src/store/phase04.test.js +0 -54
- package/dist/src/store/sprint10.test.js +0 -186
- package/dist/src/store/sqlite/game-achievements.test.js +0 -67
- package/dist/src/store/sqlite/game-scores.test.js +0 -106
- package/dist/src/store/sqlite/game-state.test.js +0 -76
- package/dist/src/store/sqlite/global-index.test.js +0 -136
- package/dist/src/store/sqlite/mechanical-fix.test.js +0 -146
- package/dist/src/store/sqlite/perf-samples.test.js +0 -146
- package/dist/src/store/sqlite/raptor.test.js +0 -106
- package/dist/src/store/sqlite/turns.test.js +0 -183
- package/dist/src/store/sqlite.cachehit.test.js +0 -55
- package/dist/src/store/sqlite.dbmaint.test.js +0 -158
- package/dist/src/store/sqlite.dbmirror.test.js +0 -184
- package/dist/src/store/turns/contract-compliance.test.js +0 -428
- package/dist/src/store/turns/memory-store.test.js +0 -9
- package/dist/src/store/turns/migrations.test.js +0 -138
- package/dist/src/store/turns/sqlite-store.test.js +0 -144
- package/dist/src/store/vectorIndex.test.js +0 -123
- package/dist/src/store.test.js +0 -161
- package/dist/src/supersede.test.js +0 -36
- package/dist/src/topics/cluster.test.js +0 -150
- package/dist/src/topics/store.test.js +0 -117
- package/dist/src/types.test.js +0 -9
- package/dist/src/vector-search-cache.test.js +0 -157
- package/dist/src/vectorStore.test.js +0 -479
- package/dist/src/wiki.test.js +0 -171
- package/extensions/conflict-scan.test.ts +0 -129
- package/extensions/dashboard-client/dist/assets/AchievementsTab-DjxfYrDc.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-Dnpv94wq.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-D4kGvsiQ.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-C0Wnrf2u.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js +0 -2
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-UqljSyP-.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-BX0bcgLu.js.map +0 -1
- package/extensions/dashboard-server/api-contracts.test.ts +0 -1065
- package/extensions/dashboard-server/html.test.ts +0 -62
- package/extensions/dashboard-server/perf-server.test.ts +0 -101
- package/extensions/dashboard-server/routes-cache.test.ts +0 -302
- package/extensions/dashboard-server/server.test.ts +0 -131
- package/extensions/dashboard-server-s32.test.ts +0 -195
- package/extensions/dashboard-server.test.ts +0 -382
- package/extensions/mega-cache-replay.test.ts +0 -526
- package/extensions/mega-compact-s38.test.ts +0 -872
- package/extensions/mega-compact.test.ts +0 -1509
- package/extensions/mega-events.test.ts +0 -55
- package/extensions/mega-game-cmds.test.ts +0 -197
- package/extensions/mega-runtime/snapshot.test.ts +0 -139
- package/extensions/mega-runtime/state.test.ts +0 -262
- package/extensions/mega-runtime/widget.test.ts +0 -468
- package/extensions/mega-shutdown-widget.test.ts +0 -141
- package/extensions/mega-teamrun.test.ts +0 -176
- package/extensions/mega-trim.test.ts +0 -64
- package/extensions/mega-turn-store.test.ts +0 -108
- package/src/boundary.test.ts +0 -187
- package/src/compact.test.ts +0 -99
- package/src/config/themes.test.ts +0 -116
- package/src/dedup/dedup.test.ts +0 -46
- package/src/dedup/l1.test.ts +0 -57
- package/src/dedup/raptor/buildHistory.test.ts +0 -353
- package/src/dedup/raptor/multilevel-serve.test.ts +0 -273
- package/src/dedup/raptor/multilevel.test.ts +0 -325
- package/src/dedup/raptor/promote.test.ts +0 -82
- package/src/dedup/raptor/raptor.test.ts +0 -297
- package/src/dedup/raptor/retrieval.test.ts +0 -118
- package/src/dedup/raptor/serve-gate.test.ts +0 -348
- package/src/dedup/sprint12.test.ts +0 -242
- package/src/dedup-engine.test.ts +0 -670
- package/src/driftDetection.test.ts +0 -100
- package/src/e2e.test.ts +0 -843
- package/src/engine.test.ts +0 -123
- package/src/extractive.test.ts +0 -174
- package/src/fork.test.ts +0 -94
- package/src/game/scoring.test.ts +0 -103
- package/src/httpEmbedder.test.ts +0 -286
- package/src/importance.test.ts +0 -538
- package/src/intent.test.ts +0 -87
- package/src/log.test.ts +0 -47
- package/src/mechanical-fix.test.ts +0 -70
- package/src/memory.test.ts +0 -92
- package/src/memoryConsolidate.test.ts +0 -47
- package/src/memoryOps.test.ts +0 -148
- package/src/memoryRecall.test.ts +0 -194
- package/src/memoryRoundtrip.test.ts +0 -155
- package/src/metrics/turns.test.ts +0 -165
- package/src/mirror/mirror.test.ts +0 -240
- package/src/raptor-inject-summaries.test.ts +0 -228
- package/src/ratio.bench.test.ts +0 -1316
- package/src/recall.integration.test.ts +0 -96
- package/src/recall.test.ts +0 -467
- package/src/sprint14.test.ts +0 -245
- package/src/sprint4x-rag-verification.test.ts +0 -119
- package/src/store/compression.test.ts +0 -168
- package/src/store/memoryIndex.test.ts +0 -61
- package/src/store/migrate.test.ts +0 -158
- package/src/store/pgOpenGuard.test.ts +0 -89
- package/src/store/phase01.test.ts +0 -88
- package/src/store/phase04.test.ts +0 -58
- package/src/store/sprint10.test.ts +0 -214
- package/src/store/sqlite/game-achievements.test.ts +0 -80
- package/src/store/sqlite/game-scores.test.ts +0 -132
- package/src/store/sqlite/game-state.test.ts +0 -89
- package/src/store/sqlite/global-index.test.ts +0 -222
- package/src/store/sqlite/mechanical-fix.test.ts +0 -162
- package/src/store/sqlite/perf-samples.test.ts +0 -169
- package/src/store/sqlite/raptor.test.ts +0 -139
- package/src/store/sqlite/turns.test.ts +0 -218
- package/src/store/sqlite.cachehit.test.ts +0 -68
- package/src/store/sqlite.dbmaint.test.ts +0 -193
- package/src/store/sqlite.dbmirror.test.ts +0 -229
- package/src/store/turns/contract-compliance.test.ts +0 -562
- package/src/store/turns/memory-store.test.ts +0 -15
- package/src/store/turns/migrations.test.ts +0 -161
- package/src/store/turns/sqlite-store.test.ts +0 -161
- package/src/store/vectorIndex.test.ts +0 -140
- package/src/store.test.ts +0 -191
- package/src/supersede.test.ts +0 -42
- package/src/topics/cluster.test.ts +0 -176
- package/src/topics/store.test.ts +0 -132
- package/src/types.test.ts +0 -10
- package/src/vector-search-cache.test.ts +0 -190
- package/src/vectorStore.test.ts +0 -533
- package/src/wiki.test.ts +0 -217
|
@@ -16,138 +16,155 @@ import { DatabaseSync } from "node:sqlite";
|
|
|
16
16
|
import type { IndexRepo, IndexIndex } from "./types.js";
|
|
17
17
|
|
|
18
18
|
export function getIndexDir(): string {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
const override = process.env.MEGACOMPACT_INDEX_DIR;
|
|
20
|
+
if (override && override.trim() !== "") return override;
|
|
21
|
+
try {
|
|
22
|
+
return join(homedir(), ".mega-compact-index");
|
|
23
|
+
} catch {
|
|
24
|
+
return join("/tmp", ".mega-compact-index");
|
|
25
|
+
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/** Read the machine-wide repo registry from SQLite (read-only, single shot). */
|
|
29
29
|
export function readIndex(): IndexIndex | null {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
30
|
+
const indexPath = join(getIndexDir(), "index.sqlite");
|
|
31
|
+
if (!existsSync(indexPath)) return null;
|
|
32
|
+
let db: DatabaseSync | undefined;
|
|
33
|
+
try {
|
|
34
|
+
// Read-only + immutable WAL so a concurrent writer's WAL never blocks us.
|
|
35
|
+
db = new DatabaseSync(indexPath, { readOnly: true });
|
|
36
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
37
|
+
const rows = db
|
|
38
|
+
.prepare("SELECT * FROM repo_registry ORDER BY last_seen DESC")
|
|
39
|
+
.all() as Record<string, unknown>[];
|
|
40
|
+
const mapped: IndexRepo[] = rows.map((r) => ({
|
|
41
|
+
repoRoot: String(r.repo_root ?? ""),
|
|
42
|
+
displayName: String(r.display_name ?? ""),
|
|
43
|
+
stateDir: String(r.state_dir ?? ""),
|
|
44
|
+
checkpointCount: Number(r.checkpoint_count ?? 0),
|
|
45
|
+
tokensSaved: Number(r.tokens_saved ?? 0),
|
|
46
|
+
compressedOriginalBytes: Number(r.compressed_original_bytes ?? 0),
|
|
47
|
+
lastCompactedAt: (r.last_compacted_at as number | null) ?? null,
|
|
48
|
+
provider: (r.provider as string | null) ?? null,
|
|
49
|
+
providerName: (r.provider_name as string | null) ?? null,
|
|
50
|
+
modelName: (r.model_name as string | null) ?? null,
|
|
51
|
+
inputRate: (r.input_rate as number | null) ?? null,
|
|
52
|
+
outputRate: (r.output_rate as number | null) ?? null,
|
|
53
|
+
lastSeen: Number(r.last_seen ?? 0),
|
|
54
|
+
// Defaults — enriched below from each repo's own store.
|
|
55
|
+
tokensKept: 0,
|
|
56
|
+
tokensDropped: 0,
|
|
57
|
+
sessions: 0,
|
|
58
|
+
contextWindow: null,
|
|
59
|
+
maxTokens: null,
|
|
60
|
+
reasoning: null,
|
|
61
|
+
providerCachePct: null,
|
|
62
|
+
providerCacheRead: null,
|
|
63
|
+
providerCacheWrite: null,
|
|
64
|
+
}));
|
|
65
|
+
// Enrich each repo with per-store token + model detail read directly via
|
|
66
|
+
// node:sqlite (same zero-dependency invariant as readIndex; no store graph
|
|
67
|
+
// import). Best-effort: a missing/corrupt store degrades to the defaults
|
|
68
|
+
// above so the dashboard never fails to render.
|
|
69
|
+
for (const repo of mapped) {
|
|
70
|
+
try {
|
|
71
|
+
const storePath = join(repo.stateDir, "sqlite.db");
|
|
72
|
+
if (existsSync(storePath)) {
|
|
73
|
+
const sdb = new DatabaseSync(storePath, { readOnly: true });
|
|
74
|
+
try {
|
|
75
|
+
const tok = sdb
|
|
76
|
+
.prepare(
|
|
77
|
+
`SELECT COALESCE(SUM(token_estimate),0) AS kept,
|
|
78
78
|
COALESCE(SUM(original_token_estimate),0) AS dropped,
|
|
79
79
|
COUNT(DISTINCT session_id) AS sess
|
|
80
80
|
FROM context_chunks WHERE dedup_status != 'removed'`,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
)
|
|
82
|
+
.get() as { kept: number; dropped: number; sess: number };
|
|
83
|
+
repo.tokensKept = Number(tok.kept ?? 0);
|
|
84
|
+
repo.tokensDropped = Number(tok.dropped ?? 0);
|
|
85
|
+
repo.sessions = Number(tok.sess ?? 0);
|
|
86
|
+
const mrow = sdb
|
|
87
|
+
.prepare(
|
|
88
|
+
`SELECT context_window, max_tokens, reasoning
|
|
89
89
|
FROM model_snapshots ORDER BY captured_at DESC LIMIT 1`,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
90
|
+
)
|
|
91
|
+
.get() as
|
|
92
|
+
| {
|
|
93
|
+
context_window: number;
|
|
94
|
+
max_tokens: number;
|
|
95
|
+
reasoning: number;
|
|
96
|
+
}
|
|
97
|
+
| undefined;
|
|
98
|
+
if (mrow) {
|
|
99
|
+
repo.contextWindow = Number(mrow.context_window ?? 0) || null;
|
|
100
|
+
repo.maxTokens = Number(mrow.max_tokens ?? 0) || null;
|
|
101
|
+
repo.reasoning = Number(mrow.reasoning ?? 0) === 1;
|
|
102
|
+
}
|
|
103
|
+
// Provider prompt-cache stats (E.3)
|
|
104
|
+
try {
|
|
105
|
+
const pRow = sdb
|
|
106
|
+
.prepare(
|
|
107
|
+
`SELECT
|
|
102
108
|
SUM(cache_read) AS totalRead,
|
|
103
109
|
SUM(cache_write) AS totalWrite,
|
|
104
110
|
SUM(cache_read + cache_write) * 1.0 / MAX(SUM(cache_read + cache_write + tokens_in), 1) AS hitPct
|
|
105
111
|
FROM perf_samples
|
|
106
112
|
WHERE cache_read > 0 OR cache_write > 0`,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
113
|
+
)
|
|
114
|
+
.get() as
|
|
115
|
+
| { totalRead: number; totalWrite: number; hitPct: number }
|
|
116
|
+
| undefined;
|
|
117
|
+
if (pRow && pRow.totalRead > 0) {
|
|
118
|
+
repo.providerCacheRead = Number(pRow.totalRead);
|
|
119
|
+
repo.providerCacheWrite = Number(pRow.totalWrite);
|
|
120
|
+
repo.providerCachePct = Number((pRow.hitPct * 100).toFixed(1));
|
|
121
|
+
}
|
|
122
|
+
} catch {
|
|
123
|
+
/* best-effort — perf_samples may not exist */
|
|
124
|
+
}
|
|
125
|
+
} finally {
|
|
126
|
+
sdb.close();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} catch {
|
|
130
|
+
/* best-effort — keep the defaults */
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Defensive display hygiene (belt-and-suspenders — the real fix is that
|
|
134
|
+
// tests now isolate via MEGACOMPACT_INDEX_DIR): drop transient test/temp
|
|
135
|
+
// paths that should never have been real repos, and collapse duplicate
|
|
136
|
+
// display names to the most-recently-seen row (rows are last_seen DESC, so
|
|
137
|
+
// the first occurrence wins). Keeps the All-repos list readable.
|
|
138
|
+
const isTransient = (p: string) =>
|
|
139
|
+
/^\/tmp\//.test(p) ||
|
|
140
|
+
/^\/private\/tmp\//.test(p) ||
|
|
141
|
+
/^\/var\/folders\//.test(p) ||
|
|
142
|
+
/\/mc-(ext|e2e|resume|recall)-/.test(p);
|
|
143
|
+
const seenName = new Set<string>();
|
|
144
|
+
const repos: IndexRepo[] = [];
|
|
145
|
+
for (const r of mapped) {
|
|
146
|
+
if (isTransient(r.repoRoot)) continue;
|
|
147
|
+
if (seenName.has(r.displayName)) continue;
|
|
148
|
+
seenName.add(r.displayName);
|
|
149
|
+
repos.push(r);
|
|
150
|
+
}
|
|
151
|
+
const summary = {
|
|
152
|
+
totalRepos: repos.length,
|
|
153
|
+
totalCheckpoints: repos.reduce((a, r) => a + r.checkpointCount, 0),
|
|
154
|
+
totalTokensSaved: repos.reduce((a, r) => a + r.tokensSaved, 0),
|
|
155
|
+
totalCompressedOriginalBytes: repos.reduce(
|
|
156
|
+
(a, r) => a + r.compressedOriginalBytes,
|
|
157
|
+
0,
|
|
158
|
+
),
|
|
159
|
+
};
|
|
160
|
+
return { updatedAt: new Date().toISOString(), summary, repos };
|
|
161
|
+
} catch {
|
|
162
|
+
return null;
|
|
163
|
+
} finally {
|
|
164
|
+
try {
|
|
165
|
+
db?.close();
|
|
166
|
+
} catch {
|
|
167
|
+
/* ignore */
|
|
168
|
+
}
|
|
169
|
+
}
|
|
153
170
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* GET /api/provider-cache — Lifetime provider prompt cache hit-rate aggregates
|
|
5
5
|
* plus dollar savings estimate (priced from latest model snapshot).
|
|
6
|
+
* Accepts optional ?minutes=N, ?since=<epoch-ms>, ?until=<epoch-ms> (S53A).
|
|
6
7
|
*
|
|
7
8
|
* Guardrails: PREVENT-PI-004 (loopback-only), PREVENT-001 (null-safe JSON parse),
|
|
8
9
|
* PREVENT-002 (parameterized SQL). Loopback-only localhost dashboard endpoint.
|
|
@@ -24,100 +25,175 @@ export function handleProviderCache(
|
|
|
24
25
|
ctx: RouteContext,
|
|
25
26
|
): boolean {
|
|
26
27
|
if (!req.url?.startsWith("/api/provider-cache")) return false;
|
|
27
|
-
|
|
28
|
-
const { stateDir } = ctx;
|
|
29
|
-
|
|
30
|
-
// /api/provider-cache — GET returns lifetime provider prompt cache aggregates
|
|
31
|
-
// from perf_samples (cache_hit_pct rows with meta JSON) plus an optional
|
|
32
|
-
// dollar savings estimate priced from the latest model snapshot. The dashboard
|
|
33
|
-
// server is a detached child with no MegaRuntime ref, so it reads via a
|
|
34
|
-
// require()'d sqlite helper (same pattern as /api/perf). Non-GET → 405.
|
|
35
|
-
// PREVENT-PI-004: loopback.
|
|
36
|
-
const pfReq = createRequire(import.meta.url);
|
|
37
|
-
const { readProviderCacheLifetime, latestModelSnapshot } = pfReq(
|
|
38
|
-
"../../src/store/sqlite.js",
|
|
39
|
-
) as typeof import("../../src/store/sqlite.js");
|
|
40
|
-
if (req.method !== "GET") {
|
|
41
|
-
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
42
|
-
res.writeHead(405, { "Content-Type": "application/json" });
|
|
43
|
-
res.end(JSON.stringify({ error: "method_not_allowed" }));
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
28
|
try {
|
|
47
|
-
const
|
|
29
|
+
const stateDir = ctx.stateDir;
|
|
30
|
+
// PREVENT-PI-004: loopback.
|
|
31
|
+
const pfReq = createRequire(import.meta.url);
|
|
32
|
+
const { readProviderCacheLifetime, readProviderCacheWindow, latestModelSnapshot } = pfReq(
|
|
33
|
+
"../../src/store/sqlite.js",
|
|
34
|
+
) as typeof import("../../src/store/sqlite.js");
|
|
35
|
+
if (req.method !== "GET") {
|
|
36
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
37
|
+
res.writeHead(405, { "Content-Type": "application/json" });
|
|
38
|
+
res.end(JSON.stringify({ error: "method_not_allowed" }));
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
48
41
|
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
42
|
+
// Parse query params: ?minutes=N | ?since=&until= (mutually exclusive).
|
|
43
|
+
let windowMinutes: number | null = null;
|
|
44
|
+
let sinceTs = 0;
|
|
45
|
+
let untilTs = 0;
|
|
46
|
+
if (req.url) {
|
|
47
|
+
const qIdx = req.url.indexOf("?");
|
|
48
|
+
if (qIdx !== -1) {
|
|
49
|
+
const params = new URLSearchParams(req.url.slice(qIdx));
|
|
50
|
+
const m = params.get("minutes");
|
|
51
|
+
if (m != null) {
|
|
52
|
+
const n = parseInt(m, 10);
|
|
53
|
+
if (Number.isFinite(n) && n > 0 && String(n) === m.trim()) {
|
|
54
|
+
windowMinutes = n;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// S53A: ?since=&until= epoch-ms timestamps.
|
|
58
|
+
const s = params.get("since");
|
|
59
|
+
const u = params.get("until");
|
|
60
|
+
if (s != null) {
|
|
61
|
+
const sn = Number(s);
|
|
62
|
+
if (Number.isFinite(sn) && sn >= 0) sinceTs = sn;
|
|
63
|
+
}
|
|
64
|
+
if (u != null) {
|
|
65
|
+
const un = Number(u);
|
|
66
|
+
if (Number.isFinite(un) && un > 0) untilTs = un;
|
|
67
|
+
}
|
|
73
68
|
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// S53A: read prefix_break samples in the same window as the aggregates.
|
|
72
|
+
// Import lazily to avoid a circular dependency in the test harness.
|
|
73
|
+
let prefixBreaks: Array<{
|
|
74
|
+
id: number;
|
|
75
|
+
ts: number;
|
|
76
|
+
cause: "recall" | "compaction" | "inject" | "other";
|
|
77
|
+
confidence: number;
|
|
78
|
+
prevHitPct: number;
|
|
79
|
+
currHitPct: number;
|
|
80
|
+
breakAt: number;
|
|
81
|
+
}> = [];
|
|
82
|
+
try {
|
|
83
|
+
// guardrails-allow PREVENT-PI-004: local SQLite read (loopback dashboard)
|
|
84
|
+
const { readPrefixBreaks } = pfReq(
|
|
85
|
+
"../../src/store/sqlite/perf-samples.js",
|
|
86
|
+
) as typeof import("../../src/store/sqlite/perf-samples.js");
|
|
87
|
+
// When ?since=&until= is used, pass those directly; otherwise derive
|
|
88
|
+
// from windowMinutes or 0 (no bounds = lifetime).
|
|
89
|
+
const pSince = sinceTs > 0 ? sinceTs : (windowMinutes != null ? Date.now() - windowMinutes * 60_000 : 0);
|
|
90
|
+
const pUntil = untilTs > 0 ? untilTs : (windowMinutes != null ? Date.now() : 0);
|
|
91
|
+
const rows = readPrefixBreaks(stateDir, pSince, pUntil);
|
|
92
|
+
prefixBreaks = rows.map((r) => ({
|
|
93
|
+
id: r.id,
|
|
94
|
+
ts: r.ts,
|
|
95
|
+
cause: r.meta.cause,
|
|
96
|
+
confidence: r.meta.confidence,
|
|
97
|
+
prevHitPct: r.meta.prevHitPct,
|
|
98
|
+
currHitPct: r.meta.currHitPct,
|
|
99
|
+
breakAt: r.meta.breakAt,
|
|
100
|
+
}));
|
|
74
101
|
} catch {
|
|
75
|
-
/*
|
|
102
|
+
/* prefix-break read unavailable — response still returns empty array */
|
|
76
103
|
}
|
|
77
104
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
latestTurnAt: string | null;
|
|
87
|
-
};
|
|
88
|
-
savings: {
|
|
105
|
+
try {
|
|
106
|
+
const lifetime = windowMinutes != null
|
|
107
|
+
? readProviderCacheWindow(stateDir, windowMinutes)
|
|
108
|
+
: readProviderCacheLifetime(stateDir); // guardrails-allow PREVENT-PI-004: local SQLite read (loopback dashboard)
|
|
109
|
+
|
|
110
|
+
// D3: compute dollar savings from the latest model snapshot. Null-safe:
|
|
111
|
+
// when no snapshot or zero input rate, savings stays null (UI shows "—").
|
|
112
|
+
let savings: {
|
|
89
113
|
cacheReadSaved: number;
|
|
90
114
|
cacheWriteCost: number;
|
|
91
115
|
netSaved: number;
|
|
92
116
|
model: string;
|
|
93
117
|
inputRate: number;
|
|
94
|
-
} | null;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
} | null = null;
|
|
119
|
+
try {
|
|
120
|
+
const snap = latestModelSnapshot(stateDir); // guardrails-allow PREVENT-PI-004: local SQLite read (loopback dashboard)
|
|
121
|
+
if (snap && snap.inputRate > 0) {
|
|
122
|
+
const s = computeCacheSavings(
|
|
123
|
+
lifetime.totalCacheRead,
|
|
124
|
+
lifetime.totalCacheWrite,
|
|
125
|
+
snap.inputRate,
|
|
126
|
+
);
|
|
127
|
+
savings = {
|
|
128
|
+
cacheReadSaved: s.cacheReadSaved,
|
|
129
|
+
cacheWriteCost: s.cacheWriteCost,
|
|
130
|
+
netSaved: s.netSaved,
|
|
131
|
+
model: snap.modelName ?? snap.modelId ?? "unknown",
|
|
132
|
+
inputRate: snap.inputRate,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
} catch {
|
|
136
|
+
/* pricing unavailable — savings stays null */
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const body: {
|
|
140
|
+
cache: {
|
|
141
|
+
avgHitPct: number;
|
|
142
|
+
turnCount: number;
|
|
143
|
+
totalCacheRead: number;
|
|
144
|
+
totalCacheWrite: number;
|
|
145
|
+
totalInput: number;
|
|
146
|
+
firstTurnAt: string | null;
|
|
147
|
+
latestTurnAt: string | null;
|
|
148
|
+
byModel: Array<{
|
|
149
|
+
model: string;
|
|
150
|
+
hitPct: number;
|
|
151
|
+
totalCacheRead: number;
|
|
152
|
+
totalCacheWrite: number;
|
|
153
|
+
sampleCount: number;
|
|
154
|
+
}>;
|
|
155
|
+
};
|
|
156
|
+
savings: {
|
|
157
|
+
cacheReadSaved: number;
|
|
158
|
+
cacheWriteCost: number;
|
|
159
|
+
netSaved: number;
|
|
160
|
+
model: string;
|
|
161
|
+
inputRate: number;
|
|
162
|
+
} | null;
|
|
163
|
+
updatedAt: string;
|
|
164
|
+
windowMinutes?: number | null;
|
|
165
|
+
prefixBreaks: typeof prefixBreaks;
|
|
166
|
+
} = {
|
|
167
|
+
cache: {
|
|
168
|
+
avgHitPct: lifetime.avgHitPct,
|
|
169
|
+
turnCount: lifetime.sampleCount,
|
|
170
|
+
totalCacheRead: lifetime.totalCacheRead,
|
|
171
|
+
totalCacheWrite: lifetime.totalCacheWrite,
|
|
172
|
+
totalInput: lifetime.totalInput,
|
|
173
|
+
firstTurnAt: lifetime.firstSampleAt,
|
|
174
|
+
latestTurnAt: lifetime.latestSampleAt,
|
|
175
|
+
byModel: lifetime.byModel,
|
|
176
|
+
},
|
|
177
|
+
savings,
|
|
178
|
+
updatedAt: new Date().toISOString(),
|
|
179
|
+
windowMinutes,
|
|
180
|
+
prefixBreaks,
|
|
181
|
+
};
|
|
182
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
183
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
184
|
+
res.end(JSON.stringify(body));
|
|
185
|
+
} catch (e) {
|
|
186
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
187
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
188
|
+
res.end(
|
|
189
|
+
JSON.stringify({
|
|
190
|
+
error: "provider_cache_unavailable",
|
|
191
|
+
detail: String(e),
|
|
192
|
+
}),
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
} catch {
|
|
197
|
+
return false;
|
|
121
198
|
}
|
|
122
|
-
|
|
123
|
-
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-server/routes-memory.ts — Memory effectiveness stats route handler (S53B).
|
|
3
|
+
*
|
|
4
|
+
* GET /api/memory-status — Returns memoryStats() aggregated data:
|
|
5
|
+
* totalMemories, memoriesInLast30Days, topStableMemories, avgRecallScore.
|
|
6
|
+
*
|
|
7
|
+
* Guardrails: PREVENT-PI-004 (loopback-only), PREVENT-001 (null-safe JSON),
|
|
8
|
+
* PREVENT-002 (parameterized SQL — memoryStats uses openStore internally).
|
|
9
|
+
* Loopback-only localhost dashboard endpoint.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { createRequire } from "node:module";
|
|
13
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
14
|
+
import type { RouteContext } from "./routes-core.js";
|
|
15
|
+
import type { MemoryStatusResponse } from "./api-contracts/memory.js";
|
|
16
|
+
|
|
17
|
+
// PREVENT-PI-004: memoryStats is a pure local module (no network, no side-effects at import time).
|
|
18
|
+
// guardrails-allow PREVENT-PI-004: local TypeScript module import (loopback-only).
|
|
19
|
+
const { memoryStats } = createRequire(import.meta.url)(
|
|
20
|
+
"../../src/memoryStats.js",
|
|
21
|
+
) as typeof import("../../src/memoryStats.js");
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// handleMemoryStatus — "/api/memory-status"
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
export function handleMemoryStatus(
|
|
28
|
+
req: IncomingMessage,
|
|
29
|
+
res: ServerResponse,
|
|
30
|
+
ctx: RouteContext,
|
|
31
|
+
): boolean {
|
|
32
|
+
if (!req.url?.startsWith("/api/memory-status")) return false;
|
|
33
|
+
if (req.method !== "GET") {
|
|
34
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
35
|
+
res.writeHead(405, { "Content-Type": "application/json" });
|
|
36
|
+
res.end(JSON.stringify({ error: "method_not_allowed" }));
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
// PREVENT-PI-004: loopback-only — memoryStats reads from local SQLite store.
|
|
40
|
+
memoryStats(ctx.stateDir)
|
|
41
|
+
.then((stats) => {
|
|
42
|
+
const body: MemoryStatusResponse = {
|
|
43
|
+
totalMemories: stats.totalMemories,
|
|
44
|
+
memoriesInLast30Days: stats.memoriesInLast30Days,
|
|
45
|
+
topStableMemories: stats.topStableMemories.map((m) => ({
|
|
46
|
+
id: m.id,
|
|
47
|
+
text: m.text,
|
|
48
|
+
recallCount: m.recallCount,
|
|
49
|
+
lastRecalledAt: m.lastRecalledAt,
|
|
50
|
+
})),
|
|
51
|
+
avgRecallScore: stats.avgRecallScore,
|
|
52
|
+
};
|
|
53
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
54
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
55
|
+
res.end(JSON.stringify(body));
|
|
56
|
+
})
|
|
57
|
+
.catch(() => {
|
|
58
|
+
// guardrails-allow PREVENT-PI-004: loopback dashboard response (local)
|
|
59
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
60
|
+
res.end(JSON.stringify({ error: "memory_stats_unavailable" }));
|
|
61
|
+
});
|
|
62
|
+
return true;
|
|
63
|
+
}
|