pi-mega-compact 0.11.7 → 0.11.9
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/gather-debug-keys.js +18 -0
- package/dist/extensions/dashboard-server/gather-debug.js +129 -0
- package/dist/extensions/dashboard-server/routes-maintenance.js +6 -0
- package/dist/extensions/dashboard-server/routes-memory-map.js +8 -15
- package/dist/extensions/mega-commands.js +65 -5
- package/dist/extensions/mega-config.js +7 -0
- package/dist/extensions/mega-events/agent-handlers.js +74 -5
- package/dist/extensions/mega-events/context-handler.js +132 -3
- package/dist/extensions/mega-runtime/snapshot.js +1 -1
- package/dist/extensions/mega-trim.js +10 -0
- package/dist/src/config/turns.js +2 -1
- package/dist/src/memoryGraph/embedding.js +50 -0
- package/dist/src/memoryGraph/gates.js +379 -0
- package/dist/src/memoryGraph/sources.js +390 -0
- package/dist/src/memoryGraph.js +133 -259
- package/dist/src/store/sqlite/embedding-cache.js +71 -0
- package/dist/src/store/sqlite.js +1 -0
- package/dist/src/topics/cluster.js +10 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-DR9cLGDL.js → AchievementTiles-DFitrb4Y.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementTiles-DR9cLGDL.js.map → AchievementTiles-DFitrb4Y.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-svNUgJ1e.js → AchievementsTab-PJrmq8pa.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AchievementsTab-svNUgJ1e.js.map → AchievementsTab-PJrmq8pa.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-C1WE7dEx.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-C1WE7dEx.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{ConfigTab-CmmWheuW.js → ConfigTab-Dx-RpO8C.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ConfigTab-CmmWheuW.js.map → ConfigTab-Dx-RpO8C.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-CFE7jLsa.js → EventsTab-C63BEWEs.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-CFE7jLsa.js.map → EventsTab-C63BEWEs.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{GameTab-CJAX_th_.js → GameTab-DHpJE6km.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{GameTab-CJAX_th_.js.map → GameTab-DHpJE6km.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-BSv0GfBb.js +2 -0
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-BSv0GfBb.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-Cg1fgEx_.js +2 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-Cg1fgEx_.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CHQscixy.js → MetricsTab-DCahxNOQ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CHQscixy.js.map → MetricsTab-DCahxNOQ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DBs4DJdd.js → OverviewTab-RYvO1SZL.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-DBs4DJdd.js.map → OverviewTab-RYvO1SZL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-DeFz76L5.js → ReposTab-BDGr_UXb.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-DeFz76L5.js.map → ReposTab-BDGr_UXb.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BWNsj1OB.js → SessionsTab-ByrTnHaB.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SessionsTab-BWNsj1OB.js.map → SessionsTab-ByrTnHaB.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{SetupTab-uS6A0xmw.js → SetupTab-CELafKis.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-uS6A0xmw.js.map → SetupTab-CELafKis.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CiqCOQuL.js → TimeSavedCard-BLWtmfr_.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-CiqCOQuL.js.map → TimeSavedCard-BLWtmfr_.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/TopicsTab-8Fsh_Igx.js +2 -0
- package/extensions/dashboard-client/dist/assets/TopicsTab-8Fsh_Igx.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CVz4f4-o.js → TurnsTab-D7mgXDe2.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TurnsTab-CVz4f4-o.js.map → TurnsTab-D7mgXDe2.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-DrktNOoT.js → index-h3jgEs6G.js} +10 -10
- package/extensions/dashboard-client/dist/assets/{index-DrktNOoT.js.map → index-h3jgEs6G.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-Bf5LOLSi.js → useSSE-C5lmipBF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-Bf5LOLSi.js.map → useSSE-C5lmipBF.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/api/client.ts +5 -0
- package/extensions/dashboard-client/src/memory-map-layout.ts +161 -0
- package/extensions/dashboard-client/src/memory-map-shapes.tsx +126 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +29 -2
- package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +101 -0
- package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +201 -165
- package/extensions/dashboard-client/src/tabs/ReposTab.tsx +21 -0
- package/extensions/dashboard-client/src/tabs/TopicsTab.tsx +1 -1
- package/extensions/dashboard-server/api-contracts/index.ts +3 -1
- package/extensions/dashboard-server/api-contracts/maintenance.ts +13 -0
- package/extensions/dashboard-server/api-contracts/memory-map.ts +14 -6
- package/extensions/dashboard-server/gather-debug-keys.ts +18 -0
- package/extensions/dashboard-server/gather-debug.ts +136 -0
- package/extensions/dashboard-server/routes-maintenance.ts +7 -0
- package/extensions/dashboard-server/routes-memory-map.ts +21 -29
- package/extensions/mega-commands.ts +63 -6
- package/extensions/mega-config.ts +22 -0
- package/extensions/mega-events/agent-handlers.ts +88 -5
- package/extensions/mega-events/context-handler.ts +152 -3
- package/extensions/mega-runtime/snapshot.ts +1 -1
- package/extensions/mega-trim.ts +15 -0
- package/package.json +1 -1
- package/src/config/turns.ts +5 -2
- package/src/memoryGraph/embedding.ts +63 -0
- package/src/memoryGraph/gates.ts +451 -0
- package/src/memoryGraph/sources.ts +484 -0
- package/src/memoryGraph.ts +188 -350
- package/src/store/sqlite/embedding-cache.ts +81 -0
- package/src/store/sqlite.ts +1 -0
- package/src/topics/cluster.ts +11 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-ASwhOMjR.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-P4SUsvMf.js +0 -2
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-P4SUsvMf.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js +0 -2
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-BBiH76eF.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TopicsTab-BWWQxltv.js +0 -2
- package/extensions/dashboard-client/dist/assets/TopicsTab-BWWQxltv.js.map +0 -1
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MemoryMapTab.tsx —
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* The simulation uses Coulomb repulsion + Hooke attraction + center gravity.
|
|
2
|
+
* MemoryMapTab.tsx — D3 memory map with force-directed graph.
|
|
3
|
+
* Node shape encodes nodeType: checkpoint=filled circle, turn=hollow circle,
|
|
4
|
+
* turn-content=hollow+ring, memory=diamond.
|
|
5
|
+
* Fetches from /api/memory-map, renders SVG force layout.
|
|
7
6
|
*/
|
|
8
7
|
import type React from "react";
|
|
9
8
|
import { useEffect, useRef, useState, useCallback, useMemo } from "react";
|
|
9
|
+
import { renderNodeShape, NODE_COLORS, NODE_TYPE_LABELS } from "../memory-map-shapes.js";
|
|
10
|
+
import type { NodeType } from "../memory-map-shapes.js";
|
|
11
|
+
import { buildLayout, applyForces } from "../memory-map-layout.js";
|
|
12
|
+
import type { LayoutNode, LayoutEdge } from "../memory-map-layout.js";
|
|
10
13
|
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
14
|
// Types (mirror of api-contracts/memory-map.ts — client-side only)
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
15
|
|
|
15
16
|
interface GraphNode {
|
|
16
17
|
id: string;
|
|
@@ -24,6 +25,8 @@ interface GraphNode {
|
|
|
24
25
|
topicSummary: string | undefined;
|
|
25
26
|
decisionCount: number;
|
|
26
27
|
textSnippet: string;
|
|
28
|
+
/** Source type discriminator for UI node-shape encoding. */
|
|
29
|
+
nodeType: "checkpoint" | "turn" | "turn-content" | "memory";
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
interface GraphEdge {
|
|
@@ -33,64 +36,45 @@ interface GraphEdge {
|
|
|
33
36
|
type: "temporal" | "semantic" | "raptor_parent";
|
|
34
37
|
}
|
|
35
38
|
|
|
39
|
+
interface GraphValidationReport {
|
|
40
|
+
readonly gatesRun: number;
|
|
41
|
+
readonly gatesPassed: number;
|
|
42
|
+
readonly dropped: { nodes: number; edges: number };
|
|
43
|
+
readonly warnings: Array<{ gate: string; code: string; count: number }>;
|
|
44
|
+
readonly sources: {
|
|
45
|
+
checkpoint: number;
|
|
46
|
+
turn: number;
|
|
47
|
+
turnContent: number;
|
|
48
|
+
memory: number;
|
|
49
|
+
};
|
|
50
|
+
readonly builtAt: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
36
53
|
interface GraphMetadata {
|
|
37
|
-
|
|
38
|
-
totalCheckpoints: number;
|
|
54
|
+
totalNodes: number;
|
|
39
55
|
totalEdges: number;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
similarityThresholdUsed: number;
|
|
44
|
-
builtAt: number;
|
|
56
|
+
avgWeight: number;
|
|
57
|
+
nodeTypeBreakdown: Record<string, number>;
|
|
58
|
+
edgeTypeBreakdown: Record<string, number>;
|
|
45
59
|
}
|
|
46
60
|
|
|
47
61
|
interface MemoryMapResponse {
|
|
48
62
|
nodes: GraphNode[];
|
|
49
63
|
edges: GraphEdge[];
|
|
50
64
|
metadata: GraphMetadata;
|
|
65
|
+
/** Validation report from the 9-gate pipeline. Optional for backward compat. */
|
|
66
|
+
validation?: GraphValidationReport;
|
|
51
67
|
}
|
|
52
68
|
|
|
53
|
-
//
|
|
54
|
-
// Force-directed layout types
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
|
|
57
|
-
interface Position {
|
|
58
|
-
x: number;
|
|
59
|
-
y: number;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface LayoutNode extends GraphNode {
|
|
63
|
-
pos: Position;
|
|
64
|
-
vx: number;
|
|
65
|
-
vy: number;
|
|
66
|
-
pinned: boolean;
|
|
67
|
-
}
|
|
69
|
+
// Simulation rendering constants (layout math is in memory-map-layout.ts)
|
|
68
70
|
|
|
69
|
-
interface LayoutEdge {
|
|
70
|
-
source: number;
|
|
71
|
-
target: number;
|
|
72
|
-
weight: number;
|
|
73
|
-
type: GraphEdge["type"];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ---------------------------------------------------------------------------
|
|
77
|
-
// Force simulation constants
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
|
-
|
|
80
|
-
const REPULSION = 5_000;
|
|
81
|
-
const ATTRACTION = 0.005;
|
|
82
|
-
const CENTER_GRAVITY = 0.01;
|
|
83
|
-
const DAMPING = 0.9;
|
|
84
|
-
const MIN_VELOCITY = 0.1;
|
|
85
71
|
const MAX_ITERATIONS = 300;
|
|
86
72
|
const EDGE_ALPHA = 0.3;
|
|
87
73
|
const SVG_WIDTH = 900;
|
|
88
74
|
const SVG_HEIGHT = 600;
|
|
89
75
|
const PADDING = 40;
|
|
90
76
|
|
|
91
|
-
// ---------------------------------------------------------------------------
|
|
92
77
|
// Helpers
|
|
93
|
-
// ---------------------------------------------------------------------------
|
|
94
78
|
|
|
95
79
|
function edgeColor(type: GraphEdge["type"]): string {
|
|
96
80
|
switch (type) {
|
|
@@ -103,106 +87,49 @@ function edgeColor(type: GraphEdge["type"]): string {
|
|
|
103
87
|
}
|
|
104
88
|
}
|
|
105
89
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// Force simulation engine
|
|
113
|
-
// ---------------------------------------------------------------------------
|
|
114
|
-
|
|
115
|
-
function buildLayout(data: MemoryMapResponse): { nodes: LayoutNode[]; edges: LayoutEdge[] } {
|
|
116
|
-
const nodes: LayoutNode[] = data.nodes.map((n, i) => {
|
|
117
|
-
const angle = (2 * Math.PI * i) / Math.max(data.nodes.length, 1);
|
|
118
|
-
const radius = 200;
|
|
119
|
-
return {
|
|
120
|
-
...n,
|
|
121
|
-
pos: { x: Math.cos(angle) * radius + 300, y: Math.sin(angle) * radius + 200 },
|
|
122
|
-
vx: 0,
|
|
123
|
-
vy: 0,
|
|
124
|
-
pinned: false,
|
|
125
|
-
};
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const nodeIndex = new Map<string, number>();
|
|
129
|
-
nodes.forEach((n, i) => nodeIndex.set(n.id, i));
|
|
130
|
-
|
|
131
|
-
const edges: LayoutEdge[] = data.edges
|
|
132
|
-
.map((e) => {
|
|
133
|
-
const si = nodeIndex.get(e.source);
|
|
134
|
-
const ti = nodeIndex.get(e.target);
|
|
135
|
-
if (si === undefined || ti === undefined || si === ti) return null;
|
|
136
|
-
return { source: si, target: ti, weight: e.weight, type: e.type };
|
|
137
|
-
})
|
|
138
|
-
.filter((e): e is LayoutEdge => e !== null);
|
|
139
|
-
|
|
140
|
-
return { nodes, edges };
|
|
90
|
+
// Minimal legend swatch component
|
|
91
|
+
interface SwatchProps {
|
|
92
|
+
type: "node" | "edge";
|
|
93
|
+
color: string;
|
|
94
|
+
shape: "filled-circle" | "hollow-circle" | "hollow-ring" | "diamond" | "line";
|
|
95
|
+
label: string;
|
|
141
96
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (e.source === i) other = e.target;
|
|
167
|
-
else if (e.target === i) other = e.source;
|
|
168
|
-
else continue;
|
|
169
|
-
const dx = nodes[other].pos.x - nodes[i].pos.x;
|
|
170
|
-
const dy = nodes[other].pos.y - nodes[i].pos.y;
|
|
171
|
-
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
172
|
-
fx += dx * ATTRACTION * e.weight;
|
|
173
|
-
fy += dy * ATTRACTION * e.weight;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
fx -= nodes[i].pos.x * CENTER_GRAVITY;
|
|
177
|
-
fy -= nodes[i].pos.y * CENTER_GRAVITY;
|
|
178
|
-
|
|
179
|
-
nodes[i].vx = (nodes[i].vx + fx) * DAMPING;
|
|
180
|
-
nodes[i].vy = (nodes[i].vy + fy) * DAMPING;
|
|
181
|
-
|
|
182
|
-
const speed = Math.sqrt(nodes[i].vx * nodes[i].vx + nodes[i].vy * nodes[i].vy);
|
|
183
|
-
if (speed > 50) {
|
|
184
|
-
nodes[i].vx = (nodes[i].vx / speed) * 50;
|
|
185
|
-
nodes[i].vy = (nodes[i].vy / speed) * 50;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (speed > MIN_VELOCITY) {
|
|
189
|
-
nodes[i].pos.x += nodes[i].vx;
|
|
190
|
-
nodes[i].pos.y += nodes[i].vy;
|
|
191
|
-
}
|
|
97
|
+
const Swatch: React.FC<SwatchProps> = ({ color, shape, label }) => {
|
|
98
|
+
const base: React.CSSProperties = {
|
|
99
|
+
display: "inline-block",
|
|
100
|
+
width: "10px",
|
|
101
|
+
height: "10px",
|
|
102
|
+
verticalAlign: "middle",
|
|
103
|
+
marginRight: "3px",
|
|
104
|
+
borderRadius: shape.startsWith("hollow") || shape === "filled-circle" ? "50%" : undefined,
|
|
105
|
+
};
|
|
106
|
+
let swatch: JSX.Element;
|
|
107
|
+
if (shape === "line") {
|
|
108
|
+
return <span style={{ color, marginRight: "6px" }}>{label}</span>;
|
|
109
|
+
} else if (shape === "filled-circle") {
|
|
110
|
+
swatch = <span style={{ ...base, backgroundColor: color }} />;
|
|
111
|
+
} else if (shape === "hollow-circle") {
|
|
112
|
+
swatch = <span style={{ ...base, border: `2px solid ${color}`, backgroundColor: "transparent" }} />;
|
|
113
|
+
} else if (shape === "hollow-ring") {
|
|
114
|
+
swatch = (
|
|
115
|
+
<span style={{ ...base, border: `2px solid ${color}`, backgroundColor: "transparent", position: "relative" }}>
|
|
116
|
+
<span style={{ display: "block", width: "4px", height: "4px", borderRadius: "50%", backgroundColor: color, margin: "2px auto" }} />
|
|
117
|
+
</span>
|
|
118
|
+
);
|
|
119
|
+
} else {
|
|
120
|
+
swatch = <span style={{ ...base, clipPath: "polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)", backgroundColor: color }} />;
|
|
192
121
|
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// ---------------------------------------------------------------------------
|
|
196
|
-
// Component
|
|
197
|
-
// ---------------------------------------------------------------------------
|
|
122
|
+
return <><span className="memory-map-legend-item">{swatch}{label}</span> </>;
|
|
123
|
+
};
|
|
198
124
|
|
|
125
|
+
// Force simulation engine (delegated to memory-map-layout.ts)
|
|
199
126
|
const MemoryMapTab: React.FC = () => {
|
|
200
127
|
const [data, setData] = useState<MemoryMapResponse | null>(null);
|
|
201
128
|
const [loading, setLoading] = useState<boolean>(true);
|
|
202
129
|
const [error, setError] = useState<string | null>(null);
|
|
203
130
|
const [selectedNode, setSelectedNode] = useState<GraphNode | null>(null);
|
|
204
131
|
const [searchQuery, setSearchQuery] = useState<string>("");
|
|
205
|
-
const [filterSession
|
|
132
|
+
const [filterSession] = useState<string>("");
|
|
206
133
|
const [frame, setFrame] = useState<number>(0);
|
|
207
134
|
|
|
208
135
|
const layoutRef = useRef<{ nodes: LayoutNode[]; edges: LayoutEdge[] } | null>(null);
|
|
@@ -291,13 +218,79 @@ const MemoryMapTab: React.FC = () => {
|
|
|
291
218
|
);
|
|
292
219
|
}, [searchQuery]);
|
|
293
220
|
|
|
294
|
-
//
|
|
221
|
+
// Health indicator helpers (D3)
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Derive graph health from validation report:
|
|
225
|
+
* green = all gates passed + no warnings
|
|
226
|
+
* yellow = warnings present but no critical gate failed
|
|
227
|
+
* red = a critical gate (gatesRun > gatesPassed) failed
|
|
228
|
+
*/
|
|
229
|
+
const graphHealth = useMemo<{ level: "green" | "yellow" | "red"; label: string }>(() => {
|
|
230
|
+
const v = data?.validation;
|
|
231
|
+
if (!v) return { level: "yellow", label: "No validation" };
|
|
232
|
+
if (v.gatesPassed < v.gatesRun) return { level: "red", label: "Gate failure" };
|
|
233
|
+
if (v.warnings.length > 0) return { level: "yellow", label: `${v.warnings.length} warning(s)` };
|
|
234
|
+
return { level: "green", label: "Healthy" };
|
|
235
|
+
}, [data?.validation]);
|
|
236
|
+
|
|
237
|
+
const healthColor: Record<string, string> = {
|
|
238
|
+
green: "#22c55e",
|
|
239
|
+
yellow: "#eab308",
|
|
240
|
+
red: "#ef4444",
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Source availability indicators (D3)
|
|
244
|
+
|
|
245
|
+
/** Count badge fragments from validation.sources. */
|
|
246
|
+
const countBadge = useMemo<string>(() => {
|
|
247
|
+
const v = data?.validation;
|
|
248
|
+
if (!v) {
|
|
249
|
+
const totalNodes = data?.metadata.totalNodes ?? 0;
|
|
250
|
+
return `${totalNodes} nodes`;
|
|
251
|
+
}
|
|
252
|
+
const parts: string[] = [];
|
|
253
|
+
if (v.sources.checkpoint > 0) parts.push(`${v.sources.checkpoint} checkpoints`);
|
|
254
|
+
if (v.sources.turn > 0) parts.push(`${v.sources.turn} turns`);
|
|
255
|
+
if (v.sources.turnContent > 0) parts.push(`${v.sources.turnContent} turn-content`);
|
|
256
|
+
if (v.sources.memory > 0) parts.push(`${v.sources.memory} memories`);
|
|
257
|
+
if (parts.length === 0) {
|
|
258
|
+
parts.push(`${data?.metadata.totalNodes ?? 0} nodes`);
|
|
259
|
+
}
|
|
260
|
+
return parts.join(" · ");
|
|
261
|
+
}, [data?.validation, data?.metadata.totalNodes]);
|
|
262
|
+
|
|
263
|
+
/** Per-source availability: ✓ for available sources, ✗ for empty ones. */
|
|
264
|
+
const sourceAvail = useMemo<string>(() => {
|
|
265
|
+
const v = data?.validation;
|
|
266
|
+
if (!v) return "";
|
|
267
|
+
const parts: string[] = [];
|
|
268
|
+
parts.push(v.sources.checkpoint > 0 ? "✓ checkpoints" : "✗ checkpoints");
|
|
269
|
+
parts.push(v.sources.turn > 0 ? "✓ turns" : "✗ turns");
|
|
270
|
+
parts.push(v.sources.turnContent > 0 ? "✓ turn-content" : "✗ turn-content");
|
|
271
|
+
parts.push(v.sources.memory > 0 ? "✓ memories" : "✗ memories");
|
|
272
|
+
return parts.join(" | ");
|
|
273
|
+
}, [data?.validation]);
|
|
274
|
+
|
|
275
|
+
/** Whether all four sources are empty (true empty state). */
|
|
276
|
+
const allSourcesEmpty = useMemo<boolean>(() => {
|
|
277
|
+
const v = data?.validation;
|
|
278
|
+
if (!v) return data?.metadata.totalNodes === 0;
|
|
279
|
+
return (
|
|
280
|
+
v.sources.checkpoint === 0 &&
|
|
281
|
+
v.sources.turn === 0 &&
|
|
282
|
+
v.sources.turnContent === 0 &&
|
|
283
|
+
v.sources.memory === 0
|
|
284
|
+
);
|
|
285
|
+
}, [data?.validation, data?.metadata.totalNodes]);
|
|
286
|
+
|
|
287
|
+
// Loading state
|
|
295
288
|
|
|
296
289
|
if (loading) {
|
|
297
290
|
return <div className="memory-map-loading">Loading memory graph...</div>;
|
|
298
291
|
}
|
|
299
292
|
|
|
300
|
-
//
|
|
293
|
+
// Error state
|
|
301
294
|
|
|
302
295
|
if (error) {
|
|
303
296
|
return (
|
|
@@ -313,15 +306,19 @@ const MemoryMapTab: React.FC = () => {
|
|
|
313
306
|
);
|
|
314
307
|
}
|
|
315
308
|
|
|
316
|
-
//
|
|
309
|
+
// Empty state (D2)
|
|
317
310
|
|
|
318
|
-
if (!data || !layoutRef.current) {
|
|
319
|
-
return
|
|
311
|
+
if (!data || !layoutRef.current || allSourcesEmpty) {
|
|
312
|
+
return (
|
|
313
|
+
<div className="memory-map-empty">
|
|
314
|
+
<p>Memories appear after your first compaction. The graph shows checkpoints (compaction summaries) linked by semantic similarity and time. Run a longer session or lower the compaction tier to see it sooner.</p>
|
|
315
|
+
</div>
|
|
316
|
+
);
|
|
320
317
|
}
|
|
321
318
|
|
|
322
319
|
const layout = layoutRef.current;
|
|
323
320
|
|
|
324
|
-
//
|
|
321
|
+
// Render
|
|
325
322
|
|
|
326
323
|
return (
|
|
327
324
|
<div className="memory-map-container">
|
|
@@ -337,18 +334,48 @@ const MemoryMapTab: React.FC = () => {
|
|
|
337
334
|
className="memory-map-search"
|
|
338
335
|
/>
|
|
339
336
|
<span className="memory-map-stats">
|
|
340
|
-
{
|
|
337
|
+
{/* Count badge */}
|
|
338
|
+
<span className="memory-map-count-badge">{countBadge}</span>
|
|
341
339
|
<br />
|
|
342
|
-
|
|
343
|
-
|
|
340
|
+
<span className="memory-map-edges">{data.edges.length} edges</span>
|
|
341
|
+
</span>
|
|
342
|
+
{/* Graph-health indicator */}
|
|
343
|
+
<span
|
|
344
|
+
className="memory-map-health-badge"
|
|
345
|
+
style={{
|
|
346
|
+
backgroundColor: healthColor[graphHealth.level] ?? "#6b7280",
|
|
347
|
+
color: "#fff",
|
|
348
|
+
padding: "2px 8px",
|
|
349
|
+
borderRadius: "10px",
|
|
350
|
+
fontSize: "11px",
|
|
351
|
+
fontWeight: 600,
|
|
352
|
+
marginLeft: "8px",
|
|
353
|
+
}}
|
|
354
|
+
title={`Validation: ${graphHealth.label}`}
|
|
355
|
+
>
|
|
356
|
+
{graphHealth.level === "green" ? "Healthy" : graphHealth.level === "yellow" ? "Warnings" : "Critical"}
|
|
344
357
|
</span>
|
|
345
358
|
</div>
|
|
346
359
|
|
|
347
|
-
{/*
|
|
360
|
+
{/* Source availability indicators */}
|
|
361
|
+
{sourceAvail ? (
|
|
362
|
+
<div className="memory-map-source-avail" style={{ fontSize: "11px", padding: "2px 12px", color: "#6b7280" }}>
|
|
363
|
+
{sourceAvail}
|
|
364
|
+
</div>
|
|
365
|
+
) : null}
|
|
366
|
+
|
|
367
|
+
{/* Legend — node types + edge types */}
|
|
348
368
|
<div className="memory-map-legend">
|
|
349
|
-
<span
|
|
350
|
-
<
|
|
351
|
-
<
|
|
369
|
+
<span className="memory-map-legend-section">Nodes:</span>
|
|
370
|
+
<Swatch type="node" color={NODE_COLORS.checkpoint} shape="filled-circle" label="Checkpoint" />
|
|
371
|
+
<Swatch type="node" color={NODE_COLORS.turn} shape="hollow-circle" label="Turn" />
|
|
372
|
+
<Swatch type="node" color={NODE_COLORS["turn-content"]} shape="hollow-ring" label="Turn Content" />
|
|
373
|
+
<Swatch type="node" color={NODE_COLORS.memory} shape="diamond" label="Memory" />
|
|
374
|
+
<span className="memory-map-legend-sep">|</span>
|
|
375
|
+
<span className="memory-map-legend-section">Edges:</span>
|
|
376
|
+
<Swatch type="edge" color={edgeColor("semantic")} shape="line" label="Semantic" />
|
|
377
|
+
<Swatch type="edge" color={edgeColor("temporal")} shape="line" label="Temporal" />
|
|
378
|
+
<Swatch type="edge" color={edgeColor("raptor_parent")} shape="line" label="Raptor" />
|
|
352
379
|
</div>
|
|
353
380
|
|
|
354
381
|
{/* SVG graph */}
|
|
@@ -378,7 +405,7 @@ const MemoryMapTab: React.FC = () => {
|
|
|
378
405
|
);
|
|
379
406
|
})}
|
|
380
407
|
|
|
381
|
-
{/* Nodes */}
|
|
408
|
+
{/* Nodes — shape encodes nodeType */}
|
|
382
409
|
{layout.nodes.map((n, i) => {
|
|
383
410
|
const cx =
|
|
384
411
|
PADDING + (n.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING);
|
|
@@ -390,18 +417,13 @@ const MemoryMapTab: React.FC = () => {
|
|
|
390
417
|
const nodeLabel = n.label.length > 20 ? n.label.slice(0, 18) + "..." : n.label;
|
|
391
418
|
|
|
392
419
|
return (
|
|
393
|
-
<g
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
stroke={isSelected ? "#ef4444" : "none"}
|
|
401
|
-
strokeWidth={isSelected ? 2 : 0}
|
|
402
|
-
className="memory-map-node"
|
|
403
|
-
onClick={() => handleNodeClick(n, i)}
|
|
404
|
-
/>
|
|
420
|
+
<g
|
|
421
|
+
key={`node-${i}`}
|
|
422
|
+
className="memory-map-node-group"
|
|
423
|
+
onClick={() => handleNodeClick(n, i)}
|
|
424
|
+
style={{ cursor: "pointer" }}
|
|
425
|
+
>
|
|
426
|
+
{renderNodeShape(cx, cy, radius, n.nodeType as NodeType, isSelected, isFiltered, n.dedupStatus)}
|
|
405
427
|
<text
|
|
406
428
|
x={cx}
|
|
407
429
|
y={cy + radius + 12}
|
|
@@ -420,7 +442,21 @@ const MemoryMapTab: React.FC = () => {
|
|
|
420
442
|
{/* Node detail panel */}
|
|
421
443
|
{selectedNode ? (
|
|
422
444
|
<div className="memory-map-detail">
|
|
423
|
-
<h3>
|
|
445
|
+
<h3>
|
|
446
|
+
<span
|
|
447
|
+
className="memory-map-detail-type"
|
|
448
|
+
style={{
|
|
449
|
+
display: "inline-block",
|
|
450
|
+
fontSize: "12px",
|
|
451
|
+
fontWeight: 400,
|
|
452
|
+
color: "#6b7280",
|
|
453
|
+
marginRight: "6px",
|
|
454
|
+
}}
|
|
455
|
+
>
|
|
456
|
+
{NODE_TYPE_LABELS[selectedNode.nodeType]}
|
|
457
|
+
</span>
|
|
458
|
+
{selectedNode.label}
|
|
459
|
+
</h3>
|
|
424
460
|
<p>{selectedNode.summaryTruncated}</p>
|
|
425
461
|
{selectedNode.topicSummary ? (
|
|
426
462
|
<p className="memory-map-topic">Topic: {selectedNode.topicSummary}</p>
|
|
@@ -70,6 +70,27 @@ export default function ReposTab(): React.ReactElement {
|
|
|
70
70
|
const repos = indexData.repos;
|
|
71
71
|
const servers = serversData?.servers ?? [];
|
|
72
72
|
|
|
73
|
+
if (repos.length === 0) {
|
|
74
|
+
return (
|
|
75
|
+
<div className="repos-tab">
|
|
76
|
+
<SummaryTiles
|
|
77
|
+
totalRepos={0}
|
|
78
|
+
totalCheckpoints={0}
|
|
79
|
+
totalTokensSaved={0}
|
|
80
|
+
compressedOriginalBytes={0}
|
|
81
|
+
/>
|
|
82
|
+
<div className="tab-stub">
|
|
83
|
+
<h3>Repositories / Memory</h3>
|
|
84
|
+
<p>
|
|
85
|
+
Repo memory appears after the first compaction. Compaction fires
|
|
86
|
+
when context crosses the tier threshold (~50-70% of the window).
|
|
87
|
+
Run a longer session or lower the compaction tier to see it sooner.
|
|
88
|
+
</p>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
73
94
|
return (
|
|
74
95
|
<div className="repos-tab">
|
|
75
96
|
<SummaryTiles
|
|
@@ -63,7 +63,7 @@ export default function TopicsTab(): React.ReactElement {
|
|
|
63
63
|
<div className="tab-stub">
|
|
64
64
|
<h3>Wiki</h3>
|
|
65
65
|
<p>
|
|
66
|
-
No topics yet. Topics are auto-generated after every
|
|
66
|
+
No topics yet. Topics are auto-generated after every 3rd compaction
|
|
67
67
|
from real memory embeddings (k-means + TF-IDF).
|
|
68
68
|
</p>
|
|
69
69
|
<p>Check back after a few more compaction cycles.</p>
|
|
@@ -186,6 +186,7 @@ export type {
|
|
|
186
186
|
SchemaHealthRow,
|
|
187
187
|
SchemaHealthResponse,
|
|
188
188
|
MaintenanceAction,
|
|
189
|
+
DebugBundleResponse,
|
|
189
190
|
} from "./maintenance.js";
|
|
190
191
|
|
|
191
192
|
// S52 — turn-by-turn memory tracking + recall + rewind
|
|
@@ -210,12 +211,13 @@ export type { MemoryStatusResponse, MemoryStatsTopMemory } from "./memory.js";
|
|
|
210
211
|
// Setup wizard — embedder configuration + backend detection
|
|
211
212
|
export type { SetupStatusResponse, SetupDetectResponse, SetupConfigureRequest, SetupConfigureResponse, DetectResult, OllamaDetectResult } from "./setup.js";
|
|
212
213
|
|
|
213
|
-
// S46 — memory graph (visual memory map)
|
|
214
|
+
// S46/D3 — memory graph (visual memory map) + validation report
|
|
214
215
|
export type {
|
|
215
216
|
MemoryMapResponse,
|
|
216
217
|
MemoryMapNode,
|
|
217
218
|
MemoryMapEdgeEntry,
|
|
218
219
|
MemoryMapQuery,
|
|
220
|
+
GraphValidationReport,
|
|
219
221
|
} from "./memory-map.js";
|
|
220
222
|
|
|
221
223
|
// A3 — cache stripe distribution + health
|
|
@@ -82,3 +82,16 @@ export type MaintenanceAction =
|
|
|
82
82
|
| { action: "reconcile-dedup" }
|
|
83
83
|
| { action: "prune"; daysOld: number }
|
|
84
84
|
| { action: "integrity-check" };
|
|
85
|
+
|
|
86
|
+
/** Debug bundle for gathering diagnostic info. */
|
|
87
|
+
export interface DebugBundleResponse {
|
|
88
|
+
builtAt: number;
|
|
89
|
+
version: string;
|
|
90
|
+
stateDir: string;
|
|
91
|
+
config: Record<string, string>;
|
|
92
|
+
schemaHealth: SchemaHealthResponse | { error: string };
|
|
93
|
+
storeStats: DbStatsResponse | { error: string };
|
|
94
|
+
dashboardSnapshot: unknown | { error: string };
|
|
95
|
+
recentEvents: unknown[];
|
|
96
|
+
criticalEvents: unknown[];
|
|
97
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* api-contracts/memory-map.ts — Memory graph API contract (S46).
|
|
2
|
+
* api-contracts/memory-map.ts — Memory graph API contract (S46/D3).
|
|
3
3
|
*
|
|
4
|
-
* Response shape for GET /api/memory-map: graph nodes, edges,
|
|
5
|
-
*
|
|
4
|
+
* Response shape for GET /api/memory-map: graph nodes, edges, metadata,
|
|
5
|
+
* and validation report. Consumed by the MemoryMapTab React component.
|
|
6
6
|
*/
|
|
7
|
-
import type { GraphMetadata } from "../../../src/memoryGraph.js";
|
|
7
|
+
import type { GraphMetadata, GraphValidationReport } from "../../../src/memoryGraph.js";
|
|
8
|
+
export type { GraphValidationReport } from "../../../src/memoryGraph.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Query parameters for GET /api/memory-map.
|
|
@@ -19,14 +20,19 @@ export interface MemoryMapQuery {
|
|
|
19
20
|
readonly maxEdgesPerNode?: number;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
/** Response body for GET /api/memory-map. */
|
|
23
|
+
/** Response body for GET /api/memory-map (D3: +validation). */
|
|
23
24
|
export interface MemoryMapResponse {
|
|
24
25
|
readonly nodes: MemoryMapNode[];
|
|
25
26
|
readonly edges: MemoryMapEdgeEntry[];
|
|
26
27
|
readonly metadata: GraphMetadata;
|
|
28
|
+
/** D3: validation report from the 9-gate pipeline. Optional for backward compat. */
|
|
29
|
+
readonly validation?: GraphValidationReport;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* A node in the response (client-safe subset — no full embedding vector).
|
|
34
|
+
* D3: +nodeType discriminator for UI node-shape rendering.
|
|
35
|
+
*/
|
|
30
36
|
export interface MemoryMapNode {
|
|
31
37
|
readonly id: string;
|
|
32
38
|
readonly sessionId: string;
|
|
@@ -39,6 +45,8 @@ export interface MemoryMapNode {
|
|
|
39
45
|
readonly topicSummary: string | undefined;
|
|
40
46
|
readonly decisionCount: number;
|
|
41
47
|
readonly textSnippet: string;
|
|
48
|
+
/** D3: source type discriminator for UI node-shape encoding. */
|
|
49
|
+
readonly nodeType: "checkpoint" | "turn" | "turn-content" | "memory";
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
/** An edge entry in the response. */
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const MEGACOMPACT_ENV_KEYS = [
|
|
2
|
+
"MEGACOMPACT_AUTO",
|
|
3
|
+
"MEGACOMPACT_THRESHOLD_TOKENS",
|
|
4
|
+
"MEGACOMPACT_TIER",
|
|
5
|
+
"MEGACOMPACT_DBMIRROR",
|
|
6
|
+
"MEGACOMPACT_MESSAGE_SEPARATION",
|
|
7
|
+
"MEGACOMPACT_CACHE_STRIPING",
|
|
8
|
+
"MEGACOMPACT_LEGACY_DURABLE_TRIM",
|
|
9
|
+
"MEGACOMPACT_RACE_GUARD_STRICT",
|
|
10
|
+
"MEGACOMPACT_RECALL_TAIL_INJECT",
|
|
11
|
+
"MEGACOMPACT_PGLITE_DISABLED",
|
|
12
|
+
"MEGACOMPACT_WIKI_REBUILD_EVERY",
|
|
13
|
+
"MEGACOMPACT_WIKI_SEED_FROM_TURNS",
|
|
14
|
+
"MEGACOMPACT_MEMORY_GRAPH_SEED_TURNS",
|
|
15
|
+
"MEGACOMPACT_MEMORY_GRAPH_SEED_TIER",
|
|
16
|
+
"MEGACOMPACT_MEMORY_GRAPH_SEED_BATCH",
|
|
17
|
+
"MEGACOMPACT_MEMORY_GRAPH_SEED_MAX",
|
|
18
|
+
];
|