pi-mega-compact 0.20.59 → 0.20.61

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 (102) hide show
  1. package/dist/config/vector-cortex-dash-0c.js +23 -0
  2. package/dist/config/vector-cortex-dash-0d.js +26 -0
  3. package/dist/config/vector-cortex.js +4 -0
  4. package/dist/config.js +1 -1
  5. package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +2 -0
  6. package/dist/src/config/vector-cortex-dash-0c.js +23 -0
  7. package/dist/src/config/vector-cortex-dash-0d.js +26 -0
  8. package/dist/src/config/vector-cortex.js +4 -0
  9. package/dist/src/config.js +1 -1
  10. package/extensions/dashboard-client/dist/assets/AdminTab-DEjVnlwe.js +2 -0
  11. package/extensions/dashboard-client/dist/assets/AdminTab-DEjVnlwe.js.map +1 -0
  12. package/extensions/dashboard-client/dist/assets/{AreaChart-GTwQxOAm.js → AreaChart-B1PoTqKJ.js} +2 -2
  13. package/extensions/dashboard-client/dist/assets/{AreaChart-GTwQxOAm.js.map → AreaChart-B1PoTqKJ.js.map} +1 -1
  14. package/extensions/dashboard-client/dist/assets/{BarChart-BFqUD5L4.js → BarChart-DaoONT_V.js} +2 -2
  15. package/extensions/dashboard-client/dist/assets/{BarChart-BFqUD5L4.js.map → BarChart-DaoONT_V.js.map} +1 -1
  16. package/extensions/dashboard-client/dist/assets/CacheTab-rD5sjlkW.js +2 -0
  17. package/extensions/dashboard-client/dist/assets/CacheTab-rD5sjlkW.js.map +1 -0
  18. package/extensions/dashboard-client/dist/assets/ConfigTab-BQkufK7t.js +2 -0
  19. package/extensions/dashboard-client/dist/assets/ConfigTab-BQkufK7t.js.map +1 -0
  20. package/extensions/dashboard-client/dist/assets/{EventsTab-BYLh6cud.js → EventsTab-DGlQzJaT.js} +2 -2
  21. package/extensions/dashboard-client/dist/assets/{EventsTab-BYLh6cud.js.map → EventsTab-DGlQzJaT.js.map} +1 -1
  22. package/extensions/dashboard-client/dist/assets/{HealthTab-CkJXEbjn.js → HealthTab-DW7kt4qm.js} +2 -2
  23. package/extensions/dashboard-client/dist/assets/{HealthTab-CkJXEbjn.js.map → HealthTab-DW7kt4qm.js.map} +1 -1
  24. package/extensions/dashboard-client/dist/assets/MaintenanceTab-CGiZ0OQ6.js +2 -0
  25. package/extensions/dashboard-client/dist/assets/{MaintenanceTab-Lm3v0nJO.js.map → MaintenanceTab-CGiZ0OQ6.js.map} +1 -1
  26. package/extensions/dashboard-client/dist/assets/MemoryMapTab-BwyrxjuW.js +2 -0
  27. package/extensions/dashboard-client/dist/assets/{MemoryMapTab-C8AeBIQi.js.map → MemoryMapTab-BwyrxjuW.js.map} +1 -1
  28. package/extensions/dashboard-client/dist/assets/{MetricsTab-m410T4vk.js → MetricsCards-IZaCOOXU.js} +2 -2
  29. package/extensions/dashboard-client/dist/assets/MetricsCards-IZaCOOXU.js.map +1 -0
  30. package/extensions/dashboard-client/dist/assets/MetricsTab-wCxVpHlC.js +2 -0
  31. package/extensions/dashboard-client/dist/assets/MetricsTab-wCxVpHlC.js.map +1 -0
  32. package/extensions/dashboard-client/dist/assets/{OverviewTab-BfDfMFXx.js → OverviewTab-DsH08Wr0.js} +2 -2
  33. package/extensions/dashboard-client/dist/assets/{OverviewTab-BfDfMFXx.js.map → OverviewTab-DsH08Wr0.js.map} +1 -1
  34. package/extensions/dashboard-client/dist/assets/{ReposTab-CsFxxqJ6.js → ReposTab-Dpb7sXWB.js} +2 -2
  35. package/extensions/dashboard-client/dist/assets/{ReposTab-CsFxxqJ6.js.map → ReposTab-Dpb7sXWB.js.map} +1 -1
  36. package/extensions/dashboard-client/dist/assets/SessionsTab-DFMo7tKA.js +2 -0
  37. package/extensions/dashboard-client/dist/assets/SessionsTab-DFMo7tKA.js.map +1 -0
  38. package/extensions/dashboard-client/dist/assets/SetupTab-D2IEBt1u.js +3 -0
  39. package/extensions/dashboard-client/dist/assets/SetupTab-D2IEBt1u.js.map +1 -0
  40. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BkRzjyRm.js → TimeSavedCard-BGPvmVFG.js} +2 -2
  41. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BkRzjyRm.js.map → TimeSavedCard-BGPvmVFG.js.map} +1 -1
  42. package/extensions/dashboard-client/dist/assets/TurnMemoryView-BZo09Jri.js +5 -0
  43. package/extensions/dashboard-client/dist/assets/TurnMemoryView-BZo09Jri.js.map +1 -0
  44. package/extensions/dashboard-client/dist/assets/TurnsTab-CosKNvMp.js +2 -0
  45. package/extensions/dashboard-client/dist/assets/TurnsTab-CosKNvMp.js.map +1 -0
  46. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-B8B8RStV.js → VcStatusBadge-UEZLL6Zj.js} +2 -2
  47. package/extensions/dashboard-client/dist/assets/{VcStatusBadge-B8B8RStV.js.map → VcStatusBadge-UEZLL6Zj.js.map} +1 -1
  48. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-CrGANNd_.js → VectorCortexTab-fDAgD2pN.js} +2 -2
  49. package/extensions/dashboard-client/dist/assets/{VectorCortexTab-CrGANNd_.js.map → VectorCortexTab-fDAgD2pN.js.map} +1 -1
  50. package/extensions/dashboard-client/dist/assets/{WikiTab-DyD0yGzI.js → WikiTab-7TIe2MkS.js} +2 -2
  51. package/extensions/dashboard-client/dist/assets/{WikiTab-DyD0yGzI.js.map → WikiTab-7TIe2MkS.js.map} +1 -1
  52. package/extensions/dashboard-client/dist/assets/button-C9qrZYdn.js +2 -0
  53. package/extensions/dashboard-client/dist/assets/{button-Bynl3ONj.js.map → button-C9qrZYdn.js.map} +1 -1
  54. package/extensions/dashboard-client/dist/assets/{card-Daf3pQIu.js → card-DxZRNC4E.js} +2 -2
  55. package/extensions/dashboard-client/dist/assets/{card-Daf3pQIu.js.map → card-DxZRNC4E.js.map} +1 -1
  56. package/extensions/dashboard-client/dist/assets/client-extra-Dj7wJs6Z.js +2 -0
  57. package/extensions/dashboard-client/dist/assets/{client-extra-DqAYZBW1.js.map → client-extra-Dj7wJs6Z.js.map} +1 -1
  58. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-fe5jjr.js → generateCategoricalChart-Dj-DYUgL.js} +2 -2
  59. package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-B-fe5jjr.js.map → generateCategoricalChart-Dj-DYUgL.js.map} +1 -1
  60. package/extensions/dashboard-client/dist/assets/{index-Bjvv23bp.js → index-Bq2n15a4.js} +31 -31
  61. package/extensions/dashboard-client/dist/assets/index-Bq2n15a4.js.map +1 -0
  62. package/extensions/dashboard-client/dist/assets/switch-1sEgLPHu.js +2 -0
  63. package/extensions/dashboard-client/dist/assets/{switch-CivyERPS.js.map → switch-1sEgLPHu.js.map} +1 -1
  64. package/extensions/dashboard-client/dist/assets/toggle-jMzQoJ2C.js +2 -0
  65. package/extensions/dashboard-client/dist/assets/{toggle-qmdkrAgF.js.map → toggle-jMzQoJ2C.js.map} +1 -1
  66. package/extensions/dashboard-client/dist/assets/{useSSE-uNuduyGe.js → useSSE-Dxy616R1.js} +2 -2
  67. package/extensions/dashboard-client/dist/assets/{useSSE-uNuduyGe.js.map → useSSE-Dxy616R1.js.map} +1 -1
  68. package/extensions/dashboard-client/dist/index.html +1 -1
  69. package/extensions/dashboard-client/src/App.tsx +150 -17
  70. package/extensions/dashboard-client/src/tabs/AdminTab.tsx +81 -0
  71. package/extensions/dashboard-client/src/tabs/CacheTab/MetricsCards.tsx +66 -0
  72. package/extensions/dashboard-client/src/tabs/CacheTab.tsx +46 -0
  73. package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +10 -51
  74. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +33 -4
  75. package/extensions/dashboard-client/src/tabs/TurnsTab.tsx +9 -366
  76. package/extensions/dashboard-client/src/tabs/dashHashRouter.ts +76 -0
  77. package/extensions/dashboard-client/src/tabs/index.ts +7 -6
  78. package/extensions/dashboard-client/src/tabs/registry.ts +26 -1
  79. package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +12 -0
  80. package/package.json +1 -1
  81. package/src/config/vector-cortex-dash-0c.ts +25 -0
  82. package/src/config/vector-cortex-dash-0d.ts +28 -0
  83. package/src/config/vector-cortex.ts +4 -0
  84. package/src/config.ts +2 -0
  85. package/extensions/dashboard-client/dist/assets/CacheTab-BLM6_PQQ.js +0 -2
  86. package/extensions/dashboard-client/dist/assets/CacheTab-BLM6_PQQ.js.map +0 -1
  87. package/extensions/dashboard-client/dist/assets/HydeDetailPanel-Dt9T7kc5.js +0 -5
  88. package/extensions/dashboard-client/dist/assets/HydeDetailPanel-Dt9T7kc5.js.map +0 -1
  89. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Lm3v0nJO.js +0 -2
  90. package/extensions/dashboard-client/dist/assets/MemoryMapTab-C8AeBIQi.js +0 -2
  91. package/extensions/dashboard-client/dist/assets/MetricsTab-m410T4vk.js.map +0 -1
  92. package/extensions/dashboard-client/dist/assets/SessionsTab-DstDOzwu.js +0 -2
  93. package/extensions/dashboard-client/dist/assets/SessionsTab-DstDOzwu.js.map +0 -1
  94. package/extensions/dashboard-client/dist/assets/SetupTab-DVT4PrH0.js +0 -3
  95. package/extensions/dashboard-client/dist/assets/SetupTab-DVT4PrH0.js.map +0 -1
  96. package/extensions/dashboard-client/dist/assets/TurnsTab-D5QTnv52.js +0 -2
  97. package/extensions/dashboard-client/dist/assets/TurnsTab-D5QTnv52.js.map +0 -1
  98. package/extensions/dashboard-client/dist/assets/button-Bynl3ONj.js +0 -2
  99. package/extensions/dashboard-client/dist/assets/client-extra-DqAYZBW1.js +0 -2
  100. package/extensions/dashboard-client/dist/assets/index-Bjvv23bp.js.map +0 -1
  101. package/extensions/dashboard-client/dist/assets/switch-CivyERPS.js +0 -2
  102. package/extensions/dashboard-client/dist/assets/toggle-qmdkrAgF.js +0 -2
