aether-react 0.1.0

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/index.js ADDED
@@ -0,0 +1,2056 @@
1
+ // src/context/AetherProvider.tsx
2
+ import { createContext, useContext, useState, useEffect, useCallback } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var AetherContext = createContext(null);
5
+ function AetherProvider({
6
+ aether,
7
+ children,
8
+ initialActor,
9
+ autoSubscribe = true
10
+ }) {
11
+ const [events, setEvents] = useState([]);
12
+ const [loading, setLoading] = useState(false);
13
+ const [error, setError] = useState(null);
14
+ useEffect(() => {
15
+ if (initialActor) {
16
+ setLoading(true);
17
+ aether.getHistory(initialActor).then(setEvents).catch(setError).finally(() => setLoading(false));
18
+ }
19
+ }, [aether, initialActor]);
20
+ useEffect(() => {
21
+ if (!autoSubscribe) return;
22
+ const unsubscribe = aether.subscribe((event) => {
23
+ setEvents((prev) => [event, ...prev]);
24
+ });
25
+ return unsubscribe;
26
+ }, [aether, autoSubscribe]);
27
+ const add = useCallback(
28
+ async (content, context) => {
29
+ try {
30
+ setLoading(true);
31
+ const event = await aether.add(content, context);
32
+ if (!autoSubscribe) {
33
+ setEvents((prev) => [event, ...prev]);
34
+ }
35
+ return event;
36
+ } catch (err) {
37
+ setError(err);
38
+ return null;
39
+ } finally {
40
+ setLoading(false);
41
+ }
42
+ },
43
+ [aether, autoSubscribe]
44
+ );
45
+ const retrieve = useCallback(
46
+ async (query, options) => {
47
+ try {
48
+ setLoading(true);
49
+ const results = await aether.retrieve(query, options);
50
+ return results;
51
+ } catch (err) {
52
+ setError(err);
53
+ return [];
54
+ } finally {
55
+ setLoading(false);
56
+ }
57
+ },
58
+ [aether]
59
+ );
60
+ const refresh = useCallback(async () => {
61
+ if (initialActor) {
62
+ setLoading(true);
63
+ try {
64
+ const history = await aether.getHistory(initialActor);
65
+ setEvents(history);
66
+ } catch (err) {
67
+ setError(err);
68
+ } finally {
69
+ setLoading(false);
70
+ }
71
+ }
72
+ }, [aether, initialActor]);
73
+ const clearEvents = useCallback(() => {
74
+ setEvents([]);
75
+ }, []);
76
+ const value = {
77
+ aether,
78
+ events,
79
+ loading,
80
+ error,
81
+ add,
82
+ retrieve,
83
+ refresh,
84
+ clearEvents
85
+ };
86
+ return /* @__PURE__ */ jsx(AetherContext.Provider, { value, children });
87
+ }
88
+ function useAether() {
89
+ const context = useContext(AetherContext);
90
+ if (!context) {
91
+ throw new Error("useAether must be used within an AetherProvider");
92
+ }
93
+ return context;
94
+ }
95
+
96
+ // src/hooks/useMemoryStream.ts
97
+ import { useState as useState2, useEffect as useEffect2, useCallback as useCallback2, useRef } from "react";
98
+ function useMemoryStream(serverUrl, options = {}) {
99
+ const {
100
+ autoConnect = true,
101
+ autoReconnect = true,
102
+ maxReconnectAttempts = 5,
103
+ reconnectDelay = 1e3
104
+ } = options;
105
+ const [events, setEvents] = useState2([]);
106
+ const [connected, setConnected] = useState2(false);
107
+ const [error, setError] = useState2(null);
108
+ const wsRef = useRef(null);
109
+ const reconnectAttemptsRef = useRef(0);
110
+ const reconnectTimeoutRef = useRef(null);
111
+ const connect = useCallback2(() => {
112
+ if (wsRef.current?.readyState === WebSocket.OPEN) {
113
+ return;
114
+ }
115
+ try {
116
+ const ws = new WebSocket(serverUrl);
117
+ wsRef.current = ws;
118
+ ws.onopen = () => {
119
+ setConnected(true);
120
+ setError(null);
121
+ reconnectAttemptsRef.current = 0;
122
+ };
123
+ ws.onclose = () => {
124
+ setConnected(false);
125
+ wsRef.current = null;
126
+ if (autoReconnect && reconnectAttemptsRef.current < maxReconnectAttempts) {
127
+ reconnectAttemptsRef.current++;
128
+ reconnectTimeoutRef.current = setTimeout(() => {
129
+ connect();
130
+ }, reconnectDelay * reconnectAttemptsRef.current);
131
+ }
132
+ };
133
+ ws.onerror = (event) => {
134
+ setError(new Error("WebSocket error"));
135
+ console.error("WebSocket error:", event);
136
+ };
137
+ ws.onmessage = (event) => {
138
+ try {
139
+ const message = JSON.parse(event.data);
140
+ if (message.type === "memory:added" && message.data) {
141
+ const memoryEvent = message.data;
142
+ setEvents((prev) => [memoryEvent, ...prev]);
143
+ }
144
+ } catch (err) {
145
+ console.error("Failed to parse WebSocket message:", err);
146
+ }
147
+ };
148
+ } catch (err) {
149
+ setError(err);
150
+ }
151
+ }, [serverUrl, autoReconnect, maxReconnectAttempts, reconnectDelay]);
152
+ const disconnect = useCallback2(() => {
153
+ if (reconnectTimeoutRef.current) {
154
+ clearTimeout(reconnectTimeoutRef.current);
155
+ reconnectTimeoutRef.current = null;
156
+ }
157
+ if (wsRef.current) {
158
+ wsRef.current.close();
159
+ wsRef.current = null;
160
+ }
161
+ setConnected(false);
162
+ }, []);
163
+ const send = useCallback2((message) => {
164
+ if (wsRef.current?.readyState === WebSocket.OPEN) {
165
+ wsRef.current.send(JSON.stringify(message));
166
+ } else {
167
+ console.warn("WebSocket is not connected");
168
+ }
169
+ }, []);
170
+ const clearEvents = useCallback2(() => {
171
+ setEvents([]);
172
+ }, []);
173
+ useEffect2(() => {
174
+ if (autoConnect) {
175
+ connect();
176
+ }
177
+ return () => {
178
+ disconnect();
179
+ };
180
+ }, [autoConnect, connect, disconnect]);
181
+ return {
182
+ events,
183
+ connected,
184
+ error,
185
+ connect,
186
+ disconnect,
187
+ send,
188
+ clearEvents
189
+ };
190
+ }
191
+
192
+ // src/components/MemoryGraphView/index.tsx
193
+ import { useEffect as useEffect3, useRef as useRef2, useMemo } from "react";
194
+ import * as d3 from "d3";
195
+ import { jsx as jsx2 } from "react/jsx-runtime";
196
+ function MemoryGraphView({
197
+ events,
198
+ width = 800,
199
+ height = 600,
200
+ onNodeClick,
201
+ highlightActor,
202
+ showRelations = true,
203
+ className = ""
204
+ }) {
205
+ const svgRef = useRef2(null);
206
+ const { nodes, links } = useMemo(() => {
207
+ const nodeMap = /* @__PURE__ */ new Map();
208
+ const linkList = [];
209
+ const actors = new Set(events.map((e) => e.actor));
210
+ for (const actor of actors) {
211
+ nodeMap.set(`actor:${actor}`, {
212
+ id: `actor:${actor}`,
213
+ type: "actor",
214
+ label: actor
215
+ });
216
+ }
217
+ const sortedEvents = [...events].sort(
218
+ (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
219
+ );
220
+ let prevEventByActor = /* @__PURE__ */ new Map();
221
+ for (const event of sortedEvents) {
222
+ const eventId = `event:${event.id}`;
223
+ nodeMap.set(eventId, {
224
+ id: eventId,
225
+ type: "event",
226
+ label: event.action,
227
+ event
228
+ });
229
+ linkList.push({
230
+ source: `actor:${event.actor}`,
231
+ target: eventId,
232
+ type: "actor"
233
+ });
234
+ const prevId = prevEventByActor.get(event.actor);
235
+ if (prevId) {
236
+ linkList.push({
237
+ source: prevId,
238
+ target: eventId,
239
+ type: "temporal"
240
+ });
241
+ }
242
+ prevEventByActor.set(event.actor, eventId);
243
+ if (showRelations && event.relations) {
244
+ for (const relation of event.relations) {
245
+ const targetId = `event:${relation.targetEventId}`;
246
+ if (nodeMap.has(targetId)) {
247
+ linkList.push({
248
+ source: eventId,
249
+ target: targetId,
250
+ type: "relation"
251
+ });
252
+ }
253
+ }
254
+ }
255
+ }
256
+ return {
257
+ nodes: Array.from(nodeMap.values()),
258
+ links: linkList
259
+ };
260
+ }, [events, showRelations]);
261
+ useEffect3(() => {
262
+ if (!svgRef.current || nodes.length === 0) return;
263
+ const svg = d3.select(svgRef.current);
264
+ svg.selectAll("*").remove();
265
+ const container = svg.append("g");
266
+ const zoom2 = d3.zoom().scaleExtent([0.1, 4]).on("zoom", (event) => {
267
+ container.attr("transform", event.transform);
268
+ });
269
+ svg.call(zoom2);
270
+ const simulation = d3.forceSimulation(nodes).force(
271
+ "link",
272
+ d3.forceLink(links).id((d) => d.id).distance((d) => d.type === "actor" ? 100 : 50)
273
+ ).force("charge", d3.forceManyBody().strength(-200)).force("center", d3.forceCenter(width / 2, height / 2)).force("collision", d3.forceCollide().radius(30));
274
+ const link = container.append("g").selectAll("line").data(links).join("line").attr("stroke", (d) => {
275
+ switch (d.type) {
276
+ case "actor":
277
+ return "#94a3b8";
278
+ case "temporal":
279
+ return "#3b82f6";
280
+ case "relation":
281
+ return "#f59e0b";
282
+ default:
283
+ return "#d1d5db";
284
+ }
285
+ }).attr("stroke-width", (d) => d.type === "temporal" ? 2 : 1).attr("stroke-dasharray", (d) => d.type === "relation" ? "4,4" : "none");
286
+ const node = container.append("g").selectAll("g").data(nodes).join("g").attr("cursor", "pointer").call(
287
+ d3.drag().on("start", (event, d) => {
288
+ if (!event.active) simulation.alphaTarget(0.3).restart();
289
+ d.fx = d.x;
290
+ d.fy = d.y;
291
+ }).on("drag", (event, d) => {
292
+ d.fx = event.x;
293
+ d.fy = event.y;
294
+ }).on("end", (event, d) => {
295
+ if (!event.active) simulation.alphaTarget(0);
296
+ d.fx = null;
297
+ d.fy = null;
298
+ })
299
+ );
300
+ node.append("circle").attr("r", (d) => d.type === "actor" ? 20 : 12).attr("fill", (d) => {
301
+ if (d.type === "actor") {
302
+ return highlightActor === d.label ? "#3b82f6" : "#6366f1";
303
+ }
304
+ return "#10b981";
305
+ }).attr("stroke", "#ffffff").attr("stroke-width", 2);
306
+ node.append("text").text((d) => d.label).attr("font-size", (d) => d.type === "actor" ? 12 : 10).attr("dx", (d) => d.type === "actor" ? 25 : 16).attr("dy", 4).attr("fill", "#374151");
307
+ node.on("click", (event, d) => {
308
+ if (d.event && onNodeClick) {
309
+ onNodeClick(d.event);
310
+ }
311
+ });
312
+ simulation.on("tick", () => {
313
+ link.attr("x1", (d) => d.source.x).attr("y1", (d) => d.source.y).attr("x2", (d) => d.target.x).attr("y2", (d) => d.target.y);
314
+ node.attr("transform", (d) => `translate(${d.x},${d.y})`);
315
+ });
316
+ return () => {
317
+ simulation.stop();
318
+ };
319
+ }, [nodes, links, width, height, highlightActor, onNodeClick]);
320
+ if (events.length === 0) {
321
+ return /* @__PURE__ */ jsx2(
322
+ "div",
323
+ {
324
+ className: `aether-graph-empty ${className}`,
325
+ style: {
326
+ width,
327
+ height,
328
+ display: "flex",
329
+ alignItems: "center",
330
+ justifyContent: "center",
331
+ color: "#9ca3af",
332
+ backgroundColor: "#f9fafb",
333
+ borderRadius: "8px"
334
+ },
335
+ children: "No events to display"
336
+ }
337
+ );
338
+ }
339
+ return /* @__PURE__ */ jsx2(
340
+ "svg",
341
+ {
342
+ ref: svgRef,
343
+ width,
344
+ height,
345
+ className: `aether-graph ${className}`,
346
+ style: {
347
+ backgroundColor: "#f9fafb",
348
+ borderRadius: "8px"
349
+ }
350
+ }
351
+ );
352
+ }
353
+
354
+ // src/components/TimelineView/index.tsx
355
+ import { useMemo as useMemo2 } from "react";
356
+
357
+ // src/components/MemoryCard/index.tsx
358
+ import "react";
359
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
360
+ function MemoryCard({
361
+ event,
362
+ onClick,
363
+ selected = false,
364
+ showContext = false,
365
+ className = ""
366
+ }) {
367
+ const formatTimestamp = (timestamp) => {
368
+ const date = new Date(timestamp);
369
+ return date.toLocaleString();
370
+ };
371
+ const handleClick = () => {
372
+ onClick?.(event);
373
+ };
374
+ return /* @__PURE__ */ jsxs(
375
+ "div",
376
+ {
377
+ className: `aether-memory-card ${selected ? "selected" : ""} ${className}`,
378
+ onClick: handleClick,
379
+ style: {
380
+ padding: "12px",
381
+ borderRadius: "8px",
382
+ border: `1px solid ${selected ? "#3b82f6" : "#e5e7eb"}`,
383
+ backgroundColor: selected ? "#eff6ff" : "#ffffff",
384
+ cursor: onClick ? "pointer" : "default",
385
+ marginBottom: "8px",
386
+ transition: "all 0.2s ease"
387
+ },
388
+ children: [
389
+ /* @__PURE__ */ jsxs(
390
+ "div",
391
+ {
392
+ style: {
393
+ display: "flex",
394
+ justifyContent: "space-between",
395
+ alignItems: "center",
396
+ marginBottom: "8px"
397
+ },
398
+ children: [
399
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
400
+ /* @__PURE__ */ jsx3(
401
+ "span",
402
+ {
403
+ style: {
404
+ fontWeight: 600,
405
+ color: "#1f2937"
406
+ },
407
+ children: event.actor
408
+ }
409
+ ),
410
+ /* @__PURE__ */ jsx3(
411
+ "span",
412
+ {
413
+ style: {
414
+ fontSize: "12px",
415
+ padding: "2px 6px",
416
+ borderRadius: "4px",
417
+ backgroundColor: "#f3f4f6",
418
+ color: "#6b7280"
419
+ },
420
+ children: event.action
421
+ }
422
+ )
423
+ ] }),
424
+ /* @__PURE__ */ jsx3(
425
+ "span",
426
+ {
427
+ style: {
428
+ fontSize: "12px",
429
+ color: "#9ca3af"
430
+ },
431
+ children: formatTimestamp(event.timestamp)
432
+ }
433
+ )
434
+ ]
435
+ }
436
+ ),
437
+ /* @__PURE__ */ jsx3(
438
+ "p",
439
+ {
440
+ style: {
441
+ margin: 0,
442
+ color: "#374151",
443
+ lineHeight: 1.5
444
+ },
445
+ children: event.content
446
+ }
447
+ ),
448
+ showContext && Object.keys(event.context).length > 0 && /* @__PURE__ */ jsxs(
449
+ "div",
450
+ {
451
+ style: {
452
+ marginTop: "8px",
453
+ padding: "8px",
454
+ borderRadius: "4px",
455
+ backgroundColor: "#f9fafb",
456
+ fontSize: "12px"
457
+ },
458
+ children: [
459
+ /* @__PURE__ */ jsx3("span", { style: { color: "#6b7280", fontWeight: 500 }, children: "Context:" }),
460
+ /* @__PURE__ */ jsx3(
461
+ "pre",
462
+ {
463
+ style: {
464
+ margin: "4px 0 0 0",
465
+ fontSize: "11px",
466
+ color: "#4b5563",
467
+ overflow: "auto"
468
+ },
469
+ children: JSON.stringify(event.context, null, 2)
470
+ }
471
+ )
472
+ ]
473
+ }
474
+ ),
475
+ /* @__PURE__ */ jsxs(
476
+ "div",
477
+ {
478
+ style: {
479
+ marginTop: "8px",
480
+ fontSize: "10px",
481
+ color: "#9ca3af",
482
+ fontFamily: "monospace"
483
+ },
484
+ children: [
485
+ event.id.slice(0, 12),
486
+ "..."
487
+ ]
488
+ }
489
+ )
490
+ ]
491
+ }
492
+ );
493
+ }
494
+
495
+ // src/components/TimelineView/index.tsx
496
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
497
+ function TimelineView({
498
+ events,
499
+ onEventClick,
500
+ selectedEventId,
501
+ showContext = false,
502
+ groupBy = "none",
503
+ maxHeight = "600px",
504
+ className = ""
505
+ }) {
506
+ const sortedEvents = useMemo2(() => {
507
+ return [...events].sort(
508
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
509
+ );
510
+ }, [events]);
511
+ const groupedEvents = useMemo2(() => {
512
+ if (groupBy === "none") {
513
+ return [{ label: "", events: sortedEvents }];
514
+ }
515
+ const groups = /* @__PURE__ */ new Map();
516
+ for (const event of sortedEvents) {
517
+ let key;
518
+ if (groupBy === "day") {
519
+ key = new Date(event.timestamp).toLocaleDateString();
520
+ } else {
521
+ key = event.actor;
522
+ }
523
+ if (!groups.has(key)) {
524
+ groups.set(key, []);
525
+ }
526
+ groups.get(key).push(event);
527
+ }
528
+ return Array.from(groups.entries()).map(([label, events2]) => ({
529
+ label,
530
+ events: events2
531
+ }));
532
+ }, [sortedEvents, groupBy]);
533
+ if (events.length === 0) {
534
+ return /* @__PURE__ */ jsx4(
535
+ "div",
536
+ {
537
+ className: `aether-timeline-empty ${className}`,
538
+ style: {
539
+ padding: "40px",
540
+ textAlign: "center",
541
+ color: "#9ca3af"
542
+ },
543
+ children: "No events to display"
544
+ }
545
+ );
546
+ }
547
+ return /* @__PURE__ */ jsx4(
548
+ "div",
549
+ {
550
+ className: `aether-timeline ${className}`,
551
+ style: {
552
+ maxHeight,
553
+ overflowY: "auto",
554
+ padding: "16px"
555
+ },
556
+ children: groupedEvents.map((group, groupIndex) => /* @__PURE__ */ jsxs2("div", { className: "aether-timeline-group", children: [
557
+ group.label && /* @__PURE__ */ jsx4(
558
+ "div",
559
+ {
560
+ style: {
561
+ padding: "8px 0",
562
+ marginBottom: "8px",
563
+ borderBottom: "1px solid #e5e7eb",
564
+ fontWeight: 600,
565
+ color: "#374151",
566
+ position: "sticky",
567
+ top: 0,
568
+ backgroundColor: "#ffffff",
569
+ zIndex: 1
570
+ },
571
+ children: group.label
572
+ }
573
+ ),
574
+ /* @__PURE__ */ jsx4("div", { className: "aether-timeline-events", children: group.events.map((event) => /* @__PURE__ */ jsxs2(
575
+ "div",
576
+ {
577
+ style: {
578
+ display: "flex",
579
+ gap: "12px"
580
+ },
581
+ children: [
582
+ /* @__PURE__ */ jsxs2(
583
+ "div",
584
+ {
585
+ style: {
586
+ display: "flex",
587
+ flexDirection: "column",
588
+ alignItems: "center",
589
+ width: "20px",
590
+ flexShrink: 0
591
+ },
592
+ children: [
593
+ /* @__PURE__ */ jsx4(
594
+ "div",
595
+ {
596
+ style: {
597
+ width: "10px",
598
+ height: "10px",
599
+ borderRadius: "50%",
600
+ backgroundColor: event.id === selectedEventId ? "#3b82f6" : "#d1d5db",
601
+ border: "2px solid #ffffff",
602
+ boxShadow: "0 0 0 2px " + (event.id === selectedEventId ? "#3b82f6" : "#d1d5db")
603
+ }
604
+ }
605
+ ),
606
+ /* @__PURE__ */ jsx4(
607
+ "div",
608
+ {
609
+ style: {
610
+ flex: 1,
611
+ width: "2px",
612
+ backgroundColor: "#e5e7eb",
613
+ minHeight: "20px"
614
+ }
615
+ }
616
+ )
617
+ ]
618
+ }
619
+ ),
620
+ /* @__PURE__ */ jsx4("div", { style: { flex: 1, paddingBottom: "8px" }, children: /* @__PURE__ */ jsx4(
621
+ MemoryCard,
622
+ {
623
+ event,
624
+ onClick: onEventClick,
625
+ selected: event.id === selectedEventId,
626
+ showContext
627
+ }
628
+ ) })
629
+ ]
630
+ },
631
+ event.id
632
+ )) })
633
+ ] }, group.label || groupIndex))
634
+ }
635
+ );
636
+ }
637
+
638
+ // src/components/ClusterMap/index.tsx
639
+ import { useMemo as useMemo3 } from "react";
640
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
641
+ function ClusterMap({
642
+ events,
643
+ width = 600,
644
+ height = 400,
645
+ onEventClick,
646
+ colorBy = "actor",
647
+ className = ""
648
+ }) {
649
+ const colorPalette = [
650
+ "#3b82f6",
651
+ "#10b981",
652
+ "#f59e0b",
653
+ "#ef4444",
654
+ "#8b5cf6",
655
+ "#ec4899",
656
+ "#06b6d4",
657
+ "#84cc16",
658
+ "#f97316",
659
+ "#6366f1"
660
+ ];
661
+ const { points, colorMap } = useMemo3(() => {
662
+ const colorKey = colorBy === "actor" ? "actor" : "action";
663
+ const uniqueValues = [...new Set(events.map((e) => e[colorKey]))];
664
+ const colorMap2 = /* @__PURE__ */ new Map();
665
+ uniqueValues.forEach((value, i) => {
666
+ colorMap2.set(value, colorPalette[i % colorPalette.length]);
667
+ });
668
+ const cols = Math.ceil(Math.sqrt(events.length));
669
+ const padding = 60;
670
+ const cellWidth = (width - padding * 2) / cols;
671
+ const cellHeight = (height - padding * 2) / cols;
672
+ const points2 = events.map((event, i) => {
673
+ const col = i % cols;
674
+ const row = Math.floor(i / cols);
675
+ const jitterX = (Math.random() - 0.5) * cellWidth * 0.5;
676
+ const jitterY = (Math.random() - 0.5) * cellHeight * 0.5;
677
+ return {
678
+ event,
679
+ x: padding + col * cellWidth + cellWidth / 2 + jitterX,
680
+ y: padding + row * cellHeight + cellHeight / 2 + jitterY,
681
+ color: colorMap2.get(event[colorKey]) ?? "#9ca3af"
682
+ };
683
+ });
684
+ return { points: points2, colorMap: colorMap2 };
685
+ }, [events, colorBy, width, height]);
686
+ if (events.length === 0) {
687
+ return /* @__PURE__ */ jsx5(
688
+ "div",
689
+ {
690
+ className: `aether-cluster-empty ${className}`,
691
+ style: {
692
+ width,
693
+ height,
694
+ display: "flex",
695
+ alignItems: "center",
696
+ justifyContent: "center",
697
+ color: "#9ca3af",
698
+ backgroundColor: "#f9fafb",
699
+ borderRadius: "8px"
700
+ },
701
+ children: "No events to display"
702
+ }
703
+ );
704
+ }
705
+ return /* @__PURE__ */ jsxs3(
706
+ "div",
707
+ {
708
+ className: `aether-cluster ${className}`,
709
+ style: {
710
+ width,
711
+ height,
712
+ position: "relative",
713
+ backgroundColor: "#f9fafb",
714
+ borderRadius: "8px",
715
+ overflow: "hidden"
716
+ },
717
+ children: [
718
+ /* @__PURE__ */ jsx5("svg", { width, height, children: points.map((point, i) => /* @__PURE__ */ jsx5("g", { children: /* @__PURE__ */ jsx5(
719
+ "circle",
720
+ {
721
+ cx: point.x,
722
+ cy: point.y,
723
+ r: 8,
724
+ fill: point.color,
725
+ stroke: "#ffffff",
726
+ strokeWidth: 2,
727
+ style: { cursor: "pointer" },
728
+ onClick: () => onEventClick?.(point.event),
729
+ children: /* @__PURE__ */ jsx5("title", { children: point.event.content })
730
+ }
731
+ ) }, point.event.id)) }),
732
+ /* @__PURE__ */ jsxs3(
733
+ "div",
734
+ {
735
+ style: {
736
+ position: "absolute",
737
+ bottom: 10,
738
+ left: 10,
739
+ backgroundColor: "rgba(255, 255, 255, 0.9)",
740
+ padding: "8px",
741
+ borderRadius: "4px",
742
+ fontSize: "12px"
743
+ },
744
+ children: [
745
+ /* @__PURE__ */ jsx5("div", { style: { fontWeight: 600, marginBottom: "4px" }, children: colorBy === "actor" ? "Actors" : "Actions" }),
746
+ Array.from(colorMap.entries()).slice(0, 5).map(([label, color]) => /* @__PURE__ */ jsxs3(
747
+ "div",
748
+ {
749
+ style: {
750
+ display: "flex",
751
+ alignItems: "center",
752
+ gap: "6px",
753
+ marginBottom: "2px"
754
+ },
755
+ children: [
756
+ /* @__PURE__ */ jsx5(
757
+ "div",
758
+ {
759
+ style: {
760
+ width: 10,
761
+ height: 10,
762
+ borderRadius: "50%",
763
+ backgroundColor: color
764
+ }
765
+ }
766
+ ),
767
+ /* @__PURE__ */ jsx5("span", { children: label })
768
+ ]
769
+ },
770
+ label
771
+ )),
772
+ colorMap.size > 5 && /* @__PURE__ */ jsxs3("div", { style: { color: "#9ca3af" }, children: [
773
+ "+",
774
+ colorMap.size - 5,
775
+ " more"
776
+ ] })
777
+ ]
778
+ }
779
+ )
780
+ ]
781
+ }
782
+ );
783
+ }
784
+
785
+ // src/components/MemoryExplorer/index.tsx
786
+ import { useState as useState3 } from "react";
787
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
788
+ function MemoryExplorer({
789
+ events,
790
+ onEventClick,
791
+ defaultView = "timeline",
792
+ showViewSwitcher = true,
793
+ className = ""
794
+ }) {
795
+ const [currentView, setCurrentView] = useState3(defaultView);
796
+ const [selectedEvent, setSelectedEvent] = useState3(null);
797
+ const handleEventClick = (event) => {
798
+ setSelectedEvent(event);
799
+ onEventClick?.(event);
800
+ };
801
+ const renderView = () => {
802
+ switch (currentView) {
803
+ case "timeline":
804
+ return /* @__PURE__ */ jsx6(
805
+ TimelineView,
806
+ {
807
+ events,
808
+ onEventClick: handleEventClick,
809
+ selectedEventId: selectedEvent?.id,
810
+ showContext: true,
811
+ maxHeight: "500px"
812
+ }
813
+ );
814
+ case "graph":
815
+ return /* @__PURE__ */ jsx6(
816
+ MemoryGraphView,
817
+ {
818
+ events,
819
+ onNodeClick: handleEventClick,
820
+ width: 700,
821
+ height: 500
822
+ }
823
+ );
824
+ case "cluster":
825
+ return /* @__PURE__ */ jsx6(
826
+ ClusterMap,
827
+ {
828
+ events,
829
+ onEventClick: handleEventClick,
830
+ width: 700,
831
+ height: 500,
832
+ colorBy: "actor"
833
+ }
834
+ );
835
+ default:
836
+ return null;
837
+ }
838
+ };
839
+ return /* @__PURE__ */ jsxs4(
840
+ "div",
841
+ {
842
+ className: `aether-explorer ${className}`,
843
+ style: {
844
+ display: "flex",
845
+ gap: "16px",
846
+ padding: "16px"
847
+ },
848
+ children: [
849
+ /* @__PURE__ */ jsxs4("div", { style: { flex: 1 }, children: [
850
+ showViewSwitcher && /* @__PURE__ */ jsx6(
851
+ "div",
852
+ {
853
+ style: {
854
+ display: "flex",
855
+ gap: "8px",
856
+ marginBottom: "16px"
857
+ },
858
+ children: ["timeline", "graph", "cluster"].map((view) => /* @__PURE__ */ jsx6(
859
+ "button",
860
+ {
861
+ onClick: () => setCurrentView(view),
862
+ style: {
863
+ padding: "8px 16px",
864
+ borderRadius: "6px",
865
+ border: "none",
866
+ backgroundColor: currentView === view ? "#3b82f6" : "#e5e7eb",
867
+ color: currentView === view ? "#ffffff" : "#374151",
868
+ cursor: "pointer",
869
+ fontWeight: 500,
870
+ textTransform: "capitalize",
871
+ transition: "all 0.2s ease"
872
+ },
873
+ children: view
874
+ },
875
+ view
876
+ ))
877
+ }
878
+ ),
879
+ /* @__PURE__ */ jsx6(
880
+ "div",
881
+ {
882
+ style: {
883
+ backgroundColor: "#ffffff",
884
+ borderRadius: "8px",
885
+ border: "1px solid #e5e7eb",
886
+ overflow: "hidden"
887
+ },
888
+ children: renderView()
889
+ }
890
+ ),
891
+ /* @__PURE__ */ jsxs4(
892
+ "div",
893
+ {
894
+ style: {
895
+ marginTop: "12px",
896
+ padding: "8px 12px",
897
+ backgroundColor: "#f9fafb",
898
+ borderRadius: "6px",
899
+ fontSize: "12px",
900
+ color: "#6b7280"
901
+ },
902
+ children: [
903
+ events.length,
904
+ " events \u2022 ",
905
+ new Set(events.map((e) => e.actor)).size,
906
+ " actors"
907
+ ]
908
+ }
909
+ )
910
+ ] }),
911
+ selectedEvent && /* @__PURE__ */ jsxs4(
912
+ "div",
913
+ {
914
+ style: {
915
+ width: "300px",
916
+ flexShrink: 0
917
+ },
918
+ children: [
919
+ /* @__PURE__ */ jsx6(
920
+ "div",
921
+ {
922
+ style: {
923
+ fontWeight: 600,
924
+ marginBottom: "8px",
925
+ color: "#374151"
926
+ },
927
+ children: "Selected Event"
928
+ }
929
+ ),
930
+ /* @__PURE__ */ jsx6(MemoryCard, { event: selectedEvent, showContext: true })
931
+ ]
932
+ }
933
+ )
934
+ ]
935
+ }
936
+ );
937
+ }
938
+
939
+ // src/components/AddMemoryForm/index.tsx
940
+ import { useState as useState4, useCallback as useCallback3 } from "react";
941
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
942
+ function AddMemoryForm({
943
+ onAdd,
944
+ loading = false,
945
+ defaultActor = "user",
946
+ placeholder = 'What happened? (e.g., "User clicked the buy button")',
947
+ className = ""
948
+ }) {
949
+ const [content, setContent] = useState4("");
950
+ const [actor, setActor] = useState4(defaultActor);
951
+ const [contextJson, setContextJson] = useState4("");
952
+ const [showAdvanced, setShowAdvanced] = useState4(false);
953
+ const [error, setError] = useState4(null);
954
+ const handleSubmit = useCallback3(
955
+ async (e) => {
956
+ e.preventDefault();
957
+ setError(null);
958
+ if (!content.trim()) {
959
+ setError("Content is required");
960
+ return;
961
+ }
962
+ let context;
963
+ if (contextJson.trim()) {
964
+ try {
965
+ context = JSON.parse(contextJson);
966
+ } catch {
967
+ setError("Invalid JSON in context field");
968
+ return;
969
+ }
970
+ }
971
+ try {
972
+ await onAdd(content.trim(), actor.trim() || "user", context);
973
+ setContent("");
974
+ setContextJson("");
975
+ } catch (err) {
976
+ setError(String(err));
977
+ }
978
+ },
979
+ [content, actor, contextJson, onAdd]
980
+ );
981
+ return /* @__PURE__ */ jsxs5(
982
+ "form",
983
+ {
984
+ onSubmit: handleSubmit,
985
+ className: `aether-add-memory-form ${className}`,
986
+ style: {
987
+ display: "flex",
988
+ flexDirection: "column",
989
+ gap: "12px",
990
+ padding: "16px",
991
+ backgroundColor: "#ffffff",
992
+ borderRadius: "8px",
993
+ border: "1px solid #e5e7eb"
994
+ },
995
+ children: [
996
+ /* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "8px" }, children: [
997
+ /* @__PURE__ */ jsx7(
998
+ "input",
999
+ {
1000
+ type: "text",
1001
+ value: content,
1002
+ onChange: (e) => setContent(e.target.value),
1003
+ placeholder,
1004
+ disabled: loading,
1005
+ style: {
1006
+ flex: 1,
1007
+ padding: "10px 14px",
1008
+ fontSize: "14px",
1009
+ border: "1px solid #d1d5db",
1010
+ borderRadius: "6px",
1011
+ outline: "none",
1012
+ transition: "border-color 0.2s"
1013
+ },
1014
+ onFocus: (e) => e.target.style.borderColor = "#3b82f6",
1015
+ onBlur: (e) => e.target.style.borderColor = "#d1d5db"
1016
+ }
1017
+ ),
1018
+ /* @__PURE__ */ jsx7(
1019
+ "button",
1020
+ {
1021
+ type: "submit",
1022
+ disabled: loading || !content.trim(),
1023
+ style: {
1024
+ padding: "10px 20px",
1025
+ fontSize: "14px",
1026
+ fontWeight: 500,
1027
+ color: "#ffffff",
1028
+ backgroundColor: loading || !content.trim() ? "#9ca3af" : "#3b82f6",
1029
+ border: "none",
1030
+ borderRadius: "6px",
1031
+ cursor: loading || !content.trim() ? "not-allowed" : "pointer",
1032
+ transition: "background-color 0.2s"
1033
+ },
1034
+ children: loading ? "Adding..." : "Add Memory"
1035
+ }
1036
+ )
1037
+ ] }),
1038
+ /* @__PURE__ */ jsx7(
1039
+ "button",
1040
+ {
1041
+ type: "button",
1042
+ onClick: () => setShowAdvanced(!showAdvanced),
1043
+ style: {
1044
+ alignSelf: "flex-start",
1045
+ padding: "4px 8px",
1046
+ fontSize: "12px",
1047
+ color: "#6b7280",
1048
+ backgroundColor: "transparent",
1049
+ border: "none",
1050
+ cursor: "pointer",
1051
+ textDecoration: "underline"
1052
+ },
1053
+ children: showAdvanced ? "Hide options" : "Show options"
1054
+ }
1055
+ ),
1056
+ showAdvanced && /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
1057
+ /* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
1058
+ /* @__PURE__ */ jsx7("label", { style: { fontSize: "13px", color: "#6b7280", minWidth: "50px" }, children: "Actor:" }),
1059
+ /* @__PURE__ */ jsx7(
1060
+ "input",
1061
+ {
1062
+ type: "text",
1063
+ value: actor,
1064
+ onChange: (e) => setActor(e.target.value),
1065
+ placeholder: "user",
1066
+ style: {
1067
+ flex: 1,
1068
+ padding: "8px 12px",
1069
+ fontSize: "13px",
1070
+ border: "1px solid #d1d5db",
1071
+ borderRadius: "4px",
1072
+ outline: "none"
1073
+ }
1074
+ }
1075
+ )
1076
+ ] }),
1077
+ /* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "8px", alignItems: "flex-start" }, children: [
1078
+ /* @__PURE__ */ jsx7("label", { style: { fontSize: "13px", color: "#6b7280", minWidth: "50px", paddingTop: "8px" }, children: "Context:" }),
1079
+ /* @__PURE__ */ jsx7(
1080
+ "textarea",
1081
+ {
1082
+ value: contextJson,
1083
+ onChange: (e) => setContextJson(e.target.value),
1084
+ placeholder: '{"key": "value"}',
1085
+ rows: 2,
1086
+ style: {
1087
+ flex: 1,
1088
+ padding: "8px 12px",
1089
+ fontSize: "13px",
1090
+ fontFamily: "monospace",
1091
+ border: "1px solid #d1d5db",
1092
+ borderRadius: "4px",
1093
+ outline: "none",
1094
+ resize: "vertical"
1095
+ }
1096
+ }
1097
+ )
1098
+ ] })
1099
+ ] }),
1100
+ error && /* @__PURE__ */ jsx7(
1101
+ "div",
1102
+ {
1103
+ style: {
1104
+ padding: "8px 12px",
1105
+ fontSize: "13px",
1106
+ color: "#dc2626",
1107
+ backgroundColor: "#fef2f2",
1108
+ borderRadius: "4px"
1109
+ },
1110
+ children: error
1111
+ }
1112
+ )
1113
+ ]
1114
+ }
1115
+ );
1116
+ }
1117
+
1118
+ // src/components/SearchBar/index.tsx
1119
+ import { useState as useState5, useCallback as useCallback4 } from "react";
1120
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1121
+ var RETRIEVAL_TYPES = [
1122
+ { value: "hybrid", label: "Hybrid", description: "Combines all strategies" },
1123
+ { value: "semantic", label: "Semantic", description: "Vector similarity search" },
1124
+ { value: "temporal", label: "Temporal", description: "Recent events first" },
1125
+ { value: "relational", label: "Relational", description: "Entity-based search" }
1126
+ ];
1127
+ function SearchBar({
1128
+ onSearch,
1129
+ loading = false,
1130
+ placeholder = "Search memories...",
1131
+ className = ""
1132
+ }) {
1133
+ const [query, setQuery] = useState5("");
1134
+ const [retrievalType, setRetrievalType] = useState5("hybrid");
1135
+ const [limit, setLimit] = useState5(10);
1136
+ const [actor, setActor] = useState5("");
1137
+ const [showFilters, setShowFilters] = useState5(false);
1138
+ const handleSubmit = useCallback4(
1139
+ async (e) => {
1140
+ e.preventDefault();
1141
+ if (!query.trim()) return;
1142
+ await onSearch(query.trim(), {
1143
+ retrievalType,
1144
+ limit,
1145
+ actor: actor.trim() || void 0
1146
+ });
1147
+ },
1148
+ [query, retrievalType, limit, actor, onSearch]
1149
+ );
1150
+ return /* @__PURE__ */ jsxs6(
1151
+ "form",
1152
+ {
1153
+ onSubmit: handleSubmit,
1154
+ className: `aether-search-bar ${className}`,
1155
+ style: {
1156
+ display: "flex",
1157
+ flexDirection: "column",
1158
+ gap: "12px"
1159
+ },
1160
+ children: [
1161
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: "8px" }, children: [
1162
+ /* @__PURE__ */ jsxs6("div", { style: { flex: 1, position: "relative" }, children: [
1163
+ /* @__PURE__ */ jsx8(
1164
+ "input",
1165
+ {
1166
+ type: "text",
1167
+ value: query,
1168
+ onChange: (e) => setQuery(e.target.value),
1169
+ placeholder,
1170
+ disabled: loading,
1171
+ style: {
1172
+ width: "100%",
1173
+ padding: "12px 16px",
1174
+ paddingLeft: "40px",
1175
+ fontSize: "14px",
1176
+ border: "1px solid #d1d5db",
1177
+ borderRadius: "8px",
1178
+ outline: "none",
1179
+ transition: "border-color 0.2s, box-shadow 0.2s"
1180
+ },
1181
+ onFocus: (e) => {
1182
+ e.target.style.borderColor = "#3b82f6";
1183
+ e.target.style.boxShadow = "0 0 0 3px rgba(59, 130, 246, 0.1)";
1184
+ },
1185
+ onBlur: (e) => {
1186
+ e.target.style.borderColor = "#d1d5db";
1187
+ e.target.style.boxShadow = "none";
1188
+ }
1189
+ }
1190
+ ),
1191
+ /* @__PURE__ */ jsx8(
1192
+ "svg",
1193
+ {
1194
+ style: {
1195
+ position: "absolute",
1196
+ left: "12px",
1197
+ top: "50%",
1198
+ transform: "translateY(-50%)",
1199
+ width: "20px",
1200
+ height: "20px",
1201
+ color: "#9ca3af"
1202
+ },
1203
+ fill: "none",
1204
+ stroke: "currentColor",
1205
+ viewBox: "0 0 24 24",
1206
+ children: /* @__PURE__ */ jsx8(
1207
+ "path",
1208
+ {
1209
+ strokeLinecap: "round",
1210
+ strokeLinejoin: "round",
1211
+ strokeWidth: 2,
1212
+ d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
1213
+ }
1214
+ )
1215
+ }
1216
+ )
1217
+ ] }),
1218
+ /* @__PURE__ */ jsx8(
1219
+ "button",
1220
+ {
1221
+ type: "button",
1222
+ onClick: () => setShowFilters(!showFilters),
1223
+ style: {
1224
+ padding: "12px",
1225
+ backgroundColor: showFilters ? "#eff6ff" : "#f9fafb",
1226
+ border: `1px solid ${showFilters ? "#3b82f6" : "#d1d5db"}`,
1227
+ borderRadius: "8px",
1228
+ cursor: "pointer",
1229
+ transition: "all 0.2s"
1230
+ },
1231
+ title: "Toggle filters",
1232
+ children: /* @__PURE__ */ jsx8(
1233
+ "svg",
1234
+ {
1235
+ style: { width: "20px", height: "20px", color: showFilters ? "#3b82f6" : "#6b7280" },
1236
+ fill: "none",
1237
+ stroke: "currentColor",
1238
+ viewBox: "0 0 24 24",
1239
+ children: /* @__PURE__ */ jsx8(
1240
+ "path",
1241
+ {
1242
+ strokeLinecap: "round",
1243
+ strokeLinejoin: "round",
1244
+ strokeWidth: 2,
1245
+ d: "M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"
1246
+ }
1247
+ )
1248
+ }
1249
+ )
1250
+ }
1251
+ ),
1252
+ /* @__PURE__ */ jsx8(
1253
+ "button",
1254
+ {
1255
+ type: "submit",
1256
+ disabled: loading || !query.trim(),
1257
+ style: {
1258
+ padding: "12px 24px",
1259
+ fontSize: "14px",
1260
+ fontWeight: 500,
1261
+ color: "#ffffff",
1262
+ backgroundColor: loading || !query.trim() ? "#9ca3af" : "#3b82f6",
1263
+ border: "none",
1264
+ borderRadius: "8px",
1265
+ cursor: loading || !query.trim() ? "not-allowed" : "pointer",
1266
+ transition: "background-color 0.2s"
1267
+ },
1268
+ children: loading ? "Searching..." : "Search"
1269
+ }
1270
+ )
1271
+ ] }),
1272
+ showFilters && /* @__PURE__ */ jsxs6(
1273
+ "div",
1274
+ {
1275
+ style: {
1276
+ display: "flex",
1277
+ gap: "16px",
1278
+ padding: "16px",
1279
+ backgroundColor: "#f9fafb",
1280
+ borderRadius: "8px",
1281
+ flexWrap: "wrap"
1282
+ },
1283
+ children: [
1284
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: [
1285
+ /* @__PURE__ */ jsx8("label", { style: { fontSize: "12px", fontWeight: 500, color: "#374151" }, children: "Retrieval Type" }),
1286
+ /* @__PURE__ */ jsx8(
1287
+ "select",
1288
+ {
1289
+ value: retrievalType,
1290
+ onChange: (e) => setRetrievalType(e.target.value),
1291
+ style: {
1292
+ padding: "8px 12px",
1293
+ fontSize: "13px",
1294
+ border: "1px solid #d1d5db",
1295
+ borderRadius: "6px",
1296
+ backgroundColor: "#ffffff",
1297
+ cursor: "pointer"
1298
+ },
1299
+ children: RETRIEVAL_TYPES.map((type) => /* @__PURE__ */ jsx8("option", { value: type.value, children: type.label }, type.value))
1300
+ }
1301
+ )
1302
+ ] }),
1303
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: [
1304
+ /* @__PURE__ */ jsx8("label", { style: { fontSize: "12px", fontWeight: 500, color: "#374151" }, children: "Max Results" }),
1305
+ /* @__PURE__ */ jsx8(
1306
+ "select",
1307
+ {
1308
+ value: limit,
1309
+ onChange: (e) => setLimit(parseInt(e.target.value, 10)),
1310
+ style: {
1311
+ padding: "8px 12px",
1312
+ fontSize: "13px",
1313
+ border: "1px solid #d1d5db",
1314
+ borderRadius: "6px",
1315
+ backgroundColor: "#ffffff",
1316
+ cursor: "pointer"
1317
+ },
1318
+ children: [5, 10, 20, 50, 100].map((n) => /* @__PURE__ */ jsx8("option", { value: n, children: n }, n))
1319
+ }
1320
+ )
1321
+ ] }),
1322
+ /* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: [
1323
+ /* @__PURE__ */ jsx8("label", { style: { fontSize: "12px", fontWeight: 500, color: "#374151" }, children: "Actor (optional)" }),
1324
+ /* @__PURE__ */ jsx8(
1325
+ "input",
1326
+ {
1327
+ type: "text",
1328
+ value: actor,
1329
+ onChange: (e) => setActor(e.target.value),
1330
+ placeholder: "Filter by actor",
1331
+ style: {
1332
+ padding: "8px 12px",
1333
+ fontSize: "13px",
1334
+ border: "1px solid #d1d5db",
1335
+ borderRadius: "6px",
1336
+ width: "150px"
1337
+ }
1338
+ }
1339
+ )
1340
+ ] })
1341
+ ]
1342
+ }
1343
+ )
1344
+ ]
1345
+ }
1346
+ );
1347
+ }
1348
+
1349
+ // src/components/StatsPanel/index.tsx
1350
+ import "react";
1351
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1352
+ function StatItem({ label, value, icon, color }) {
1353
+ return /* @__PURE__ */ jsxs7(
1354
+ "div",
1355
+ {
1356
+ style: {
1357
+ display: "flex",
1358
+ alignItems: "center",
1359
+ gap: "12px",
1360
+ padding: "16px",
1361
+ backgroundColor: "#ffffff",
1362
+ borderRadius: "8px",
1363
+ border: "1px solid #e5e7eb"
1364
+ },
1365
+ children: [
1366
+ /* @__PURE__ */ jsx9(
1367
+ "div",
1368
+ {
1369
+ style: {
1370
+ display: "flex",
1371
+ alignItems: "center",
1372
+ justifyContent: "center",
1373
+ width: "40px",
1374
+ height: "40px",
1375
+ borderRadius: "8px",
1376
+ backgroundColor: color
1377
+ },
1378
+ children: icon
1379
+ }
1380
+ ),
1381
+ /* @__PURE__ */ jsxs7("div", { children: [
1382
+ /* @__PURE__ */ jsx9("div", { style: { fontSize: "24px", fontWeight: 600, color: "#1f2937" }, children: value }),
1383
+ /* @__PURE__ */ jsx9("div", { style: { fontSize: "13px", color: "#6b7280" }, children: label })
1384
+ ] })
1385
+ ]
1386
+ }
1387
+ );
1388
+ }
1389
+ function StatsPanel({ stats, loading = false, className = "" }) {
1390
+ if (loading) {
1391
+ return /* @__PURE__ */ jsx9(
1392
+ "div",
1393
+ {
1394
+ className: `aether-stats-panel ${className}`,
1395
+ style: {
1396
+ display: "grid",
1397
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
1398
+ gap: "12px"
1399
+ },
1400
+ children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx9(
1401
+ "div",
1402
+ {
1403
+ style: {
1404
+ height: "88px",
1405
+ backgroundColor: "#f3f4f6",
1406
+ borderRadius: "8px",
1407
+ animation: "pulse 2s infinite"
1408
+ }
1409
+ },
1410
+ i
1411
+ ))
1412
+ }
1413
+ );
1414
+ }
1415
+ if (!stats) {
1416
+ return /* @__PURE__ */ jsx9(
1417
+ "div",
1418
+ {
1419
+ className: `aether-stats-panel ${className}`,
1420
+ style: {
1421
+ padding: "24px",
1422
+ textAlign: "center",
1423
+ color: "#9ca3af",
1424
+ backgroundColor: "#f9fafb",
1425
+ borderRadius: "8px"
1426
+ },
1427
+ children: "No statistics available"
1428
+ }
1429
+ );
1430
+ }
1431
+ const formatDate = (dateStr) => {
1432
+ if (!dateStr) return "N/A";
1433
+ return new Date(dateStr).toLocaleDateString();
1434
+ };
1435
+ return /* @__PURE__ */ jsxs7(
1436
+ "div",
1437
+ {
1438
+ className: `aether-stats-panel ${className}`,
1439
+ style: {
1440
+ display: "grid",
1441
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
1442
+ gap: "12px"
1443
+ },
1444
+ children: [
1445
+ /* @__PURE__ */ jsx9(
1446
+ StatItem,
1447
+ {
1448
+ label: "Total Memories",
1449
+ value: stats.totalEvents.toLocaleString(),
1450
+ color: "#dbeafe",
1451
+ icon: /* @__PURE__ */ jsx9(
1452
+ "svg",
1453
+ {
1454
+ style: { width: "20px", height: "20px", color: "#3b82f6" },
1455
+ fill: "none",
1456
+ stroke: "currentColor",
1457
+ viewBox: "0 0 24 24",
1458
+ children: /* @__PURE__ */ jsx9(
1459
+ "path",
1460
+ {
1461
+ strokeLinecap: "round",
1462
+ strokeLinejoin: "round",
1463
+ strokeWidth: 2,
1464
+ d: "M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"
1465
+ }
1466
+ )
1467
+ }
1468
+ )
1469
+ }
1470
+ ),
1471
+ /* @__PURE__ */ jsx9(
1472
+ StatItem,
1473
+ {
1474
+ label: "Unique Actors",
1475
+ value: stats.uniqueActors,
1476
+ color: "#dcfce7",
1477
+ icon: /* @__PURE__ */ jsx9(
1478
+ "svg",
1479
+ {
1480
+ style: { width: "20px", height: "20px", color: "#22c55e" },
1481
+ fill: "none",
1482
+ stroke: "currentColor",
1483
+ viewBox: "0 0 24 24",
1484
+ children: /* @__PURE__ */ jsx9(
1485
+ "path",
1486
+ {
1487
+ strokeLinecap: "round",
1488
+ strokeLinejoin: "round",
1489
+ strokeWidth: 2,
1490
+ d: "M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
1491
+ }
1492
+ )
1493
+ }
1494
+ )
1495
+ }
1496
+ ),
1497
+ /* @__PURE__ */ jsx9(
1498
+ StatItem,
1499
+ {
1500
+ label: "First Event",
1501
+ value: formatDate(stats.oldestEvent),
1502
+ color: "#fef3c7",
1503
+ icon: /* @__PURE__ */ jsx9(
1504
+ "svg",
1505
+ {
1506
+ style: { width: "20px", height: "20px", color: "#f59e0b" },
1507
+ fill: "none",
1508
+ stroke: "currentColor",
1509
+ viewBox: "0 0 24 24",
1510
+ children: /* @__PURE__ */ jsx9(
1511
+ "path",
1512
+ {
1513
+ strokeLinecap: "round",
1514
+ strokeLinejoin: "round",
1515
+ strokeWidth: 2,
1516
+ d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
1517
+ }
1518
+ )
1519
+ }
1520
+ )
1521
+ }
1522
+ ),
1523
+ /* @__PURE__ */ jsx9(
1524
+ StatItem,
1525
+ {
1526
+ label: "Latest Event",
1527
+ value: formatDate(stats.newestEvent),
1528
+ color: "#fce7f3",
1529
+ icon: /* @__PURE__ */ jsx9(
1530
+ "svg",
1531
+ {
1532
+ style: { width: "20px", height: "20px", color: "#ec4899" },
1533
+ fill: "none",
1534
+ stroke: "currentColor",
1535
+ viewBox: "0 0 24 24",
1536
+ children: /* @__PURE__ */ jsx9(
1537
+ "path",
1538
+ {
1539
+ strokeLinecap: "round",
1540
+ strokeLinejoin: "round",
1541
+ strokeWidth: 2,
1542
+ d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
1543
+ }
1544
+ )
1545
+ }
1546
+ )
1547
+ }
1548
+ )
1549
+ ]
1550
+ }
1551
+ );
1552
+ }
1553
+
1554
+ // src/components/ActorSelector/index.tsx
1555
+ import "react";
1556
+ import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1557
+ function ActorSelector({
1558
+ actors,
1559
+ selectedActor,
1560
+ onSelect,
1561
+ loading = false,
1562
+ className = ""
1563
+ }) {
1564
+ if (loading) {
1565
+ return /* @__PURE__ */ jsx10(
1566
+ "div",
1567
+ {
1568
+ className: `aether-actor-selector ${className}`,
1569
+ style: {
1570
+ display: "flex",
1571
+ gap: "8px",
1572
+ flexWrap: "wrap"
1573
+ },
1574
+ children: [1, 2, 3].map((i) => /* @__PURE__ */ jsx10(
1575
+ "div",
1576
+ {
1577
+ style: {
1578
+ width: "80px",
1579
+ height: "32px",
1580
+ backgroundColor: "#f3f4f6",
1581
+ borderRadius: "9999px",
1582
+ animation: "pulse 2s infinite"
1583
+ }
1584
+ },
1585
+ i
1586
+ ))
1587
+ }
1588
+ );
1589
+ }
1590
+ if (actors.length === 0) {
1591
+ return /* @__PURE__ */ jsx10(
1592
+ "div",
1593
+ {
1594
+ className: `aether-actor-selector ${className}`,
1595
+ style: {
1596
+ padding: "12px",
1597
+ fontSize: "13px",
1598
+ color: "#9ca3af",
1599
+ textAlign: "center"
1600
+ },
1601
+ children: "No actors found"
1602
+ }
1603
+ );
1604
+ }
1605
+ return /* @__PURE__ */ jsxs8(
1606
+ "div",
1607
+ {
1608
+ className: `aether-actor-selector ${className}`,
1609
+ style: {
1610
+ display: "flex",
1611
+ gap: "8px",
1612
+ flexWrap: "wrap",
1613
+ alignItems: "center"
1614
+ },
1615
+ children: [
1616
+ /* @__PURE__ */ jsx10("span", { style: { fontSize: "13px", color: "#6b7280", marginRight: "4px" }, children: "Filter by actor:" }),
1617
+ /* @__PURE__ */ jsx10(
1618
+ "button",
1619
+ {
1620
+ onClick: () => onSelect(null),
1621
+ style: {
1622
+ padding: "6px 14px",
1623
+ fontSize: "13px",
1624
+ fontWeight: 500,
1625
+ color: selectedActor === null ? "#ffffff" : "#374151",
1626
+ backgroundColor: selectedActor === null ? "#3b82f6" : "#f3f4f6",
1627
+ border: "none",
1628
+ borderRadius: "9999px",
1629
+ cursor: "pointer",
1630
+ transition: "all 0.2s"
1631
+ },
1632
+ children: "All"
1633
+ }
1634
+ ),
1635
+ actors.map((actor) => /* @__PURE__ */ jsx10(
1636
+ "button",
1637
+ {
1638
+ onClick: () => onSelect(actor),
1639
+ style: {
1640
+ padding: "6px 14px",
1641
+ fontSize: "13px",
1642
+ fontWeight: 500,
1643
+ color: selectedActor === actor ? "#ffffff" : "#374151",
1644
+ backgroundColor: selectedActor === actor ? "#3b82f6" : "#f3f4f6",
1645
+ border: "none",
1646
+ borderRadius: "9999px",
1647
+ cursor: "pointer",
1648
+ transition: "all 0.2s"
1649
+ },
1650
+ children: actor
1651
+ },
1652
+ actor
1653
+ ))
1654
+ ]
1655
+ }
1656
+ );
1657
+ }
1658
+
1659
+ // src/components/ConnectionStatus/index.tsx
1660
+ import "react";
1661
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1662
+ function ConnectionStatus({
1663
+ connected,
1664
+ error,
1665
+ onReconnect,
1666
+ className = ""
1667
+ }) {
1668
+ return /* @__PURE__ */ jsxs9(
1669
+ "div",
1670
+ {
1671
+ className: `aether-connection-status ${className}`,
1672
+ style: {
1673
+ display: "inline-flex",
1674
+ alignItems: "center",
1675
+ gap: "8px",
1676
+ padding: "6px 12px",
1677
+ borderRadius: "9999px",
1678
+ fontSize: "12px",
1679
+ fontWeight: 500,
1680
+ backgroundColor: connected ? "#dcfce7" : error ? "#fef2f2" : "#fef3c7",
1681
+ color: connected ? "#166534" : error ? "#991b1b" : "#92400e"
1682
+ },
1683
+ children: [
1684
+ /* @__PURE__ */ jsx11(
1685
+ "span",
1686
+ {
1687
+ style: {
1688
+ width: "8px",
1689
+ height: "8px",
1690
+ borderRadius: "50%",
1691
+ backgroundColor: connected ? "#22c55e" : error ? "#ef4444" : "#f59e0b",
1692
+ animation: connected ? "none" : "pulse 2s infinite"
1693
+ }
1694
+ }
1695
+ ),
1696
+ /* @__PURE__ */ jsx11("span", { children: connected ? "Connected" : error ? "Connection Error" : "Connecting..." }),
1697
+ !connected && onReconnect && /* @__PURE__ */ jsx11(
1698
+ "button",
1699
+ {
1700
+ onClick: onReconnect,
1701
+ style: {
1702
+ marginLeft: "4px",
1703
+ padding: "2px 8px",
1704
+ fontSize: "11px",
1705
+ color: "#374151",
1706
+ backgroundColor: "#ffffff",
1707
+ border: "1px solid #d1d5db",
1708
+ borderRadius: "4px",
1709
+ cursor: "pointer"
1710
+ },
1711
+ children: "Retry"
1712
+ }
1713
+ )
1714
+ ]
1715
+ }
1716
+ );
1717
+ }
1718
+
1719
+ // src/components/Dashboard/index.tsx
1720
+ import { useState as useState6, useEffect as useEffect4, useCallback as useCallback5, useMemo as useMemo4 } from "react";
1721
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1722
+ function Dashboard({ aether, title = "Aether Memory Explorer", className = "" }) {
1723
+ const [events, setEvents] = useState6([]);
1724
+ const [searchResults, setSearchResults] = useState6(null);
1725
+ const [stats, setStats] = useState6(null);
1726
+ const [actors, setActors] = useState6([]);
1727
+ const [selectedActor, setSelectedActor] = useState6(null);
1728
+ const [selectedEvent, setSelectedEvent] = useState6(null);
1729
+ const [viewMode, setViewMode] = useState6("timeline");
1730
+ const [loading, setLoading] = useState6(false);
1731
+ const [searchQuery, setSearchQuery] = useState6("");
1732
+ useEffect4(() => {
1733
+ const loadData = async () => {
1734
+ setLoading(true);
1735
+ try {
1736
+ const [statsData] = await Promise.all([
1737
+ aether.stats()
1738
+ ]);
1739
+ setStats(statsData);
1740
+ const actorsList = [];
1741
+ setActors(actorsList);
1742
+ } catch (err) {
1743
+ console.error("Failed to load data:", err);
1744
+ } finally {
1745
+ setLoading(false);
1746
+ }
1747
+ };
1748
+ loadData();
1749
+ }, [aether]);
1750
+ useEffect4(() => {
1751
+ const unsubscribe = aether.subscribe((event) => {
1752
+ setEvents((prev) => [event, ...prev]);
1753
+ setActors((prev) => {
1754
+ if (!prev.includes(event.actor)) {
1755
+ return [...prev, event.actor];
1756
+ }
1757
+ return prev;
1758
+ });
1759
+ setStats((prev) => prev ? {
1760
+ ...prev,
1761
+ totalEvents: prev.totalEvents + 1,
1762
+ newestEvent: event.timestamp
1763
+ } : null);
1764
+ });
1765
+ return unsubscribe;
1766
+ }, [aether]);
1767
+ const handleAddMemory = useCallback5(
1768
+ async (content, actor, context) => {
1769
+ await aether.add({ content, actor, context });
1770
+ },
1771
+ [aether]
1772
+ );
1773
+ const handleSearch = useCallback5(
1774
+ async (query, options) => {
1775
+ setLoading(true);
1776
+ setSearchQuery(query);
1777
+ try {
1778
+ const results = await aether.retrieve(query, {
1779
+ retrievalType: options.retrievalType,
1780
+ limit: options.limit,
1781
+ actor: options.actor
1782
+ });
1783
+ setSearchResults(results);
1784
+ } catch (err) {
1785
+ console.error("Search failed:", err);
1786
+ } finally {
1787
+ setLoading(false);
1788
+ }
1789
+ },
1790
+ [aether]
1791
+ );
1792
+ const handleActorChange = useCallback5(
1793
+ async (actor) => {
1794
+ setSelectedActor(actor);
1795
+ setLoading(true);
1796
+ try {
1797
+ if (actor) {
1798
+ const history = await aether.getHistory(actor, 50);
1799
+ setEvents(history);
1800
+ } else {
1801
+ setEvents([]);
1802
+ }
1803
+ setSearchResults(null);
1804
+ setSearchQuery("");
1805
+ } catch (err) {
1806
+ console.error("Failed to load actor history:", err);
1807
+ } finally {
1808
+ setLoading(false);
1809
+ }
1810
+ },
1811
+ [aether]
1812
+ );
1813
+ const handleClearSearch = useCallback5(() => {
1814
+ setSearchResults(null);
1815
+ setSearchQuery("");
1816
+ }, []);
1817
+ const displayedEvents = searchResults ?? events;
1818
+ const filteredEvents = useMemo4(() => {
1819
+ if (searchResults) return searchResults;
1820
+ if (!selectedActor) return events;
1821
+ return events.filter((e) => e.actor === selectedActor);
1822
+ }, [events, searchResults, selectedActor]);
1823
+ return /* @__PURE__ */ jsxs10(
1824
+ "div",
1825
+ {
1826
+ className: `aether-dashboard ${className}`,
1827
+ style: {
1828
+ display: "flex",
1829
+ flexDirection: "column",
1830
+ height: "100%",
1831
+ backgroundColor: "#f9fafb",
1832
+ fontFamily: "Inter, -apple-system, BlinkMacSystemFont, sans-serif"
1833
+ },
1834
+ children: [
1835
+ /* @__PURE__ */ jsx12(
1836
+ "header",
1837
+ {
1838
+ style: {
1839
+ padding: "16px 24px",
1840
+ backgroundColor: "#ffffff",
1841
+ borderBottom: "1px solid #e5e7eb"
1842
+ },
1843
+ children: /* @__PURE__ */ jsxs10("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1844
+ /* @__PURE__ */ jsx12("h1", { style: { margin: 0, fontSize: "20px", fontWeight: 600, color: "#1f2937" }, children: title }),
1845
+ /* @__PURE__ */ jsxs10("div", { style: { display: "flex", gap: "8px" }, children: [
1846
+ /* @__PURE__ */ jsx12(
1847
+ "button",
1848
+ {
1849
+ onClick: () => setViewMode("timeline"),
1850
+ style: {
1851
+ padding: "8px 16px",
1852
+ fontSize: "13px",
1853
+ fontWeight: 500,
1854
+ color: viewMode === "timeline" ? "#3b82f6" : "#6b7280",
1855
+ backgroundColor: viewMode === "timeline" ? "#eff6ff" : "transparent",
1856
+ border: `1px solid ${viewMode === "timeline" ? "#3b82f6" : "#d1d5db"}`,
1857
+ borderRadius: "6px",
1858
+ cursor: "pointer"
1859
+ },
1860
+ children: "Timeline"
1861
+ }
1862
+ ),
1863
+ /* @__PURE__ */ jsx12(
1864
+ "button",
1865
+ {
1866
+ onClick: () => setViewMode("graph"),
1867
+ style: {
1868
+ padding: "8px 16px",
1869
+ fontSize: "13px",
1870
+ fontWeight: 500,
1871
+ color: viewMode === "graph" ? "#3b82f6" : "#6b7280",
1872
+ backgroundColor: viewMode === "graph" ? "#eff6ff" : "transparent",
1873
+ border: `1px solid ${viewMode === "graph" ? "#3b82f6" : "#d1d5db"}`,
1874
+ borderRadius: "6px",
1875
+ cursor: "pointer"
1876
+ },
1877
+ children: "Graph"
1878
+ }
1879
+ )
1880
+ ] })
1881
+ ] })
1882
+ }
1883
+ ),
1884
+ /* @__PURE__ */ jsxs10("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
1885
+ /* @__PURE__ */ jsxs10(
1886
+ "aside",
1887
+ {
1888
+ style: {
1889
+ width: "320px",
1890
+ padding: "16px",
1891
+ borderRight: "1px solid #e5e7eb",
1892
+ backgroundColor: "#ffffff",
1893
+ overflowY: "auto",
1894
+ display: "flex",
1895
+ flexDirection: "column",
1896
+ gap: "16px"
1897
+ },
1898
+ children: [
1899
+ /* @__PURE__ */ jsxs10("div", { children: [
1900
+ /* @__PURE__ */ jsx12("h2", { style: { margin: "0 0 12px 0", fontSize: "14px", fontWeight: 600, color: "#374151" }, children: "Add Memory" }),
1901
+ /* @__PURE__ */ jsx12(AddMemoryForm, { onAdd: handleAddMemory, loading })
1902
+ ] }),
1903
+ /* @__PURE__ */ jsxs10("div", { children: [
1904
+ /* @__PURE__ */ jsx12("h2", { style: { margin: "0 0 12px 0", fontSize: "14px", fontWeight: 600, color: "#374151" }, children: "Statistics" }),
1905
+ /* @__PURE__ */ jsx12(StatsPanel, { stats, loading })
1906
+ ] }),
1907
+ actors.length > 0 && /* @__PURE__ */ jsxs10("div", { children: [
1908
+ /* @__PURE__ */ jsx12("h2", { style: { margin: "0 0 12px 0", fontSize: "14px", fontWeight: 600, color: "#374151" }, children: "Actors" }),
1909
+ /* @__PURE__ */ jsx12(
1910
+ ActorSelector,
1911
+ {
1912
+ actors,
1913
+ selectedActor,
1914
+ onSelect: handleActorChange
1915
+ }
1916
+ )
1917
+ ] })
1918
+ ]
1919
+ }
1920
+ ),
1921
+ /* @__PURE__ */ jsxs10("main", { style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }, children: [
1922
+ /* @__PURE__ */ jsxs10("div", { style: { padding: "16px", backgroundColor: "#ffffff", borderBottom: "1px solid #e5e7eb" }, children: [
1923
+ /* @__PURE__ */ jsx12(SearchBar, { onSearch: handleSearch, loading }),
1924
+ searchQuery && /* @__PURE__ */ jsxs10("div", { style: { marginTop: "8px", display: "flex", alignItems: "center", gap: "8px" }, children: [
1925
+ /* @__PURE__ */ jsxs10("span", { style: { fontSize: "13px", color: "#6b7280" }, children: [
1926
+ 'Showing results for "',
1927
+ searchQuery,
1928
+ '"'
1929
+ ] }),
1930
+ /* @__PURE__ */ jsx12(
1931
+ "button",
1932
+ {
1933
+ onClick: handleClearSearch,
1934
+ style: {
1935
+ padding: "4px 8px",
1936
+ fontSize: "12px",
1937
+ color: "#3b82f6",
1938
+ backgroundColor: "transparent",
1939
+ border: "none",
1940
+ cursor: "pointer",
1941
+ textDecoration: "underline"
1942
+ },
1943
+ children: "Clear"
1944
+ }
1945
+ )
1946
+ ] })
1947
+ ] }),
1948
+ /* @__PURE__ */ jsxs10("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
1949
+ /* @__PURE__ */ jsx12("div", { style: { flex: 1, overflowY: "auto", padding: "16px" }, children: filteredEvents.length === 0 ? /* @__PURE__ */ jsxs10(
1950
+ "div",
1951
+ {
1952
+ style: {
1953
+ display: "flex",
1954
+ flexDirection: "column",
1955
+ alignItems: "center",
1956
+ justifyContent: "center",
1957
+ height: "100%",
1958
+ color: "#9ca3af"
1959
+ },
1960
+ children: [
1961
+ /* @__PURE__ */ jsx12(
1962
+ "svg",
1963
+ {
1964
+ style: { width: "48px", height: "48px", marginBottom: "12px" },
1965
+ fill: "none",
1966
+ stroke: "currentColor",
1967
+ viewBox: "0 0 24 24",
1968
+ children: /* @__PURE__ */ jsx12(
1969
+ "path",
1970
+ {
1971
+ strokeLinecap: "round",
1972
+ strokeLinejoin: "round",
1973
+ strokeWidth: 1.5,
1974
+ d: "M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"
1975
+ }
1976
+ )
1977
+ }
1978
+ ),
1979
+ /* @__PURE__ */ jsx12("p", { style: { margin: 0, fontSize: "14px" }, children: "No memories yet" }),
1980
+ /* @__PURE__ */ jsx12("p", { style: { margin: "4px 0 0 0", fontSize: "13px" }, children: "Add your first memory using the form on the left" })
1981
+ ]
1982
+ }
1983
+ ) : viewMode === "timeline" ? /* @__PURE__ */ jsx12(
1984
+ TimelineView,
1985
+ {
1986
+ events: filteredEvents,
1987
+ onEventClick: setSelectedEvent,
1988
+ selectedEventId: selectedEvent?.id,
1989
+ showContext: true
1990
+ }
1991
+ ) : /* @__PURE__ */ jsx12(
1992
+ MemoryGraphView,
1993
+ {
1994
+ events: filteredEvents,
1995
+ onNodeClick: setSelectedEvent,
1996
+ highlightActor: selectedActor ?? void 0,
1997
+ width: 600,
1998
+ height: 500
1999
+ }
2000
+ ) }),
2001
+ selectedEvent && /* @__PURE__ */ jsxs10(
2002
+ "aside",
2003
+ {
2004
+ style: {
2005
+ width: "300px",
2006
+ padding: "16px",
2007
+ borderLeft: "1px solid #e5e7eb",
2008
+ backgroundColor: "#ffffff",
2009
+ overflowY: "auto"
2010
+ },
2011
+ children: [
2012
+ /* @__PURE__ */ jsxs10("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "12px" }, children: [
2013
+ /* @__PURE__ */ jsx12("h3", { style: { margin: 0, fontSize: "14px", fontWeight: 600, color: "#374151" }, children: "Event Details" }),
2014
+ /* @__PURE__ */ jsx12(
2015
+ "button",
2016
+ {
2017
+ onClick: () => setSelectedEvent(null),
2018
+ style: {
2019
+ padding: "4px",
2020
+ backgroundColor: "transparent",
2021
+ border: "none",
2022
+ cursor: "pointer",
2023
+ color: "#9ca3af"
2024
+ },
2025
+ children: /* @__PURE__ */ jsx12("svg", { style: { width: "20px", height: "20px" }, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx12("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
2026
+ }
2027
+ )
2028
+ ] }),
2029
+ /* @__PURE__ */ jsx12(MemoryCard, { event: selectedEvent, showContext: true })
2030
+ ]
2031
+ }
2032
+ )
2033
+ ] })
2034
+ ] })
2035
+ ] })
2036
+ ]
2037
+ }
2038
+ );
2039
+ }
2040
+ export {
2041
+ ActorSelector,
2042
+ AddMemoryForm,
2043
+ AetherProvider,
2044
+ ClusterMap,
2045
+ ConnectionStatus,
2046
+ Dashboard,
2047
+ MemoryCard,
2048
+ MemoryExplorer,
2049
+ MemoryGraphView,
2050
+ SearchBar,
2051
+ StatsPanel,
2052
+ TimelineView,
2053
+ useAether,
2054
+ useMemoryStream
2055
+ };
2056
+ //# sourceMappingURL=index.js.map