@thehoneyjar/sigil-hud 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,3079 @@
1
+ import { create } from 'zustand';
2
+ import { persist } from 'zustand/middleware';
3
+ import { createContext, useMemo, useContext, useState, useCallback, useRef, useEffect } from 'react';
4
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
+
6
+ // src/types.ts
7
+ var DEFAULT_HUD_STATE = {
8
+ isOpen: false,
9
+ activePanel: null,
10
+ position: "bottom-right",
11
+ isMinimized: false
12
+ };
13
+ var DEFAULT_HUD_CONFIG = {
14
+ shortcuts: true,
15
+ position: "bottom-right",
16
+ persist: true,
17
+ observationCapture: true,
18
+ signalCapture: true
19
+ };
20
+ var DEFAULT_LENS_STATE = {
21
+ enabled: false,
22
+ impersonatedAddress: null,
23
+ realAddress: null,
24
+ savedAddresses: []
25
+ };
26
+ var useHudStore = create()(
27
+ persist(
28
+ (set) => ({
29
+ ...DEFAULT_HUD_STATE,
30
+ open: () => set({ isOpen: true }),
31
+ close: () => set({ isOpen: false }),
32
+ toggle: () => set((state) => ({ isOpen: !state.isOpen })),
33
+ setActivePanel: (panel) => set({ activePanel: panel }),
34
+ setPosition: (position) => set({ position }),
35
+ toggleMinimized: () => set((state) => ({ isMinimized: !state.isMinimized }))
36
+ }),
37
+ {
38
+ name: "sigil-hud-storage",
39
+ partialize: (state) => ({
40
+ position: state.position,
41
+ isMinimized: state.isMinimized
42
+ })
43
+ }
44
+ )
45
+ );
46
+ function getHudState() {
47
+ const state = useHudStore.getState();
48
+ return {
49
+ isOpen: state.isOpen,
50
+ activePanel: state.activePanel,
51
+ position: state.position,
52
+ isMinimized: state.isMinimized
53
+ };
54
+ }
55
+ var HudContext = createContext(null);
56
+ function HudProvider({
57
+ children,
58
+ config = {},
59
+ lensService,
60
+ forkService,
61
+ simulationService,
62
+ diagnosticsService,
63
+ anchorClient
64
+ }) {
65
+ const isOpen = useHudStore((state) => state.isOpen);
66
+ const activePanel = useHudStore((state) => state.activePanel);
67
+ const position = useHudStore((state) => state.position);
68
+ const isMinimized = useHudStore((state) => state.isMinimized);
69
+ const open = useHudStore((state) => state.open);
70
+ const close = useHudStore((state) => state.close);
71
+ const toggle = useHudStore((state) => state.toggle);
72
+ const setActivePanel = useHudStore((state) => state.setActivePanel);
73
+ const setPosition = useHudStore((state) => state.setPosition);
74
+ const toggleMinimized = useHudStore((state) => state.toggleMinimized);
75
+ const mergedConfig = useMemo(
76
+ () => ({
77
+ ...DEFAULT_HUD_CONFIG,
78
+ ...config
79
+ }),
80
+ [config]
81
+ );
82
+ const value = useMemo(
83
+ () => ({
84
+ // State
85
+ isOpen,
86
+ activePanel,
87
+ position,
88
+ isMinimized,
89
+ // Actions
90
+ open,
91
+ close,
92
+ toggle,
93
+ setActivePanel,
94
+ setPosition,
95
+ toggleMinimized,
96
+ // Services
97
+ lensService: lensService ?? null,
98
+ forkService: forkService ?? null,
99
+ simulationService: simulationService ?? null,
100
+ diagnosticsService: diagnosticsService ?? null,
101
+ anchorClient: anchorClient ?? null,
102
+ // Config
103
+ config: mergedConfig
104
+ }),
105
+ [
106
+ isOpen,
107
+ activePanel,
108
+ position,
109
+ isMinimized,
110
+ open,
111
+ close,
112
+ toggle,
113
+ setActivePanel,
114
+ setPosition,
115
+ toggleMinimized,
116
+ lensService,
117
+ forkService,
118
+ simulationService,
119
+ diagnosticsService,
120
+ anchorClient,
121
+ mergedConfig
122
+ ]
123
+ );
124
+ return /* @__PURE__ */ jsx(HudContext.Provider, { value, children });
125
+ }
126
+ function useHud() {
127
+ const context = useContext(HudContext);
128
+ if (!context) {
129
+ throw new Error("useHud must be used within a HudProvider");
130
+ }
131
+ return context;
132
+ }
133
+ function useHudOptional() {
134
+ return useContext(HudContext);
135
+ }
136
+ function HudPanel({ children, className = "" }) {
137
+ const {
138
+ isOpen,
139
+ isMinimized,
140
+ activePanel,
141
+ position,
142
+ setActivePanel,
143
+ toggleMinimized,
144
+ close,
145
+ lensService,
146
+ forkService,
147
+ simulationService,
148
+ diagnosticsService
149
+ } = useHud();
150
+ if (!isOpen)
151
+ return null;
152
+ const tabs = [
153
+ { id: "lens", label: "Lens", available: lensService !== null },
154
+ { id: "simulation", label: "Simulation", available: simulationService !== null },
155
+ { id: "diagnostics", label: "Diagnostics", available: diagnosticsService !== null },
156
+ { id: "state", label: "State", available: forkService !== null },
157
+ { id: "signals", label: "Signals", available: true }
158
+ ];
159
+ const availableTabs = tabs.filter((t) => t.available);
160
+ const positionClasses = {
161
+ "bottom-right": "bottom-4 right-4",
162
+ "bottom-left": "bottom-4 left-4",
163
+ "top-right": "top-4 right-4",
164
+ "top-left": "top-4 left-4"
165
+ };
166
+ return /* @__PURE__ */ jsxs(
167
+ "div",
168
+ {
169
+ className: `fixed ${positionClasses[position]} z-50 ${className}`,
170
+ style: {
171
+ width: isMinimized ? "200px" : "400px",
172
+ maxHeight: isMinimized ? "40px" : "600px",
173
+ backgroundColor: "rgba(0, 0, 0, 0.9)",
174
+ borderRadius: "8px",
175
+ border: "1px solid rgba(255, 255, 255, 0.1)",
176
+ boxShadow: "0 4px 20px rgba(0, 0, 0, 0.5)",
177
+ fontFamily: "ui-monospace, monospace",
178
+ fontSize: "12px",
179
+ color: "#fff",
180
+ overflow: "hidden"
181
+ },
182
+ children: [
183
+ /* @__PURE__ */ jsxs(
184
+ "div",
185
+ {
186
+ style: {
187
+ display: "flex",
188
+ alignItems: "center",
189
+ justifyContent: "space-between",
190
+ padding: "8px 12px",
191
+ borderBottom: isMinimized ? "none" : "1px solid rgba(255, 255, 255, 0.1)",
192
+ backgroundColor: "rgba(255, 255, 255, 0.05)"
193
+ },
194
+ children: [
195
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 600, color: "#10b981" }, children: "\u25C6 Sigil HUD" }),
196
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px" }, children: [
197
+ /* @__PURE__ */ jsx(
198
+ "button",
199
+ {
200
+ onClick: toggleMinimized,
201
+ style: {
202
+ background: "none",
203
+ border: "none",
204
+ color: "#666",
205
+ cursor: "pointer",
206
+ fontSize: "14px"
207
+ },
208
+ children: isMinimized ? "\u25FB" : "\u2013"
209
+ }
210
+ ),
211
+ /* @__PURE__ */ jsx(
212
+ "button",
213
+ {
214
+ onClick: close,
215
+ style: {
216
+ background: "none",
217
+ border: "none",
218
+ color: "#666",
219
+ cursor: "pointer",
220
+ fontSize: "14px"
221
+ },
222
+ children: "\xD7"
223
+ }
224
+ )
225
+ ] })
226
+ ]
227
+ }
228
+ ),
229
+ !isMinimized && /* @__PURE__ */ jsxs(Fragment, { children: [
230
+ /* @__PURE__ */ jsx(
231
+ "div",
232
+ {
233
+ style: {
234
+ display: "flex",
235
+ gap: "2px",
236
+ padding: "4px",
237
+ backgroundColor: "rgba(255, 255, 255, 0.02)"
238
+ },
239
+ children: availableTabs.map((tab) => /* @__PURE__ */ jsx(
240
+ "button",
241
+ {
242
+ onClick: () => setActivePanel(tab.id),
243
+ style: {
244
+ flex: 1,
245
+ padding: "6px 8px",
246
+ background: activePanel === tab.id ? "rgba(16, 185, 129, 0.2)" : "transparent",
247
+ border: "none",
248
+ borderRadius: "4px",
249
+ color: activePanel === tab.id ? "#10b981" : "#888",
250
+ cursor: "pointer",
251
+ fontSize: "11px",
252
+ fontWeight: 500
253
+ },
254
+ children: tab.label
255
+ },
256
+ tab.id
257
+ ))
258
+ }
259
+ ),
260
+ /* @__PURE__ */ jsxs(
261
+ "div",
262
+ {
263
+ style: {
264
+ padding: "12px",
265
+ overflowY: "auto",
266
+ maxHeight: "500px"
267
+ },
268
+ children: [
269
+ children,
270
+ !activePanel && /* @__PURE__ */ jsx("div", { style: { color: "#666", textAlign: "center", padding: "20px" }, children: "Select a panel to get started" })
271
+ ]
272
+ }
273
+ )
274
+ ] })
275
+ ]
276
+ }
277
+ );
278
+ }
279
+ function HudTrigger({
280
+ className = "",
281
+ children,
282
+ position: overridePosition
283
+ }) {
284
+ const { isOpen, toggle, position: hudPosition } = useHud();
285
+ const position = overridePosition ?? hudPosition;
286
+ const positionClasses = {
287
+ "bottom-right": "bottom-4 right-4",
288
+ "bottom-left": "bottom-4 left-4",
289
+ "top-right": "top-4 right-4",
290
+ "top-left": "top-4 left-4"
291
+ };
292
+ if (isOpen)
293
+ return null;
294
+ return /* @__PURE__ */ jsx(
295
+ "button",
296
+ {
297
+ onClick: toggle,
298
+ className: `fixed ${positionClasses[position]} z-50 ${className}`,
299
+ style: {
300
+ width: "44px",
301
+ height: "44px",
302
+ borderRadius: "50%",
303
+ backgroundColor: "rgba(16, 185, 129, 0.9)",
304
+ border: "2px solid rgba(16, 185, 129, 0.3)",
305
+ boxShadow: "0 4px 12px rgba(16, 185, 129, 0.3)",
306
+ cursor: "pointer",
307
+ display: "flex",
308
+ alignItems: "center",
309
+ justifyContent: "center",
310
+ transition: "transform 0.2s, box-shadow 0.2s"
311
+ },
312
+ onMouseEnter: (e) => {
313
+ e.currentTarget.style.transform = "scale(1.1)";
314
+ e.currentTarget.style.boxShadow = "0 6px 16px rgba(16, 185, 129, 0.4)";
315
+ },
316
+ onMouseLeave: (e) => {
317
+ e.currentTarget.style.transform = "scale(1)";
318
+ e.currentTarget.style.boxShadow = "0 4px 12px rgba(16, 185, 129, 0.3)";
319
+ },
320
+ "aria-label": "Open Sigil HUD",
321
+ title: "Sigil HUD (\u2318\u21E7D)",
322
+ children: children ?? /* @__PURE__ */ jsx("span", { style: { color: "#fff", fontSize: "18px", fontWeight: 600 }, children: "\u25C6" })
323
+ }
324
+ );
325
+ }
326
+ function LensPanel({ className = "" }) {
327
+ const { lensService, activePanel } = useHud();
328
+ const [inputAddress, setInputAddress] = useState("");
329
+ const [inputLabel, setInputLabel] = useState("");
330
+ const state = lensService?.getState() ?? DEFAULT_LENS_STATE;
331
+ const isImpersonating = state.enabled && state.impersonatedAddress !== null;
332
+ const handleImpersonate = useCallback(() => {
333
+ if (!lensService || !inputAddress)
334
+ return;
335
+ if (!/^0x[a-fA-F0-9]{40}$/.test(inputAddress)) {
336
+ alert("Invalid address format");
337
+ return;
338
+ }
339
+ lensService.setImpersonatedAddress(inputAddress);
340
+ setInputAddress("");
341
+ }, [lensService, inputAddress]);
342
+ const handleSaveAddress = useCallback(() => {
343
+ if (!lensService || !inputAddress || !inputLabel)
344
+ return;
345
+ lensService.saveAddress({
346
+ address: inputAddress,
347
+ label: inputLabel
348
+ });
349
+ setInputAddress("");
350
+ setInputLabel("");
351
+ }, [lensService, inputAddress, inputLabel]);
352
+ const handleStopImpersonation = useCallback(() => {
353
+ if (!lensService)
354
+ return;
355
+ lensService.clearImpersonation();
356
+ }, [lensService]);
357
+ if (activePanel !== "lens")
358
+ return null;
359
+ if (!lensService) {
360
+ return /* @__PURE__ */ jsxs("div", { className, style: { color: "#666" }, children: [
361
+ /* @__PURE__ */ jsx("p", { children: "Lens service not available." }),
362
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "10px", marginTop: "8px" }, children: "Install @sigil/lens to enable address impersonation." })
363
+ ] });
364
+ }
365
+ return /* @__PURE__ */ jsxs("div", { className, children: [
366
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "16px" }, children: [
367
+ /* @__PURE__ */ jsxs(
368
+ "div",
369
+ {
370
+ style: {
371
+ display: "flex",
372
+ alignItems: "center",
373
+ gap: "8px",
374
+ marginBottom: "8px"
375
+ },
376
+ children: [
377
+ /* @__PURE__ */ jsx(
378
+ "div",
379
+ {
380
+ style: {
381
+ width: "8px",
382
+ height: "8px",
383
+ borderRadius: "50%",
384
+ backgroundColor: isImpersonating ? "#10b981" : "#666"
385
+ }
386
+ }
387
+ ),
388
+ /* @__PURE__ */ jsx("span", { style: { color: isImpersonating ? "#10b981" : "#888" }, children: isImpersonating ? "Impersonating" : "Not impersonating" })
389
+ ]
390
+ }
391
+ ),
392
+ isImpersonating && /* @__PURE__ */ jsxs("div", { style: { marginLeft: "16px" }, children: [
393
+ /* @__PURE__ */ jsx(
394
+ "code",
395
+ {
396
+ style: {
397
+ fontSize: "11px",
398
+ color: "#10b981",
399
+ wordBreak: "break-all"
400
+ },
401
+ children: state.impersonatedAddress
402
+ }
403
+ ),
404
+ /* @__PURE__ */ jsx(
405
+ "button",
406
+ {
407
+ onClick: handleStopImpersonation,
408
+ style: {
409
+ display: "block",
410
+ marginTop: "8px",
411
+ padding: "4px 8px",
412
+ backgroundColor: "rgba(239, 68, 68, 0.2)",
413
+ border: "1px solid rgba(239, 68, 68, 0.3)",
414
+ borderRadius: "4px",
415
+ color: "#ef4444",
416
+ fontSize: "10px",
417
+ cursor: "pointer"
418
+ },
419
+ children: "Stop Impersonation"
420
+ }
421
+ )
422
+ ] }),
423
+ state.realAddress && /* @__PURE__ */ jsxs("div", { style: { marginTop: "8px", color: "#666", fontSize: "10px" }, children: [
424
+ "Real: ",
425
+ state.realAddress.slice(0, 6),
426
+ "...",
427
+ state.realAddress.slice(-4)
428
+ ] })
429
+ ] }),
430
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "16px" }, children: [
431
+ /* @__PURE__ */ jsx(
432
+ "label",
433
+ {
434
+ style: {
435
+ display: "block",
436
+ color: "#888",
437
+ fontSize: "10px",
438
+ marginBottom: "4px"
439
+ },
440
+ children: "Impersonate Address"
441
+ }
442
+ ),
443
+ /* @__PURE__ */ jsx(
444
+ "input",
445
+ {
446
+ type: "text",
447
+ value: inputAddress,
448
+ onChange: (e) => setInputAddress(e.target.value),
449
+ placeholder: "0x...",
450
+ style: {
451
+ width: "100%",
452
+ padding: "8px",
453
+ backgroundColor: "rgba(255, 255, 255, 0.05)",
454
+ border: "1px solid rgba(255, 255, 255, 0.1)",
455
+ borderRadius: "4px",
456
+ color: "#fff",
457
+ fontSize: "11px",
458
+ fontFamily: "ui-monospace, monospace"
459
+ }
460
+ }
461
+ ),
462
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "8px", marginTop: "8px" }, children: /* @__PURE__ */ jsx(
463
+ "button",
464
+ {
465
+ onClick: handleImpersonate,
466
+ disabled: !inputAddress,
467
+ style: {
468
+ flex: 1,
469
+ padding: "6px 12px",
470
+ backgroundColor: inputAddress ? "rgba(16, 185, 129, 0.2)" : "rgba(255, 255, 255, 0.05)",
471
+ border: "1px solid rgba(16, 185, 129, 0.3)",
472
+ borderRadius: "4px",
473
+ color: inputAddress ? "#10b981" : "#666",
474
+ fontSize: "11px",
475
+ cursor: inputAddress ? "pointer" : "not-allowed"
476
+ },
477
+ children: "Impersonate"
478
+ }
479
+ ) })
480
+ ] }),
481
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "16px" }, children: [
482
+ /* @__PURE__ */ jsx(
483
+ "label",
484
+ {
485
+ style: {
486
+ display: "block",
487
+ color: "#888",
488
+ fontSize: "10px",
489
+ marginBottom: "4px"
490
+ },
491
+ children: "Save with Label"
492
+ }
493
+ ),
494
+ /* @__PURE__ */ jsx(
495
+ "input",
496
+ {
497
+ type: "text",
498
+ value: inputLabel,
499
+ onChange: (e) => setInputLabel(e.target.value),
500
+ placeholder: "Label (e.g., Whale)",
501
+ style: {
502
+ width: "100%",
503
+ padding: "8px",
504
+ backgroundColor: "rgba(255, 255, 255, 0.05)",
505
+ border: "1px solid rgba(255, 255, 255, 0.1)",
506
+ borderRadius: "4px",
507
+ color: "#fff",
508
+ fontSize: "11px",
509
+ marginBottom: "8px"
510
+ }
511
+ }
512
+ ),
513
+ /* @__PURE__ */ jsx(
514
+ "button",
515
+ {
516
+ onClick: handleSaveAddress,
517
+ disabled: !inputAddress || !inputLabel,
518
+ style: {
519
+ width: "100%",
520
+ padding: "6px 12px",
521
+ backgroundColor: inputAddress && inputLabel ? "rgba(59, 130, 246, 0.2)" : "rgba(255, 255, 255, 0.05)",
522
+ border: "1px solid rgba(59, 130, 246, 0.3)",
523
+ borderRadius: "4px",
524
+ color: inputAddress && inputLabel ? "#3b82f6" : "#666",
525
+ fontSize: "11px",
526
+ cursor: inputAddress && inputLabel ? "pointer" : "not-allowed"
527
+ },
528
+ children: "Save Address"
529
+ }
530
+ )
531
+ ] }),
532
+ state.savedAddresses.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
533
+ /* @__PURE__ */ jsx(
534
+ "label",
535
+ {
536
+ style: {
537
+ display: "block",
538
+ color: "#888",
539
+ fontSize: "10px",
540
+ marginBottom: "8px"
541
+ },
542
+ children: "Saved Addresses"
543
+ }
544
+ ),
545
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: state.savedAddresses.map((saved) => /* @__PURE__ */ jsxs(
546
+ "button",
547
+ {
548
+ onClick: () => lensService?.setImpersonatedAddress(saved.address),
549
+ style: {
550
+ display: "flex",
551
+ justifyContent: "space-between",
552
+ alignItems: "center",
553
+ padding: "8px",
554
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
555
+ border: "1px solid rgba(255, 255, 255, 0.05)",
556
+ borderRadius: "4px",
557
+ cursor: "pointer",
558
+ textAlign: "left"
559
+ },
560
+ children: [
561
+ /* @__PURE__ */ jsx("span", { style: { color: "#fff", fontSize: "11px" }, children: saved.label }),
562
+ /* @__PURE__ */ jsxs("code", { style: { color: "#666", fontSize: "10px" }, children: [
563
+ saved.address.slice(0, 6),
564
+ "...",
565
+ saved.address.slice(-4)
566
+ ] })
567
+ ]
568
+ },
569
+ saved.address
570
+ )) })
571
+ ] })
572
+ ] });
573
+ }
574
+ function SimulationPanel({ className = "" }) {
575
+ const { simulationService, forkService, activePanel } = useHud();
576
+ if (activePanel !== "simulation")
577
+ return null;
578
+ if (!simulationService) {
579
+ return /* @__PURE__ */ jsxs("div", { className, style: { color: "#666" }, children: [
580
+ /* @__PURE__ */ jsx("p", { children: "Simulation service not available." }),
581
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "10px", marginTop: "8px" }, children: "Install @sigil/simulation to enable transaction simulation." })
582
+ ] });
583
+ }
584
+ const forkState = forkService?.getState();
585
+ const forkActive = forkState?.active ?? false;
586
+ return /* @__PURE__ */ jsxs("div", { className, children: [
587
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "16px" }, children: [
588
+ /* @__PURE__ */ jsxs(
589
+ "div",
590
+ {
591
+ style: {
592
+ display: "flex",
593
+ alignItems: "center",
594
+ gap: "8px",
595
+ marginBottom: "8px"
596
+ },
597
+ children: [
598
+ /* @__PURE__ */ jsx(
599
+ "div",
600
+ {
601
+ style: {
602
+ width: "8px",
603
+ height: "8px",
604
+ borderRadius: "50%",
605
+ backgroundColor: forkActive ? "#10b981" : "#666"
606
+ }
607
+ }
608
+ ),
609
+ /* @__PURE__ */ jsx("span", { style: { color: forkActive ? "#10b981" : "#888" }, children: forkActive ? "Fork Active" : "No Fork" })
610
+ ]
611
+ }
612
+ ),
613
+ forkState && forkActive && /* @__PURE__ */ jsxs(
614
+ "div",
615
+ {
616
+ style: {
617
+ padding: "8px",
618
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
619
+ borderRadius: "4px",
620
+ fontSize: "10px"
621
+ },
622
+ children: [
623
+ /* @__PURE__ */ jsxs("div", { style: { color: "#888", marginBottom: "4px" }, children: [
624
+ "Chain: ",
625
+ forkState.chainId
626
+ ] }),
627
+ /* @__PURE__ */ jsxs("div", { style: { color: "#888", marginBottom: "4px" }, children: [
628
+ "Block: ",
629
+ forkState.blockNumber?.toString()
630
+ ] }),
631
+ /* @__PURE__ */ jsxs("div", { style: { color: "#888" }, children: [
632
+ "Snapshots: ",
633
+ forkState.snapshotCount
634
+ ] })
635
+ ]
636
+ }
637
+ )
638
+ ] }),
639
+ /* @__PURE__ */ jsxs(
640
+ "div",
641
+ {
642
+ style: {
643
+ padding: "12px",
644
+ backgroundColor: "rgba(59, 130, 246, 0.05)",
645
+ border: "1px solid rgba(59, 130, 246, 0.2)",
646
+ borderRadius: "4px"
647
+ },
648
+ children: [
649
+ /* @__PURE__ */ jsx("div", { style: { color: "#3b82f6", fontSize: "11px", marginBottom: "8px" }, children: "Transaction Simulation" }),
650
+ /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: "10px", lineHeight: 1.6 }, children: "Simulate transactions before sending them on-chain. View gas estimates, balance changes, and potential revert reasons." }),
651
+ /* @__PURE__ */ jsxs(
652
+ "div",
653
+ {
654
+ style: {
655
+ marginTop: "12px",
656
+ padding: "8px",
657
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
658
+ borderRadius: "4px",
659
+ fontSize: "10px",
660
+ color: "#666"
661
+ },
662
+ children: [
663
+ "To simulate a transaction, use the simulation service programmatically:",
664
+ /* @__PURE__ */ jsx(
665
+ "pre",
666
+ {
667
+ style: {
668
+ marginTop: "8px",
669
+ fontFamily: "ui-monospace, monospace",
670
+ color: "#10b981"
671
+ },
672
+ children: `simulationService.simulate({
673
+ from: '0x...',
674
+ to: '0x...',
675
+ value: 1000000n,
676
+ data: '0x...'
677
+ })`
678
+ }
679
+ )
680
+ ]
681
+ }
682
+ )
683
+ ]
684
+ }
685
+ ),
686
+ /* @__PURE__ */ jsxs("div", { style: { marginTop: "16px" }, children: [
687
+ /* @__PURE__ */ jsx(
688
+ "label",
689
+ {
690
+ style: {
691
+ display: "block",
692
+ color: "#888",
693
+ fontSize: "10px",
694
+ marginBottom: "8px"
695
+ },
696
+ children: "Simulation Features"
697
+ }
698
+ ),
699
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: [
700
+ { icon: "\u26FD", label: "Gas estimation" },
701
+ { icon: "\u{1F4B0}", label: "Balance changes" },
702
+ { icon: "\u{1F4DD}", label: "State changes" },
703
+ { icon: "\u274C", label: "Revert reasons" },
704
+ { icon: "\u{1F4CA}", label: "Event logs" }
705
+ ].map((feature) => /* @__PURE__ */ jsxs(
706
+ "div",
707
+ {
708
+ style: {
709
+ display: "flex",
710
+ alignItems: "center",
711
+ gap: "8px",
712
+ padding: "6px 8px",
713
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
714
+ borderRadius: "4px",
715
+ fontSize: "11px",
716
+ color: "#888"
717
+ },
718
+ children: [
719
+ /* @__PURE__ */ jsx("span", { children: feature.icon }),
720
+ /* @__PURE__ */ jsx("span", { children: feature.label })
721
+ ]
722
+ },
723
+ feature.label
724
+ )) })
725
+ ] })
726
+ ] });
727
+ }
728
+ var effectLabels = {
729
+ financial: "Financial",
730
+ destructive: "Destructive",
731
+ "soft-delete": "Soft Delete",
732
+ standard: "Standard",
733
+ local: "Local State",
734
+ navigation: "Navigation",
735
+ query: "Query"
736
+ };
737
+ var effectColors = {
738
+ financial: "#ef4444",
739
+ // red
740
+ destructive: "#f97316",
741
+ // orange
742
+ "soft-delete": "#eab308",
743
+ // yellow
744
+ standard: "#22c55e",
745
+ // green
746
+ local: "#3b82f6",
747
+ // blue
748
+ navigation: "#8b5cf6",
749
+ // purple
750
+ query: "#06b6d4"
751
+ // cyan
752
+ };
753
+ function PhysicsAnalysis({
754
+ effect,
755
+ compliance,
756
+ isLoading = false,
757
+ className = ""
758
+ }) {
759
+ if (isLoading) {
760
+ return /* @__PURE__ */ jsx("div", { className, style: styles.container, children: /* @__PURE__ */ jsxs("div", { style: styles.header, children: [
761
+ /* @__PURE__ */ jsx("span", { style: styles.title, children: "Physics" }),
762
+ /* @__PURE__ */ jsx("span", { style: styles.loading, children: "Analyzing..." })
763
+ ] }) });
764
+ }
765
+ if (!effect) {
766
+ return /* @__PURE__ */ jsxs("div", { className, style: styles.container, children: [
767
+ /* @__PURE__ */ jsx("div", { style: styles.header, children: /* @__PURE__ */ jsx("span", { style: styles.title, children: "Physics" }) }),
768
+ /* @__PURE__ */ jsx("div", { style: styles.empty, children: "No component selected. Select a component to view physics analysis." })
769
+ ] });
770
+ }
771
+ const color = effectColors[effect];
772
+ const behavioral = compliance?.behavioral;
773
+ const animation = compliance?.animation;
774
+ const material = compliance?.material;
775
+ return /* @__PURE__ */ jsxs("div", { className, style: styles.container, children: [
776
+ /* @__PURE__ */ jsxs("div", { style: styles.effectRow, children: [
777
+ /* @__PURE__ */ jsx(
778
+ "span",
779
+ {
780
+ style: {
781
+ ...styles.effectBadge,
782
+ backgroundColor: `${color}20`,
783
+ borderColor: `${color}50`,
784
+ color
785
+ },
786
+ children: effectLabels[effect]
787
+ }
788
+ ),
789
+ behavioral && !behavioral.compliant && /* @__PURE__ */ jsx("span", { style: styles.warningBadge, children: "\u26A0 Non-compliant" })
790
+ ] }),
791
+ compliance && /* @__PURE__ */ jsxs("div", { style: styles.grid, children: [
792
+ /* @__PURE__ */ jsxs("div", { style: styles.section, children: [
793
+ /* @__PURE__ */ jsx("span", { style: styles.sectionLabel, children: "Behavioral" }),
794
+ /* @__PURE__ */ jsxs("div", { style: styles.values, children: [
795
+ /* @__PURE__ */ jsxs("span", { style: styles.value, children: [
796
+ /* @__PURE__ */ jsx("span", { style: styles.valueLabel, children: "Sync:" }),
797
+ /* @__PURE__ */ jsx("span", { style: getValueStyle(behavioral?.compliant), children: behavioral?.sync ?? "unknown" })
798
+ ] }),
799
+ /* @__PURE__ */ jsxs("span", { style: styles.value, children: [
800
+ /* @__PURE__ */ jsx("span", { style: styles.valueLabel, children: "Timing:" }),
801
+ /* @__PURE__ */ jsx("span", { style: getValueStyle(behavioral?.compliant), children: behavioral?.timing ? `${behavioral.timing}ms` : "unknown" })
802
+ ] }),
803
+ /* @__PURE__ */ jsxs("span", { style: styles.value, children: [
804
+ /* @__PURE__ */ jsx("span", { style: styles.valueLabel, children: "Confirm:" }),
805
+ /* @__PURE__ */ jsx("span", { style: getValueStyle(behavioral?.compliant), children: behavioral?.confirmation ? "yes" : "no" })
806
+ ] })
807
+ ] })
808
+ ] }),
809
+ /* @__PURE__ */ jsxs("div", { style: styles.section, children: [
810
+ /* @__PURE__ */ jsx("span", { style: styles.sectionLabel, children: "Animation" }),
811
+ /* @__PURE__ */ jsxs("div", { style: styles.values, children: [
812
+ /* @__PURE__ */ jsxs("span", { style: styles.value, children: [
813
+ /* @__PURE__ */ jsx("span", { style: styles.valueLabel, children: "Easing:" }),
814
+ /* @__PURE__ */ jsx("span", { style: getValueStyle(animation?.compliant), children: animation?.easing ?? "unknown" })
815
+ ] }),
816
+ /* @__PURE__ */ jsxs("span", { style: styles.value, children: [
817
+ /* @__PURE__ */ jsx("span", { style: styles.valueLabel, children: "Duration:" }),
818
+ /* @__PURE__ */ jsx("span", { style: getValueStyle(animation?.compliant), children: animation?.duration ? `${animation.duration}ms` : "unknown" })
819
+ ] })
820
+ ] })
821
+ ] }),
822
+ /* @__PURE__ */ jsxs("div", { style: styles.section, children: [
823
+ /* @__PURE__ */ jsx("span", { style: styles.sectionLabel, children: "Material" }),
824
+ /* @__PURE__ */ jsxs("div", { style: styles.values, children: [
825
+ /* @__PURE__ */ jsxs("span", { style: styles.value, children: [
826
+ /* @__PURE__ */ jsx("span", { style: styles.valueLabel, children: "Surface:" }),
827
+ /* @__PURE__ */ jsx("span", { style: getValueStyle(material?.compliant), children: material?.surface ?? "unknown" })
828
+ ] }),
829
+ /* @__PURE__ */ jsxs("span", { style: styles.value, children: [
830
+ /* @__PURE__ */ jsx("span", { style: styles.valueLabel, children: "Shadow:" }),
831
+ /* @__PURE__ */ jsx("span", { style: getValueStyle(material?.compliant), children: material?.shadow ?? "unknown" })
832
+ ] })
833
+ ] })
834
+ ] })
835
+ ] })
836
+ ] });
837
+ }
838
+ function getValueStyle(compliant) {
839
+ if (compliant === void 0)
840
+ return styles.valueText;
841
+ return compliant ? { ...styles.valueText, color: "#22c55e" } : { ...styles.valueText, color: "#ef4444" };
842
+ }
843
+ var styles = {
844
+ container: {
845
+ padding: "12px",
846
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
847
+ borderRadius: "8px",
848
+ border: "1px solid rgba(255, 255, 255, 0.05)"
849
+ },
850
+ header: {
851
+ display: "flex",
852
+ justifyContent: "space-between",
853
+ alignItems: "center",
854
+ marginBottom: "8px"
855
+ },
856
+ title: {
857
+ fontSize: "11px",
858
+ fontWeight: 600,
859
+ color: "#888",
860
+ textTransform: "uppercase",
861
+ letterSpacing: "0.5px"
862
+ },
863
+ loading: {
864
+ fontSize: "10px",
865
+ color: "#666"
866
+ },
867
+ empty: {
868
+ fontSize: "11px",
869
+ color: "#666",
870
+ fontStyle: "italic"
871
+ },
872
+ effectRow: {
873
+ display: "flex",
874
+ alignItems: "center",
875
+ gap: "8px",
876
+ marginBottom: "12px"
877
+ },
878
+ effectBadge: {
879
+ padding: "4px 8px",
880
+ borderRadius: "4px",
881
+ fontSize: "11px",
882
+ fontWeight: 600,
883
+ border: "1px solid"
884
+ },
885
+ warningBadge: {
886
+ padding: "2px 6px",
887
+ borderRadius: "4px",
888
+ fontSize: "10px",
889
+ backgroundColor: "rgba(239, 68, 68, 0.1)",
890
+ color: "#ef4444",
891
+ border: "1px solid rgba(239, 68, 68, 0.2)"
892
+ },
893
+ grid: {
894
+ display: "flex",
895
+ flexDirection: "column",
896
+ gap: "8px"
897
+ },
898
+ section: {
899
+ display: "flex",
900
+ flexDirection: "column",
901
+ gap: "4px"
902
+ },
903
+ sectionLabel: {
904
+ fontSize: "10px",
905
+ fontWeight: 600,
906
+ color: "#666",
907
+ textTransform: "uppercase",
908
+ letterSpacing: "0.3px"
909
+ },
910
+ values: {
911
+ display: "flex",
912
+ flexWrap: "wrap",
913
+ gap: "8px"
914
+ },
915
+ value: {
916
+ display: "flex",
917
+ gap: "4px",
918
+ fontSize: "11px"
919
+ },
920
+ valueLabel: {
921
+ color: "#888"
922
+ },
923
+ valueText: {
924
+ color: "#fff"
925
+ }
926
+ };
927
+ var severityColors = {
928
+ error: { bg: "rgba(239, 68, 68, 0.1)", border: "rgba(239, 68, 68, 0.3)", text: "#ef4444" },
929
+ warning: { bg: "rgba(234, 179, 8, 0.1)", border: "rgba(234, 179, 8, 0.3)", text: "#eab308" },
930
+ info: { bg: "rgba(59, 130, 246, 0.1)", border: "rgba(59, 130, 246, 0.3)", text: "#3b82f6" }
931
+ };
932
+ var severityIcons = {
933
+ error: "\u2715",
934
+ warning: "\u26A0",
935
+ info: "\u2139"
936
+ };
937
+ function IssueList({
938
+ issues,
939
+ maxVisible = 5,
940
+ onIssueClick,
941
+ className = ""
942
+ }) {
943
+ const hasMore = issues.length > maxVisible;
944
+ const visibleIssues = hasMore ? issues.slice(0, maxVisible) : issues;
945
+ if (issues.length === 0) {
946
+ return /* @__PURE__ */ jsxs("div", { className, style: styles2.container, children: [
947
+ /* @__PURE__ */ jsxs("div", { style: styles2.header, children: [
948
+ /* @__PURE__ */ jsx("span", { style: styles2.title, children: "Issues" }),
949
+ /* @__PURE__ */ jsx("span", { style: styles2.count, children: "0" })
950
+ ] }),
951
+ /* @__PURE__ */ jsxs("div", { style: styles2.empty, children: [
952
+ /* @__PURE__ */ jsx("span", { style: styles2.checkIcon, children: "\u2713" }),
953
+ "No issues detected"
954
+ ] })
955
+ ] });
956
+ }
957
+ const errorCount = issues.filter((i) => i.severity === "error").length;
958
+ const warningCount = issues.filter((i) => i.severity === "warning").length;
959
+ return /* @__PURE__ */ jsxs("div", { className, style: styles2.container, children: [
960
+ /* @__PURE__ */ jsxs("div", { style: styles2.header, children: [
961
+ /* @__PURE__ */ jsx("span", { style: styles2.title, children: "Issues" }),
962
+ /* @__PURE__ */ jsxs("div", { style: styles2.counts, children: [
963
+ errorCount > 0 && /* @__PURE__ */ jsxs("span", { style: { ...styles2.countBadge, ...severityColors.error }, children: [
964
+ errorCount,
965
+ " error",
966
+ errorCount !== 1 ? "s" : ""
967
+ ] }),
968
+ warningCount > 0 && /* @__PURE__ */ jsxs("span", { style: { ...styles2.countBadge, ...severityColors.warning }, children: [
969
+ warningCount,
970
+ " warning",
971
+ warningCount !== 1 ? "s" : ""
972
+ ] })
973
+ ] })
974
+ ] }),
975
+ /* @__PURE__ */ jsx("div", { style: styles2.list, children: visibleIssues.map((issue, index) => {
976
+ const colors2 = severityColors[issue.severity];
977
+ const icon = severityIcons[issue.severity];
978
+ return /* @__PURE__ */ jsxs(
979
+ "button",
980
+ {
981
+ onClick: () => onIssueClick?.(issue),
982
+ style: {
983
+ ...styles2.issue,
984
+ backgroundColor: colors2.bg,
985
+ borderColor: colors2.border
986
+ },
987
+ children: [
988
+ /* @__PURE__ */ jsx("span", { style: { ...styles2.icon, color: colors2.text }, children: icon }),
989
+ /* @__PURE__ */ jsxs("div", { style: styles2.issueContent, children: [
990
+ /* @__PURE__ */ jsxs("span", { style: styles2.issueCode, children: [
991
+ "[",
992
+ issue.code,
993
+ "]"
994
+ ] }),
995
+ /* @__PURE__ */ jsx("span", { style: styles2.issueMessage, children: issue.message }),
996
+ issue.suggestion && /* @__PURE__ */ jsxs("span", { style: styles2.issueSuggestion, children: [
997
+ "Fix: ",
998
+ issue.suggestion
999
+ ] })
1000
+ ] })
1001
+ ]
1002
+ },
1003
+ `${issue.code}-${index}`
1004
+ );
1005
+ }) }),
1006
+ hasMore && /* @__PURE__ */ jsxs("div", { style: styles2.more, children: [
1007
+ "+ ",
1008
+ issues.length - maxVisible,
1009
+ " more issues"
1010
+ ] })
1011
+ ] });
1012
+ }
1013
+ var styles2 = {
1014
+ container: {
1015
+ padding: "12px",
1016
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
1017
+ borderRadius: "8px",
1018
+ border: "1px solid rgba(255, 255, 255, 0.05)"
1019
+ },
1020
+ header: {
1021
+ display: "flex",
1022
+ justifyContent: "space-between",
1023
+ alignItems: "center",
1024
+ marginBottom: "12px"
1025
+ },
1026
+ title: {
1027
+ fontSize: "11px",
1028
+ fontWeight: 600,
1029
+ color: "#888",
1030
+ textTransform: "uppercase",
1031
+ letterSpacing: "0.5px"
1032
+ },
1033
+ count: {
1034
+ fontSize: "10px",
1035
+ color: "#666"
1036
+ },
1037
+ counts: {
1038
+ display: "flex",
1039
+ gap: "6px"
1040
+ },
1041
+ countBadge: {
1042
+ padding: "2px 6px",
1043
+ borderRadius: "4px",
1044
+ fontSize: "10px",
1045
+ border: "1px solid"
1046
+ },
1047
+ empty: {
1048
+ display: "flex",
1049
+ alignItems: "center",
1050
+ gap: "6px",
1051
+ fontSize: "11px",
1052
+ color: "#22c55e"
1053
+ },
1054
+ checkIcon: {
1055
+ fontWeight: 600
1056
+ },
1057
+ list: {
1058
+ display: "flex",
1059
+ flexDirection: "column",
1060
+ gap: "6px"
1061
+ },
1062
+ issue: {
1063
+ display: "flex",
1064
+ alignItems: "flex-start",
1065
+ gap: "8px",
1066
+ padding: "8px",
1067
+ border: "1px solid",
1068
+ borderRadius: "4px",
1069
+ cursor: "pointer",
1070
+ textAlign: "left",
1071
+ width: "100%",
1072
+ transition: "opacity 0.15s ease-out"
1073
+ },
1074
+ icon: {
1075
+ fontSize: "12px",
1076
+ fontWeight: 600,
1077
+ flexShrink: 0,
1078
+ marginTop: "1px"
1079
+ },
1080
+ issueContent: {
1081
+ display: "flex",
1082
+ flexDirection: "column",
1083
+ gap: "2px",
1084
+ overflow: "hidden"
1085
+ },
1086
+ issueCode: {
1087
+ fontSize: "10px",
1088
+ fontWeight: 600,
1089
+ color: "#888",
1090
+ fontFamily: "monospace"
1091
+ },
1092
+ issueMessage: {
1093
+ fontSize: "11px",
1094
+ color: "#fff",
1095
+ lineHeight: 1.4
1096
+ },
1097
+ issueSuggestion: {
1098
+ fontSize: "10px",
1099
+ color: "#888",
1100
+ fontStyle: "italic"
1101
+ },
1102
+ more: {
1103
+ marginTop: "8px",
1104
+ fontSize: "10px",
1105
+ color: "#666",
1106
+ textAlign: "center"
1107
+ }
1108
+ };
1109
+ var sourceConfig = {
1110
+ "on-chain": { label: "On-Chain", color: "#22c55e", bgColor: "rgba(34, 197, 94, 0.1)" },
1111
+ indexed: { label: "Indexed", color: "#3b82f6", bgColor: "rgba(59, 130, 246, 0.1)" },
1112
+ cached: { label: "Cached", color: "#eab308", bgColor: "rgba(234, 179, 8, 0.1)" },
1113
+ unknown: { label: "Unknown", color: "#666", bgColor: "rgba(100, 100, 100, 0.1)" }
1114
+ };
1115
+ function getStaleness(props) {
1116
+ const { source, blockNumber, currentBlock, timestamp } = props;
1117
+ if (source === "on-chain" && blockNumber && currentBlock) {
1118
+ const blocksBehind = currentBlock - blockNumber;
1119
+ if (blocksBehind <= 1)
1120
+ return { level: "fresh", label: "current" };
1121
+ if (blocksBehind <= 5)
1122
+ return { level: "stale", label: `${blocksBehind} blocks behind` };
1123
+ return { level: "very-stale", label: `${blocksBehind} blocks behind` };
1124
+ }
1125
+ if (timestamp) {
1126
+ const secondsAgo = Math.floor((Date.now() - timestamp) / 1e3);
1127
+ if (secondsAgo < 30)
1128
+ return { level: "fresh", label: "just now" };
1129
+ if (secondsAgo < 60)
1130
+ return { level: "fresh", label: `${secondsAgo}s ago` };
1131
+ if (secondsAgo < 300)
1132
+ return { level: "stale", label: `${Math.floor(secondsAgo / 60)}m ago` };
1133
+ return { level: "very-stale", label: `${Math.floor(secondsAgo / 60)}m ago` };
1134
+ }
1135
+ return { level: "fresh", label: "" };
1136
+ }
1137
+ var stalenessColors = {
1138
+ fresh: "#22c55e",
1139
+ stale: "#eab308",
1140
+ "very-stale": "#ef4444"
1141
+ };
1142
+ function DataSourceIndicator({
1143
+ source,
1144
+ blockNumber,
1145
+ currentBlock,
1146
+ timestamp,
1147
+ expanded = false,
1148
+ onClick,
1149
+ className = ""
1150
+ }) {
1151
+ const config = sourceConfig[source];
1152
+ const staleness = getStaleness({ source, blockNumber, currentBlock, timestamp });
1153
+ return /* @__PURE__ */ jsxs(
1154
+ "button",
1155
+ {
1156
+ onClick,
1157
+ className,
1158
+ style: {
1159
+ ...styles3.container,
1160
+ cursor: onClick ? "pointer" : "default"
1161
+ },
1162
+ children: [
1163
+ /* @__PURE__ */ jsx(
1164
+ "span",
1165
+ {
1166
+ style: {
1167
+ ...styles3.badge,
1168
+ backgroundColor: config.bgColor,
1169
+ borderColor: `${config.color}40`,
1170
+ color: config.color
1171
+ },
1172
+ children: config.label
1173
+ }
1174
+ ),
1175
+ staleness.label && /* @__PURE__ */ jsxs("span", { style: { ...styles3.staleness, color: stalenessColors[staleness.level] }, children: [
1176
+ /* @__PURE__ */ jsx("span", { style: styles3.dot, children: "\u25CF" }),
1177
+ staleness.label
1178
+ ] }),
1179
+ expanded && blockNumber && /* @__PURE__ */ jsxs("div", { style: styles3.expanded, children: [
1180
+ /* @__PURE__ */ jsx("span", { style: styles3.detailLabel, children: "Block:" }),
1181
+ /* @__PURE__ */ jsxs("span", { style: styles3.detailValue, children: [
1182
+ "#",
1183
+ blockNumber.toLocaleString()
1184
+ ] })
1185
+ ] })
1186
+ ]
1187
+ }
1188
+ );
1189
+ }
1190
+ var styles3 = {
1191
+ container: {
1192
+ display: "inline-flex",
1193
+ alignItems: "center",
1194
+ gap: "6px",
1195
+ padding: "0",
1196
+ backgroundColor: "transparent",
1197
+ border: "none",
1198
+ fontSize: "10px",
1199
+ fontFamily: "inherit"
1200
+ },
1201
+ badge: {
1202
+ padding: "2px 6px",
1203
+ borderRadius: "4px",
1204
+ fontSize: "9px",
1205
+ fontWeight: 600,
1206
+ border: "1px solid",
1207
+ textTransform: "uppercase",
1208
+ letterSpacing: "0.3px"
1209
+ },
1210
+ staleness: {
1211
+ display: "flex",
1212
+ alignItems: "center",
1213
+ gap: "3px",
1214
+ fontSize: "10px"
1215
+ },
1216
+ dot: {
1217
+ fontSize: "6px"
1218
+ },
1219
+ expanded: {
1220
+ display: "flex",
1221
+ gap: "4px",
1222
+ marginLeft: "4px",
1223
+ paddingLeft: "4px",
1224
+ borderLeft: "1px solid rgba(255, 255, 255, 0.1)"
1225
+ },
1226
+ detailLabel: {
1227
+ color: "#666"
1228
+ },
1229
+ detailValue: {
1230
+ color: "#888",
1231
+ fontFamily: "monospace"
1232
+ }
1233
+ };
1234
+ var initialAnalysisState = {
1235
+ component: null,
1236
+ effect: null,
1237
+ compliance: null,
1238
+ issues: [],
1239
+ isLoading: false
1240
+ };
1241
+ function DiagnosticsPanel({ className = "" }) {
1242
+ const { diagnosticsService, activePanel, config } = useHud();
1243
+ const [analysis, setAnalysis] = useState(initialAnalysisState);
1244
+ const [symptom, setSymptom] = useState("");
1245
+ const [diagnosis, setDiagnosis] = useState(null);
1246
+ const [isLoading, setIsLoading] = useState(false);
1247
+ const [showSymptomInput, setShowSymptomInput] = useState(false);
1248
+ useCallback(
1249
+ async (componentName, code) => {
1250
+ if (!diagnosticsService)
1251
+ return;
1252
+ setAnalysis((prev) => ({ ...prev, isLoading: true }));
1253
+ try {
1254
+ const result = await diagnosticsService.analyze(componentName, code);
1255
+ setAnalysis({
1256
+ component: result.component,
1257
+ effect: result.effect,
1258
+ compliance: result.compliance,
1259
+ issues: result.issues,
1260
+ isLoading: false
1261
+ });
1262
+ } catch (error) {
1263
+ setAnalysis({
1264
+ ...initialAnalysisState,
1265
+ isLoading: false
1266
+ });
1267
+ }
1268
+ },
1269
+ [diagnosticsService]
1270
+ );
1271
+ const handleDiagnose = useCallback(async () => {
1272
+ if (!diagnosticsService || !symptom)
1273
+ return;
1274
+ setIsLoading(true);
1275
+ try {
1276
+ const result = diagnosticsService.diagnose(symptom);
1277
+ setDiagnosis(result);
1278
+ } catch (error) {
1279
+ setDiagnosis(`Error: ${error instanceof Error ? error.message : "Unknown error"}`);
1280
+ } finally {
1281
+ setIsLoading(false);
1282
+ }
1283
+ }, [diagnosticsService, symptom]);
1284
+ const handleClear = useCallback(() => {
1285
+ setSymptom("");
1286
+ setDiagnosis(null);
1287
+ setShowSymptomInput(false);
1288
+ }, []);
1289
+ const handleCaptureObservation = useCallback(() => {
1290
+ const event = new KeyboardEvent("keydown", {
1291
+ key: "o",
1292
+ metaKey: true,
1293
+ shiftKey: true
1294
+ });
1295
+ window.dispatchEvent(event);
1296
+ }, []);
1297
+ const handleRecordSignal = useCallback(() => {
1298
+ console.log("Record signal triggered");
1299
+ }, []);
1300
+ const handleIssueClick = useCallback((issue) => {
1301
+ console.log("Issue clicked:", issue.code);
1302
+ }, []);
1303
+ if (activePanel !== "diagnostics")
1304
+ return null;
1305
+ if (!diagnosticsService) {
1306
+ return /* @__PURE__ */ jsxs("div", { className, style: styles4.container, children: [
1307
+ /* @__PURE__ */ jsx("div", { style: styles4.header, children: /* @__PURE__ */ jsx("span", { style: styles4.title, children: "Diagnostics" }) }),
1308
+ /* @__PURE__ */ jsxs("div", { style: styles4.unavailable, children: [
1309
+ /* @__PURE__ */ jsx("p", { style: styles4.unavailableText, children: "Diagnostics service not available." }),
1310
+ /* @__PURE__ */ jsx("p", { style: styles4.unavailableHint, children: "Install @sigil/diagnostics to enable physics analysis." })
1311
+ ] })
1312
+ ] });
1313
+ }
1314
+ return /* @__PURE__ */ jsxs("div", { className, style: styles4.container, children: [
1315
+ /* @__PURE__ */ jsxs("div", { style: styles4.header, children: [
1316
+ /* @__PURE__ */ jsx("span", { style: styles4.title, children: "Diagnostics" }),
1317
+ /* @__PURE__ */ jsxs("div", { style: styles4.quickActions, children: [
1318
+ config.observationCapture && /* @__PURE__ */ jsx(
1319
+ "button",
1320
+ {
1321
+ onClick: handleCaptureObservation,
1322
+ style: styles4.quickActionButton,
1323
+ title: "Capture Observation (Cmd+Shift+O)",
1324
+ children: "\u{1F4F8}"
1325
+ }
1326
+ ),
1327
+ config.signalCapture && /* @__PURE__ */ jsx(
1328
+ "button",
1329
+ {
1330
+ onClick: handleRecordSignal,
1331
+ style: styles4.quickActionButton,
1332
+ title: "Record Signal",
1333
+ children: "\u{1F4E1}"
1334
+ }
1335
+ )
1336
+ ] })
1337
+ ] }),
1338
+ /* @__PURE__ */ jsx(
1339
+ PhysicsAnalysis,
1340
+ {
1341
+ effect: analysis.effect,
1342
+ compliance: analysis.compliance,
1343
+ isLoading: analysis.isLoading
1344
+ }
1345
+ ),
1346
+ /* @__PURE__ */ jsxs("div", { style: styles4.section, children: [
1347
+ /* @__PURE__ */ jsx("span", { style: styles4.sectionLabel, children: "Data Sources" }),
1348
+ /* @__PURE__ */ jsx("div", { style: styles4.dataSourceRow, children: /* @__PURE__ */ jsx(DataSourceIndicator, { source: "on-chain", blockNumber: 19234567, currentBlock: 19234569 }) })
1349
+ ] }),
1350
+ /* @__PURE__ */ jsx("div", { style: styles4.section, children: /* @__PURE__ */ jsx(
1351
+ IssueList,
1352
+ {
1353
+ issues: analysis.issues,
1354
+ onIssueClick: handleIssueClick,
1355
+ maxVisible: 3
1356
+ }
1357
+ ) }),
1358
+ !showSymptomInput ? /* @__PURE__ */ jsx(
1359
+ "button",
1360
+ {
1361
+ onClick: () => setShowSymptomInput(true),
1362
+ style: styles4.showDiagnoseButton,
1363
+ children: "+ Describe a symptom to diagnose"
1364
+ }
1365
+ ) : /* @__PURE__ */ jsxs("div", { style: styles4.diagnoseSection, children: [
1366
+ /* @__PURE__ */ jsx("label", { style: styles4.inputLabel, children: "Describe the issue or symptom" }),
1367
+ /* @__PURE__ */ jsx(
1368
+ "textarea",
1369
+ {
1370
+ value: symptom,
1371
+ onChange: (e) => setSymptom(e.target.value),
1372
+ placeholder: "e.g., Dialog flickers on open, Hydration mismatch, Button feels slow...",
1373
+ rows: 2,
1374
+ style: styles4.textarea
1375
+ }
1376
+ ),
1377
+ /* @__PURE__ */ jsxs("div", { style: styles4.diagnoseActions, children: [
1378
+ /* @__PURE__ */ jsx(
1379
+ "button",
1380
+ {
1381
+ onClick: handleDiagnose,
1382
+ disabled: !symptom || isLoading,
1383
+ style: {
1384
+ ...styles4.diagnoseButton,
1385
+ opacity: symptom ? 1 : 0.5,
1386
+ cursor: symptom ? "pointer" : "not-allowed"
1387
+ },
1388
+ children: isLoading ? "Analyzing..." : "Diagnose"
1389
+ }
1390
+ ),
1391
+ /* @__PURE__ */ jsx("button", { onClick: handleClear, style: styles4.cancelButton, children: "Cancel" })
1392
+ ] })
1393
+ ] }),
1394
+ diagnosis && /* @__PURE__ */ jsx("div", { style: styles4.diagnosisResult, children: /* @__PURE__ */ jsx(
1395
+ "div",
1396
+ {
1397
+ style: styles4.diagnosisContent,
1398
+ dangerouslySetInnerHTML: {
1399
+ __html: formatDiagnosis(diagnosis)
1400
+ }
1401
+ }
1402
+ ) }),
1403
+ /* @__PURE__ */ jsxs("div", { style: styles4.quickDiagnose, children: [
1404
+ /* @__PURE__ */ jsx("span", { style: styles4.quickDiagnoseLabel, children: "Quick Diagnose" }),
1405
+ /* @__PURE__ */ jsx("div", { style: styles4.quickDiagnoseGrid, children: ["hydration mismatch", "dialog glitch", "slow performance", "layout shift"].map(
1406
+ (quick) => /* @__PURE__ */ jsx(
1407
+ "button",
1408
+ {
1409
+ onClick: () => {
1410
+ setSymptom(quick);
1411
+ setShowSymptomInput(true);
1412
+ },
1413
+ style: styles4.quickDiagnoseButton,
1414
+ children: quick
1415
+ },
1416
+ quick
1417
+ )
1418
+ ) })
1419
+ ] })
1420
+ ] });
1421
+ }
1422
+ function formatDiagnosis(text) {
1423
+ return text.replace(/\*\*(.*?)\*\*/g, '<strong style="color: #10b981">$1</strong>').replace(
1424
+ /`([^`]+)`/g,
1425
+ '<code style="background: rgba(255,255,255,0.1); padding: 2px 4px; border-radius: 2px;">$1</code>'
1426
+ ).replace(
1427
+ /```(\w+)?\n([\s\S]*?)```/g,
1428
+ '<pre style="background: rgba(0,0,0,0.3); padding: 8px; border-radius: 4px; overflow-x: auto; margin: 8px 0;">$2</pre>'
1429
+ );
1430
+ }
1431
+ var styles4 = {
1432
+ container: {
1433
+ display: "flex",
1434
+ flexDirection: "column",
1435
+ gap: "16px"
1436
+ },
1437
+ header: {
1438
+ display: "flex",
1439
+ justifyContent: "space-between",
1440
+ alignItems: "center"
1441
+ },
1442
+ title: {
1443
+ fontSize: "12px",
1444
+ fontWeight: 600,
1445
+ color: "#fff"
1446
+ },
1447
+ quickActions: {
1448
+ display: "flex",
1449
+ gap: "4px"
1450
+ },
1451
+ quickActionButton: {
1452
+ width: "28px",
1453
+ height: "28px",
1454
+ display: "flex",
1455
+ alignItems: "center",
1456
+ justifyContent: "center",
1457
+ backgroundColor: "rgba(255, 255, 255, 0.05)",
1458
+ border: "1px solid rgba(255, 255, 255, 0.1)",
1459
+ borderRadius: "4px",
1460
+ cursor: "pointer",
1461
+ fontSize: "12px",
1462
+ transition: "background-color 0.15s ease-out"
1463
+ },
1464
+ unavailable: {
1465
+ padding: "16px",
1466
+ textAlign: "center"
1467
+ },
1468
+ unavailableText: {
1469
+ color: "#666",
1470
+ fontSize: "11px",
1471
+ margin: 0
1472
+ },
1473
+ unavailableHint: {
1474
+ color: "#555",
1475
+ fontSize: "10px",
1476
+ marginTop: "4px"
1477
+ },
1478
+ section: {
1479
+ display: "flex",
1480
+ flexDirection: "column",
1481
+ gap: "8px"
1482
+ },
1483
+ sectionLabel: {
1484
+ fontSize: "10px",
1485
+ fontWeight: 600,
1486
+ color: "#888",
1487
+ textTransform: "uppercase",
1488
+ letterSpacing: "0.5px"
1489
+ },
1490
+ dataSourceRow: {
1491
+ display: "flex",
1492
+ alignItems: "center",
1493
+ gap: "8px"
1494
+ },
1495
+ showDiagnoseButton: {
1496
+ width: "100%",
1497
+ padding: "8px 12px",
1498
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
1499
+ border: "1px dashed rgba(255, 255, 255, 0.1)",
1500
+ borderRadius: "4px",
1501
+ color: "#666",
1502
+ fontSize: "11px",
1503
+ cursor: "pointer",
1504
+ textAlign: "left"
1505
+ },
1506
+ diagnoseSection: {
1507
+ display: "flex",
1508
+ flexDirection: "column",
1509
+ gap: "8px"
1510
+ },
1511
+ inputLabel: {
1512
+ fontSize: "10px",
1513
+ color: "#888"
1514
+ },
1515
+ textarea: {
1516
+ width: "100%",
1517
+ padding: "8px",
1518
+ backgroundColor: "rgba(255, 255, 255, 0.05)",
1519
+ border: "1px solid rgba(255, 255, 255, 0.1)",
1520
+ borderRadius: "4px",
1521
+ color: "#fff",
1522
+ fontSize: "11px",
1523
+ fontFamily: "inherit",
1524
+ resize: "vertical"
1525
+ },
1526
+ diagnoseActions: {
1527
+ display: "flex",
1528
+ gap: "8px"
1529
+ },
1530
+ diagnoseButton: {
1531
+ flex: 1,
1532
+ padding: "6px 12px",
1533
+ backgroundColor: "rgba(16, 185, 129, 0.2)",
1534
+ border: "1px solid rgba(16, 185, 129, 0.3)",
1535
+ borderRadius: "4px",
1536
+ color: "#10b981",
1537
+ fontSize: "11px",
1538
+ cursor: "pointer"
1539
+ },
1540
+ cancelButton: {
1541
+ padding: "6px 12px",
1542
+ backgroundColor: "rgba(255, 255, 255, 0.05)",
1543
+ border: "1px solid rgba(255, 255, 255, 0.1)",
1544
+ borderRadius: "4px",
1545
+ color: "#888",
1546
+ fontSize: "11px",
1547
+ cursor: "pointer"
1548
+ },
1549
+ diagnosisResult: {
1550
+ padding: "12px",
1551
+ backgroundColor: "rgba(16, 185, 129, 0.05)",
1552
+ border: "1px solid rgba(16, 185, 129, 0.2)",
1553
+ borderRadius: "4px"
1554
+ },
1555
+ diagnosisContent: {
1556
+ fontSize: "11px",
1557
+ color: "#fff",
1558
+ whiteSpace: "pre-wrap",
1559
+ lineHeight: 1.6
1560
+ },
1561
+ quickDiagnose: {
1562
+ display: "flex",
1563
+ flexDirection: "column",
1564
+ gap: "8px"
1565
+ },
1566
+ quickDiagnoseLabel: {
1567
+ fontSize: "10px",
1568
+ color: "#888"
1569
+ },
1570
+ quickDiagnoseGrid: {
1571
+ display: "grid",
1572
+ gridTemplateColumns: "repeat(2, 1fr)",
1573
+ gap: "4px"
1574
+ },
1575
+ quickDiagnoseButton: {
1576
+ padding: "6px 8px",
1577
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
1578
+ border: "1px solid rgba(255, 255, 255, 0.05)",
1579
+ borderRadius: "4px",
1580
+ color: "#888",
1581
+ fontSize: "10px",
1582
+ cursor: "pointer",
1583
+ textAlign: "center"
1584
+ }
1585
+ };
1586
+ function StateComparison({ className = "" }) {
1587
+ const { lensService, forkService, activePanel } = useHud();
1588
+ if (activePanel !== "state")
1589
+ return null;
1590
+ const lensState = lensService?.getState() ?? DEFAULT_LENS_STATE;
1591
+ const forkState = forkService?.getState();
1592
+ const isImpersonating = lensState.enabled && lensState.impersonatedAddress !== null;
1593
+ return /* @__PURE__ */ jsxs("div", { className, children: [
1594
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "16px" }, children: [
1595
+ /* @__PURE__ */ jsx(
1596
+ "label",
1597
+ {
1598
+ style: {
1599
+ display: "block",
1600
+ color: "#888",
1601
+ fontSize: "10px",
1602
+ marginBottom: "8px"
1603
+ },
1604
+ children: "Address Context"
1605
+ }
1606
+ ),
1607
+ /* @__PURE__ */ jsxs(
1608
+ "div",
1609
+ {
1610
+ style: {
1611
+ display: "flex",
1612
+ flexDirection: "column",
1613
+ gap: "8px"
1614
+ },
1615
+ children: [
1616
+ /* @__PURE__ */ jsxs(
1617
+ "div",
1618
+ {
1619
+ style: {
1620
+ padding: "8px",
1621
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
1622
+ borderRadius: "4px",
1623
+ border: !isImpersonating ? "1px solid rgba(16, 185, 129, 0.3)" : "1px solid rgba(255, 255, 255, 0.05)"
1624
+ },
1625
+ children: [
1626
+ /* @__PURE__ */ jsxs(
1627
+ "div",
1628
+ {
1629
+ style: {
1630
+ display: "flex",
1631
+ justifyContent: "space-between",
1632
+ alignItems: "center",
1633
+ marginBottom: "4px"
1634
+ },
1635
+ children: [
1636
+ /* @__PURE__ */ jsx("span", { style: { color: "#888", fontSize: "10px" }, children: "Real" }),
1637
+ !isImpersonating && /* @__PURE__ */ jsx(
1638
+ "span",
1639
+ {
1640
+ style: {
1641
+ fontSize: "9px",
1642
+ padding: "2px 6px",
1643
+ backgroundColor: "rgba(16, 185, 129, 0.2)",
1644
+ borderRadius: "4px",
1645
+ color: "#10b981"
1646
+ },
1647
+ children: "Active"
1648
+ }
1649
+ )
1650
+ ]
1651
+ }
1652
+ ),
1653
+ /* @__PURE__ */ jsx(
1654
+ "code",
1655
+ {
1656
+ style: {
1657
+ fontSize: "10px",
1658
+ color: lensState.realAddress ? "#fff" : "#666",
1659
+ wordBreak: "break-all"
1660
+ },
1661
+ children: lensState.realAddress ?? "Not connected"
1662
+ }
1663
+ )
1664
+ ]
1665
+ }
1666
+ ),
1667
+ /* @__PURE__ */ jsxs(
1668
+ "div",
1669
+ {
1670
+ style: {
1671
+ padding: "8px",
1672
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
1673
+ borderRadius: "4px",
1674
+ border: isImpersonating ? "1px solid rgba(16, 185, 129, 0.3)" : "1px solid rgba(255, 255, 255, 0.05)"
1675
+ },
1676
+ children: [
1677
+ /* @__PURE__ */ jsxs(
1678
+ "div",
1679
+ {
1680
+ style: {
1681
+ display: "flex",
1682
+ justifyContent: "space-between",
1683
+ alignItems: "center",
1684
+ marginBottom: "4px"
1685
+ },
1686
+ children: [
1687
+ /* @__PURE__ */ jsx("span", { style: { color: "#888", fontSize: "10px" }, children: "Impersonated" }),
1688
+ isImpersonating && /* @__PURE__ */ jsx(
1689
+ "span",
1690
+ {
1691
+ style: {
1692
+ fontSize: "9px",
1693
+ padding: "2px 6px",
1694
+ backgroundColor: "rgba(16, 185, 129, 0.2)",
1695
+ borderRadius: "4px",
1696
+ color: "#10b981"
1697
+ },
1698
+ children: "Active"
1699
+ }
1700
+ )
1701
+ ]
1702
+ }
1703
+ ),
1704
+ /* @__PURE__ */ jsx(
1705
+ "code",
1706
+ {
1707
+ style: {
1708
+ fontSize: "10px",
1709
+ color: lensState.impersonatedAddress ? "#fff" : "#666",
1710
+ wordBreak: "break-all"
1711
+ },
1712
+ children: lensState.impersonatedAddress ?? "None"
1713
+ }
1714
+ )
1715
+ ]
1716
+ }
1717
+ )
1718
+ ]
1719
+ }
1720
+ )
1721
+ ] }),
1722
+ forkState && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "16px" }, children: [
1723
+ /* @__PURE__ */ jsx(
1724
+ "label",
1725
+ {
1726
+ style: {
1727
+ display: "block",
1728
+ color: "#888",
1729
+ fontSize: "10px",
1730
+ marginBottom: "8px"
1731
+ },
1732
+ children: "Fork State"
1733
+ }
1734
+ ),
1735
+ /* @__PURE__ */ jsxs(
1736
+ "div",
1737
+ {
1738
+ style: {
1739
+ padding: "8px",
1740
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
1741
+ borderRadius: "4px"
1742
+ },
1743
+ children: [
1744
+ /* @__PURE__ */ jsxs(
1745
+ "div",
1746
+ {
1747
+ style: {
1748
+ display: "grid",
1749
+ gridTemplateColumns: "1fr 1fr",
1750
+ gap: "8px",
1751
+ fontSize: "10px"
1752
+ },
1753
+ children: [
1754
+ /* @__PURE__ */ jsxs("div", { children: [
1755
+ /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: "Status: " }),
1756
+ /* @__PURE__ */ jsx("span", { style: { color: forkState.active ? "#10b981" : "#888" }, children: forkState.active ? "Active" : "Inactive" })
1757
+ ] }),
1758
+ /* @__PURE__ */ jsxs("div", { children: [
1759
+ /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: "Chain: " }),
1760
+ /* @__PURE__ */ jsx("span", { style: { color: "#fff" }, children: forkState.chainId ?? "\u2014" })
1761
+ ] }),
1762
+ /* @__PURE__ */ jsxs("div", { children: [
1763
+ /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: "Block: " }),
1764
+ /* @__PURE__ */ jsx("span", { style: { color: "#fff" }, children: forkState.blockNumber?.toString() ?? "\u2014" })
1765
+ ] }),
1766
+ /* @__PURE__ */ jsxs("div", { children: [
1767
+ /* @__PURE__ */ jsx("span", { style: { color: "#666" }, children: "Snapshots: " }),
1768
+ /* @__PURE__ */ jsx("span", { style: { color: "#fff" }, children: forkState.snapshotCount })
1769
+ ] })
1770
+ ]
1771
+ }
1772
+ ),
1773
+ forkState.rpcUrl && /* @__PURE__ */ jsxs("div", { style: { marginTop: "8px" }, children: [
1774
+ /* @__PURE__ */ jsx("span", { style: { color: "#666", fontSize: "10px" }, children: "RPC: " }),
1775
+ /* @__PURE__ */ jsx(
1776
+ "code",
1777
+ {
1778
+ style: {
1779
+ fontSize: "9px",
1780
+ color: "#888",
1781
+ wordBreak: "break-all"
1782
+ },
1783
+ children: forkState.rpcUrl
1784
+ }
1785
+ )
1786
+ ] })
1787
+ ]
1788
+ }
1789
+ )
1790
+ ] }),
1791
+ /* @__PURE__ */ jsxs(
1792
+ "div",
1793
+ {
1794
+ style: {
1795
+ padding: "12px",
1796
+ backgroundColor: "rgba(251, 191, 36, 0.05)",
1797
+ border: "1px solid rgba(251, 191, 36, 0.2)",
1798
+ borderRadius: "4px"
1799
+ },
1800
+ children: [
1801
+ /* @__PURE__ */ jsx(
1802
+ "div",
1803
+ {
1804
+ style: { color: "#fbbf24", fontSize: "11px", marginBottom: "8px" },
1805
+ children: "State Comparison"
1806
+ }
1807
+ ),
1808
+ /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: "10px", lineHeight: 1.6 }, children: "When impersonating, reads use the impersonated address while writes still use your real wallet. This lets you test how the UI looks for different users without affecting their funds." })
1809
+ ]
1810
+ }
1811
+ )
1812
+ ] });
1813
+ }
1814
+ function generateObservationId() {
1815
+ const timestamp = Date.now().toString(36);
1816
+ const random = Math.random().toString(36).substring(2, 7);
1817
+ return `obs-${timestamp}-${random}`;
1818
+ }
1819
+ function useObservationCapture({
1820
+ enabled = true,
1821
+ onObservation
1822
+ } = {}) {
1823
+ const observationsRef = useRef([]);
1824
+ const capture = useCallback(
1825
+ async (content, type = "insight", context, tags = []) => {
1826
+ const observation = {
1827
+ id: generateObservationId(),
1828
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1829
+ type,
1830
+ content,
1831
+ tags,
1832
+ context
1833
+ };
1834
+ if (enabled) {
1835
+ observationsRef.current.push(observation);
1836
+ onObservation?.(observation);
1837
+ if (process.env.NODE_ENV === "development") {
1838
+ console.log("[Sigil HUD] Observation captured:", observation);
1839
+ }
1840
+ }
1841
+ return observation;
1842
+ },
1843
+ [enabled, onObservation]
1844
+ );
1845
+ const captureUserTruth = useCallback(
1846
+ (content, context) => {
1847
+ return capture(content, "user-truth", context, ["user-truth"]);
1848
+ },
1849
+ [capture]
1850
+ );
1851
+ const captureIssue = useCallback(
1852
+ (content, context) => {
1853
+ return capture(content, "issue", context, ["issue"]);
1854
+ },
1855
+ [capture]
1856
+ );
1857
+ const captureInsight = useCallback(
1858
+ (content, context) => {
1859
+ return capture(content, "insight", context, ["insight"]);
1860
+ },
1861
+ [capture]
1862
+ );
1863
+ const linkToSignals = useCallback(
1864
+ (observationId, signalIds) => {
1865
+ const observation = observationsRef.current.find(
1866
+ (o) => o.id === observationId
1867
+ );
1868
+ if (observation) {
1869
+ observation.linkedSignals = [
1870
+ ...observation.linkedSignals ?? [],
1871
+ ...signalIds
1872
+ ];
1873
+ }
1874
+ },
1875
+ []
1876
+ );
1877
+ const getObservations = useCallback(() => {
1878
+ return [...observationsRef.current];
1879
+ }, []);
1880
+ const getObservationsByType = useCallback((type) => {
1881
+ return observationsRef.current.filter((o) => o.type === type);
1882
+ }, []);
1883
+ const clearObservations = useCallback(() => {
1884
+ observationsRef.current = [];
1885
+ }, []);
1886
+ return {
1887
+ capture,
1888
+ captureUserTruth,
1889
+ captureIssue,
1890
+ captureInsight,
1891
+ linkToSignals,
1892
+ getObservations,
1893
+ getObservationsByType,
1894
+ clearObservations
1895
+ };
1896
+ }
1897
+ var typeConfig = {
1898
+ "user-truth": {
1899
+ label: "User Truth",
1900
+ color: "#22c55e",
1901
+ bgColor: "rgba(34, 197, 94, 0.1)",
1902
+ description: "What users actually do vs. what we assumed"
1903
+ },
1904
+ issue: {
1905
+ label: "Issue",
1906
+ color: "#ef4444",
1907
+ bgColor: "rgba(239, 68, 68, 0.1)",
1908
+ description: "Problems, bugs, or friction points"
1909
+ },
1910
+ insight: {
1911
+ label: "Insight",
1912
+ color: "#3b82f6",
1913
+ bgColor: "rgba(59, 130, 246, 0.1)",
1914
+ description: "Patterns, discoveries, or aha moments"
1915
+ }
1916
+ };
1917
+ var suggestedTags = {
1918
+ "user-truth": ["assumption-violated", "behavior-change", "feedback", "preference"],
1919
+ issue: ["ux", "performance", "physics-violation", "accessibility", "mobile"],
1920
+ insight: ["pattern", "optimization", "physics", "taste", "workflow"]
1921
+ };
1922
+ function ObservationCaptureModal({
1923
+ isOpen,
1924
+ onClose,
1925
+ onCapture,
1926
+ componentContext,
1927
+ className = ""
1928
+ }) {
1929
+ const [type, setType] = useState("insight");
1930
+ const [content, setContent] = useState("");
1931
+ const [tags, setTags] = useState([]);
1932
+ const [customTag, setCustomTag] = useState("");
1933
+ const contentRef = useRef(null);
1934
+ const { capture } = useObservationCapture({
1935
+ enabled: true,
1936
+ onObservation: onCapture
1937
+ });
1938
+ useEffect(() => {
1939
+ if (isOpen && contentRef.current) {
1940
+ contentRef.current.focus();
1941
+ }
1942
+ }, [isOpen]);
1943
+ useEffect(() => {
1944
+ if (!isOpen) {
1945
+ setType("insight");
1946
+ setContent("");
1947
+ setTags([]);
1948
+ setCustomTag("");
1949
+ }
1950
+ }, [isOpen]);
1951
+ useEffect(() => {
1952
+ if (!isOpen)
1953
+ return;
1954
+ const handleKeyDown = (e) => {
1955
+ if (e.key === "Escape") {
1956
+ onClose();
1957
+ }
1958
+ if (e.key === "Enter" && e.metaKey) {
1959
+ handleSubmit();
1960
+ }
1961
+ };
1962
+ window.addEventListener("keydown", handleKeyDown);
1963
+ return () => window.removeEventListener("keydown", handleKeyDown);
1964
+ }, [isOpen, onClose, content]);
1965
+ const toggleTag = useCallback((tag) => {
1966
+ setTags(
1967
+ (prev) => prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]
1968
+ );
1969
+ }, []);
1970
+ const addCustomTag = useCallback(() => {
1971
+ if (customTag && !tags.includes(customTag)) {
1972
+ setTags((prev) => [...prev, customTag]);
1973
+ setCustomTag("");
1974
+ }
1975
+ }, [customTag, tags]);
1976
+ const handleSubmit = useCallback(async () => {
1977
+ if (!content.trim())
1978
+ return;
1979
+ await capture(
1980
+ content.trim(),
1981
+ type,
1982
+ componentContext,
1983
+ tags
1984
+ );
1985
+ onClose();
1986
+ }, [content, type, componentContext, tags, capture, onClose]);
1987
+ if (!isOpen)
1988
+ return null;
1989
+ const config = typeConfig[type];
1990
+ const suggested = suggestedTags[type];
1991
+ return /* @__PURE__ */ jsx("div", { className, style: styles5.overlay, children: /* @__PURE__ */ jsxs("div", { style: styles5.modal, children: [
1992
+ /* @__PURE__ */ jsxs("div", { style: styles5.header, children: [
1993
+ /* @__PURE__ */ jsx("h2", { style: styles5.title, children: "Capture Observation" }),
1994
+ /* @__PURE__ */ jsx("button", { onClick: onClose, style: styles5.closeButton, children: "\xD7" })
1995
+ ] }),
1996
+ /* @__PURE__ */ jsxs("div", { style: styles5.section, children: [
1997
+ /* @__PURE__ */ jsx("label", { style: styles5.label, children: "Type" }),
1998
+ /* @__PURE__ */ jsx("div", { style: styles5.typeButtons, children: Object.keys(typeConfig).map((t) => {
1999
+ const c = typeConfig[t];
2000
+ const isSelected = type === t;
2001
+ return /* @__PURE__ */ jsx(
2002
+ "button",
2003
+ {
2004
+ onClick: () => setType(t),
2005
+ style: {
2006
+ ...styles5.typeButton,
2007
+ backgroundColor: isSelected ? c.bgColor : "rgba(255, 255, 255, 0.02)",
2008
+ borderColor: isSelected ? c.color : "rgba(255, 255, 255, 0.1)",
2009
+ color: isSelected ? c.color : "#888"
2010
+ },
2011
+ children: c.label
2012
+ },
2013
+ t
2014
+ );
2015
+ }) }),
2016
+ /* @__PURE__ */ jsx("p", { style: styles5.typeDescription, children: config.description })
2017
+ ] }),
2018
+ /* @__PURE__ */ jsxs("div", { style: styles5.section, children: [
2019
+ /* @__PURE__ */ jsx("label", { style: styles5.label, children: "What did you observe?" }),
2020
+ /* @__PURE__ */ jsx(
2021
+ "textarea",
2022
+ {
2023
+ ref: contentRef,
2024
+ value: content,
2025
+ onChange: (e) => setContent(e.target.value),
2026
+ placeholder: type === "user-truth" ? 'e.g., "Users expected the claim button to show pending state, but it shows stale balance..."' : type === "issue" ? 'e.g., "Dialog animation causes layout shift on mobile Safari..."' : 'e.g., "Power users prefer 500ms timing over 800ms for financial operations..."',
2027
+ rows: 4,
2028
+ style: styles5.textarea
2029
+ }
2030
+ )
2031
+ ] }),
2032
+ /* @__PURE__ */ jsxs("div", { style: styles5.section, children: [
2033
+ /* @__PURE__ */ jsx("label", { style: styles5.label, children: "Tags" }),
2034
+ /* @__PURE__ */ jsxs("div", { style: styles5.tagContainer, children: [
2035
+ suggested.map((tag) => /* @__PURE__ */ jsx(
2036
+ "button",
2037
+ {
2038
+ onClick: () => toggleTag(tag),
2039
+ style: {
2040
+ ...styles5.tag,
2041
+ backgroundColor: tags.includes(tag) ? config.bgColor : "rgba(255, 255, 255, 0.02)",
2042
+ borderColor: tags.includes(tag) ? config.color : "rgba(255, 255, 255, 0.1)",
2043
+ color: tags.includes(tag) ? config.color : "#888"
2044
+ },
2045
+ children: tag
2046
+ },
2047
+ tag
2048
+ )),
2049
+ tags.filter((t) => !suggested.includes(t)).map((tag) => /* @__PURE__ */ jsxs(
2050
+ "button",
2051
+ {
2052
+ onClick: () => toggleTag(tag),
2053
+ style: {
2054
+ ...styles5.tag,
2055
+ backgroundColor: config.bgColor,
2056
+ borderColor: config.color,
2057
+ color: config.color
2058
+ },
2059
+ children: [
2060
+ tag,
2061
+ " \xD7"
2062
+ ]
2063
+ },
2064
+ tag
2065
+ ))
2066
+ ] }),
2067
+ /* @__PURE__ */ jsxs("div", { style: styles5.customTagRow, children: [
2068
+ /* @__PURE__ */ jsx(
2069
+ "input",
2070
+ {
2071
+ type: "text",
2072
+ value: customTag,
2073
+ onChange: (e) => setCustomTag(e.target.value),
2074
+ onKeyDown: (e) => e.key === "Enter" && addCustomTag(),
2075
+ placeholder: "Add custom tag...",
2076
+ style: styles5.customTagInput
2077
+ }
2078
+ ),
2079
+ /* @__PURE__ */ jsx(
2080
+ "button",
2081
+ {
2082
+ onClick: addCustomTag,
2083
+ disabled: !customTag,
2084
+ style: {
2085
+ ...styles5.addTagButton,
2086
+ opacity: customTag ? 1 : 0.5
2087
+ },
2088
+ children: "+"
2089
+ }
2090
+ )
2091
+ ] })
2092
+ ] }),
2093
+ componentContext && /* @__PURE__ */ jsxs("div", { style: styles5.section, children: [
2094
+ /* @__PURE__ */ jsx("label", { style: styles5.label, children: "Context" }),
2095
+ /* @__PURE__ */ jsxs("div", { style: styles5.contextRow, children: [
2096
+ componentContext.name && /* @__PURE__ */ jsxs("span", { style: styles5.contextBadge, children: [
2097
+ "Component: ",
2098
+ componentContext.name
2099
+ ] }),
2100
+ componentContext.effect && /* @__PURE__ */ jsxs("span", { style: styles5.contextBadge, children: [
2101
+ "Effect: ",
2102
+ componentContext.effect
2103
+ ] }),
2104
+ componentContext.lensAddress && /* @__PURE__ */ jsxs("span", { style: styles5.contextBadge, children: [
2105
+ "Lens: ",
2106
+ componentContext.lensAddress.slice(0, 6),
2107
+ "..."
2108
+ ] })
2109
+ ] })
2110
+ ] }),
2111
+ /* @__PURE__ */ jsxs("div", { style: styles5.actions, children: [
2112
+ /* @__PURE__ */ jsx("button", { onClick: onClose, style: styles5.cancelButton, children: "Cancel" }),
2113
+ /* @__PURE__ */ jsx(
2114
+ "button",
2115
+ {
2116
+ onClick: handleSubmit,
2117
+ disabled: !content.trim(),
2118
+ style: {
2119
+ ...styles5.submitButton,
2120
+ backgroundColor: content.trim() ? config.bgColor : "rgba(255, 255, 255, 0.02)",
2121
+ borderColor: content.trim() ? config.color : "rgba(255, 255, 255, 0.1)",
2122
+ color: content.trim() ? config.color : "#666",
2123
+ cursor: content.trim() ? "pointer" : "not-allowed"
2124
+ },
2125
+ children: "Capture (\u2318+Enter)"
2126
+ }
2127
+ )
2128
+ ] })
2129
+ ] }) });
2130
+ }
2131
+ var styles5 = {
2132
+ overlay: {
2133
+ position: "fixed",
2134
+ top: 0,
2135
+ left: 0,
2136
+ right: 0,
2137
+ bottom: 0,
2138
+ backgroundColor: "rgba(0, 0, 0, 0.6)",
2139
+ backdropFilter: "blur(4px)",
2140
+ display: "flex",
2141
+ alignItems: "center",
2142
+ justifyContent: "center",
2143
+ zIndex: 1e4
2144
+ },
2145
+ modal: {
2146
+ width: "100%",
2147
+ maxWidth: "480px",
2148
+ backgroundColor: "#1a1a1a",
2149
+ borderRadius: "12px",
2150
+ border: "1px solid rgba(255, 255, 255, 0.1)",
2151
+ boxShadow: "0 20px 40px rgba(0, 0, 0, 0.4)",
2152
+ overflow: "hidden"
2153
+ },
2154
+ header: {
2155
+ display: "flex",
2156
+ justifyContent: "space-between",
2157
+ alignItems: "center",
2158
+ padding: "16px 20px",
2159
+ borderBottom: "1px solid rgba(255, 255, 255, 0.05)"
2160
+ },
2161
+ title: {
2162
+ margin: 0,
2163
+ fontSize: "14px",
2164
+ fontWeight: 600,
2165
+ color: "#fff"
2166
+ },
2167
+ closeButton: {
2168
+ width: "28px",
2169
+ height: "28px",
2170
+ display: "flex",
2171
+ alignItems: "center",
2172
+ justifyContent: "center",
2173
+ backgroundColor: "transparent",
2174
+ border: "none",
2175
+ borderRadius: "4px",
2176
+ color: "#888",
2177
+ fontSize: "20px",
2178
+ cursor: "pointer"
2179
+ },
2180
+ section: {
2181
+ padding: "16px 20px"
2182
+ },
2183
+ label: {
2184
+ display: "block",
2185
+ fontSize: "11px",
2186
+ fontWeight: 600,
2187
+ color: "#888",
2188
+ textTransform: "uppercase",
2189
+ letterSpacing: "0.5px",
2190
+ marginBottom: "8px"
2191
+ },
2192
+ typeButtons: {
2193
+ display: "flex",
2194
+ gap: "8px"
2195
+ },
2196
+ typeButton: {
2197
+ flex: 1,
2198
+ padding: "8px 12px",
2199
+ borderRadius: "6px",
2200
+ border: "1px solid",
2201
+ fontSize: "12px",
2202
+ fontWeight: 500,
2203
+ cursor: "pointer",
2204
+ transition: "all 0.15s ease-out"
2205
+ },
2206
+ typeDescription: {
2207
+ margin: "8px 0 0 0",
2208
+ fontSize: "11px",
2209
+ color: "#666",
2210
+ fontStyle: "italic"
2211
+ },
2212
+ textarea: {
2213
+ width: "100%",
2214
+ padding: "12px",
2215
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
2216
+ border: "1px solid rgba(255, 255, 255, 0.1)",
2217
+ borderRadius: "6px",
2218
+ color: "#fff",
2219
+ fontSize: "13px",
2220
+ fontFamily: "inherit",
2221
+ resize: "vertical",
2222
+ lineHeight: 1.5
2223
+ },
2224
+ tagContainer: {
2225
+ display: "flex",
2226
+ flexWrap: "wrap",
2227
+ gap: "6px"
2228
+ },
2229
+ tag: {
2230
+ padding: "4px 8px",
2231
+ borderRadius: "4px",
2232
+ border: "1px solid",
2233
+ fontSize: "11px",
2234
+ cursor: "pointer",
2235
+ transition: "all 0.15s ease-out"
2236
+ },
2237
+ customTagRow: {
2238
+ display: "flex",
2239
+ gap: "8px",
2240
+ marginTop: "8px"
2241
+ },
2242
+ customTagInput: {
2243
+ flex: 1,
2244
+ padding: "6px 10px",
2245
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
2246
+ border: "1px solid rgba(255, 255, 255, 0.1)",
2247
+ borderRadius: "4px",
2248
+ color: "#fff",
2249
+ fontSize: "11px",
2250
+ fontFamily: "inherit"
2251
+ },
2252
+ addTagButton: {
2253
+ width: "28px",
2254
+ height: "28px",
2255
+ display: "flex",
2256
+ alignItems: "center",
2257
+ justifyContent: "center",
2258
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
2259
+ border: "1px solid rgba(255, 255, 255, 0.1)",
2260
+ borderRadius: "4px",
2261
+ color: "#888",
2262
+ fontSize: "16px",
2263
+ cursor: "pointer"
2264
+ },
2265
+ contextRow: {
2266
+ display: "flex",
2267
+ flexWrap: "wrap",
2268
+ gap: "6px"
2269
+ },
2270
+ contextBadge: {
2271
+ padding: "4px 8px",
2272
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
2273
+ border: "1px solid rgba(255, 255, 255, 0.05)",
2274
+ borderRadius: "4px",
2275
+ fontSize: "10px",
2276
+ color: "#888"
2277
+ },
2278
+ actions: {
2279
+ display: "flex",
2280
+ justifyContent: "flex-end",
2281
+ gap: "8px",
2282
+ padding: "16px 20px",
2283
+ borderTop: "1px solid rgba(255, 255, 255, 0.05)"
2284
+ },
2285
+ cancelButton: {
2286
+ padding: "8px 16px",
2287
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
2288
+ border: "1px solid rgba(255, 255, 255, 0.1)",
2289
+ borderRadius: "6px",
2290
+ color: "#888",
2291
+ fontSize: "12px",
2292
+ cursor: "pointer"
2293
+ },
2294
+ submitButton: {
2295
+ padding: "8px 16px",
2296
+ borderRadius: "6px",
2297
+ border: "1px solid",
2298
+ fontSize: "12px",
2299
+ fontWeight: 500,
2300
+ transition: "all 0.15s ease-out"
2301
+ }
2302
+ };
2303
+ function useSignalCapture({
2304
+ enabled = true,
2305
+ onSignal
2306
+ } = {}) {
2307
+ const signalsRef = useRef([]);
2308
+ const appendSignal = useCallback(
2309
+ async (signalData) => {
2310
+ if (!enabled)
2311
+ return;
2312
+ const signal = {
2313
+ ...signalData,
2314
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2315
+ source: "hud"
2316
+ };
2317
+ signalsRef.current.push(signal);
2318
+ onSignal?.(signal);
2319
+ if (process.env.NODE_ENV === "development") {
2320
+ console.log("[Sigil HUD] Signal captured:", signal);
2321
+ }
2322
+ },
2323
+ [enabled, onSignal]
2324
+ );
2325
+ const accept = useCallback(
2326
+ (component, effect, craftType = "generate") => {
2327
+ return appendSignal({
2328
+ signal: "ACCEPT",
2329
+ component: {
2330
+ name: component,
2331
+ effect,
2332
+ craft_type: craftType
2333
+ }
2334
+ });
2335
+ },
2336
+ [appendSignal]
2337
+ );
2338
+ const modify = useCallback(
2339
+ (component, effect, change, learning) => {
2340
+ return appendSignal({
2341
+ signal: "MODIFY",
2342
+ component: {
2343
+ name: component,
2344
+ effect,
2345
+ craft_type: "generate"
2346
+ },
2347
+ change,
2348
+ learning
2349
+ });
2350
+ },
2351
+ [appendSignal]
2352
+ );
2353
+ const reject = useCallback(
2354
+ (component, effect, reason) => {
2355
+ return appendSignal({
2356
+ signal: "REJECT",
2357
+ component: {
2358
+ name: component,
2359
+ effect,
2360
+ craft_type: "generate"
2361
+ },
2362
+ rejection_reason: reason
2363
+ });
2364
+ },
2365
+ [appendSignal]
2366
+ );
2367
+ const getSignals = useCallback(() => {
2368
+ return [...signalsRef.current];
2369
+ }, []);
2370
+ const clearSignals = useCallback(() => {
2371
+ signalsRef.current = [];
2372
+ }, []);
2373
+ return {
2374
+ appendSignal,
2375
+ accept,
2376
+ modify,
2377
+ reject,
2378
+ getSignals,
2379
+ clearSignals
2380
+ };
2381
+ }
2382
+ var defaultOptions = [
2383
+ {
2384
+ id: "looks-good",
2385
+ label: "Looks good",
2386
+ description: "The physics feel right for this use case",
2387
+ signal: "ACCEPT"
2388
+ },
2389
+ {
2390
+ id: "timing-off",
2391
+ label: "Timing feels off",
2392
+ description: "The duration should be faster or slower",
2393
+ signal: "MODIFY"
2394
+ },
2395
+ {
2396
+ id: "animation-wrong",
2397
+ label: "Animation wrong",
2398
+ description: "The easing or motion feels incorrect",
2399
+ signal: "MODIFY"
2400
+ },
2401
+ {
2402
+ id: "needs-confirmation",
2403
+ label: "Needs confirmation",
2404
+ description: "Should have (or shouldn't have) a confirmation step",
2405
+ signal: "MODIFY"
2406
+ },
2407
+ {
2408
+ id: "other",
2409
+ label: "Something else",
2410
+ description: "Describe what feels wrong",
2411
+ signal: "MODIFY"
2412
+ }
2413
+ ];
2414
+ function FeedbackPrompt({
2415
+ componentName,
2416
+ effect,
2417
+ physics,
2418
+ options = defaultOptions,
2419
+ onFeedback,
2420
+ onClose,
2421
+ visible = true,
2422
+ className = ""
2423
+ }) {
2424
+ const [selectedOption, setSelectedOption] = useState(null);
2425
+ const [customFeedback, setCustomFeedback] = useState("");
2426
+ const [showDetailInput, setShowDetailInput] = useState(false);
2427
+ const { accept, modify, reject } = useSignalCapture({ enabled: true });
2428
+ const { captureInsight, captureIssue } = useObservationCapture({ enabled: true });
2429
+ const handleSelectOption = useCallback((option) => {
2430
+ setSelectedOption(option);
2431
+ if (option.signal === "ACCEPT") {
2432
+ handleSubmit(option, "");
2433
+ } else if (option.id === "other") {
2434
+ setShowDetailInput(true);
2435
+ } else {
2436
+ setShowDetailInput(true);
2437
+ }
2438
+ }, []);
2439
+ const handleSubmit = useCallback(
2440
+ async (option, detail) => {
2441
+ let observation;
2442
+ if (option.signal === "ACCEPT") {
2443
+ await accept(componentName, effect, "diagnose");
2444
+ } else if (option.signal === "MODIFY") {
2445
+ const content = detail || option.description;
2446
+ observation = await captureInsight(content, {
2447
+ component: componentName,
2448
+ effect
2449
+ });
2450
+ await modify(
2451
+ componentName,
2452
+ effect,
2453
+ { from: "current", to: content },
2454
+ { inference: `User feedback: ${option.label}` }
2455
+ );
2456
+ } else if (option.signal === "REJECT") {
2457
+ observation = await captureIssue(detail || option.description, {
2458
+ component: componentName,
2459
+ effect
2460
+ });
2461
+ await reject(componentName, effect, detail || option.description);
2462
+ }
2463
+ const signal = {
2464
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2465
+ signal: option.signal,
2466
+ source: "hud",
2467
+ component: {
2468
+ name: componentName,
2469
+ effect,
2470
+ craft_type: "diagnose"
2471
+ },
2472
+ physics,
2473
+ hud_context: {
2474
+ panel_visible: true,
2475
+ diagnostics_shown: true,
2476
+ observation_linked: observation?.id
2477
+ }
2478
+ };
2479
+ onFeedback?.(signal, observation);
2480
+ setSelectedOption(null);
2481
+ setCustomFeedback("");
2482
+ setShowDetailInput(false);
2483
+ onClose?.();
2484
+ },
2485
+ [componentName, effect, physics, accept, modify, reject, captureInsight, captureIssue, onFeedback, onClose]
2486
+ );
2487
+ const handleCancel = useCallback(() => {
2488
+ setSelectedOption(null);
2489
+ setCustomFeedback("");
2490
+ setShowDetailInput(false);
2491
+ onClose?.();
2492
+ }, [onClose]);
2493
+ if (!visible)
2494
+ return null;
2495
+ return /* @__PURE__ */ jsxs("div", { className, style: styles6.container, children: [
2496
+ /* @__PURE__ */ jsx("div", { style: styles6.promptRow, children: /* @__PURE__ */ jsx("span", { style: styles6.promptText, children: "Does this feel right for your user?" }) }),
2497
+ !showDetailInput && /* @__PURE__ */ jsx("div", { style: styles6.optionsGrid, children: options.map((option) => /* @__PURE__ */ jsx(
2498
+ "button",
2499
+ {
2500
+ onClick: () => handleSelectOption(option),
2501
+ style: {
2502
+ ...styles6.optionButton,
2503
+ borderColor: option.signal === "ACCEPT" ? "rgba(34, 197, 94, 0.3)" : option.signal === "REJECT" ? "rgba(239, 68, 68, 0.3)" : "rgba(255, 255, 255, 0.1)"
2504
+ },
2505
+ children: /* @__PURE__ */ jsx("span", { style: styles6.optionLabel, children: option.label })
2506
+ },
2507
+ option.id
2508
+ )) }),
2509
+ showDetailInput && selectedOption && /* @__PURE__ */ jsxs("div", { style: styles6.detailSection, children: [
2510
+ /* @__PURE__ */ jsx("p", { style: styles6.detailPrompt, children: selectedOption.id === "other" ? "What feels wrong?" : `Describe what would feel better:` }),
2511
+ /* @__PURE__ */ jsx(
2512
+ "textarea",
2513
+ {
2514
+ value: customFeedback,
2515
+ onChange: (e) => setCustomFeedback(e.target.value),
2516
+ placeholder: selectedOption.id === "timing-off" ? 'e.g., "Should be faster, around 500ms..."' : selectedOption.id === "animation-wrong" ? 'e.g., "Should use spring instead of ease-out..."' : "Describe the issue or desired feel...",
2517
+ rows: 2,
2518
+ style: styles6.detailTextarea,
2519
+ autoFocus: true
2520
+ }
2521
+ ),
2522
+ /* @__PURE__ */ jsxs("div", { style: styles6.detailActions, children: [
2523
+ /* @__PURE__ */ jsx("button", { onClick: handleCancel, style: styles6.cancelButton, children: "Cancel" }),
2524
+ /* @__PURE__ */ jsx(
2525
+ "button",
2526
+ {
2527
+ onClick: () => handleSubmit(selectedOption, customFeedback),
2528
+ disabled: selectedOption.id === "other" && !customFeedback.trim(),
2529
+ style: {
2530
+ ...styles6.submitButton,
2531
+ opacity: selectedOption.id === "other" && !customFeedback.trim() ? 0.5 : 1
2532
+ },
2533
+ children: "Submit Feedback"
2534
+ }
2535
+ )
2536
+ ] })
2537
+ ] })
2538
+ ] });
2539
+ }
2540
+ var styles6 = {
2541
+ container: {
2542
+ padding: "12px",
2543
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
2544
+ borderRadius: "8px",
2545
+ border: "1px solid rgba(255, 255, 255, 0.05)"
2546
+ },
2547
+ promptRow: {
2548
+ marginBottom: "12px"
2549
+ },
2550
+ promptText: {
2551
+ fontSize: "11px",
2552
+ fontWeight: 600,
2553
+ color: "#888",
2554
+ textTransform: "uppercase",
2555
+ letterSpacing: "0.5px"
2556
+ },
2557
+ optionsGrid: {
2558
+ display: "grid",
2559
+ gridTemplateColumns: "repeat(2, 1fr)",
2560
+ gap: "6px"
2561
+ },
2562
+ optionButton: {
2563
+ padding: "8px 10px",
2564
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
2565
+ border: "1px solid",
2566
+ borderRadius: "4px",
2567
+ textAlign: "left",
2568
+ cursor: "pointer",
2569
+ transition: "all 0.15s ease-out"
2570
+ },
2571
+ optionLabel: {
2572
+ fontSize: "11px",
2573
+ color: "#fff"
2574
+ },
2575
+ detailSection: {
2576
+ display: "flex",
2577
+ flexDirection: "column",
2578
+ gap: "8px"
2579
+ },
2580
+ detailPrompt: {
2581
+ margin: 0,
2582
+ fontSize: "12px",
2583
+ color: "#888"
2584
+ },
2585
+ detailTextarea: {
2586
+ width: "100%",
2587
+ padding: "8px",
2588
+ backgroundColor: "rgba(255, 255, 255, 0.05)",
2589
+ border: "1px solid rgba(255, 255, 255, 0.1)",
2590
+ borderRadius: "4px",
2591
+ color: "#fff",
2592
+ fontSize: "11px",
2593
+ fontFamily: "inherit",
2594
+ resize: "vertical"
2595
+ },
2596
+ detailActions: {
2597
+ display: "flex",
2598
+ justifyContent: "flex-end",
2599
+ gap: "8px"
2600
+ },
2601
+ cancelButton: {
2602
+ padding: "6px 12px",
2603
+ backgroundColor: "rgba(255, 255, 255, 0.02)",
2604
+ border: "1px solid rgba(255, 255, 255, 0.1)",
2605
+ borderRadius: "4px",
2606
+ color: "#888",
2607
+ fontSize: "11px",
2608
+ cursor: "pointer"
2609
+ },
2610
+ submitButton: {
2611
+ padding: "6px 12px",
2612
+ backgroundColor: "rgba(59, 130, 246, 0.2)",
2613
+ border: "1px solid rgba(59, 130, 246, 0.3)",
2614
+ borderRadius: "4px",
2615
+ color: "#3b82f6",
2616
+ fontSize: "11px",
2617
+ cursor: "pointer"
2618
+ }
2619
+ };
2620
+ function useKeyboardShortcuts({
2621
+ enabled = true,
2622
+ customShortcuts = {}
2623
+ } = {}) {
2624
+ const toggle = useHudStore((state) => state.toggle);
2625
+ const setActivePanel = useHudStore((state) => state.setActivePanel);
2626
+ const isOpen = useHudStore((state) => state.isOpen);
2627
+ const handleKeyDown = useCallback(
2628
+ (event) => {
2629
+ if (!enabled)
2630
+ return;
2631
+ const target = event.target;
2632
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable) {
2633
+ return;
2634
+ }
2635
+ if ((event.metaKey || event.ctrlKey) && event.shiftKey && event.key === "d") {
2636
+ event.preventDefault();
2637
+ toggle();
2638
+ return;
2639
+ }
2640
+ if (!isOpen)
2641
+ return;
2642
+ const panelMap = {
2643
+ "1": "lens",
2644
+ "2": "simulation",
2645
+ "3": "diagnostics",
2646
+ "4": "state",
2647
+ "5": "signals"
2648
+ };
2649
+ if (panelMap[event.key]) {
2650
+ event.preventDefault();
2651
+ setActivePanel(panelMap[event.key]);
2652
+ return;
2653
+ }
2654
+ if (event.key === "Escape") {
2655
+ event.preventDefault();
2656
+ toggle();
2657
+ return;
2658
+ }
2659
+ const shortcutKey = getShortcutKey(event);
2660
+ if (customShortcuts[shortcutKey]) {
2661
+ event.preventDefault();
2662
+ customShortcuts[shortcutKey]();
2663
+ }
2664
+ },
2665
+ [enabled, toggle, setActivePanel, isOpen, customShortcuts]
2666
+ );
2667
+ useEffect(() => {
2668
+ if (!enabled)
2669
+ return;
2670
+ window.addEventListener("keydown", handleKeyDown);
2671
+ return () => window.removeEventListener("keydown", handleKeyDown);
2672
+ }, [enabled, handleKeyDown]);
2673
+ }
2674
+ function getShortcutKey(event) {
2675
+ const parts = [];
2676
+ if (event.metaKey)
2677
+ parts.push("cmd");
2678
+ if (event.ctrlKey)
2679
+ parts.push("ctrl");
2680
+ if (event.altKey)
2681
+ parts.push("alt");
2682
+ if (event.shiftKey)
2683
+ parts.push("shift");
2684
+ parts.push(event.key.toLowerCase());
2685
+ return parts.join("+");
2686
+ }
2687
+ function getShortcutHelp() {
2688
+ return [
2689
+ { keys: "\u2318\u21E7D", description: "Toggle HUD" },
2690
+ { keys: "1-5", description: "Switch panels (when open)" },
2691
+ { keys: "Esc", description: "Close HUD" }
2692
+ ];
2693
+ }
2694
+ var DEFAULT_STALE_SECONDS = 60;
2695
+ var DEFAULT_VERY_STALE_SECONDS = 300;
2696
+ var DEFAULT_STALE_BLOCKS = 5;
2697
+ var DEFAULT_VERY_STALE_BLOCKS = 20;
2698
+ var DEFAULT_POLL_INTERVAL = 1e4;
2699
+ function calculateTimeStaleness(fetchedAt, staleThreshold, veryStaleThreshold) {
2700
+ const secondsAgo = Math.floor((Date.now() - fetchedAt) / 1e3);
2701
+ if (secondsAgo < 30) {
2702
+ return { isStale: false, level: "fresh", label: "just now" };
2703
+ }
2704
+ if (secondsAgo < 60) {
2705
+ return { isStale: false, level: "fresh", label: `${secondsAgo}s ago` };
2706
+ }
2707
+ if (secondsAgo < staleThreshold) {
2708
+ return { isStale: false, level: "fresh", label: `${Math.floor(secondsAgo / 60)}m ago` };
2709
+ }
2710
+ if (secondsAgo < veryStaleThreshold) {
2711
+ return { isStale: true, level: "stale", label: `${Math.floor(secondsAgo / 60)}m ago` };
2712
+ }
2713
+ return { isStale: true, level: "very-stale", label: `${Math.floor(secondsAgo / 60)}m ago` };
2714
+ }
2715
+ function calculateBlockStaleness(blockNumber, currentBlock, staleThreshold, veryStaleThreshold) {
2716
+ const blocksBehind = currentBlock - blockNumber;
2717
+ if (blocksBehind <= 1) {
2718
+ return { isStale: false, level: "fresh", label: "current" };
2719
+ }
2720
+ if (blocksBehind <= staleThreshold) {
2721
+ return { isStale: false, level: "fresh", label: `${blocksBehind} blocks behind` };
2722
+ }
2723
+ if (blocksBehind <= veryStaleThreshold) {
2724
+ return { isStale: true, level: "stale", label: `${blocksBehind} blocks behind` };
2725
+ }
2726
+ return { isStale: true, level: "very-stale", label: `${blocksBehind} blocks behind` };
2727
+ }
2728
+ function useDataSource({
2729
+ source,
2730
+ blockNumber,
2731
+ pollInterval = DEFAULT_POLL_INTERVAL,
2732
+ staleThresholdSeconds = DEFAULT_STALE_SECONDS,
2733
+ veryStaleThresholdSeconds = DEFAULT_VERY_STALE_SECONDS,
2734
+ staleThresholdBlocks = DEFAULT_STALE_BLOCKS,
2735
+ veryStaleThresholdBlocks = DEFAULT_VERY_STALE_BLOCKS,
2736
+ onStale
2737
+ }) {
2738
+ const [meta, setMeta] = useState(() => ({
2739
+ source,
2740
+ fetchedAt: Date.now(),
2741
+ blockNumber,
2742
+ currentBlock: blockNumber,
2743
+ isStale: false,
2744
+ stalenessLevel: "fresh",
2745
+ stalenessLabel: "just now"
2746
+ }));
2747
+ const wasStaleRef = useRef(false);
2748
+ const onStaleRef = useRef(onStale);
2749
+ onStaleRef.current = onStale;
2750
+ const markRefreshed = useCallback(
2751
+ (newBlockNumber) => {
2752
+ setMeta((prev) => ({
2753
+ ...prev,
2754
+ fetchedAt: Date.now(),
2755
+ blockNumber: newBlockNumber ?? prev.blockNumber,
2756
+ currentBlock: newBlockNumber ?? prev.currentBlock,
2757
+ isStale: false,
2758
+ stalenessLevel: "fresh",
2759
+ stalenessLabel: "just now"
2760
+ }));
2761
+ wasStaleRef.current = false;
2762
+ },
2763
+ []
2764
+ );
2765
+ const updateCurrentBlock = useCallback((newCurrentBlock) => {
2766
+ setMeta((prev) => ({
2767
+ ...prev,
2768
+ currentBlock: newCurrentBlock
2769
+ }));
2770
+ }, []);
2771
+ const recalculateStaleness = useCallback(() => {
2772
+ setMeta((prev) => {
2773
+ let staleness;
2774
+ if (source === "on-chain" && prev.blockNumber && prev.currentBlock) {
2775
+ staleness = calculateBlockStaleness(
2776
+ prev.blockNumber,
2777
+ prev.currentBlock,
2778
+ staleThresholdBlocks,
2779
+ veryStaleThresholdBlocks
2780
+ );
2781
+ } else {
2782
+ staleness = calculateTimeStaleness(
2783
+ prev.fetchedAt,
2784
+ staleThresholdSeconds,
2785
+ veryStaleThresholdSeconds
2786
+ );
2787
+ }
2788
+ if (staleness.isStale && !wasStaleRef.current) {
2789
+ wasStaleRef.current = true;
2790
+ onStaleRef.current?.();
2791
+ }
2792
+ return {
2793
+ ...prev,
2794
+ isStale: staleness.isStale,
2795
+ stalenessLevel: staleness.level,
2796
+ stalenessLabel: staleness.label
2797
+ };
2798
+ });
2799
+ }, [
2800
+ source,
2801
+ staleThresholdSeconds,
2802
+ veryStaleThresholdSeconds,
2803
+ staleThresholdBlocks,
2804
+ veryStaleThresholdBlocks
2805
+ ]);
2806
+ useEffect(() => {
2807
+ const interval = setInterval(recalculateStaleness, pollInterval);
2808
+ return () => clearInterval(interval);
2809
+ }, [recalculateStaleness, pollInterval]);
2810
+ useEffect(() => {
2811
+ setMeta((prev) => ({
2812
+ ...prev,
2813
+ source,
2814
+ blockNumber: blockNumber ?? prev.blockNumber
2815
+ }));
2816
+ recalculateStaleness();
2817
+ }, [source, blockNumber, recalculateStaleness]);
2818
+ return {
2819
+ meta,
2820
+ markRefreshed,
2821
+ updateCurrentBlock,
2822
+ recalculateStaleness
2823
+ };
2824
+ }
2825
+ function useMultipleDataSources(entries) {
2826
+ const [sources, setSources] = useState(/* @__PURE__ */ new Map());
2827
+ useEffect(() => {
2828
+ const newSources = /* @__PURE__ */ new Map();
2829
+ const now = Date.now();
2830
+ for (const entry of entries) {
2831
+ newSources.set(entry.key, {
2832
+ source: entry.source,
2833
+ fetchedAt: now,
2834
+ blockNumber: entry.blockNumber,
2835
+ currentBlock: entry.blockNumber,
2836
+ isStale: false,
2837
+ stalenessLevel: "fresh",
2838
+ stalenessLabel: "just now"
2839
+ });
2840
+ }
2841
+ setSources(newSources);
2842
+ }, [entries]);
2843
+ const markRefreshed = useCallback((key, newBlockNumber) => {
2844
+ setSources((prev) => {
2845
+ const newMap = new Map(prev);
2846
+ const existing = newMap.get(key);
2847
+ if (existing) {
2848
+ newMap.set(key, {
2849
+ ...existing,
2850
+ fetchedAt: Date.now(),
2851
+ blockNumber: newBlockNumber ?? existing.blockNumber,
2852
+ currentBlock: newBlockNumber ?? existing.currentBlock,
2853
+ isStale: false,
2854
+ stalenessLevel: "fresh",
2855
+ stalenessLabel: "just now"
2856
+ });
2857
+ }
2858
+ return newMap;
2859
+ });
2860
+ }, []);
2861
+ const getMeta = useCallback(
2862
+ (key) => {
2863
+ return sources.get(key);
2864
+ },
2865
+ [sources]
2866
+ );
2867
+ const getStaleSources = useCallback(() => {
2868
+ const stale = [];
2869
+ sources.forEach((meta, key) => {
2870
+ if (meta.isStale) {
2871
+ stale.push(key);
2872
+ }
2873
+ });
2874
+ return stale;
2875
+ }, [sources]);
2876
+ return {
2877
+ sources,
2878
+ markRefreshed,
2879
+ getMeta,
2880
+ getStaleSources
2881
+ };
2882
+ }
2883
+
2884
+ // src/styles/theme.ts
2885
+ var colors = {
2886
+ // Brand
2887
+ primary: "#10b981",
2888
+ // emerald-500
2889
+ primaryLight: "rgba(16, 185, 129, 0.2)",
2890
+ primaryBorder: "rgba(16, 185, 129, 0.3)",
2891
+ // Status
2892
+ success: "#22c55e",
2893
+ // green-500
2894
+ successLight: "rgba(34, 197, 94, 0.1)",
2895
+ successBorder: "rgba(34, 197, 94, 0.3)",
2896
+ warning: "#eab308",
2897
+ // yellow-500
2898
+ warningLight: "rgba(234, 179, 8, 0.1)",
2899
+ warningBorder: "rgba(234, 179, 8, 0.3)",
2900
+ error: "#ef4444",
2901
+ // red-500
2902
+ errorLight: "rgba(239, 68, 68, 0.1)",
2903
+ errorBorder: "rgba(239, 68, 68, 0.3)",
2904
+ info: "#3b82f6",
2905
+ // blue-500
2906
+ infoLight: "rgba(59, 130, 246, 0.1)",
2907
+ infoBorder: "rgba(59, 130, 246, 0.3)",
2908
+ // Neutral
2909
+ text: "#fff",
2910
+ textMuted: "#888",
2911
+ textDim: "#666",
2912
+ textDisabled: "#555",
2913
+ background: "rgba(0, 0, 0, 0.9)",
2914
+ backgroundElevated: "rgba(26, 26, 26, 1)",
2915
+ backgroundHover: "rgba(255, 255, 255, 0.05)",
2916
+ backgroundActive: "rgba(255, 255, 255, 0.08)",
2917
+ backgroundInput: "rgba(255, 255, 255, 0.02)",
2918
+ border: "rgba(255, 255, 255, 0.1)",
2919
+ borderSubtle: "rgba(255, 255, 255, 0.05)",
2920
+ borderStrong: "rgba(255, 255, 255, 0.2)",
2921
+ // Effects
2922
+ financial: "#ef4444",
2923
+ destructive: "#f97316",
2924
+ softDelete: "#eab308",
2925
+ standard: "#22c55e",
2926
+ local: "#3b82f6",
2927
+ navigation: "#8b5cf6",
2928
+ query: "#06b6d4"
2929
+ };
2930
+ var typography = {
2931
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
2932
+ fontFamilySans: "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif",
2933
+ // Sizes
2934
+ xs: "10px",
2935
+ sm: "11px",
2936
+ base: "12px",
2937
+ md: "13px",
2938
+ lg: "14px",
2939
+ // Weights
2940
+ normal: 400,
2941
+ medium: 500,
2942
+ semibold: 600,
2943
+ bold: 700,
2944
+ // Line heights
2945
+ lineHeightTight: 1.25,
2946
+ lineHeightNormal: 1.5,
2947
+ lineHeightRelaxed: 1.6,
2948
+ // Letter spacing
2949
+ letterSpacingTight: "-0.02em",
2950
+ letterSpacingNormal: "0",
2951
+ letterSpacingWide: "0.5px"
2952
+ };
2953
+ var spacing = {
2954
+ xs: "4px",
2955
+ sm: "6px",
2956
+ md: "8px",
2957
+ lg: "12px",
2958
+ xl: "16px",
2959
+ "2xl": "20px",
2960
+ "3xl": "24px"
2961
+ };
2962
+ var radii = {
2963
+ sm: "4px",
2964
+ md: "6px",
2965
+ lg: "8px",
2966
+ xl: "12px",
2967
+ full: "9999px"
2968
+ };
2969
+ var shadows = {
2970
+ sm: "0 2px 4px rgba(0, 0, 0, 0.2)",
2971
+ md: "0 4px 12px rgba(0, 0, 0, 0.3)",
2972
+ lg: "0 8px 20px rgba(0, 0, 0, 0.4)",
2973
+ xl: "0 20px 40px rgba(0, 0, 0, 0.5)",
2974
+ primary: "0 4px 12px rgba(16, 185, 129, 0.3)",
2975
+ primaryHover: "0 6px 16px rgba(16, 185, 129, 0.4)"
2976
+ };
2977
+ var transitions = {
2978
+ fast: "0.1s ease-out",
2979
+ normal: "0.15s ease-out",
2980
+ slow: "0.2s ease-out",
2981
+ spring: "0.3s cubic-bezier(0.34, 1.56, 0.64, 1)"
2982
+ };
2983
+ var zIndex = {
2984
+ base: 1,
2985
+ dropdown: 100,
2986
+ sticky: 1e3,
2987
+ fixed: 5e3,
2988
+ modal: 1e4,
2989
+ tooltip: 15e3
2990
+ };
2991
+ var patterns = {
2992
+ // Buttons
2993
+ button: {
2994
+ base: {
2995
+ padding: `${spacing.md} ${spacing.lg}`,
2996
+ borderRadius: radii.md,
2997
+ fontSize: typography.sm,
2998
+ fontWeight: typography.medium,
2999
+ cursor: "pointer",
3000
+ transition: transitions.normal,
3001
+ border: "1px solid"
3002
+ },
3003
+ primary: {
3004
+ backgroundColor: colors.primaryLight,
3005
+ borderColor: colors.primaryBorder,
3006
+ color: colors.primary
3007
+ },
3008
+ secondary: {
3009
+ backgroundColor: colors.backgroundInput,
3010
+ borderColor: colors.border,
3011
+ color: colors.textMuted
3012
+ },
3013
+ danger: {
3014
+ backgroundColor: colors.errorLight,
3015
+ borderColor: colors.errorBorder,
3016
+ color: colors.error
3017
+ }
3018
+ },
3019
+ // Inputs
3020
+ input: {
3021
+ base: {
3022
+ padding: spacing.md,
3023
+ backgroundColor: colors.backgroundInput,
3024
+ border: `1px solid ${colors.border}`,
3025
+ borderRadius: radii.md,
3026
+ color: colors.text,
3027
+ fontSize: typography.sm,
3028
+ fontFamily: typography.fontFamily
3029
+ }
3030
+ },
3031
+ // Cards
3032
+ card: {
3033
+ base: {
3034
+ padding: spacing.lg,
3035
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
3036
+ borderRadius: radii.lg,
3037
+ border: `1px solid ${colors.borderSubtle}`
3038
+ }
3039
+ },
3040
+ // Labels
3041
+ label: {
3042
+ base: {
3043
+ fontSize: typography.xs,
3044
+ fontWeight: typography.semibold,
3045
+ color: colors.textMuted,
3046
+ textTransform: "uppercase",
3047
+ letterSpacing: typography.letterSpacingWide
3048
+ }
3049
+ },
3050
+ // Badges
3051
+ badge: {
3052
+ base: {
3053
+ padding: `2px ${spacing.sm}`,
3054
+ borderRadius: radii.sm,
3055
+ fontSize: "9px",
3056
+ fontWeight: typography.semibold,
3057
+ border: "1px solid",
3058
+ textTransform: "uppercase",
3059
+ letterSpacing: "0.3px"
3060
+ }
3061
+ }
3062
+ };
3063
+ var effectColors2 = {
3064
+ financial: colors.financial,
3065
+ destructive: colors.destructive,
3066
+ "soft-delete": colors.softDelete,
3067
+ standard: colors.standard,
3068
+ local: colors.local,
3069
+ navigation: colors.navigation,
3070
+ query: colors.query
3071
+ };
3072
+ function getEffectColor(effect) {
3073
+ return effectColors2[effect] ?? colors.textMuted;
3074
+ }
3075
+ function createStyles(styles7) {
3076
+ return styles7;
3077
+ }
3078
+
3079
+ export { DEFAULT_HUD_CONFIG, DEFAULT_HUD_STATE, DEFAULT_LENS_STATE, DataSourceIndicator, DiagnosticsPanel, FeedbackPrompt, HudPanel, HudProvider, HudTrigger, IssueList, LensPanel, ObservationCaptureModal, PhysicsAnalysis, SimulationPanel, StateComparison, colors, createStyles, effectColors2 as effectColors, getEffectColor, getHudState, getShortcutHelp, patterns, radii, shadows, spacing, transitions, typography, useDataSource, useHud, useHudOptional, useHudStore, useKeyboardShortcuts, useMultipleDataSources, useObservationCapture, useSignalCapture, zIndex };