@@ -1,374 +1,17 @@
1
1
  /**
2
- * dashboard-client/src/tabs/TurnsTab.tsx — Turn-by-turn memory tracking + recall (S52).
2
+ * dashboard-client/src/tabs/TurnsTab.tsx — Turn-by-turn memory surface (S52).
3
3
  *
4
- * Fetches /api/turns (conversation list), expands the active conversation into
5
- * per-turn detail (/api/turns/conversation/:id), and renders:
6
- * - Conversation summary list (turn count, recall total, epochs, last turn).
7
- * - Per-turn rows: turn index, role, ctx tokens/percent + pressure band,
8
- * epoch id, and the injected-checkpoint recall set (the memory recalled
9
- * at each turn, with score + source).
10
- * - Pending rewind intents (S52A) + Fork action (S50C primitive).
11
- *
12
- * Read-mostly via /api/turns; fork/intent/prune via POST. No absolute URLs
13
- * (PREVENT-PI-004: loopback-only, same-origin static bundle).
4
+ * DASH-0d consolidation: the sessions surface owns the turns body as a drill-
5
+ * down (`SessionsTab/TurnMemoryView.tsx`, re-homed VERBATIM in DASH-0b). This
6
+ * standalone top-level file is reduced to a thin shell re-exporting
7
+ * `TurnMemoryView`, so the flag-off pre-rollup 13-tab surface set still
8
+ * resolves `TurnsTab` (deep-link + lazy-import anchor) with no duplicated
9
+ * render body. The canonical home is `SessionsTab/TurnMemoryView.tsx`.
14
10
  */
15
11
 
16
12
  import type React from "react";
