@nice-code/action 0.2.11 → 0.2.12

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.
@@ -0,0 +1,1275 @@
1
+ // src/ActionDefinition/Action/RunningAction.types.ts
2
+ var ERunningActionState;
3
+ ((ERunningActionState2) => {
4
+ ERunningActionState2["running"] = "running";
5
+ ERunningActionState2["completed"] = "completed";
6
+ })(ERunningActionState ||= {});
7
+ var ERunningActionUpdateType;
8
+ ((ERunningActionUpdateType2) => {
9
+ ERunningActionUpdateType2["started"] = "started";
10
+ ERunningActionUpdateType2["progress"] = "progress";
11
+ ERunningActionUpdateType2["finished"] = "finished";
12
+ })(ERunningActionUpdateType ||= {});
13
+ var ERunningActionFinishedType;
14
+ ((ERunningActionFinishedType2) => {
15
+ ERunningActionFinishedType2["aborted"] = "aborted";
16
+ ERunningActionFinishedType2["failed"] = "failed";
17
+ ERunningActionFinishedType2["success"] = "success";
18
+ })(ERunningActionFinishedType ||= {});
19
+
20
+ // src/devtools/core/ActionDevtoolsCore.ts
21
+ function extractRouting(context) {
22
+ return (context?.routing ?? []).map((item) => {
23
+ const handler = item.handler;
24
+ const isExternal = handler?.type === "external";
25
+ return {
26
+ runtime: {
27
+ envId: item.runtime?.envId ?? "unknown",
28
+ perId: item.runtime?.perId,
29
+ insId: item.runtime?.insId
30
+ },
31
+ handlerType: isExternal ? "external" : "local",
32
+ handlerClient: isExternal && handler.client != null ? {
33
+ envId: handler.client.envId ?? "unknown",
34
+ perId: handler.client.perId,
35
+ insId: handler.client.insId
36
+ } : undefined,
37
+ transport: isExternal ? handler.transType : undefined,
38
+ time: item.time
39
+ };
40
+ });
41
+ }
42
+ function extractMeta(context) {
43
+ return {
44
+ timeCreated: context?.timeCreated ?? Date.now(),
45
+ originClient: {
46
+ envId: context?.originClient?.envId ?? "unknown",
47
+ perId: context?.originClient?.perId,
48
+ insId: context?.originClient?.insId
49
+ },
50
+ routing: extractRouting(context)
51
+ };
52
+ }
53
+
54
+ class ActionDevtoolsCore {
55
+ _entries = [];
56
+ _listeners = new Set;
57
+ _maxEntries;
58
+ constructor(options = {}) {
59
+ this._maxEntries = options.maxEntries ?? 100;
60
+ }
61
+ attachToDomain(domain) {
62
+ return domain.addActionListener((update) => {
63
+ const { runningAction, type, time } = update;
64
+ if (type === "started" /* started */) {
65
+ const entry = {
66
+ cuid: runningAction.cuid,
67
+ actionId: runningAction.id,
68
+ domain: runningAction.domain,
69
+ allDomains: [...runningAction.allDomains],
70
+ status: "running",
71
+ startTime: time,
72
+ input: runningAction.state?.request?.input,
73
+ progressUpdates: [],
74
+ meta: extractMeta(runningAction.context)
75
+ };
76
+ this._entries = [entry, ...this._entries].slice(0, this._maxEntries);
77
+ this._notify();
78
+ } else if (type === "progress" /* progress */) {
79
+ this._updateEntry(runningAction.cuid, (e) => ({
80
+ ...e,
81
+ progressUpdates: [...e.progressUpdates, update.progress]
82
+ }));
83
+ } else if (type === "finished" /* finished */) {
84
+ this._updateEntry(runningAction.cuid, (e) => {
85
+ const finishedRoutingContext = update.response?.context ?? runningAction.context;
86
+ const base = {
87
+ ...e,
88
+ endTime: time,
89
+ meta: { ...e.meta, routing: extractRouting(finishedRoutingContext) }
90
+ };
91
+ const finishType = update.finishType;
92
+ if (finishType === "success" /* success */) {
93
+ return { ...base, status: "success", output: update.response?.result?.output };
94
+ }
95
+ if (finishType === "failed" /* failed */) {
96
+ return { ...base, status: "failed", error: update.error };
97
+ }
98
+ return { ...base, status: "aborted", abortReason: update.reason };
99
+ });
100
+ }
101
+ });
102
+ }
103
+ getEntries() {
104
+ return this._entries;
105
+ }
106
+ subscribe(listener) {
107
+ this._listeners.add(listener);
108
+ listener(this._entries);
109
+ return () => {
110
+ this._listeners.delete(listener);
111
+ };
112
+ }
113
+ clear() {
114
+ this._entries = [];
115
+ this._notify();
116
+ }
117
+ _updateEntry(cuid, updater) {
118
+ this._entries = this._entries.map((e) => e.cuid === cuid ? updater(e) : e);
119
+ this._notify();
120
+ }
121
+ _notify() {
122
+ const snapshot = this._entries;
123
+ for (const listener of this._listeners)
124
+ listener(snapshot);
125
+ }
126
+ }
127
+ // src/devtools/browser/NiceActionDevtools.tsx
128
+ import { useVirtualizer } from "@tanstack/react-virtual";
129
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
130
+ import { jsxDEV, Fragment as Fragment2 } from "react/jsx-dev-runtime";
131
+ if (typeof document !== "undefined" && !document.getElementById("__nice-action-devtools-styles")) {
132
+ const style = document.createElement("style");
133
+ style.id = "__nice-action-devtools-styles";
134
+ style.textContent = `
135
+ @keyframes __nice-action-pulse {
136
+ 0%, 100% { opacity: 1; }
137
+ 50% { opacity: 0.35; }
138
+ }
139
+ `;
140
+ document.head?.appendChild(style);
141
+ }
142
+ var STATUS_COLOR = {
143
+ running: "#60a5fa",
144
+ success: "#4ade80",
145
+ failed: "#f87171",
146
+ aborted: "#9ca3af"
147
+ };
148
+ var STATUS_SYMBOL = {
149
+ running: "●",
150
+ success: "✓",
151
+ failed: "✗",
152
+ aborted: "○"
153
+ };
154
+ var PREFS_KEY = "__nice-action-devtools-prefs";
155
+ var DOCKED_HEIGHT_DEFAULT = 320;
156
+ var DOCKED_WIDTH_DEFAULT = 420;
157
+ var DOCKED_SIZE_MIN = 140;
158
+ var ROW_HEIGHT = 50;
159
+ var SUB_ROW_HEIGHT = 30;
160
+ function getDockSide(pos) {
161
+ if (pos === "dock-top")
162
+ return "top";
163
+ if (pos === "dock-bottom")
164
+ return "bottom";
165
+ if (pos === "dock-left")
166
+ return "left";
167
+ if (pos === "dock-right")
168
+ return "right";
169
+ return null;
170
+ }
171
+ function readPrefs(defaultPosition, initialOpen) {
172
+ const fallback = {
173
+ position: defaultPosition,
174
+ isOpen: initialOpen,
175
+ dockedHeight: DOCKED_HEIGHT_DEFAULT,
176
+ dockedWidth: DOCKED_WIDTH_DEFAULT
177
+ };
178
+ try {
179
+ if (typeof localStorage === "undefined")
180
+ return fallback;
181
+ const stored = localStorage.getItem(PREFS_KEY);
182
+ return stored != null ? { ...fallback, ...JSON.parse(stored) } : fallback;
183
+ } catch (_e) {
184
+ return fallback;
185
+ }
186
+ }
187
+ function writePrefs(prefs) {
188
+ try {
189
+ localStorage.setItem(PREFS_KEY, JSON.stringify(prefs));
190
+ } catch (_e) {
191
+ return;
192
+ }
193
+ }
194
+ function getHandlerKey(entry) {
195
+ const hop = entry.meta.routing[0];
196
+ if (hop == null)
197
+ return "none";
198
+ if (hop.handlerType === "local")
199
+ return "local";
200
+ return `ext:${hop.transport ?? "ext"}`;
201
+ }
202
+ function canGroupWith(a, b) {
203
+ if (a.status === "running" || b.status === "running")
204
+ return false;
205
+ const handlerA = getHandlerKey(a);
206
+ const handlerB = getHandlerKey(b);
207
+ const handlerConflict = handlerA !== "none" && handlerB !== "none" && handlerA !== handlerB;
208
+ return a.actionId === b.actionId && a.domain === b.domain && a.status === b.status && !handlerConflict && safeStringify(a.input, 0) === safeStringify(b.input, 0);
209
+ }
210
+ function groupEntries(entries) {
211
+ const groups = [];
212
+ for (const entry of entries) {
213
+ const last = groups[groups.length - 1];
214
+ if (last != null && canGroupWith(entry, last.representative)) {
215
+ last.rest.push(entry);
216
+ } else {
217
+ groups.push({ representative: entry, rest: [] });
218
+ }
219
+ }
220
+ return groups;
221
+ }
222
+ function NiceActionDevtools(props) {
223
+ if (false) {}
224
+ return /* @__PURE__ */ jsxDEV(NiceActionDevtools_Panel, {
225
+ ...props
226
+ }, undefined, false, undefined, this);
227
+ }
228
+ function NiceActionDevtools_Panel({
229
+ core,
230
+ position: defaultPosition = "bottom-right",
231
+ initialOpen = false
232
+ }) {
233
+ const [prefs, setPrefsRaw] = useState(() => readPrefs(defaultPosition, initialOpen));
234
+ const [entries, setEntries] = useState([]);
235
+ const [selectedCuid, setSelectedCuid] = useState(null);
236
+ const [expandedGroupCuids, setExpandedGroupCuids] = useState(new Set);
237
+ useEffect(() => core.subscribe(setEntries), [core]);
238
+ const groups = useMemo(() => groupEntries(entries), [entries]);
239
+ const handleGroupRowClick = (group) => {
240
+ const repCuid = group.representative.cuid;
241
+ const isExpanded = expandedGroupCuids.has(repCuid);
242
+ const isSelected = selectedCuid === repCuid;
243
+ if (group.rest.length === 0) {
244
+ setSelectedCuid(isSelected ? null : repCuid);
245
+ setExpandedGroupCuids(new Set);
246
+ } else if (isSelected && isExpanded) {
247
+ setSelectedCuid(null);
248
+ setExpandedGroupCuids(new Set);
249
+ } else {
250
+ setSelectedCuid(repCuid);
251
+ setExpandedGroupCuids(new Set([repCuid]));
252
+ }
253
+ };
254
+ const setPrefs = (update) => {
255
+ setPrefsRaw((prev) => {
256
+ const next = { ...prev, ...update };
257
+ writePrefs(next);
258
+ return next;
259
+ });
260
+ };
261
+ const { position, isOpen, dockedHeight, dockedWidth } = prefs;
262
+ const dockSide = getDockSide(position);
263
+ const isHorizDock = dockSide === "top" || dockSide === "bottom";
264
+ const dockedSize = isHorizDock ? dockedHeight : dockedWidth;
265
+ const selectedEntry = selectedCuid != null ? entries.find((e) => e.cuid === selectedCuid) : null;
266
+ const runningCount = entries.filter((e) => e.status === "running").length;
267
+ useEffect(() => {
268
+ const sides = ["top", "bottom", "left", "right"];
269
+ const clearAll = () => {
270
+ sides.forEach((s) => {
271
+ document.body.style.removeProperty(`margin-${s}`);
272
+ });
273
+ };
274
+ if (!isOpen || dockSide == null) {
275
+ clearAll();
276
+ return clearAll;
277
+ }
278
+ clearAll();
279
+ document.body.style.setProperty(`margin-${dockSide}`, `${dockedSize}px`);
280
+ return clearAll;
281
+ }, [dockSide, isOpen, dockedSize]);
282
+ const closedAnchor = (() => {
283
+ switch (position) {
284
+ case "dock-bottom":
285
+ return { bottom: "16px", right: "16px" };
286
+ case "dock-top":
287
+ return { top: "16px", right: "16px" };
288
+ case "dock-left":
289
+ return { top: "16px", left: "16px" };
290
+ case "dock-right":
291
+ return { top: "16px", right: "16px" };
292
+ default:
293
+ return {
294
+ ...position.includes("right") ? { right: "16px" } : { left: "16px" },
295
+ ...position.includes("bottom") ? { bottom: "16px" } : { top: "16px" }
296
+ };
297
+ }
298
+ })();
299
+ const baseStyle = {
300
+ position: "fixed",
301
+ zIndex: 2147483647,
302
+ fontFamily: "ui-monospace, 'Cascadia Code', 'Source Code Pro', monospace",
303
+ fontSize: "12px"
304
+ };
305
+ if (!isOpen) {
306
+ return /* @__PURE__ */ jsxDEV("button", {
307
+ onClick: () => setPrefs({ isOpen: true }),
308
+ style: {
309
+ ...baseStyle,
310
+ ...closedAnchor,
311
+ background: "#1e293b",
312
+ color: "#94a3b8",
313
+ border: "1px solid #334155",
314
+ borderRadius: "6px",
315
+ padding: "5px 10px",
316
+ cursor: "pointer",
317
+ lineHeight: "1.5"
318
+ },
319
+ children: [
320
+ "⚡ actions",
321
+ runningCount > 0 && /* @__PURE__ */ jsxDEV("span", {
322
+ style: {
323
+ marginLeft: "6px",
324
+ color: "#60a5fa",
325
+ animation: "__nice-action-pulse 1.2s ease-in-out infinite"
326
+ },
327
+ children: [
328
+ runningCount,
329
+ " running"
330
+ ]
331
+ }, undefined, true, undefined, this)
332
+ ]
333
+ }, undefined, true, undefined, this);
334
+ }
335
+ const panelStyle = dockSide != null ? {
336
+ ...baseStyle,
337
+ background: "#0f172a",
338
+ border: "1px solid #1e293b",
339
+ color: "#e2e8f0",
340
+ display: "flex",
341
+ flexDirection: "column",
342
+ boxShadow: "0 -4px 24px rgba(0,0,0,0.4)",
343
+ overflow: "hidden",
344
+ ...dockSide === "bottom" ? { bottom: 0, left: 0, right: 0, height: `${dockedSize}px`, borderRadius: "8px 8px 0 0" } : dockSide === "top" ? { top: 0, left: 0, right: 0, height: `${dockedSize}px`, borderRadius: "0 0 8px 8px" } : dockSide === "left" ? { top: 0, left: 0, bottom: 0, width: `${dockedSize}px`, borderRadius: "0 8px 8px 0" } : { top: 0, right: 0, bottom: 0, width: `${dockedSize}px`, borderRadius: "8px 0 0 8px" }
345
+ } : {
346
+ ...baseStyle,
347
+ ...closedAnchor,
348
+ width: "460px",
349
+ maxHeight: "560px",
350
+ background: "#0f172a",
351
+ border: "1px solid #1e293b",
352
+ borderRadius: "10px",
353
+ color: "#e2e8f0",
354
+ display: "flex",
355
+ flexDirection: "column",
356
+ boxShadow: "0 25px 50px rgba(0,0,0,0.5)",
357
+ overflow: "hidden"
358
+ };
359
+ const virtualListProps = {
360
+ groups,
361
+ selectedCuid,
362
+ expandedGroupCuids,
363
+ onGroupClick: handleGroupRowClick,
364
+ onSubClick: (cuid, isSelected) => setSelectedCuid(isSelected ? null : cuid)
365
+ };
366
+ return /* @__PURE__ */ jsxDEV("div", {
367
+ style: panelStyle,
368
+ children: [
369
+ dockSide != null && /* @__PURE__ */ jsxDEV(ResizeHandle, {
370
+ dockSide,
371
+ dockedSize,
372
+ onChange: (size) => setPrefs(isHorizDock ? { dockedHeight: size } : { dockedWidth: size })
373
+ }, undefined, false, undefined, this),
374
+ /* @__PURE__ */ jsxDEV(PanelHeader, {
375
+ position,
376
+ onPositionChange: (p) => setPrefs({ position: p }),
377
+ onClose: () => setPrefs({ isOpen: false }),
378
+ onClear: entries.length > 0 ? () => {
379
+ core.clear();
380
+ setSelectedCuid(null);
381
+ setExpandedGroupCuids(new Set);
382
+ } : undefined
383
+ }, undefined, false, undefined, this),
384
+ isHorizDock ? /* @__PURE__ */ jsxDEV("div", {
385
+ style: { flex: 1, display: "flex", overflow: "hidden" },
386
+ children: [
387
+ /* @__PURE__ */ jsxDEV(VirtualActionList, {
388
+ ...virtualListProps,
389
+ style: { width: "340px", flexShrink: 0, overflowY: "auto", borderRight: "1px solid #1e293b" }
390
+ }, undefined, false, undefined, this),
391
+ /* @__PURE__ */ jsxDEV("div", {
392
+ style: { flex: 1, overflowY: "auto" },
393
+ children: selectedEntry != null ? /* @__PURE__ */ jsxDEV(ActionDetailPanel, {
394
+ entry: selectedEntry
395
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV("div", {
396
+ style: { padding: "24px", textAlign: "center", color: "#475569", fontSize: "11px" },
397
+ children: "Select an action to inspect"
398
+ }, undefined, false, undefined, this)
399
+ }, undefined, false, undefined, this)
400
+ ]
401
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV(Fragment2, {
402
+ children: [
403
+ /* @__PURE__ */ jsxDEV(VirtualActionList, {
404
+ ...virtualListProps,
405
+ style: {
406
+ overflowY: "auto",
407
+ flex: 1,
408
+ minHeight: "80px",
409
+ borderBottom: selectedEntry != null ? "1px solid #1e293b" : "none"
410
+ }
411
+ }, undefined, false, undefined, this),
412
+ selectedEntry != null && /* @__PURE__ */ jsxDEV("div", {
413
+ style: { flexShrink: 0, maxHeight: "45%", overflow: "hidden" },
414
+ children: /* @__PURE__ */ jsxDEV(ActionDetailPanel, {
415
+ entry: selectedEntry
416
+ }, undefined, false, undefined, this)
417
+ }, undefined, false, undefined, this)
418
+ ]
419
+ }, undefined, true, undefined, this)
420
+ ]
421
+ }, undefined, true, undefined, this);
422
+ }
423
+ function VirtualActionList({
424
+ groups,
425
+ selectedCuid,
426
+ expandedGroupCuids,
427
+ onGroupClick,
428
+ onSubClick,
429
+ style
430
+ }) {
431
+ const outerRef = useRef(null);
432
+ const latestTime = groups[0]?.representative.startTime;
433
+ const flatItems = useMemo(() => {
434
+ const result = [];
435
+ for (let gi = 0;gi < groups.length; gi++) {
436
+ const group = groups[gi];
437
+ const repCuid = group.representative.cuid;
438
+ const isExpanded = expandedGroupCuids.has(repCuid) || group.rest.some((e) => e.cuid === selectedCuid);
439
+ result.push({ type: "group", group, groupIndex: gi });
440
+ if (isExpanded) {
441
+ for (const entry of group.rest) {
442
+ result.push({ type: "sub", entry, group });
443
+ }
444
+ }
445
+ }
446
+ return result;
447
+ }, [groups, expandedGroupCuids, selectedCuid]);
448
+ const flatItemsRef = useRef(flatItems);
449
+ flatItemsRef.current = flatItems;
450
+ const virtualizer = useVirtualizer({
451
+ count: flatItems.length,
452
+ getScrollElement: () => outerRef.current,
453
+ estimateSize: (i) => flatItemsRef.current[i]?.type === "sub" ? SUB_ROW_HEIGHT : ROW_HEIGHT,
454
+ overscan: 5,
455
+ measureElement: (el) => el.getBoundingClientRect().height
456
+ });
457
+ const prevGroupLenRef = useRef(groups.length);
458
+ useLayoutEffect(() => {
459
+ const el = outerRef.current;
460
+ if (el == null)
461
+ return;
462
+ const prev = prevGroupLenRef.current;
463
+ prevGroupLenRef.current = groups.length;
464
+ const added = groups.length - prev;
465
+ if (added > 0 && el.scrollTop > 10) {
466
+ el.scrollTop += added * ROW_HEIGHT;
467
+ }
468
+ }, [groups]);
469
+ const prevSelectedRef = useRef(selectedCuid);
470
+ useEffect(() => {
471
+ if (selectedCuid === prevSelectedRef.current)
472
+ return;
473
+ prevSelectedRef.current = selectedCuid;
474
+ if (selectedCuid == null)
475
+ return;
476
+ const idx = flatItemsRef.current.findIndex((item) => item.type === "group" && (item.group.representative.cuid === selectedCuid || item.group.rest.some((e) => e.cuid === selectedCuid)) || item.type === "sub" && item.entry.cuid === selectedCuid);
477
+ if (idx >= 0)
478
+ virtualizer.scrollToIndex(idx, { align: "auto" });
479
+ }, [selectedCuid, virtualizer]);
480
+ if (groups.length === 0) {
481
+ return /* @__PURE__ */ jsxDEV("div", {
482
+ style,
483
+ children: /* @__PURE__ */ jsxDEV("div", {
484
+ style: { padding: "24px", textAlign: "center", color: "#475569" },
485
+ children: "No actions recorded yet"
486
+ }, undefined, false, undefined, this)
487
+ }, undefined, false, undefined, this);
488
+ }
489
+ const virtualItems = virtualizer.getVirtualItems();
490
+ return /* @__PURE__ */ jsxDEV("div", {
491
+ ref: outerRef,
492
+ style,
493
+ children: /* @__PURE__ */ jsxDEV("div", {
494
+ style: { height: `${virtualizer.getTotalSize()}px`, position: "relative" },
495
+ children: virtualItems.map((vi) => {
496
+ const item = flatItems[vi.index];
497
+ if (item == null)
498
+ return null;
499
+ return /* @__PURE__ */ jsxDEV("div", {
500
+ "data-index": vi.index,
501
+ ref: virtualizer.measureElement,
502
+ style: {
503
+ position: "absolute",
504
+ top: 0,
505
+ left: 0,
506
+ width: "100%",
507
+ transform: `translateY(${vi.start}px)`
508
+ },
509
+ children: item.type === "group" ? /* @__PURE__ */ jsxDEV(ActionEntryRow, {
510
+ entry: item.group.representative,
511
+ isSelected: selectedCuid === item.group.representative.cuid,
512
+ groupCount: item.group.rest.length > 0 ? item.group.rest.length + 1 : undefined,
513
+ isLatest: item.groupIndex === 0,
514
+ latestTime,
515
+ onClick: () => onGroupClick(item.group)
516
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV(ActionEntryRow, {
517
+ entry: item.entry,
518
+ isSelected: selectedCuid === item.entry.cuid,
519
+ isSubEntry: true,
520
+ isLatest: false,
521
+ latestTime,
522
+ onClick: () => onSubClick(item.entry.cuid, selectedCuid === item.entry.cuid)
523
+ }, undefined, false, undefined, this)
524
+ }, vi.key, false, undefined, this);
525
+ })
526
+ }, undefined, false, undefined, this)
527
+ }, undefined, false, undefined, this);
528
+ }
529
+ function PanelHeader({
530
+ position,
531
+ onPositionChange,
532
+ onClose,
533
+ onClear
534
+ }) {
535
+ return /* @__PURE__ */ jsxDEV("div", {
536
+ style: {
537
+ display: "flex",
538
+ alignItems: "center",
539
+ justifyContent: "space-between",
540
+ padding: "8px 12px",
541
+ background: "#1e293b",
542
+ borderBottom: "1px solid #0f172a",
543
+ flexShrink: 0
544
+ },
545
+ children: [
546
+ /* @__PURE__ */ jsxDEV("span", {
547
+ style: { color: "#60a5fa", fontWeight: "bold", fontSize: "11px" },
548
+ children: "⚡ nice-action devtools"
549
+ }, undefined, false, undefined, this),
550
+ /* @__PURE__ */ jsxDEV("div", {
551
+ style: { display: "flex", gap: "10px", alignItems: "center" },
552
+ children: [
553
+ /* @__PURE__ */ jsxDEV(PositionPicker, {
554
+ position,
555
+ onChange: onPositionChange
556
+ }, undefined, false, undefined, this),
557
+ onClear != null && /* @__PURE__ */ jsxDEV("button", {
558
+ onClick: onClear,
559
+ style: {
560
+ background: "none",
561
+ border: "none",
562
+ color: "#475569",
563
+ cursor: "pointer",
564
+ fontSize: "11px",
565
+ padding: "0"
566
+ },
567
+ children: "clear"
568
+ }, undefined, false, undefined, this),
569
+ /* @__PURE__ */ jsxDEV("button", {
570
+ onClick: onClose,
571
+ style: {
572
+ background: "none",
573
+ border: "none",
574
+ color: "#475569",
575
+ cursor: "pointer",
576
+ fontSize: "16px",
577
+ padding: "0",
578
+ lineHeight: "1"
579
+ },
580
+ children: "×"
581
+ }, undefined, false, undefined, this)
582
+ ]
583
+ }, undefined, true, undefined, this)
584
+ ]
585
+ }, undefined, true, undefined, this);
586
+ }
587
+ var POSITION_GRID = [
588
+ ["top-left", "dock-top", "top-right"],
589
+ ["dock-left", null, "dock-right"],
590
+ ["bottom-left", "dock-bottom", "bottom-right"]
591
+ ];
592
+ function PositionPicker({
593
+ position,
594
+ onChange
595
+ }) {
596
+ return /* @__PURE__ */ jsxDEV("div", {
597
+ title: "Move / dock panel",
598
+ style: { display: "grid", gridTemplateColumns: "repeat(3, 9px)", gap: "2px", padding: "2px" },
599
+ children: POSITION_GRID.flat().map((pos) => {
600
+ if (pos == null)
601
+ return /* @__PURE__ */ jsxDEV("div", {
602
+ style: { width: "9px", height: "9px" }
603
+ }, "center-empty", false, undefined, this);
604
+ const isDock = pos.startsWith("dock-");
605
+ const isTopBottom = pos === "dock-top" || pos === "dock-bottom";
606
+ const isActive = pos === position;
607
+ return /* @__PURE__ */ jsxDEV("div", {
608
+ title: pos,
609
+ onClick: () => onChange(pos),
610
+ style: { width: "9px", height: "9px", display: "flex", alignItems: "center", justifyContent: "center", cursor: "pointer" },
611
+ children: /* @__PURE__ */ jsxDEV("div", {
612
+ style: {
613
+ width: isDock ? isTopBottom ? "9px" : "3px" : "7px",
614
+ height: isDock ? isTopBottom ? "3px" : "9px" : "7px",
615
+ borderRadius: isDock ? "1px" : "50%",
616
+ background: isActive ? "#60a5fa" : "#334155"
617
+ }
618
+ }, undefined, false, undefined, this)
619
+ }, pos, false, undefined, this);
620
+ })
621
+ }, undefined, false, undefined, this);
622
+ }
623
+ function ResizeHandle({
624
+ dockSide,
625
+ dockedSize,
626
+ onChange
627
+ }) {
628
+ const isHoriz = dockSide === "left" || dockSide === "right";
629
+ const onMouseDown = (e) => {
630
+ e.preventDefault();
631
+ const startCoord = isHoriz ? e.clientX : e.clientY;
632
+ const startSize = dockedSize;
633
+ const maxSize = isHoriz ? window.innerWidth * 0.85 : window.innerHeight * 0.85;
634
+ const sign = dockSide === "bottom" || dockSide === "right" ? -1 : 1;
635
+ const onMove = (me) => {
636
+ const delta = (isHoriz ? me.clientX : me.clientY) - startCoord;
637
+ onChange(Math.max(DOCKED_SIZE_MIN, Math.min(maxSize, startSize + sign * delta)));
638
+ };
639
+ const onUp = () => {
640
+ window.removeEventListener("mousemove", onMove);
641
+ window.removeEventListener("mouseup", onUp);
642
+ };
643
+ window.addEventListener("mousemove", onMove);
644
+ window.addEventListener("mouseup", onUp);
645
+ };
646
+ const edgeStyle = dockSide === "bottom" ? { top: 0, left: 0, right: 0, height: "5px", cursor: "ns-resize" } : dockSide === "top" ? { bottom: 0, left: 0, right: 0, height: "5px", cursor: "ns-resize" } : dockSide === "right" ? { top: 0, bottom: 0, left: 0, width: "5px", cursor: "ew-resize" } : { top: 0, bottom: 0, right: 0, width: "5px", cursor: "ew-resize" };
647
+ return /* @__PURE__ */ jsxDEV("div", {
648
+ onMouseDown,
649
+ style: {
650
+ position: "absolute",
651
+ zIndex: 10,
652
+ background: "transparent",
653
+ ...edgeStyle
654
+ }
655
+ }, undefined, false, undefined, this);
656
+ }
657
+ function formatRelativeAge(ms) {
658
+ if (ms < 1000)
659
+ return `${ms}ms`;
660
+ if (ms < 60000)
661
+ return `${(ms / 1000).toFixed(1)}s`;
662
+ return `${Math.floor(ms / 60000)}m`;
663
+ }
664
+ function ActionEntryRow({
665
+ entry,
666
+ isSelected,
667
+ onClick,
668
+ groupCount,
669
+ isSubEntry = false,
670
+ isLatest = false,
671
+ latestTime
672
+ }) {
673
+ const color = STATUS_COLOR[entry.status];
674
+ const symbol = STATUS_SYMBOL[entry.status];
675
+ const parentDomains = entry.allDomains.slice(0, -1);
676
+ const breadcrumb = parentDomains.length > 0 ? `[${parentDomains.join(".")}]` : "";
677
+ const duration = entry.endTime != null ? `${entry.endTime - entry.startTime}ms` : null;
678
+ const timestamp = new Date(entry.startTime).toLocaleTimeString([], {
679
+ hour: "2-digit",
680
+ minute: "2-digit",
681
+ second: "2-digit",
682
+ hour12: false
683
+ });
684
+ const firstHop = entry.meta.routing[0];
685
+ const handlerLabel = firstHop == null ? null : firstHop.handlerType === "local" ? "local" : `→ ${firstHop.transport ?? "ext"}`;
686
+ const handlerColor = handlerLabel === "local" ? "#34d399" : "#fbbf24";
687
+ const handlerBorder = handlerLabel === "local" ? "#14532d" : "#78350f";
688
+ if (isSubEntry) {
689
+ return /* @__PURE__ */ jsxDEV("div", {
690
+ "data-cuid": entry.cuid,
691
+ onClick,
692
+ style: {
693
+ display: "flex",
694
+ alignItems: "center",
695
+ gap: "8px",
696
+ padding: "4px 10px 4px 26px",
697
+ cursor: "pointer",
698
+ background: isSelected ? "#131f35" : "#070d18",
699
+ borderBottom: "1px solid #0f172a",
700
+ borderLeft: isSelected ? "2px solid #3b82f6" : "2px solid transparent",
701
+ userSelect: "none"
702
+ },
703
+ children: [
704
+ /* @__PURE__ */ jsxDEV("span", {
705
+ style: { color: "#334155", fontSize: "10px", flexShrink: 0 },
706
+ children: symbol
707
+ }, undefined, false, undefined, this),
708
+ /* @__PURE__ */ jsxDEV("span", {
709
+ style: {
710
+ flex: 1,
711
+ color: "#475569",
712
+ fontSize: "11px",
713
+ overflow: "hidden",
714
+ textOverflow: "ellipsis",
715
+ whiteSpace: "nowrap",
716
+ minWidth: 0
717
+ },
718
+ children: [
719
+ entry.actionId,
720
+ /* @__PURE__ */ jsxDEV("span", {
721
+ style: { color: "#334155", marginLeft: "4px" },
722
+ children: [
723
+ "(",
724
+ entry.domain,
725
+ ")"
726
+ ]
727
+ }, undefined, true, undefined, this)
728
+ ]
729
+ }, undefined, true, undefined, this),
730
+ /* @__PURE__ */ jsxDEV("span", {
731
+ style: { color: "#334155", fontSize: "11px", flexShrink: 0 },
732
+ children: duration ?? /* @__PURE__ */ jsxDEV(RunningTimer, {
733
+ startTime: entry.startTime
734
+ }, undefined, false, undefined, this)
735
+ }, undefined, false, undefined, this)
736
+ ]
737
+ }, undefined, true, undefined, this);
738
+ }
739
+ return /* @__PURE__ */ jsxDEV("div", {
740
+ "data-cuid": entry.cuid,
741
+ onClick,
742
+ style: {
743
+ display: "flex",
744
+ alignItems: "flex-start",
745
+ gap: "8px",
746
+ padding: isSelected ? "6px 12px 6px 10px" : "6px 12px",
747
+ cursor: "pointer",
748
+ background: isSelected ? "#131f35" : "transparent",
749
+ borderBottom: "1px solid #0f172a",
750
+ borderLeft: isSelected ? "2px solid #60a5fa" : "2px solid transparent",
751
+ userSelect: "none"
752
+ },
753
+ children: [
754
+ /* @__PURE__ */ jsxDEV("span", {
755
+ style: { flexShrink: 0, paddingTop: "2px" },
756
+ children: isLatest ? /* @__PURE__ */ jsxDEV("span", {
757
+ style: {
758
+ color: "#60a5fa",
759
+ fontSize: "8px",
760
+ background: "#0f172a",
761
+ border: "1px solid #1e3a5f",
762
+ padding: "1px 4px",
763
+ borderRadius: "3px"
764
+ },
765
+ children: "latest"
766
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV("span", {
767
+ style: {
768
+ color: "#475569",
769
+ fontSize: "8px",
770
+ background: "#0f172a",
771
+ border: "1px solid #1e293b",
772
+ padding: "1px 4px",
773
+ borderRadius: "3px",
774
+ whiteSpace: "nowrap"
775
+ },
776
+ children: [
777
+ "+",
778
+ latestTime != null ? formatRelativeAge(latestTime - entry.startTime) : "?"
779
+ ]
780
+ }, undefined, true, undefined, this)
781
+ }, undefined, false, undefined, this),
782
+ /* @__PURE__ */ jsxDEV("span", {
783
+ style: {
784
+ color,
785
+ fontSize: "10px",
786
+ flexShrink: 0,
787
+ paddingTop: "2px",
788
+ animation: entry.status === "running" ? "__nice-action-pulse 1.2s ease-in-out infinite" : undefined
789
+ },
790
+ children: symbol
791
+ }, undefined, false, undefined, this),
792
+ /* @__PURE__ */ jsxDEV("div", {
793
+ style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: "3px" },
794
+ children: [
795
+ /* @__PURE__ */ jsxDEV("div", {
796
+ style: { display: "flex", alignItems: "baseline", minWidth: 0, overflow: "hidden" },
797
+ children: [
798
+ /* @__PURE__ */ jsxDEV("span", {
799
+ style: {
800
+ color: "#cbd5e1",
801
+ fontSize: "11px",
802
+ overflow: "hidden",
803
+ textOverflow: "ellipsis",
804
+ whiteSpace: "nowrap",
805
+ flexShrink: 1,
806
+ minWidth: "24px"
807
+ },
808
+ children: entry.actionId
809
+ }, undefined, false, undefined, this),
810
+ /* @__PURE__ */ jsxDEV("span", {
811
+ style: {
812
+ color: "#7592b6",
813
+ fontSize: "11px",
814
+ marginLeft: "4px",
815
+ whiteSpace: "nowrap",
816
+ overflow: "hidden",
817
+ textOverflow: "ellipsis",
818
+ flexShrink: 2,
819
+ minWidth: "24px"
820
+ },
821
+ children: [
822
+ "(",
823
+ entry.domain,
824
+ ")"
825
+ ]
826
+ }, undefined, true, undefined, this)
827
+ ]
828
+ }, undefined, true, undefined, this),
829
+ /* @__PURE__ */ jsxDEV("div", {
830
+ style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: "6px" },
831
+ children: [
832
+ /* @__PURE__ */ jsxDEV("div", {
833
+ style: { display: "flex", alignItems: "center", gap: "5px", minWidth: 0, overflow: "hidden" },
834
+ children: [
835
+ handlerLabel != null && /* @__PURE__ */ jsxDEV("span", {
836
+ style: {
837
+ color: handlerColor,
838
+ fontSize: "8px",
839
+ background: "#0f172a",
840
+ border: `1px solid ${handlerBorder}`,
841
+ padding: "1px 4px",
842
+ borderRadius: "3px",
843
+ flexShrink: 0,
844
+ whiteSpace: "nowrap"
845
+ },
846
+ children: handlerLabel
847
+ }, undefined, false, undefined, this),
848
+ breadcrumb !== "" && /* @__PURE__ */ jsxDEV("span", {
849
+ style: {
850
+ color: "#475569",
851
+ fontSize: "9px",
852
+ overflow: "hidden",
853
+ textOverflow: "ellipsis",
854
+ whiteSpace: "nowrap",
855
+ minWidth: 0
856
+ },
857
+ children: breadcrumb
858
+ }, undefined, false, undefined, this)
859
+ ]
860
+ }, undefined, true, undefined, this),
861
+ /* @__PURE__ */ jsxDEV("div", {
862
+ style: { display: "flex", alignItems: "center", gap: "6px", flexShrink: 0 },
863
+ children: [
864
+ groupCount != null && /* @__PURE__ */ jsxDEV("span", {
865
+ style: {
866
+ color: "#3b82f6",
867
+ fontSize: "9px",
868
+ background: "#0f172a",
869
+ border: "1px solid #1e3a5f",
870
+ padding: "1px 5px",
871
+ borderRadius: "3px"
872
+ },
873
+ children: [
874
+ "×",
875
+ groupCount
876
+ ]
877
+ }, undefined, true, undefined, this),
878
+ /* @__PURE__ */ jsxDEV("span", {
879
+ style: { color: "#1e3a5f", fontSize: "10px", letterSpacing: "0.02em" },
880
+ children: timestamp
881
+ }, undefined, false, undefined, this),
882
+ /* @__PURE__ */ jsxDEV("span", {
883
+ style: { color: "#475569", fontSize: "11px" },
884
+ children: duration ?? /* @__PURE__ */ jsxDEV(RunningTimer, {
885
+ startTime: entry.startTime
886
+ }, undefined, false, undefined, this)
887
+ }, undefined, false, undefined, this)
888
+ ]
889
+ }, undefined, true, undefined, this)
890
+ ]
891
+ }, undefined, true, undefined, this)
892
+ ]
893
+ }, undefined, true, undefined, this)
894
+ ]
895
+ }, undefined, true, undefined, this);
896
+ }
897
+ function RunningTimer({ startTime }) {
898
+ const [elapsed, setElapsed] = useState(() => Date.now() - startTime);
899
+ useEffect(() => {
900
+ const interval = setInterval(() => setElapsed(Date.now() - startTime), 100);
901
+ return () => clearInterval(interval);
902
+ }, [startTime]);
903
+ return /* @__PURE__ */ jsxDEV(Fragment2, {
904
+ children: [
905
+ elapsed,
906
+ "ms"
907
+ ]
908
+ }, undefined, true, undefined, this);
909
+ }
910
+ function ActionDetailPanel({ entry }) {
911
+ return /* @__PURE__ */ jsxDEV("div", {
912
+ style: {
913
+ flex: 1,
914
+ overflowY: "auto",
915
+ padding: "10px 12px",
916
+ display: "flex",
917
+ flexDirection: "column",
918
+ gap: "8px"
919
+ },
920
+ children: [
921
+ /* @__PURE__ */ jsxDEV(MetaSection, {
922
+ entry
923
+ }, undefined, false, undefined, this),
924
+ /* @__PURE__ */ jsxDEV(RoutingSection, {
925
+ entry
926
+ }, undefined, false, undefined, this),
927
+ /* @__PURE__ */ jsxDEV(DetailSection, {
928
+ label: "Input",
929
+ value: entry.input
930
+ }, undefined, false, undefined, this),
931
+ entry.status === "success" && /* @__PURE__ */ jsxDEV(DetailSection, {
932
+ label: "Output",
933
+ value: entry.output,
934
+ color: "#4ade80"
935
+ }, undefined, false, undefined, this),
936
+ entry.status === "failed" && /* @__PURE__ */ jsxDEV(DetailSection, {
937
+ label: "Error",
938
+ value: entry.error,
939
+ color: "#f87171"
940
+ }, undefined, false, undefined, this),
941
+ entry.status === "aborted" && entry.abortReason != null && /* @__PURE__ */ jsxDEV(DetailSection, {
942
+ label: "Abort Reason",
943
+ value: entry.abortReason,
944
+ color: "#9ca3af"
945
+ }, undefined, false, undefined, this),
946
+ entry.progressUpdates.length > 0 && /* @__PURE__ */ jsxDEV(DetailSection, {
947
+ label: `Progress (${entry.progressUpdates.length})`,
948
+ value: entry.progressUpdates
949
+ }, undefined, false, undefined, this)
950
+ ]
951
+ }, undefined, true, undefined, this);
952
+ }
953
+ function MetaSection({ entry }) {
954
+ const [expanded, setExpanded] = useState(false);
955
+ const { meta, cuid, startTime: _startTime } = entry;
956
+ const expandedRows = [
957
+ { label: "cuid", value: cuid },
958
+ { label: "origin", value: meta.originClient.envId },
959
+ ...meta.originClient.perId != null ? [{ label: "perId", value: meta.originClient.perId }] : [],
960
+ ...meta.originClient.insId != null ? [{ label: "insId", value: meta.originClient.insId }] : []
961
+ ];
962
+ return /* @__PURE__ */ jsxDEV("div", {
963
+ children: [
964
+ /* @__PURE__ */ jsxDEV("div", {
965
+ style: {
966
+ display: "flex",
967
+ alignItems: "center",
968
+ justifyContent: "space-between",
969
+ marginBottom: "3px",
970
+ userSelect: "none"
971
+ },
972
+ children: [
973
+ /* @__PURE__ */ jsxDEV("div", {
974
+ style: {
975
+ color: "#60a5fa",
976
+ fontSize: "10px",
977
+ textTransform: "uppercase",
978
+ letterSpacing: "0.05em"
979
+ },
980
+ children: "Meta"
981
+ }, undefined, false, undefined, this),
982
+ /* @__PURE__ */ jsxDEV("span", {
983
+ style: { color: "#334155", fontSize: "11px" },
984
+ children: expanded ? "▾" : "▸"
985
+ }, undefined, false, undefined, this)
986
+ ]
987
+ }, undefined, true, undefined, this),
988
+ expanded ? /* @__PURE__ */ jsxDEV("div", {
989
+ onClick: () => setExpanded(false),
990
+ style: {
991
+ background: "#1e293b",
992
+ borderRadius: "4px",
993
+ overflow: "hidden",
994
+ cursor: "pointer"
995
+ },
996
+ children: expandedRows.map(({ label, value }, i) => /* @__PURE__ */ jsxDEV("div", {
997
+ style: {
998
+ display: "grid",
999
+ gridTemplateColumns: "52px 1fr",
1000
+ columnGap: "8px",
1001
+ padding: "4px 8px",
1002
+ borderBottom: i < expandedRows.length - 1 ? "1px solid #0f172a" : "none",
1003
+ alignItems: "start"
1004
+ },
1005
+ children: [
1006
+ /* @__PURE__ */ jsxDEV("span", {
1007
+ style: { textAlign: "left", color: "#475569", fontSize: "10px", paddingTop: "1px" },
1008
+ children: label
1009
+ }, undefined, false, undefined, this),
1010
+ /* @__PURE__ */ jsxDEV("span", {
1011
+ style: {
1012
+ textAlign: "left",
1013
+ color: "#cbd5e1",
1014
+ fontSize: "11px",
1015
+ wordBreak: "break-all"
1016
+ },
1017
+ children: value
1018
+ }, undefined, false, undefined, this)
1019
+ ]
1020
+ }, label, true, undefined, this))
1021
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV("div", {
1022
+ onClick: () => setExpanded(true),
1023
+ style: {
1024
+ background: "#1e293b",
1025
+ borderRadius: "4px",
1026
+ padding: "5px 8px",
1027
+ fontSize: "11px",
1028
+ display: "flex",
1029
+ gap: "10px",
1030
+ rowGap: "2px",
1031
+ flexWrap: "wrap",
1032
+ cursor: "pointer"
1033
+ },
1034
+ children: [
1035
+ /* @__PURE__ */ jsxDEV(MetaChip, {
1036
+ label: "cuid",
1037
+ value: `…${cuid.slice(-8)}`
1038
+ }, undefined, false, undefined, this),
1039
+ /* @__PURE__ */ jsxDEV(MetaChip, {
1040
+ label: "origin",
1041
+ value: meta.originClient.envId
1042
+ }, undefined, false, undefined, this),
1043
+ meta.originClient.perId != null && /* @__PURE__ */ jsxDEV(MetaChip, {
1044
+ label: "perId",
1045
+ value: meta.originClient.perId.length > 10 ? `${meta.originClient.perId.slice(0, 10)}…` : meta.originClient.perId
1046
+ }, undefined, false, undefined, this),
1047
+ meta.originClient.insId != null && /* @__PURE__ */ jsxDEV(MetaChip, {
1048
+ label: "insId",
1049
+ value: meta.originClient.insId.length > 10 ? `${meta.originClient.insId.slice(0, 10)}…` : meta.originClient.insId
1050
+ }, undefined, false, undefined, this)
1051
+ ]
1052
+ }, undefined, true, undefined, this)
1053
+ ]
1054
+ }, undefined, true, undefined, this);
1055
+ }
1056
+ function MetaChip({ label, value }) {
1057
+ return /* @__PURE__ */ jsxDEV("span", {
1058
+ style: { whiteSpace: "nowrap" },
1059
+ children: [
1060
+ /* @__PURE__ */ jsxDEV("span", {
1061
+ style: { color: "#475569" },
1062
+ children: [
1063
+ label,
1064
+ " "
1065
+ ]
1066
+ }, undefined, true, undefined, this),
1067
+ /* @__PURE__ */ jsxDEV("span", {
1068
+ style: { color: "#cbd5e1" },
1069
+ children: value
1070
+ }, undefined, false, undefined, this)
1071
+ ]
1072
+ }, undefined, true, undefined, this);
1073
+ }
1074
+ function RoutingSection({ entry }) {
1075
+ const { meta, startTime } = entry;
1076
+ if (meta.routing.length === 0)
1077
+ return null;
1078
+ const hopCount = meta.routing.length;
1079
+ return /* @__PURE__ */ jsxDEV("div", {
1080
+ children: [
1081
+ /* @__PURE__ */ jsxDEV(SectionLabel, {
1082
+ label: `Routing · ${hopCount} hop${hopCount !== 1 ? "s" : ""}`
1083
+ }, undefined, false, undefined, this),
1084
+ /* @__PURE__ */ jsxDEV("div", {
1085
+ style: { display: "flex", flexDirection: "column", gap: "2px" },
1086
+ children: meta.routing.map((hop, i) => {
1087
+ const isLocal = hop.handlerType === "local";
1088
+ const isLast = i === hopCount - 1;
1089
+ const badgeColor = isLocal ? "#34d399" : "#fbbf24";
1090
+ const badgeText = isLocal ? "● exec" : `→ ${hop.transport ?? "ext"}`;
1091
+ const runtimeTitle = [hop.runtime.perId, hop.runtime.insId].filter(Boolean).join(" · ") || undefined;
1092
+ const rowBorder = isLast ? undefined : "1px solid #0f172a";
1093
+ return /* @__PURE__ */ jsxDEV("div", {
1094
+ style: {
1095
+ background: "#1e293b",
1096
+ borderRadius: "4px",
1097
+ overflow: "hidden",
1098
+ display: "grid",
1099
+ gridTemplateColumns: "30% 1fr 30%",
1100
+ alignItems: "center",
1101
+ columnGap: "8px",
1102
+ borderBottom: rowBorder,
1103
+ padding: "4px 8px"
1104
+ },
1105
+ children: [
1106
+ /* @__PURE__ */ jsxDEV("span", {
1107
+ style: { display: "flex", flexDirection: "row", alignItems: "center", gap: "10px" },
1108
+ children: [
1109
+ /* @__PURE__ */ jsxDEV("span", {
1110
+ style: {
1111
+ color: "#334155",
1112
+ fontSize: "10px",
1113
+ width: "16px",
1114
+ textAlign: "right"
1115
+ },
1116
+ children: i + 1
1117
+ }, undefined, false, undefined, this),
1118
+ /* @__PURE__ */ jsxDEV("span", {
1119
+ title: runtimeTitle,
1120
+ style: {
1121
+ color: "#94a3b8",
1122
+ fontSize: "11px",
1123
+ overflow: "hidden",
1124
+ textOverflow: "ellipsis",
1125
+ whiteSpace: "nowrap",
1126
+ textAlign: "center"
1127
+ },
1128
+ children: hop.runtime.envId
1129
+ }, undefined, false, undefined, this)
1130
+ ]
1131
+ }, undefined, true, undefined, this),
1132
+ /* @__PURE__ */ jsxDEV("span", {
1133
+ style: { color: badgeColor, fontSize: "10px", whiteSpace: "nowrap" },
1134
+ children: badgeText
1135
+ }, undefined, false, undefined, this),
1136
+ /* @__PURE__ */ jsxDEV("span", {
1137
+ style: {
1138
+ display: "flex",
1139
+ alignItems: "center",
1140
+ justifyContent: "space-between",
1141
+ paddingRight: "8px",
1142
+ overflow: "hidden"
1143
+ },
1144
+ children: [
1145
+ /* @__PURE__ */ jsxDEV("span", {
1146
+ style: {
1147
+ color: "#475569",
1148
+ fontSize: "10px",
1149
+ whiteSpace: "nowrap",
1150
+ overflow: "hidden",
1151
+ textOverflow: "ellipsis"
1152
+ },
1153
+ children: hop.handlerClient != null ? `↳ ${hop.handlerClient.envId}` : ""
1154
+ }, undefined, false, undefined, this),
1155
+ /* @__PURE__ */ jsxDEV("span", {
1156
+ style: {
1157
+ color: "#334155",
1158
+ fontSize: "10px",
1159
+ flexShrink: 0,
1160
+ marginLeft: "auto"
1161
+ },
1162
+ children: [
1163
+ "+",
1164
+ hop.time - startTime,
1165
+ "ms"
1166
+ ]
1167
+ }, undefined, true, undefined, this)
1168
+ ]
1169
+ }, undefined, true, undefined, this)
1170
+ ]
1171
+ }, `${hop.time}-${hop.runtime.envId}`, true, undefined, this);
1172
+ })
1173
+ }, undefined, false, undefined, this)
1174
+ ]
1175
+ }, undefined, true, undefined, this);
1176
+ }
1177
+ function SectionLabel({ label, color = "#60a5fa" }) {
1178
+ return /* @__PURE__ */ jsxDEV("div", {
1179
+ style: {
1180
+ color,
1181
+ fontSize: "10px",
1182
+ marginBottom: "3px",
1183
+ textTransform: "uppercase",
1184
+ letterSpacing: "0.05em"
1185
+ },
1186
+ children: label
1187
+ }, undefined, false, undefined, this);
1188
+ }
1189
+ var COMPACT_CHAR_LIMIT = 120;
1190
+ function DetailSection({
1191
+ label,
1192
+ value,
1193
+ color = "#60a5fa"
1194
+ }) {
1195
+ const [expanded, setExpanded] = useState(false);
1196
+ const fullJson = safeStringify(value, 2);
1197
+ const compactJson = safeStringify(value, 0);
1198
+ const canExpand = fullJson !== compactJson || compactJson.length > COMPACT_CHAR_LIMIT;
1199
+ const compactDisplay = compactJson.length > COMPACT_CHAR_LIMIT ? `${compactJson.slice(0, COMPACT_CHAR_LIMIT)}…` : compactJson;
1200
+ return /* @__PURE__ */ jsxDEV("div", {
1201
+ children: [
1202
+ /* @__PURE__ */ jsxDEV("div", {
1203
+ style: {
1204
+ display: "flex",
1205
+ alignItems: "center",
1206
+ justifyContent: "space-between",
1207
+ marginBottom: "3px",
1208
+ userSelect: "none"
1209
+ },
1210
+ children: [
1211
+ /* @__PURE__ */ jsxDEV("div", {
1212
+ style: {
1213
+ color,
1214
+ fontSize: "10px",
1215
+ textTransform: "uppercase",
1216
+ letterSpacing: "0.05em"
1217
+ },
1218
+ children: label
1219
+ }, undefined, false, undefined, this),
1220
+ canExpand && /* @__PURE__ */ jsxDEV("span", {
1221
+ style: { color: "#334155", fontSize: "11px" },
1222
+ children: expanded ? "▾" : "▸"
1223
+ }, undefined, false, undefined, this)
1224
+ ]
1225
+ }, undefined, true, undefined, this),
1226
+ expanded ? /* @__PURE__ */ jsxDEV("div", {
1227
+ onClick: canExpand ? () => setExpanded(false) : undefined,
1228
+ style: {
1229
+ margin: 0,
1230
+ padding: "6px 8px",
1231
+ background: "#1e293b",
1232
+ borderRadius: "4px",
1233
+ fontSize: "11px",
1234
+ color: "#cbd5e1",
1235
+ overflowX: "auto",
1236
+ textAlign: "left",
1237
+ whiteSpace: "pre-wrap",
1238
+ wordBreak: "break-all",
1239
+ cursor: canExpand ? "pointer" : "default"
1240
+ },
1241
+ children: fullJson
1242
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV("div", {
1243
+ onClick: canExpand ? () => setExpanded(true) : undefined,
1244
+ style: {
1245
+ padding: "5px 8px",
1246
+ background: "#1e293b",
1247
+ borderRadius: "4px",
1248
+ fontSize: "11px",
1249
+ color: "#94a3b8",
1250
+ fontFamily: "inherit",
1251
+ whiteSpace: "nowrap",
1252
+ overflow: "hidden",
1253
+ textOverflow: "ellipsis",
1254
+ cursor: canExpand ? "pointer" : "default"
1255
+ },
1256
+ children: compactDisplay
1257
+ }, undefined, false, undefined, this)
1258
+ ]
1259
+ }, undefined, true, undefined, this);
1260
+ }
1261
+ function safeStringify(value, indent = 2) {
1262
+ if (value === undefined)
1263
+ return "undefined";
1264
+ if (value === null)
1265
+ return "null";
1266
+ try {
1267
+ return JSON.stringify(value, null, indent);
1268
+ } catch {
1269
+ return String(value);
1270
+ }
1271
+ }
1272
+ export {
1273
+ NiceActionDevtools,
1274
+ ActionDevtoolsCore
1275
+ };