17
- import { useCallback, useState } from "react";
18
- import { useApi } from "../hooks/useApi";
19
- import {
20
- fetchTurns,
21
- fetchConversationTurns,
22
- fetchTurnIntents,
23
- postFork,
24
- postTurnIntent,
25
- } from "../api/client";
26
- import type {
27
- TurnsResponse,
28
- ConversationTurnsResponse,
29
- RewindIntentsResponse,
30
- TurnRow,
31
- ConversationSummary,
32
- } from "@contracts";
33
- import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card";
34
- import { Badge } from "../components/ui/badge";
35
- import { Button } from "../components/ui/button";
36
- import { HydeDetailPanel } from "../components/HydeDetailPanel";
37
-
38
- function fmtTs(ms: number): string {
39
- if (!ms) return "—";
40
- return new Date(ms).toLocaleString();
41
- }
42
-
43
- function bandVariant(band: TurnRow["pressureBand"]): "success" | "warning" | "danger" | "default" {
44
- if (band === "green") return "success";
45
- if (band === "yellow") return "warning";
46
- if (band === "red") return "danger";
47
- return "default";
48
- }
49
-
50
- function sourceLabel(s: TurnRow["recall"][number]["source"]): string {
51
- if (s === "checkpoint") return "ckpt";
52
- if (s === "cluster_summary") return "raptor";
53
- return "mem";
54
- }
13
+ import { TurnMemoryView } from "./SessionsTab/TurnMemoryView";
55
14
 
56
15
  export default function TurnsTab(): React.ReactElement {
57
- const {
58
- data: turns,
59
- loading,
60
- error,
61
- } = useApi<TurnsResponse>(
62
- useCallback(() => fetchTurns(), []),
63
- {
64
- pollInterval: 10_000,
65
- },
66
- );
67
- const { data: intents } = useApi<RewindIntentsResponse>(
68
- useCallback(() => fetchTurnIntents(), []),
69
- { pollInterval: 5_000 },
70
- );
71
- const [expanded, setExpanded] = useState<string | null>(null);
72
- const [detail, setDetail] = useState<ConversationTurnsResponse | null>(null);
73
- const [detailLoading, setDetailLoading] = useState(false);
74
- const [busy, setBusy] = useState<string | null>(null);
75
- const [notice, setNotice] = useState<string | null>(null);
76
-
77
- const expand = useCallback(
78
- async (conversationId: string) => {
79
- if (expanded === conversationId) {
80
- setExpanded(null);
81
- setDetail(null);
82
- return;
83
- }
84
- setExpanded(conversationId);
85
- setDetailLoading(true);
86
- setDetail(null);
87
- try {
88
- const d = await fetchConversationTurns(conversationId);
89
- setDetail(d);
90
- } finally {
91
- setDetailLoading(false);
92
- }
93
- },
94
- [expanded],
95
- );
96
-
97
- const onFork = useCallback(
98
- async (conversationId: string, turnIndex: number) => {
99
- setBusy(`fork:${conversationId}:${turnIndex}`);
100
- setNotice(null);
101
- try {
102
- const out = await postFork(conversationId, turnIndex);
103
- setNotice(
104
- `Forked → ${out.childConversationId} (${out.recalledCount} recalled)`,
105
- );
106
- } catch (e) {
107
- setNotice(`Fork failed: ${(e as Error).message}`);
108
- } finally {
109
- setBusy(null);
110
- }
111
- },
112
- [],
113
- );
114
-
115
- const onRewind = useCallback(
116
- async (conversationId: string, turnIndex: number) => {
117
- setBusy(`rewind:${conversationId}:${turnIndex}`);
118
- setNotice(null);
119
- try {
120
- await postTurnIntent(conversationId, turnIndex);
121
- setNotice(`Rewind intent queued for turn ${turnIndex}`);
122
- } catch (e) {
123
- setNotice(`Rewind failed: ${(e as Error).message}`);
124
- } finally {
125
- setBusy(null);
126
- }
127
- },
128
- [],
129
- );
130
-
131
- if (error && !turns) {
132
- return <div className="tab-stub">Error loading turns: {error.message}</div>;
133
- }
134
- if (loading && !turns) {
135
- return <div className="tab-stub">Loading turns…</div>;
136
- }
137
- if (!turns || turns.conversations.length === 0) {
138
- return (
139
- <div className="tab-stub">
140
- <h3>Turn-by-turn memory</h3>
141
- <p>
142
- No turns recorded yet. Per-turn tracking starts when{" "}
143
- <code>MEGACOMPACT_TURNS_DB=1</code> and the session runs through a
144
- compaction. Each turn records its context metrics + the checkpoints
145
- recalled into it.
146
- </p>
147
- </div>
148
- );
149
- }
150
-
151
- return (
152
- <div className="flex flex-col gap-4">
153
- <h3 className="font-heading text-lg font-semibold">
154
- Turn-by-turn memory tracking + recall
155
- </h3>
156
- {notice && <Badge variant="warning">{notice}</Badge>}
157
-
158
- {intents && intents.intents.length > 0 && (
159
- <Card>
160
- <CardHeader>
161
- <CardTitle>
162
- Pending rewind intents ({intents.intents.length})
163
- </CardTitle>
164
- </CardHeader>
165
- <CardContent>
166
- <ul className="list-disc space-y-1 pl-5">
167
- {intents.intents.map((i) => (
168
- <li key={i.id}>
169
- {fmtTs(i.createdAt)} — rewind{" "}
170
- <code>{i.conversationId}</code> to turn {i.targetTurnIndex}
171
- </li>
172
- ))}
173
- </ul>
174
- </CardContent>
175
- </Card>
176
- )}
177
-
178
- <Card>
179
- <CardHeader>
180
- <CardTitle>
181
- Conversations ({turns.conversations.length})
182
- </CardTitle>
183
- </CardHeader>
184
- <CardContent>
185
- <table className="w-full border-collapse text-sm">
186
- <thead>
187
- <tr>
188
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Conversation</th>
189
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Turns</th>
190
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Recall</th>
191
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Epochs</th>
192
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Avg ctx%</th>
193
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Last turn</th>
194
- <th className="border-b border-border px-3 py-2"></th>
195
- </tr>
196
- </thead>
197
- <tbody>
198
- {turns.conversations.map((c: ConversationSummary) => (
199
- <ConversationRow
200
- key={c.conversationId}
201
- c={c}
202
- active={turns.activeConversationId === c.conversationId}
203
- expanded={expanded === c.conversationId}
204
- onExpand={() => expand(c.conversationId)}
205
- />
206
- ))}
207
- </tbody>
208
- </table>
209
- </CardContent>
210
- </Card>
211
-
212
- {expanded && (
213
- <Card>
214
- <CardHeader>
215
- <CardTitle>
216
- Turns in <code>{expanded}</code>
217
- </CardTitle>
218
- </CardHeader>
219
- <CardContent>
220
- {detailLoading ? (
221
- <div className="text-sm text-muted-foreground">Loading turns…</div>
222
- ) : detail ? (
223
- <TurnDetail
224
- detail={detail}
225
- busy={busy}
226
- onFork={onFork}
227
- onRewind={onRewind}
228
- />
229
- ) : (
230
- <div className="text-sm text-muted-foreground">No detail.</div>
231
- )}
232
- </CardContent>
233
- </Card>
234
- )}
235
- </div>
236
- );
237
- }
238
-
239
- function ConversationRow({
240
- c,
241
- active,
242
- expanded,
243
- onExpand,
244
- }: {
245
- c: ConversationSummary;
246
- active: boolean;
247
- expanded: boolean;
248
- onExpand: () => void;
249
- }): React.ReactElement {
250
- return (
251
- <>
252
- <tr
253
- className={`border-b border-border/50 hover:bg-bg-elevated/40 ${
254
- active ? "bg-primary/10" : ""
255
- }`}
256
- onClick={onExpand}
257
- style={{ cursor: "pointer" }}
258
- >
259
- <td className="px-3 py-2">
260
- {expanded ? "▾" : "▸"} <code>{c.conversationId}</code>
261
- {active && <Badge variant="accent" className="ml-2">active</Badge>}
262
- </td>
263
- <td className="px-3 py-2 text-right">{c.turnCount}</td>
264
- <td className="px-3 py-2 text-right">{c.totalRecall}</td>
265
- <td className="px-3 py-2 text-right">{c.epochCount}</td>
266
- <td className="px-3 py-2 text-right">{c.avgCtxPercent.toFixed(0)}%</td>
267
- <td className="px-3 py-2">{fmtTs(c.lastTurnAt)}</td>
268
- <td className="px-3 py-2" />
269
- </tr>
270
- </>
271
- );
272
- }
273
-
274
- function TurnDetail({
275
- detail,
276
- busy,
277
- onFork,
278
- onRewind,
279
- }: {
280
- detail: ConversationTurnsResponse;
281
- busy: string | null;
282
- onFork: (conversationId: string, turnIndex: number) => void;
283
- onRewind: (conversationId: string, turnIndex: number) => void;
284
- }): React.ReactElement {
285
- return (
286
- <table className="w-full border-collapse text-sm">
287
- <thead>
288
- <tr>
289
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">#</th>
290
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Role</th>
291
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Ctx</th>
292
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Band</th>
293
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Epoch</th>
294
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Recalled checkpoints (memory recall)</th>
295
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">HyDE</th>
296
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Ended</th>
297
- <th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Actions</th>
298
- </tr>
299
- </thead>
300
- <tbody>
301
- {detail.turns.map((t) => (
302
- <tr
303
- key={`${t.conversationId}:${t.turnIndex}`}
304
- className="border-b border-border/50 hover:bg-bg-elevated/40"
305
- >
306
- <td className="px-3 py-2 text-right">{t.turnIndex}</td>
307
- <td className="px-3 py-2">{t.role}</td>
308
- <td className="px-3 py-2">
309
- {t.ctxTokens ?? "—"}
310
- {t.ctxPercent != null && (
311
- <span className="text-muted-foreground">
312
- {" "}
313
- · {t.ctxPercent.toFixed(0)}%
314
- </span>
315
- )}
316
- </td>
317
- <td className="px-3 py-2">
318
- <Badge variant={bandVariant(t.pressureBand)}>
319
- {t.pressureBand ?? "—"}
320
- </Badge>
321
- </td>
322
- <td className="px-3 py-2">{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : "—"}</td>
323
- <td className="px-3 py-2">
324
- {t.recall.length === 0 ? (
325
- <span className="text-muted-foreground">—</span>
326
- ) : (
327
- <ul className="space-y-1">
328
- {t.recall.map((r) => (
329
- <li key={r.checkpointId}>
330
- <code>{r.checkpointId.slice(0, 12)}</code>{" "}
331
- <span className="text-muted-foreground">
332
- {sourceLabel(r.source)} · {r.score.toFixed(2)}
333
- {r.raptorLevel != null ? ` · L${r.raptorLevel}` : ""}
334
- </span>
335
- </li>
336
- ))}
337
- </ul>
338
- )}
339
- </td>
340
- <td className="px-3 py-2 align-top">
341
- <HydeDetailPanel
342
- conversationId={t.conversationId}
343
- turnIndex={t.turnIndex}
344
- />
345
- </td>
346
- <td className="px-3 py-2">{fmtTs(t.endedAt)}</td>
347
- <td className="px-3 py-2">
348
- <div className="flex gap-2">
349
- <Button
350
- type="button"
351
- variant="outline"
352
- size="sm"
353
- disabled={busy !== null}
354
- onClick={() => onFork(t.conversationId, t.turnIndex)}
355
- >
356
- fork
357
- </Button>
358
- <Button
359
- type="button"
360
- variant="outline"
361
- size="sm"
362
- disabled={busy !== null}
363
- onClick={() => onRewind(t.conversationId, t.turnIndex)}
364
- >
365
- rewind
366
- </Button>
367
- </div>
368
- </td>
369
- </tr>
370
- ))}
371
- </tbody>
372
- </table>
373
- );
16
+ return <TurnMemoryView />;
374
17
  }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * dashboard-client/src/tabs/dashHashRouter.ts — DASH-0d additive hash→surface
3
+ * deep-link router.
4
+ *
5
+ * The dashboard has historically had NO URL-routing (single `useState<TabId>
6
+ * ("overview")` in App.tsx). DASH-0d adds an ADDITIVE hash listener so every
7
+ * legacy deep link (e.g. `#turns`, `#metrics`, `#repos`) still lands on a live
8
+ * consolidated surface, and an empty hash keeps the current behavior (the
9
+ * caller's default tab). It does NOT replace the existing tab state — App.tsx
10
+ * keeps `useState` and this hook only *points* at a surface when the hash maps
11
+ * to one.
12
+ *
13
+ * Mapping (DASH-0a `DEEP_LINK_TARGETS` + the DASH-0d release set):
14
+ * #sessions, #turns → sessions
15
+ * #cache, #metrics → cache-perf
16
+ * #repos, #wiki, #memory-map → memory-graph
17
+ * #events, #health, #vector-cortex → diagnostics
18
+ * #maintenance, #config → admin
19
+ * #setup, #overview → themselves
20
+ * (empty) → null (current behavior)
21
+ *
22
+ * PREVENT-PI-004: browser `location` + `hashchange` only — no network.
23
+ * PREVENT-011: no `any`. Pure client view concern; no endpoint reads added.
24
+ */
25
+
26
+ import { useEffect, useState } from "react";
27
+ import type { DashTabId } from "./registry";
28
+
29
+ /**
30
+ * The consolidated surface a legacy hash resolves to. Every key is a legacy
31
+ * deep-link fragment mapped onto the fixed 7 surfaces. `config`/`setup`/
32
+ * `overview` are explicit release aliases so no old bookmark goes dead.
33
+ */
34
+ export const HASH_TO_SURFACE: Readonly<Record<string, DashTabId>> = {
35
+ overview: "overview",
36
+ sessions: "sessions",
37
+ turns: "sessions",
38
+ cache: "cache-perf",
39
+ metrics: "cache-perf",
40
+ "memory-map": "memory-graph",
41
+ repos: "memory-graph",
42
+ wiki: "memory-graph",
43
+ "vector-cortex": "diagnostics",
44
+ events: "diagnostics",
45
+ health: "diagnostics",
46
+ setup: "setup",
47
+ config: "admin",
48
+ maintenance: "admin",
49
+ };
50
+
51
+ /** Resolve the current `location.hash` to a consolidated surface (null if empty). */
52
+ export function resolveHashToSurface(hash: string): DashTabId | null {
53
+ const clean = hash.replace(/^#/, "").trim();
54
+ if (!clean) return null;
55
+ const surface = HASH_TO_SURFACE[clean];
56
+ return surface ?? null;
57
+ }
58
+
59
+ /**
60
+ * Additive hash listener. Returns the consolidated `DashTabId` the current
61
+ * `location.hash` maps to, or `null` when the hash is empty (current behavior)
62
+ * or unmapped. Re-syncs whenever the hash changes.
63
+ */
64
+ export function useHashTab(): DashTabId | null {
65
+ const [surface, setSurface] = useState<DashTabId | null>(() =>
66
+ resolveHashToSurface(window.location.hash),
67
+ );
68
+
69
+ useEffect(() => {
70
+ const onHashChange = () => setSurface(resolveHashToSurface(window.location.hash));
71
+ window.addEventListener("hashchange", onHashChange);
72
+ return () => window.removeEventListener("hashchange", onHashChange);
73
+ }, []);
74
+
75
+ return surface;
76
+ }
@@ -10,12 +10,13 @@
10
10
  * Host mapping (surface → component):
11
11
  * - overview → OverviewTab
12
12
  * - sessions → SessionsTab (TurnsTab folded in via TurnMemoryView)
13
- * - cache-perf → CacheTab
13
+ * - cache-perf → CacheTab (label "Cache+Performance"; MetricsTab
14
+ * folded in via CacheTab/MetricsCards)
14
15
  * - memory-graph → MemoryMapTab
15
16
  * - diagnostics → VectorCortexTab
16
- * - setup → SetupTab
17
- * - admin → AdminTab (RESERVED alias — maps to the existent
18
- * MaintenanceTab; no standalone AdminTab.tsx yet)
17
+ * - setup → SetupTab (config sub-tab hidden when DASH-0c ON)
18
+ * - admin → AdminTab (DASH-0c: MaintenanceTab + ConfigTab
19
+ * combined via an AdminViews toggle)
19
20
  *
20
21
  * PREVENT-PI-004: imports only — no network. PREVENT-011: no `any`.
21
22
  */
@@ -26,5 +27,5 @@ export { default as CacheTab } from "./CacheTab";
26
27
  export { default as MemoryMapTab } from "./MemoryMapTab";
27
28
  export { default as VectorCortexTab } from "./VectorCortexTab";
28
29
  export { default as SetupTab } from "./SetupTab";
29
- /** Reserved admin-surface alias: maps to the existent MaintenanceTab host. */
30
- export { default as AdminTab } from "./MaintenanceTab";
30
+ /** DASH-0c: the Admin surface combines MaintenanceTab + ConfigTab. */
31
+ export { default as AdminTab } from "./AdminTab";
@@ -66,7 +66,7 @@ export const ADVANCED_TAB_IDS: ReadonlySet<TabId> = new Set(
66
66
  * LEFT UNCHANGED (rollback-safe) — this constant documents the 7 surfaces the
67
67
  * DASH-0d rewire will navigate, and deliberately does NOT replace TabId.
68
68
  */
69
- export const DASH_SURFACE_IDS: readonly string[] = [
69
+ export const DASH_SURFACE_IDS = [
70
70
  "overview",
71
71
  "sessions",
72
72
  "cache-perf",
@@ -75,3 +75,28 @@ export const DASH_SURFACE_IDS: readonly string[] = [
75
75
  "setup",
76
76
  "admin",
77
77
  ] as const;
78
+
79
+ /** The fixed 7 consolidated navigational surface ids (DASH-0d navigation set).
80
+ * Distinct from the legacy 13-tab `TabId` union, which is retained for the
81
+ * flag-off (pre-rollup) surface set + the sidebar/AppShell nav types. */
82
+ export type DashTabId = (typeof DASH_SURFACE_IDS)[number];
83
+
84
+ /** Exactly 7 top-level navigational surfaces (DASH-0d tab-count contract). */
85
+ export const DASH_TAB_COUNT: number = DASH_SURFACE_IDS.length;
86
+
87
+ /**
88
+ * DASH-0c: labels for the consolidated surfaces. Additive — the 13-tab
89
+ * `PRIMARY_TABS`/`ADVANCED_TABS` labels above stay untouched (rollback-safe;
90
+ * the live 13-tab UI renders as today until the DASH-0d rewire). `cache-perf`
91
+ * takes the "Cache+Performance" label once MetricsTab folds in as a Performance
92
+ * section; `admin` hosts the combined Maintenance+Config AdminTab.
93
+ */
94
+ export const DASH_SURFACE_LABELS: Readonly<Record<string, string>> = {
95
+ overview: "Overview",
96
+ sessions: "Sessions",
97
+ "cache-perf": "Cache+Performance",
98
+ "memory-graph": "Memory Graph",
99
+ diagnostics: "Diagnostics",
100
+ setup: "Setup",
101
+ admin: "Admin",
102
+ } as const;
@@ -342,5 +342,17 @@ export const VECTOR_CORTEX_SETTINGS: SettingGroup = {
342
342
  "DASH-0b dashboard consolidation execution: (1) the Sessions surface absorbs TurnsTab as a drill-down — a SessionsViews toggle renders the existent session summary/chart/table or the turns view (TurnMemoryView); (2) VectorCortexTab re-groups its flat 14-card layout under 4 <section aria-labelledby> headers (Cortex status / repair / cache / adaptive). OFF = SessionsTab renders only its own body (no toggle, no TurnMemoryView) and VectorCortexTab keeps its flat card layout (byte-identical predecessor).",
343
343
  true,
344
344
  ),
345
+ boolDirect(
346
+ "MEGACOMPACT_DASH_0C",
347
+ "Dashboard Consolidation — Cache+Performance / Admin",
348
+ "DASH-0c dashboard consolidation execution: (1) the Cache surface absorbs MetricsTab as a Performance section (CacheTab label becomes 'Cache+Performance'); (2) MaintenanceTab + ConfigTab combine under a new AdminTab delegate-shell with an AdminViews toggle (maintenance/config), and SetupTab hides its Config sub-tab. OFF = CacheTab renders only its cache sections, MetricsTab/MaintenanceTab/ConfigTab render as standalone surfaces, SetupTab keeps its Config sub-tab (byte-identical predecessor).",
349
+ true,
350
+ ),
351
+ boolDirect(
352
+ "MEGACOMPACT_DASH_0D",
353
+ "Dashboard Consolidation — Rollup / 7-surface",
354
+ "DASH-0d dashboard consolidation roll-up: App.tsx consolidates its lazy list + TabContent switch onto the 7 fixed navigational surfaces (Overview, Sessions, Cache+Performance, Memory Graph, Diagnostics, Setup, Admin) with an additive hash→surface deep-link router; the duplicate TurnsTab/MetricsTab indirection bodies are reconciled to their canonical homes. OFF = App.tsx reproduces the pre-rollup 13-tab surface set byte-identically (byte-identical DASH-0c predecessor).",
355
+ true,
356
+ ),
345
357
  ],
346
358
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-mega-compact",
3
- "version": "0.20.59",
3
+ "version": "0.20.61",
4
4
  "description": "Layered, local, vector-backed context compressor for pi — supersede/collapse/cluster compaction with deduped inline recall.",
5
5
  "type": "module",
6
6
  "license": "BSD-3-Clause",
@@ -0,0 +1,25 @@
1
+ /**
2
+ * config/vector-cortex-dash-0c.ts — DASH-0c dashboard consolidation execution flag.
3
+ *
4
+ * Extracted to this sibling (per the vector-cortex-dash-0a.ts precedent) so
5
+ * src/config/vector-cortex.ts stays under the 300-line soft limit. The flag is
6
+ * positive, defaults ON, and `MEGACOMPACT_DASH_0C=0` is byte-identical to the
7
+ * predecessor: CacheTab and MetricsTab render as two independent top-level
8
+ * surfaces, MaintenanceTab and ConfigTab render exactly as today, and SetupTab
9
+ * keeps its Config sub-tab. Registered as a visible VECTOR_CORTEX_SETTINGS
10
+ * boolDirect toggle, never EXCLUDED.
11
+ *
12
+ * Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
13
+ */
14
+
15
+ import { sprintFlag } from "./vector-cortex-flag.js";
16
+
17
+ /**
18
+ * DASH-0c — second execution sprint of the DASH consolidation plan:
19
+ * (1) Cache+Performance — CacheTab absorbs MetricsTab as a Performance section
20
+ * via MetricsCards; (2) Admin — MaintenanceTab + ConfigTab combine under a
21
+ * new AdminTab delegate-shell with an AdminViews toggle, and SetupTab hides
22
+ * its Config sub-tab. `MEGACOMPACT_DASH_0C=0` renders the predecessor
23
+ * standalone surfaces — byte-identical.
24
+ */
25
+ export const DASH_0C_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_DASH_0C");
@@ -0,0 +1,28 @@
1
+ /**
2
+ * config/vector-cortex-dash-0d.ts — DASH-0d dashboard consolidation roll-up flag.
3
+ *
4
+ * Extracted to this sibling (per the vector-cortex-dash-0c.ts precedent) so
5
+ * src/config/vector-cortex.ts stays under the 300-line soft limit. The flag is
6
+ * positive, defaults ON, and `MEGACOMPACT_DASH_0D=0` is byte-identical to the
7
+ * predecessor (DASH-0c): App.tsx renders the pre-rollup 13-tab surface set and
8
+ * the registry holds the 13-tab union; no indirection name is removed and no
9
+ * audit/verifier script is invoked by CI. Registered as a visible
10
+ * VECTOR_CORTEX_SETTINGS boolDirect toggle, never EXCLUDED.
11
+ *
12
+ * Pi-agnostic, dependency-free (PREVENT-PI-004 / PREVENT-011).
13
+ */
14
+
15
+ import { sprintFlag } from "./vector-cortex-flag.js";
16
+
17
+ /**
18
+ * DASH-0d — final DASH sprint, the roll-up that makes the 7-surface target
19
+ * externally provable: (1) App.tsx consolidates its lazy list to the 7 fixed
20
+ * navigational surfaces (Overview, Sessions, Cache+Performance, Memory Graph,
21
+ * Diagnostics, Setup, Admin) with an additive hash→surface router; (2) the
22
+ * duplicate TurnsTab/MetricsTab indirection bodies are reconciled to their
23
+ * canonical homes (TurnMemoryView / MetricsCards); (3) new dash-tab-count.mjs
24
+ * and dashboard-audit.mjs verifiers prove the consolidated surface count + a11y
25
+ * contract; (4) conformance fixtures DASH-0D-001..004 + evidence roll-up.
26
+ * `MEGACOMPACT_DASH_0D=0` renders the pre-rollup 13-surface set — byte-identical.
27
+ */
28
+ export const DASH_0D_ENABLED = (): boolean => sprintFlag("MEGACOMPACT_DASH_0D");
@@ -73,6 +73,10 @@ export { REPO_CORPUS_ENABLED } from "./repo-corpus.js";
73
73
  export { DASH_0A_ENABLED } from "./vector-cortex-dash-0a.js";
74
74
  // DASH-0b dashboard consolidation execution flag extracted to vector-cortex-dash-0b.ts.
75
75
  export { DASH_0B_ENABLED } from "./vector-cortex-dash-0b.js";
76
+ // DASH-0c dashboard consolidation execution flag extracted to vector-cortex-dash-0c.ts.
77
+ export { DASH_0C_ENABLED } from "./vector-cortex-dash-0c.js";
78
+ // DASH-0d dashboard consolidation roll-up flag extracted to vector-cortex-dash-0d.ts.
79
+ export { DASH_0D_ENABLED } from "./vector-cortex-dash-0d.js";
76
80
  export { ENC_1A_ENABLED } from "./vector-cortex-enc1a.js";
77
81
  export {
78
82
  ENC_1B_ENABLED,
package/src/config.ts CHANGED
@@ -207,6 +207,8 @@ export {
207
207
  REPO_CORPUS_ENABLED,
208
208
  DASH_0A_ENABLED,
209
209
  DASH_0B_ENABLED,
210
+ DASH_0C_ENABLED,
211
+ DASH_0D_ENABLED,
210
212
  BREAKER_WINDOW_MS,
211
213
  BREAKER_MIN_ATTEMPTS,
212
214
  BREAKER_PERF_FAILURES,
@@ -1,2 +0,0 @@
1
- import{j as e,r as h,u as m,y as I,z as k,x as w,l as D}from"./index-Bjvv23bp.js";import{C as W,T as F}from"./TimeSavedCard-BkRzjyRm.js";import{b as u,c as v,d as _,e as O,f as x}from"./format-COjDIVGj.js";import{l as G}from"./pricing-DkYp8-vi.js";import{C as f,a as C,b as S,c as N}from"./card-Daf3pQIu.js";import{B}from"./button-Bynl3ONj.js";import{a as z}from"./client-extra-DqAYZBW1.js";function L(t){return t>=80?"ov-stat-value-green":t>=50?"ov-stat-value-yellow":"ov-stat-value-red"}function K(t){return t==null?"":t>=0?"ov-stat-value-green":"ov-stat-value-red"}function n({label:t,value:a,className:s,title:l}){return e.jsxs("div",{className:"flex items-baseline justify-between border-b border-border py-1 text-sm",children:[e.jsx("span",{className:"text-xs text-muted-foreground",title:l,children:t}),e.jsx("span",{className:`font-semibold${s?` ${s}`:""}`,children:a})]})}function U(t){return e.jsxs(f,{className:"electric-hover",children:[e.jsx(C,{children:e.jsx(S,{children:"Provider Prompt Cache"})}),e.jsxs(N,{children:[e.jsx(n,{label:"Cache Hit Rate",value:`${t.hitPct.toFixed(1)}%`,className:L(t.hitPct)}),e.jsx(n,{label:"Turns Recorded",value:String(t.turnCount)}),e.jsx(n,{label:"Cache Read Tokens",value:u(t.totalCacheRead)}),e.jsx(n,{label:"Cache Write Tokens",value:u(t.totalCacheWrite)}),e.jsx(n,{label:"Input Tokens",value:u(t.totalInput)}),e.jsx(n,{label:"$ Saved (reads)",value:v(t.cacheReadSaved)}),e.jsx(n,{label:"Write Investment",value:v(t.cacheWriteCost)}),e.jsx(n,{label:"Net Saved",value:v(t.netSaved),className:K(t.netSaved)}),e.jsx(n,{label:"Model",value:t.modelLabel??"—"}),e.jsx(n,{label:"Tracked Since",value:_(t.firstTurnAt)}),e.jsx(n,{label:"Last Updated",value:O(t.latestTurnAt)}),t.byModel.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"mt-2 text-xs font-semibold text-muted-foreground",children:"Per Model"}),t.byModel.map(a=>{const s=G(a.model),l=s!=null?a.totalCacheRead/1e6*s:null,r=s!=null?a.totalCacheWrite/1e6*s:null;return e.jsxs("div",{className:"mt-2",children:[e.jsx(n,{label:"Model",value:a.model}),e.jsx(n,{label:"Hit Rate",value:`${a.hitPct.toFixed(1)}%`,className:L(a.hitPct)}),e.jsx(n,{label:"Cache Read",value:u(a.totalCacheRead)}),e.jsx(n,{label:"Cache Write",value:u(a.totalCacheWrite)}),e.jsx(n,{label:"Samples",value:String(a.sampleCount)}),e.jsx(n,{label:"$ Saved (reads)",value:l!=null?v(l):"—"}),e.jsx(n,{label:"Write Investment",value:r!=null?v(r):"—"})]},a.model)})]})]})]})}const V=["ov-bar-green","ov-bar-blue","ov-bar-teal","ov-bar-yellow","ov-bar-gray"],q=["Permanent","Epoch","Topic","Thread","Volatile"],J={good:"ov-text-green",fair:"ov-text-yellow",degraded:"ov-text-orange",poor:"ov-text-red"};function Q({data:t}){const a=Math.max(...t.buckets.map(l=>l.count),1),s=J[t.health.label]??"ov-text-gray";return e.jsxs("div",{className:"ov-card",children:[e.jsx("h3",{className:"ov-card-title",children:"Cache Stripe Distribution"}),e.jsxs("div",{className:"ov-stripe-health-summary",children:[e.jsx("span",{className:`ov-stripe-health-badge ${s}`,children:t.health.label}),e.jsx("span",{className:"ov-stripe-health-score",children:x(t.health.score)}),e.jsxs("span",{className:"ov-stripe-churn",children:["Churn: ",x(t.health.churnRate)]}),e.jsxs("span",{className:"ov-stripe-total",children:[t.totalChunks," total chunks"]})]}),e.jsx("div",{className:"ov-stripe-bars",children:t.buckets.map(l=>{const r=a>0?Math.max(0,Math.min(100,l.count/a*100)):0,i=V[l.stripe]??"ov-bar-gray",o=l.label||(q[l.stripe]??`Stripe ${l.stripe}`);return e.jsxs("div",{className:"ov-stripe-row",children:[e.jsx("span",{className:"ov-stripe-label",title:o,children:o}),e.jsx("div",{className:"ov-bar-track",children:e.jsx("div",{className:`ov-bar-fill ${i}`,style:{width:`${r}%`}})}),e.jsx("span",{className:"ov-stripe-count",children:l.count}),e.jsx("span",{className:"ov-stripe-stability",title:`min ${x(l.minStability)} / max ${x(l.maxStability)}`,children:x(l.avgStability)})]},l.stripe)})}),e.jsxs("div",{className:"ov-stripe-footer",children:["Epoch: ",t.epochId??"—","· Dominant tier: ",x(t.health.dominantTier)]})]})}function g(t){return`${t.toFixed(1)}%`}function X(t){return t>=80?"ov-bar-green":t>=60?"ov-bar-teal":t>=40?"ov-bar-yellow":t>=20?"ov-bar-orange":"ov-bar-red"}const Y=({perf:t})=>{const{cache_hit_pct:a}=t,s=a.samples&&a.samples.length>0?a.samples:[];return e.jsxs(f,{className:"electric-hover",children:[e.jsx(C,{children:e.jsx(S,{children:"Cache Hit-Rate Trend"})}),e.jsxs(N,{children:[e.jsxs("div",{className:"mb-3 flex gap-4 text-sm text-muted-foreground",children:[e.jsxs("div",{children:["Avg: ",e.jsx("strong",{className:"text-foreground",children:g(a.avg)})]}),e.jsxs("div",{children:["Latest: ",e.jsx("strong",{className:"text-foreground",children:g(a.latest)})]}),e.jsxs("div",{children:["Samples: ",e.jsx("strong",{className:"text-foreground",children:a.n})]})]}),s.length>0?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"ov-sparkline",role:"img","aria-label":`Cache hit rate trend: ${a.n} samples, average ${g(a.avg)}, latest ${g(a.latest)}`,children:s.map((l,r)=>{const i=Math.max(2,Math.round(l.pct*.6)),o=X(l.pct),c=r===s.length-1;return e.jsx("div",{className:`ov-sparkline-bar ${o}${c?" ov-bar-latest":""}`,style:{height:`${i}px`},title:`${g(l.pct)} at ${new Date(l.ts).toLocaleTimeString()}`},r)})}),e.jsxs("div",{className:"mt-1 text-xs text-muted-foreground",children:[s.length," sample",s.length!==1?"s":""," over"," ",s.length>1?`${Math.round((s[s.length-1].ts-s[0].ts)/1e3)}s`:"latest turn"]})]}):e.jsx("div",{className:"text-sm text-muted-foreground",children:"No cache-hit samples yet"})]})]})};function T(t){return`${(t*100).toFixed(1)}%`}function Z(t){const a=t*100;return a>=80?"ov-bar-green":a>=60?"ov-bar-teal":a>=40?"ov-bar-yellow":a>=20?"ov-bar-orange":"ov-bar-red"}const A={improving:"Improving",stable:"Stable",degrading:"Degrading"},ee=({data:t})=>{const{turns:a,avgRatio:s,trend:l}=t;return e.jsxs(f,{className:"electric-hover",children:[e.jsx(C,{children:e.jsx(S,{children:"Per-Turn Stable Prefix"})}),e.jsxs(N,{children:[e.jsxs("div",{className:"mb-3 flex gap-4 text-sm text-muted-foreground",children:[e.jsxs("div",{children:["Avg:"," ",e.jsx("strong",{className:"text-foreground",children:T(s)})]}),e.jsxs("div",{children:["Trend:"," ",e.jsx("strong",{className:"text-foreground",children:A[l]})]}),e.jsxs("div",{children:["Turns: ",e.jsx("strong",{className:"text-foreground",children:a.length})]})]}),a.length>0?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"ov-sparkline",role:"img","aria-label":`Per-turn stable-prefix ratio trend: ${a.length} turns, average ${T(s)}, trend ${A[l]}`,children:a.map((r,i)=>{const o=Math.max(2,Math.round(r.ratio*60)),c=Z(r.ratio),p=i===a.length-1;return e.jsx("div",{className:`ov-sparkline-bar ${c}${p?" ov-bar-latest":""}`,style:{height:`${o}px`},title:`Turn ${r.turnIndex}: ${T(r.ratio)} (${r.stablePrefix}/${r.totalMessages} msg) @ ${new Date(r.timestamp).toLocaleTimeString()}`},i)})}),e.jsx("div",{className:"mt-1 text-xs text-muted-foreground",children:"Shared prompt-cache prefix ratio per turn — higher is better."})]}):e.jsx("div",{className:"text-sm text-muted-foreground",children:"No stable-prefix samples yet"})]})]})};function oe(){const[t,a]=h.useState(!1),{data:s,loading:l,error:r}=m(h.useCallback(()=>I(),[]),{pollInterval:5e3}),{data:i,loading:o,error:c}=m(h.useCallback(()=>k(),[]),{pollInterval:15e3}),{data:p,loading:E,error:y}=m(h.useCallback(()=>w({minutes:30}),[]),{pollInterval:15e3}),{data:P,loading:M}=m(h.useCallback(()=>z(50),[]),{pollInterval:15e3}),{data:d,loading:H,error:$}=m(h.useCallback(()=>D(),[]),{pollInterval:5e3});return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{children:[e.jsx(B,{type:"button",variant:"outline",onClick:()=>a(!t),children:t?"Hide Guidance":"Show Cache-Friendly Prompt Ordering Guidance"}),t&&e.jsxs(f,{className:"mt-3",children:[e.jsx(C,{children:e.jsx(S,{children:"Cache-Friendly Prompt Ordering"})}),e.jsxs(N,{children:[e.jsxs("ul",{className:"list-disc space-y-1 pl-5",children:[e.jsx("li",{children:"Keep system prompts and stable context at the top of your conversation — the provider caches the leading prefix."}),e.jsxs("li",{children:["Tool results and volatile content are automatically moved to the tail by message separation (",e.jsx("code",{children:"MEGACOMPACT_MESSAGE_SEPARATION"}),") so they don't invalidate the cache prefix."]}),e.jsxs("li",{children:["Cache striping (",e.jsx("code",{children:"MEGACOMPACT_CACHE_STRIPING"}),") further orders stable context by a stability score so the most durable chunks lead."]}),e.jsx("li",{children:"Avoid inserting new instructions mid-conversation — prepend them instead."})]}),d&&e.jsxs("div",{className:"mt-2 text-sm",children:[e.jsx("strong",{children:"Status:"})," ",d.config.auto?"Auto-compaction Enabled":"Auto-compaction Disabled"," |"," ","fast-gate ",d.config.fastGatePct,"% / threshold"," ",d.config.thresholdTokens.toLocaleString()," tokens"]})]})]})]}),e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Provider Prompt Cache"}),l?e.jsx("p",{className:"tab-stub",children:"Loading..."}):r?e.jsxs("p",{className:"tab-stub",children:["Provider cache unavailable: ",r.message]}):s?e.jsx(U,{hitPct:s.cache.avgHitPct,turnCount:s.cache.turnCount,totalCacheRead:s.cache.totalCacheRead,totalCacheWrite:s.cache.totalCacheWrite,totalInput:s.cache.totalInput,cacheReadSaved:s.savings?.cacheReadSaved??null,cacheWriteCost:s.savings?.cacheWriteCost??null,netSaved:s.savings?.netSaved??null,modelLabel:s.savings?.model??null,firstTurnAt:s.cache.firstTurnAt,latestTurnAt:s.cache.latestTurnAt,byModel:s.cache.byModel??[]}):null,e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Cache Stripe Distribution"}),o?e.jsx("p",{className:"tab-stub",children:"Loading..."}):c?e.jsxs("p",{className:"tab-stub",children:["Cache stripe data unavailable: ",c.message]}):i?e.jsx(Q,{data:i}):null,e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Cache Hit-Rate Trend"}),E?e.jsx("p",{className:"tab-stub",children:"Loading..."}):y?e.jsxs("p",{className:"tab-stub",children:["Hit-rate trend unavailable: ",y.message]}):p?e.jsx(Y,{perf:p}):null,P&&!M?e.jsxs("div",{children:[e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Per-Turn Stable Prefix"}),e.jsx(ee,{data:P})]}):null,e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Mega-Compact Dedup Cache"}),H?e.jsx("p",{className:"tab-stub",children:"Loading..."}):$?e.jsxs("p",{className:"tab-stub",children:["Snapshot unavailable: ",$.message]}):d&&(()=>{const{cacheHits:b,compacts:R,timeSaved:j}=d;return e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3",children:[e.jsx(W,{cacheHitsSession:b.session,cacheHitsTotal:b.total,tokensSavedSession:b.sessionTokensSaved,tokensSavedTotal:b.totalTokensSaved,compactionsSession:R.session,compactionsTotal:R.total}),e.jsx(F,{compactSessionSec:j.compact.sessionSec,compactTotalSec:j.compact.totalSec,cacheHitSessionSec:j.cacheHit.sessionSec,cacheHitTotalSec:j.cacheHit.totalSec})]})})()]})}export{oe as default};
2
- //# sourceMappingURL=CacheTab-BLM6_PQQ.js.map