@nice-code/action 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/build/devtools/browser/index.js +1799 -964
  2. package/build/devtools/server/index.js +11 -8
  3. package/build/index.js +42 -12
  4. package/build/types/ActionDefinition/Action/Payload/ActionPayload_Request.d.ts +1 -0
  5. package/build/types/ActionDefinition/Action/RunningAction.d.ts +2 -0
  6. package/build/types/ActionDefinition/Action/RunningAction.types.d.ts +2 -0
  7. package/build/types/ActionRuntime/HandlerCallStack.d.ts +3 -0
  8. package/build/types/devtools/browser/components/ActionDetailPanel.d.ts +7 -0
  9. package/build/types/devtools/browser/components/ActionEntryRow.d.ts +11 -0
  10. package/build/types/devtools/browser/components/CallStackSection.d.ts +8 -0
  11. package/build/types/devtools/browser/components/ChildDispatchChips.d.ts +4 -0
  12. package/build/types/devtools/browser/components/Chip.d.ts +11 -0
  13. package/build/types/devtools/browser/components/DetailSection.d.ts +5 -0
  14. package/build/types/devtools/browser/components/DomainChip.d.ts +15 -0
  15. package/build/types/devtools/browser/components/HandlerChips.d.ts +8 -0
  16. package/build/types/devtools/browser/components/MetaSection.d.ts +4 -0
  17. package/build/types/devtools/browser/components/PanelChrome.d.ts +14 -0
  18. package/build/types/devtools/browser/components/RoutingSection.d.ts +5 -0
  19. package/build/types/devtools/browser/components/RunningTimer.d.ts +7 -0
  20. package/build/types/devtools/browser/components/SectionLabel.d.ts +4 -0
  21. package/build/types/devtools/browser/components/StackTraceSection.d.ts +5 -0
  22. package/build/types/devtools/browser/components/utils.d.ts +7 -0
  23. package/build/types/devtools/core/ActionDevtools.types.d.ts +3 -0
  24. package/build/types/devtools/core/ActionDevtoolsCore.d.ts +1 -3
  25. package/build/types/devtools/core/devtools_colors.d.ts +4 -0
  26. package/package.json +3 -3
@@ -54,10 +54,7 @@ function extractMeta(context) {
54
54
  class ActionDevtoolsCore {
55
55
  _entries = [];
56
56
  _listeners = new Set;
57
- _maxEntries;
58
- constructor(options = {}) {
59
- this._maxEntries = options.maxEntries ?? 100;
60
- }
57
+ constructor(_options = {}) {}
61
58
  attachToDomain(domain) {
62
59
  return domain.addActionListener((update) => {
63
60
  const { runningAction, type, time } = update;
@@ -71,9 +68,11 @@ class ActionDevtoolsCore {
71
68
  startTime: time,
72
69
  input: runningAction.state?.request?.input,
73
70
  progressUpdates: [],
74
- meta: extractMeta(runningAction.context)
71
+ meta: extractMeta(runningAction.context),
72
+ parentCuid: runningAction.parentCuid,
73
+ callSite: runningAction.callSite
75
74
  };
76
- this._entries = [entry, ...this._entries].slice(0, this._maxEntries);
75
+ this._entries = [entry, ...this._entries];
77
76
  this._notify();
78
77
  } else if (type === "progress" /* progress */) {
79
78
  this._updateEntry(runningAction.cuid, (e) => ({
@@ -93,9 +92,13 @@ class ActionDevtoolsCore {
93
92
  return { ...base, status: "success", output: update.response?.result?.output };
94
93
  }
95
94
  if (finishType === "failed" /* failed */) {
96
- return { ...base, status: "failed", error: update.error };
95
+ const rawError = update.error;
96
+ const errorStack2 = rawError instanceof Error ? rawError.stack : undefined;
97
+ return { ...base, status: "failed", error: rawError, errorStack: errorStack2 };
97
98
  }
98
- return { ...base, status: "aborted", abortReason: update.reason };
99
+ const abortReason = update.reason;
100
+ const errorStack = abortReason instanceof Error ? abortReason.stack : undefined;
101
+ return { ...base, status: "aborted", abortReason, errorStack };
99
102
  });
100
103
  }
101
104
  });
@@ -125,20 +128,126 @@ class ActionDevtoolsCore {
125
128
  }
126
129
  }
127
130
  // 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);
131
+ import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState6 } from "react";
132
+
133
+ // src/devtools/browser/components/ActionDetailPanel.tsx
134
+ import { useMemo, useState as useState5 } from "react";
135
+
136
+ // src/devtools/browser/components/DomainChip.tsx
137
+ import { createContext, useContext, useRef } from "react";
138
+ import { jsxDEV } from "react/jsx-dev-runtime";
139
+ var DomainTooltipCtx = createContext(null);
140
+ function DomainHierarchyTooltip({
141
+ allDomains,
142
+ anchor
143
+ }) {
144
+ return /* @__PURE__ */ jsxDEV("div", {
145
+ style: {
146
+ position: "fixed",
147
+ left: anchor.left,
148
+ top: anchor.top - 6,
149
+ transform: "translateY(-100%)",
150
+ zIndex: 2147483647,
151
+ background: "#0c1526",
152
+ border: "1px solid #312e81",
153
+ borderRadius: "5px",
154
+ padding: "6px 8px",
155
+ fontFamily: "ui-monospace, 'Cascadia Code', 'Source Code Pro', monospace",
156
+ boxShadow: "0 4px 20px rgba(0,0,0,0.6)",
157
+ pointerEvents: "none",
158
+ minWidth: "80px"
159
+ },
160
+ children: allDomains.map((d, i) => {
161
+ const isCurrent = i === allDomains.length - 1;
162
+ return /* @__PURE__ */ jsxDEV("div", {
163
+ style: {
164
+ display: "flex",
165
+ alignItems: "center",
166
+ gap: "0.3rem",
167
+ paddingLeft: `${i * 10}px`,
168
+ paddingTop: i > 0 ? "0.1rem" : undefined
169
+ },
170
+ children: [
171
+ /* @__PURE__ */ jsxDEV("span", {
172
+ style: {
173
+ fontSize: "0.8rem",
174
+ height: "0.6em",
175
+ width: "0.6em",
176
+ overflow: "hidden",
177
+ color: isCurrent ? "#818cf8" : "#3730a3",
178
+ display: "flex",
179
+ alignItems: "center",
180
+ justifyContent: "center"
181
+ },
182
+ children: "⬢"
183
+ }, undefined, false, undefined, this),
184
+ /* @__PURE__ */ jsxDEV("span", {
185
+ style: {
186
+ color: isCurrent ? "#a5b4fc" : "#4b5563",
187
+ fontSize: "0.7rem",
188
+ fontWeight: isCurrent ? 500 : undefined
189
+ },
190
+ children: d
191
+ }, undefined, false, undefined, this)
192
+ ]
193
+ }, d, true, undefined, this);
194
+ })
195
+ }, undefined, false, undefined, this);
196
+ }
197
+ function DomainChip({
198
+ subtle = false,
199
+ domain,
200
+ allDomains,
201
+ size
202
+ }) {
203
+ const ctx = useContext(DomainTooltipCtx);
204
+ const chipRef = useRef(null);
205
+ const hasHierarchy = allDomains != null && allDomains.length > 1;
206
+ const fontSize = size === "md" ? "0.7rem" : "0.6rem";
207
+ const padding = size === "md" ? "1px 5px" : "1px 4px";
208
+ return /* @__PURE__ */ jsxDEV("span", {
209
+ ref: chipRef,
210
+ onMouseEnter: hasHierarchy && ctx != null ? () => {
211
+ if (chipRef.current != null)
212
+ ctx.show(chipRef.current.getBoundingClientRect(), allDomains);
213
+ } : undefined,
214
+ onMouseLeave: hasHierarchy && ctx != null ? () => ctx.hide() : undefined,
215
+ style: {
216
+ display: "flex",
217
+ alignItems: "center",
218
+ gap: "0.4em",
219
+ color: subtle ? "#4b5563" : "#818cf8",
220
+ fontSize,
221
+ background: "#0f172a",
222
+ border: !subtle ? "1px solid #312e81" : "1px solid transparent",
223
+ padding,
224
+ borderRadius: "0.6rem",
225
+ flexShrink: 0,
226
+ whiteSpace: "nowrap"
227
+ },
228
+ children: [
229
+ /* @__PURE__ */ jsxDEV("span", {
230
+ style: {
231
+ fontSize: size === "md" ? "0.9rem" : "0.8rem",
232
+ height: "0.6em",
233
+ width: "0.6em",
234
+ display: "flex",
235
+ alignItems: "center",
236
+ justifyContent: "center"
237
+ },
238
+ children: "⬢"
239
+ }, undefined, false, undefined, this),
240
+ /* @__PURE__ */ jsxDEV("span", {
241
+ children: domain
242
+ }, undefined, false, undefined, this)
243
+ ]
244
+ }, undefined, true, undefined, this);
141
245
  }
246
+
247
+ // src/devtools/browser/components/RunningTimer.tsx
248
+ import { useEffect, useState } from "react";
249
+
250
+ // src/devtools/browser/components/utils.ts
142
251
  var STATUS_COLOR = {
143
252
  running: "#60a5fa",
144
253
  success: "#4ade80",
@@ -151,826 +260,363 @@ var STATUS_SYMBOL = {
151
260
  failed: "✗",
152
261
  aborted: "○"
153
262
  };
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
- };
263
+ function safeStringify(value, indent = 2) {
264
+ if (value === undefined)
265
+ return "undefined";
266
+ if (value === null)
267
+ return "null";
178
268
  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;
269
+ return JSON.stringify(value, null, indent);
270
+ } catch {
271
+ return String(value);
185
272
  }
186
273
  }
187
- function writePrefs(prefs) {
188
- try {
189
- localStorage.setItem(PREFS_KEY, JSON.stringify(prefs));
190
- } catch (_e) {
191
- return;
192
- }
274
+ function formatRelativeAge(ms) {
275
+ if (ms < 1000)
276
+ return `${ms}ms`;
277
+ if (ms < 60000)
278
+ return `${(ms / 1000).toFixed(1)}s`;
279
+ return `${Math.floor(ms / 60000)}m`;
193
280
  }
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"}`;
281
+ function formatDuration(entry) {
282
+ return entry.endTime != null ? `${entry.endTime - entry.startTime}ms` : null;
201
283
  }
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);
284
+ function formatTimestamp(startTime) {
285
+ return new Date(startTime).toLocaleTimeString([], {
286
+ hour: "2-digit",
287
+ minute: "2-digit",
288
+ second: "2-digit",
289
+ hour12: false
290
+ });
209
291
  }
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;
292
+
293
+ // src/devtools/browser/components/RunningTimer.tsx
294
+ import { jsxDEV as jsxDEV2, Fragment } from "react/jsx-dev-runtime";
295
+ function RunningTimer({ startTime }) {
296
+ const [elapsed, setElapsed] = useState(() => Date.now() - startTime);
297
+ useEffect(() => {
298
+ const interval = setInterval(() => setElapsed(Date.now() - startTime), 100);
299
+ return () => clearInterval(interval);
300
+ }, [startTime]);
301
+ return /* @__PURE__ */ jsxDEV2(Fragment, {
302
+ children: [
303
+ elapsed,
304
+ "ms"
305
+ ]
306
+ }, undefined, true, undefined, this);
221
307
  }
222
- function NiceActionDevtools(props) {
223
- if (false) {}
224
- return /* @__PURE__ */ jsxDEV(NiceActionDevtools_Panel, {
225
- ...props
308
+ function DurationDisplay({ entry }) {
309
+ const d = formatDuration(entry);
310
+ return /* @__PURE__ */ jsxDEV2(Fragment, {
311
+ children: d ?? /* @__PURE__ */ jsxDEV2(RunningTimer, {
312
+ startTime: entry.startTime
313
+ }, undefined, false, undefined, this)
226
314
  }, undefined, false, undefined, this);
227
315
  }
228
- function NiceActionDevtools_Panel({
229
- core,
230
- position: defaultPosition = "bottom-right",
231
- initialOpen = false
316
+
317
+ // src/devtools/browser/components/SectionLabel.tsx
318
+ import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
319
+ function SectionLabel({ label, color = "#60a5fa" }) {
320
+ return /* @__PURE__ */ jsxDEV3("div", {
321
+ style: {
322
+ color,
323
+ fontSize: "10px",
324
+ marginBottom: "3px",
325
+ textTransform: "uppercase",
326
+ letterSpacing: "0.05em"
327
+ },
328
+ children: label
329
+ }, undefined, false, undefined, this);
330
+ }
331
+
332
+ // src/devtools/browser/components/CallStackSection.tsx
333
+ import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
334
+ function CallStackLink({
335
+ entry,
336
+ entryRole,
337
+ isFocused,
338
+ onClick
232
339
  }) {
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,
340
+ const color = STATUS_COLOR[entry.status];
341
+ const symbol = STATUS_SYMBOL[entry.status];
342
+ return /* @__PURE__ */ jsxDEV4("div", {
343
+ onClick,
344
+ style: {
345
+ background: isFocused ? "#1e2e45" : "#1e293b",
346
+ borderRadius: "4px",
347
+ borderLeft: isFocused ? "2px solid #a78bfa" : "2px solid transparent",
348
+ padding: isFocused ? "5px 8px 5px 6px" : "5px 8px",
349
+ display: "flex",
350
+ alignItems: "center",
351
+ gap: "8px",
352
+ cursor: "pointer"
353
+ },
368
354
  children: [
369
- dockSide != null && /* @__PURE__ */ jsxDEV(ResizeHandle, {
370
- dockSide,
371
- dockedSize,
372
- onChange: (size) => setPrefs(isHorizDock ? { dockedHeight: size } : { dockedWidth: size })
355
+ /* @__PURE__ */ jsxDEV4("span", {
356
+ style: {
357
+ color: entryRole === "caller" ? "#94a3b8" : "#a78bfa",
358
+ fontSize: "9px",
359
+ flexShrink: 0,
360
+ minWidth: "34px",
361
+ fontFamily: "inherit"
362
+ },
363
+ children: entryRole === "caller" ? "↑ from" : "↓ call"
373
364
  }, 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
365
+ /* @__PURE__ */ jsxDEV4("span", {
366
+ style: { color, fontSize: "10px", flexShrink: 0 },
367
+ children: symbol
383
368
  }, undefined, false, undefined, this),
384
- isHorizDock ? /* @__PURE__ */ jsxDEV("div", {
385
- style: { flex: 1, display: "flex", overflow: "hidden" },
369
+ /* @__PURE__ */ jsxDEV4("span", {
370
+ style: {
371
+ color: "#cbd5e1",
372
+ fontSize: "11px",
373
+ flex: 1,
374
+ overflow: "hidden",
375
+ textOverflow: "ellipsis",
376
+ whiteSpace: "nowrap",
377
+ gap: "0.5em",
378
+ display: "flex",
379
+ alignItems: "center",
380
+ justifyContent: "center"
381
+ },
386
382
  children: [
387
- /* @__PURE__ */ jsxDEV(VirtualActionList, {
388
- ...virtualListProps,
389
- style: { width: "340px", flexShrink: 0, overflowY: "auto", borderRight: "1px solid #1e293b" }
383
+ /* @__PURE__ */ jsxDEV4("span", {
384
+ children: entry.actionId
390
385
  }, 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)
386
+ /* @__PURE__ */ jsxDEV4(DomainChip, {
387
+ domain: entry.domain,
388
+ allDomains: entry.allDomains,
389
+ size: "sm"
399
390
  }, undefined, false, undefined, this)
400
391
  ]
401
- }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV(Fragment2, {
392
+ }, undefined, true, undefined, this),
393
+ /* @__PURE__ */ jsxDEV4("span", {
394
+ style: { color: "#475569", fontSize: "10px", flexShrink: 0 },
395
+ children: /* @__PURE__ */ jsxDEV4(DurationDisplay, {
396
+ entry
397
+ }, undefined, false, undefined, this)
398
+ }, undefined, false, undefined, this)
399
+ ]
400
+ }, undefined, true, undefined, this);
401
+ }
402
+ function CallStackSection({
403
+ parent,
404
+ childEntries,
405
+ focusedChildCuid,
406
+ onFocusChild,
407
+ onSelectParent
408
+ }) {
409
+ if (parent == null && childEntries.length === 0)
410
+ return null;
411
+ return /* @__PURE__ */ jsxDEV4("div", {
412
+ children: [
413
+ /* @__PURE__ */ jsxDEV4(SectionLabel, {
414
+ label: "Call Stack",
415
+ color: "#a78bfa"
416
+ }, undefined, false, undefined, this),
417
+ /* @__PURE__ */ jsxDEV4("div", {
418
+ style: { display: "flex", flexDirection: "column", gap: "2px" },
402
419
  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
- }
420
+ parent != null && /* @__PURE__ */ jsxDEV4(CallStackLink, {
421
+ entry: parent,
422
+ entryRole: "caller",
423
+ isFocused: false,
424
+ onClick: () => onSelectParent(parent.cuid)
411
425
  }, 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)
426
+ childEntries.map((child) => /* @__PURE__ */ jsxDEV4(CallStackLink, {
427
+ entry: child,
428
+ entryRole: "called",
429
+ isFocused: focusedChildCuid === child.cuid,
430
+ onClick: () => onFocusChild(child.cuid)
431
+ }, child.cuid, false, undefined, this))
418
432
  ]
419
433
  }, undefined, true, undefined, this)
420
434
  ]
421
435
  }, undefined, true, undefined, this);
422
436
  }
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
437
+
438
+ // src/devtools/browser/components/DetailSection.tsx
439
+ import { useState as useState2 } from "react";
440
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
441
+ var COMPACT_CHAR_LIMIT = 120;
442
+ function DetailSection({
443
+ label,
444
+ value,
445
+ color = "#60a5fa"
534
446
  }) {
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
- },
447
+ const [expanded, setExpanded] = useState2(false);
448
+ const fullJson = safeStringify(value, 2);
449
+ const compactJson = safeStringify(value, 0);
450
+ const canExpand = fullJson !== compactJson || compactJson.length > COMPACT_CHAR_LIMIT;
451
+ const compactDisplay = compactJson.length > COMPACT_CHAR_LIMIT ? `${compactJson.slice(0, COMPACT_CHAR_LIMIT)}…` : compactJson;
452
+ return /* @__PURE__ */ jsxDEV5("div", {
545
453
  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" },
454
+ /* @__PURE__ */ jsxDEV5("div", {
455
+ style: {
456
+ display: "flex",
457
+ alignItems: "center",
458
+ justifyContent: "space-between",
459
+ marginBottom: "3px"
460
+ },
552
461
  children: [
553
- /* @__PURE__ */ jsxDEV(PositionPicker, {
554
- position,
555
- onChange: onPositionChange
556
- }, undefined, false, undefined, this),
557
- onClear != null && /* @__PURE__ */ jsxDEV("button", {
558
- onClick: onClear,
462
+ /* @__PURE__ */ jsxDEV5("div", {
559
463
  style: {
560
- background: "none",
561
- border: "none",
562
- color: "#475569",
563
- cursor: "pointer",
564
- fontSize: "11px",
565
- padding: "0"
464
+ color,
465
+ fontSize: "10px",
466
+ textTransform: "uppercase",
467
+ letterSpacing: "0.05em"
566
468
  },
567
- children: "clear"
469
+ children: label
568
470
  }, 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: "×"
471
+ canExpand && /* @__PURE__ */ jsxDEV5("span", {
472
+ style: { color: "#334155", fontSize: "11px" },
473
+ children: expanded ? "▾" : "▸"
581
474
  }, undefined, false, undefined, this)
582
475
  ]
583
- }, undefined, true, undefined, this)
476
+ }, undefined, true, undefined, this),
477
+ expanded ? /* @__PURE__ */ jsxDEV5("div", {
478
+ onClick: canExpand ? () => setExpanded(false) : undefined,
479
+ style: {
480
+ margin: 0,
481
+ padding: "6px 8px",
482
+ background: "#1e293b",
483
+ borderRadius: "4px",
484
+ fontSize: "11px",
485
+ color: "#cbd5e1",
486
+ overflowX: "auto",
487
+ textAlign: "left",
488
+ whiteSpace: "pre-wrap",
489
+ wordBreak: "break-all",
490
+ cursor: canExpand ? "pointer" : "default"
491
+ },
492
+ children: fullJson
493
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV5("div", {
494
+ onClick: canExpand ? () => setExpanded(true) : undefined,
495
+ style: {
496
+ padding: "5px 8px",
497
+ background: "#1e293b",
498
+ borderRadius: "4px",
499
+ fontSize: "11px",
500
+ color: "#94a3b8",
501
+ fontFamily: "inherit",
502
+ whiteSpace: "nowrap",
503
+ overflow: "hidden",
504
+ textOverflow: "ellipsis",
505
+ cursor: canExpand ? "pointer" : "default"
506
+ },
507
+ children: compactDisplay
508
+ }, undefined, false, undefined, this)
584
509
  ]
585
510
  }, undefined, true, undefined, this);
586
511
  }
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
512
+
513
+ // src/devtools/core/devtools_colors.ts
514
+ var DEVTOOL_COLOR_HANDLER_LOCAL_TEXT = "#34bb89";
515
+ var DEVTOOL_COLOR_HANDLER_LOCAL_BORDER = "#144427";
516
+ var DEVTOOL_COLOR_HANDLER_EXTERNAL_TEXT = "#cfa12a";
517
+ var DEVTOOL_COLOR_HANDLER_EXTERNAL_BORDER = "#723917";
518
+
519
+ // src/devtools/browser/components/Chip.tsx
520
+ import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
521
+ function Chip({
522
+ color,
523
+ borderColor,
524
+ fontSize = "8px",
525
+ padding = "1px 4px",
526
+ children,
527
+ style
595
528
  }) {
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
- })
529
+ return /* @__PURE__ */ jsxDEV6("span", {
530
+ style: {
531
+ color,
532
+ fontSize,
533
+ background: "#0f172a",
534
+ border: `1px solid ${borderColor}`,
535
+ padding,
536
+ borderRadius: "3px",
537
+ flexShrink: 0,
538
+ whiteSpace: "nowrap",
539
+ ...style
540
+ },
541
+ children
621
542
  }, undefined, false, undefined, this);
622
543
  }
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`;
544
+
545
+ // src/devtools/browser/components/HandlerChips.tsx
546
+ import { jsxDEV as jsxDEV7, Fragment as Fragment2 } from "react/jsx-dev-runtime";
547
+ function getExternalLabel(hop) {
548
+ if (hop.handlerType !== "external")
549
+ return null;
550
+ return hop.handlerClient != null ? `${hop.transport ?? "ext"} → ${hop.handlerClient.envId}` : `→ ${hop.transport ?? "ext"}`;
663
551
  }
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
- });
552
+ function HandlerChips({ entry, size }) {
684
553
  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
- },
554
+ const localEnvId = firstHop != null ? firstHop.runtime.envId : null;
555
+ const externalLabel = firstHop != null ? getExternalLabel(firstHop) : null;
556
+ const fontSize = size === "md" ? "1em" : "0.8em";
557
+ const padding = size === "md" ? "1px 5px" : "1px 4px";
558
+ const firstHopIsLocal = firstHop != null && firstHop.handlerType === "local";
559
+ return /* @__PURE__ */ jsxDEV7(Fragment2, {
753
560
  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
561
+ localEnvId != null && (firstHopIsLocal || externalLabel == null) && /* @__PURE__ */ jsxDEV7(Chip, {
562
+ color: DEVTOOL_COLOR_HANDLER_LOCAL_TEXT,
563
+ borderColor: DEVTOOL_COLOR_HANDLER_LOCAL_BORDER,
564
+ fontSize,
565
+ padding,
566
+ children: "local"
791
567
  }, 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"
568
+ externalLabel != null && /* @__PURE__ */ jsxDEV7(Chip, {
569
+ color: DEVTOOL_COLOR_HANDLER_EXTERNAL_TEXT,
570
+ borderColor: DEVTOOL_COLOR_HANDLER_EXTERNAL_BORDER,
571
+ fontSize,
572
+ padding,
573
+ children: externalLabel
574
+ }, undefined, false, undefined, this)
907
575
  ]
908
576
  }, undefined, true, undefined, this);
909
577
  }
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
- },
578
+
579
+ // src/devtools/browser/components/MetaSection.tsx
580
+ import { useState as useState3 } from "react";
581
+ import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
582
+ function MetaChip({ label, value }) {
583
+ return /* @__PURE__ */ jsxDEV8("span", {
584
+ style: { whiteSpace: "nowrap" },
920
585
  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
586
+ /* @__PURE__ */ jsxDEV8("span", {
587
+ style: { color: "#475569" },
588
+ children: [
589
+ label,
590
+ " "
591
+ ]
592
+ }, undefined, true, undefined, this),
593
+ /* @__PURE__ */ jsxDEV8("span", {
594
+ style: { color: "#cbd5e1" },
595
+ children: value
949
596
  }, undefined, false, undefined, this)
950
597
  ]
951
598
  }, undefined, true, undefined, this);
952
599
  }
953
600
  function MetaSection({ entry }) {
954
- const [expanded, setExpanded] = useState(false);
955
- const { meta, cuid, startTime: _startTime } = entry;
601
+ const [expanded, setExpanded] = useState3(false);
602
+ const { meta, cuid } = entry;
956
603
  const expandedRows = [
957
604
  { label: "cuid", value: cuid },
958
605
  { label: "origin", value: meta.originClient.envId },
959
606
  ...meta.originClient.perId != null ? [{ label: "perId", value: meta.originClient.perId }] : [],
960
607
  ...meta.originClient.insId != null ? [{ label: "insId", value: meta.originClient.insId }] : []
961
608
  ];
962
- return /* @__PURE__ */ jsxDEV("div", {
609
+ return /* @__PURE__ */ jsxDEV8("div", {
963
610
  children: [
964
- /* @__PURE__ */ jsxDEV("div", {
611
+ /* @__PURE__ */ jsxDEV8("div", {
965
612
  style: {
966
613
  display: "flex",
967
614
  alignItems: "center",
968
615
  justifyContent: "space-between",
969
- marginBottom: "3px",
970
- userSelect: "none"
616
+ marginBottom: "3px"
971
617
  },
972
618
  children: [
973
- /* @__PURE__ */ jsxDEV("div", {
619
+ /* @__PURE__ */ jsxDEV8("div", {
974
620
  style: {
975
621
  color: "#60a5fa",
976
622
  fontSize: "10px",
@@ -979,21 +625,16 @@ function MetaSection({ entry }) {
979
625
  },
980
626
  children: "Meta"
981
627
  }, undefined, false, undefined, this),
982
- /* @__PURE__ */ jsxDEV("span", {
628
+ /* @__PURE__ */ jsxDEV8("span", {
983
629
  style: { color: "#334155", fontSize: "11px" },
984
630
  children: expanded ? "▾" : "▸"
985
631
  }, undefined, false, undefined, this)
986
632
  ]
987
633
  }, undefined, true, undefined, this),
988
- expanded ? /* @__PURE__ */ jsxDEV("div", {
634
+ expanded ? /* @__PURE__ */ jsxDEV8("div", {
989
635
  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", {
636
+ style: { background: "#1e293b", borderRadius: "4px", overflow: "hidden", cursor: "pointer" },
637
+ children: expandedRows.map(({ label, value }, i) => /* @__PURE__ */ jsxDEV8("div", {
997
638
  style: {
998
639
  display: "grid",
999
640
  gridTemplateColumns: "52px 1fr",
@@ -1003,22 +644,17 @@ function MetaSection({ entry }) {
1003
644
  alignItems: "start"
1004
645
  },
1005
646
  children: [
1006
- /* @__PURE__ */ jsxDEV("span", {
647
+ /* @__PURE__ */ jsxDEV8("span", {
1007
648
  style: { textAlign: "left", color: "#475569", fontSize: "10px", paddingTop: "1px" },
1008
649
  children: label
1009
650
  }, undefined, false, undefined, this),
1010
- /* @__PURE__ */ jsxDEV("span", {
1011
- style: {
1012
- textAlign: "left",
1013
- color: "#cbd5e1",
1014
- fontSize: "11px",
1015
- wordBreak: "break-all"
1016
- },
651
+ /* @__PURE__ */ jsxDEV8("span", {
652
+ style: { textAlign: "left", color: "#cbd5e1", fontSize: "11px", wordBreak: "break-all" },
1017
653
  children: value
1018
654
  }, undefined, false, undefined, this)
1019
655
  ]
1020
656
  }, label, true, undefined, this))
1021
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV("div", {
657
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV8("div", {
1022
658
  onClick: () => setExpanded(true),
1023
659
  style: {
1024
660
  background: "#1e293b",
@@ -1032,19 +668,19 @@ function MetaSection({ entry }) {
1032
668
  cursor: "pointer"
1033
669
  },
1034
670
  children: [
1035
- /* @__PURE__ */ jsxDEV(MetaChip, {
671
+ /* @__PURE__ */ jsxDEV8(MetaChip, {
1036
672
  label: "cuid",
1037
673
  value: `…${cuid.slice(-8)}`
1038
674
  }, undefined, false, undefined, this),
1039
- /* @__PURE__ */ jsxDEV(MetaChip, {
675
+ /* @__PURE__ */ jsxDEV8(MetaChip, {
1040
676
  label: "origin",
1041
677
  value: meta.originClient.envId
1042
678
  }, undefined, false, undefined, this),
1043
- meta.originClient.perId != null && /* @__PURE__ */ jsxDEV(MetaChip, {
679
+ meta.originClient.perId != null && /* @__PURE__ */ jsxDEV8(MetaChip, {
1044
680
  label: "perId",
1045
681
  value: meta.originClient.perId.length > 10 ? `${meta.originClient.perId.slice(0, 10)}…` : meta.originClient.perId
1046
682
  }, undefined, false, undefined, this),
1047
- meta.originClient.insId != null && /* @__PURE__ */ jsxDEV(MetaChip, {
683
+ meta.originClient.insId != null && /* @__PURE__ */ jsxDEV8(MetaChip, {
1048
684
  label: "insId",
1049
685
  value: meta.originClient.insId.length > 10 ? `${meta.originClient.insId.slice(0, 10)}…` : meta.originClient.insId
1050
686
  }, undefined, false, undefined, this)
@@ -1053,221 +689,1420 @@ function MetaSection({ entry }) {
1053
689
  ]
1054
690
  }, undefined, true, undefined, this);
1055
691
  }
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 }) {
692
+
693
+ // src/devtools/browser/components/RoutingSection.tsx
694
+ import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
695
+ function RoutingSection({
696
+ entry,
697
+ minHopCount = 0
698
+ }) {
1075
699
  const { meta, startTime } = entry;
1076
- if (meta.routing.length === 0)
1077
- return null;
1078
700
  const hopCount = meta.routing.length;
1079
- return /* @__PURE__ */ jsxDEV("div", {
701
+ const phantomCount = Math.max(0, minHopCount - hopCount);
702
+ if (hopCount === 0 && phantomCount === 0)
703
+ return null;
704
+ return /* @__PURE__ */ jsxDEV9("div", {
1080
705
  children: [
1081
- /* @__PURE__ */ jsxDEV(SectionLabel, {
1082
- label: `Routing · ${hopCount} hop${hopCount !== 1 ? "s" : ""}`
706
+ /* @__PURE__ */ jsxDEV9(SectionLabel, {
707
+ label: hopCount > 0 ? `Routing · ${hopCount} hop${hopCount !== 1 ? "s" : ""}` : "Routing"
1083
708
  }, undefined, false, undefined, this),
1084
- /* @__PURE__ */ jsxDEV("div", {
709
+ /* @__PURE__ */ jsxDEV9("div", {
1085
710
  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", {
711
+ children: [
712
+ meta.routing.map((hop, i) => {
713
+ const isLocal = hop.handlerType === "local";
714
+ const isLast = i === hopCount - 1 && phantomCount === 0;
715
+ const badgeColor = isLocal ? "#34d399" : "#fbbf24";
716
+ const badgeText = isLocal ? "● exec" : `→ ${hop.transport ?? "ext"}`;
717
+ const runtimeTitle = [hop.runtime.perId, hop.runtime.insId].filter(Boolean).join(" · ") || undefined;
718
+ return /* @__PURE__ */ jsxDEV9("div", {
719
+ style: {
720
+ background: "#1e293b",
721
+ borderRadius: "4px",
722
+ overflow: "hidden",
723
+ display: "grid",
724
+ gridTemplateColumns: "30% 1fr 30%",
725
+ alignItems: "center",
726
+ columnGap: "8px",
727
+ borderBottom: isLast ? undefined : "1px solid #0f172a",
728
+ padding: "4px 8px"
729
+ },
730
+ children: [
731
+ /* @__PURE__ */ jsxDEV9("span", {
732
+ style: { display: "flex", flexDirection: "row", alignItems: "center", gap: "10px" },
733
+ children: [
734
+ /* @__PURE__ */ jsxDEV9("span", {
735
+ style: { color: "#334155", fontSize: "10px", width: "16px", textAlign: "right" },
736
+ children: i + 1
737
+ }, undefined, false, undefined, this),
738
+ /* @__PURE__ */ jsxDEV9("span", {
739
+ title: runtimeTitle,
740
+ style: {
741
+ color: "#94a3b8",
742
+ fontSize: "11px",
743
+ overflow: "hidden",
744
+ textOverflow: "ellipsis",
745
+ whiteSpace: "nowrap",
746
+ textAlign: "center"
747
+ },
748
+ children: hop.runtime.envId
749
+ }, undefined, false, undefined, this)
750
+ ]
751
+ }, undefined, true, undefined, this),
752
+ /* @__PURE__ */ jsxDEV9("span", {
753
+ style: { color: badgeColor, fontSize: "10px", whiteSpace: "nowrap" },
754
+ children: badgeText
755
+ }, undefined, false, undefined, this),
756
+ /* @__PURE__ */ jsxDEV9("span", {
757
+ style: {
758
+ display: "flex",
759
+ alignItems: "center",
760
+ justifyContent: "space-between",
761
+ paddingRight: "8px",
762
+ overflow: "hidden"
763
+ },
764
+ children: [
765
+ /* @__PURE__ */ jsxDEV9("span", {
766
+ style: {
767
+ color: "#475569",
768
+ fontSize: "10px",
769
+ whiteSpace: "nowrap",
770
+ overflow: "hidden",
771
+ textOverflow: "ellipsis"
772
+ },
773
+ children: hop.handlerClient != null ? `↳ ${hop.handlerClient.envId}` : ""
774
+ }, undefined, false, undefined, this),
775
+ /* @__PURE__ */ jsxDEV9("span", {
776
+ style: { color: "#334155", fontSize: "10px", flexShrink: 0, marginLeft: "auto" },
777
+ children: [
778
+ "+",
779
+ hop.time - startTime,
780
+ "ms"
781
+ ]
782
+ }, undefined, true, undefined, this)
783
+ ]
784
+ }, undefined, true, undefined, this)
785
+ ]
786
+ }, `${hop.time}-${hop.runtime.envId}`, true, undefined, this);
787
+ }),
788
+ Array.from({ length: phantomCount }, (_, i) => `routing-phantom-${hopCount + i}`).map((key) => /* @__PURE__ */ jsxDEV9("div", {
789
+ "aria-hidden": "true",
1094
790
  style: {
791
+ visibility: "hidden",
1095
792
  background: "#1e293b",
1096
793
  borderRadius: "4px",
1097
- overflow: "hidden",
1098
794
  display: "grid",
1099
795
  gridTemplateColumns: "30% 1fr 30%",
1100
796
  alignItems: "center",
1101
797
  columnGap: "8px",
1102
- borderBottom: rowBorder,
1103
798
  padding: "4px 8px"
1104
799
  },
1105
800
  children: [
1106
- /* @__PURE__ */ jsxDEV("span", {
801
+ /* @__PURE__ */ jsxDEV9("span", {
1107
802
  style: { display: "flex", flexDirection: "row", alignItems: "center", gap: "10px" },
1108
803
  children: [
1109
- /* @__PURE__ */ jsxDEV("span", {
1110
- style: {
1111
- color: "#334155",
1112
- fontSize: "10px",
1113
- width: "16px",
1114
- textAlign: "right"
1115
- },
1116
- children: i + 1
804
+ /* @__PURE__ */ jsxDEV9("span", {
805
+ style: { fontSize: "10px", width: "16px" },
806
+ children: "0"
1117
807
  }, 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
808
+ /* @__PURE__ */ jsxDEV9("span", {
809
+ style: { fontSize: "11px" },
810
+ children: "placeholder"
1129
811
  }, undefined, false, undefined, this)
1130
812
  ]
1131
813
  }, undefined, true, undefined, this),
1132
- /* @__PURE__ */ jsxDEV("span", {
1133
- style: { color: badgeColor, fontSize: "10px", whiteSpace: "nowrap" },
1134
- children: badgeText
814
+ /* @__PURE__ */ jsxDEV9("span", {
815
+ style: { fontSize: "10px" },
816
+ children: "placeholder"
1135
817
  }, 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)
818
+ /* @__PURE__ */ jsxDEV9("span", {}, undefined, false, undefined, this)
1170
819
  ]
1171
- }, `${hop.time}-${hop.runtime.envId}`, true, undefined, this);
1172
- })
1173
- }, undefined, false, undefined, this)
820
+ }, key, true, undefined, this))
821
+ ]
822
+ }, undefined, true, undefined, this)
1174
823
  ]
1175
824
  }, undefined, true, undefined, this);
1176
825
  }
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);
826
+
827
+ // src/devtools/browser/components/StackTraceSection.tsx
828
+ import { useState as useState4 } from "react";
829
+ import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
830
+ var INTERNAL_PATTERNS = [
831
+ "/nice-action/",
832
+ "@nice-code/action",
833
+ "node_modules/",
834
+ "native code",
835
+ "<anonymous>"
836
+ ];
837
+ function isInternalFrame(file) {
838
+ return INTERNAL_PATTERNS.some((p) => file.includes(p));
1188
839
  }
1189
- var COMPACT_CHAR_LIMIT = 120;
1190
- function DetailSection({
840
+ function parseStackFrames(stack) {
841
+ return stack.split(`
842
+ `).slice(1).map((line) => {
843
+ const raw = line.trim();
844
+ if (raw === "")
845
+ return null;
846
+ const matchFn = raw.match(/^at (.+?) \((.+):(\d+):(\d+)\)$/);
847
+ if (matchFn != null) {
848
+ const file = matchFn[2];
849
+ return { fn: matchFn[1], file, raw, isInternal: isInternalFrame(file) };
850
+ }
851
+ const matchUrl = raw.match(/^at (.+):(\d+):(\d+)$/);
852
+ if (matchUrl != null) {
853
+ const file = matchUrl[1];
854
+ return { file, raw, isInternal: isInternalFrame(file) };
855
+ }
856
+ return { raw, isInternal: true };
857
+ }).filter((f) => f != null);
858
+ }
859
+ function formatFrameFile(file) {
860
+ if (file == null)
861
+ return "?";
862
+ let path = file;
863
+ try {
864
+ const url = new URL(file);
865
+ path = url.pathname.split("?")[0] ?? url.pathname;
866
+ if (path.startsWith("/@fs/"))
867
+ path = path.slice(4);
868
+ } catch {}
869
+ const parts = path.replace(/\\/g, "/").split("/").filter(Boolean);
870
+ const filtered = parts[0]?.match(/^[a-zA-Z]:$/) != null ? parts.slice(1) : parts;
871
+ const tail = filtered.slice(-4);
872
+ return tail.join("/") || file;
873
+ }
874
+ function StackTraceSection({
1191
875
  label,
1192
- value,
876
+ stack,
1193
877
  color = "#60a5fa"
1194
878
  }) {
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", {
879
+ const [showAll, setShowAll] = useState4(false);
880
+ if (stack == null)
881
+ return null;
882
+ const allFrames = parseStackFrames(stack);
883
+ const userFrames = allFrames.filter((f) => !f.isInternal);
884
+ const hasInternalFrames = allFrames.length > userFrames.length;
885
+ const displayFrames = showAll ? allFrames : userFrames;
886
+ if (allFrames.length === 0)
887
+ return null;
888
+ return /* @__PURE__ */ jsxDEV10("div", {
1201
889
  children: [
1202
- /* @__PURE__ */ jsxDEV("div", {
890
+ /* @__PURE__ */ jsxDEV10("div", {
1203
891
  style: {
1204
892
  display: "flex",
1205
893
  alignItems: "center",
1206
894
  justifyContent: "space-between",
1207
- marginBottom: "3px",
1208
- userSelect: "none"
895
+ marginBottom: "3px"
1209
896
  },
1210
897
  children: [
1211
- /* @__PURE__ */ jsxDEV("div", {
1212
- style: {
1213
- color,
1214
- fontSize: "10px",
1215
- textTransform: "uppercase",
1216
- letterSpacing: "0.05em"
1217
- },
1218
- children: label
898
+ /* @__PURE__ */ jsxDEV10(SectionLabel, {
899
+ label,
900
+ color
1219
901
  }, undefined, false, undefined, this),
1220
- canExpand && /* @__PURE__ */ jsxDEV("span", {
1221
- style: { color: "#334155", fontSize: "11px" },
1222
- children: expanded ? "" : "▸"
902
+ hasInternalFrames && /* @__PURE__ */ jsxDEV10("span", {
903
+ style: { color: "#475569", fontSize: "9px" },
904
+ children: !showAll ? "user only" : `all (${allFrames.length})`
1223
905
  }, undefined, false, undefined, this)
1224
906
  ]
1225
907
  }, 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,
908
+ /* @__PURE__ */ jsxDEV10("div", {
909
+ onClick: () => setShowAll((s) => !s),
1244
910
  style: {
1245
- padding: "5px 8px",
1246
- background: "#1e293b",
911
+ background: "#040a13",
1247
912
  borderRadius: "4px",
1248
- fontSize: "11px",
1249
- color: "#94a3b8",
1250
- fontFamily: "inherit",
1251
- whiteSpace: "nowrap",
913
+ padding: "2px",
1252
914
  overflow: "hidden",
1253
- textOverflow: "ellipsis",
1254
- cursor: canExpand ? "pointer" : "default"
915
+ cursor: "pointer"
1255
916
  },
1256
- children: compactDisplay
917
+ children: displayFrames.length === 0 ? /* @__PURE__ */ jsxDEV10("div", {
918
+ style: { padding: "6px 10px", color: "#64748b", fontSize: "10px", fontStyle: "italic" },
919
+ children: "no user frames captured"
920
+ }, undefined, false, undefined, this) : displayFrames.map((frame, idx) => {
921
+ const displayFile = formatFrameFile(frame.file);
922
+ const slashIdx = displayFile.lastIndexOf("/");
923
+ const folderPrefix = slashIdx >= 0 ? displayFile.slice(0, slashIdx + 1) : "";
924
+ const bareFilename = slashIdx >= 0 ? displayFile.slice(slashIdx + 1) : displayFile;
925
+ const titleStr = frame.file != null ? frame.file : frame.raw;
926
+ const isUser = !frame.isInternal;
927
+ return /* @__PURE__ */ jsxDEV10("div", {
928
+ title: titleStr,
929
+ style: {
930
+ display: "flex",
931
+ flexDirection: "row",
932
+ gap: "0.5em",
933
+ padding: "4px",
934
+ borderBottom: idx < displayFrames.length - 1 ? "1px solid #0f172a" : undefined
935
+ },
936
+ children: [
937
+ /* @__PURE__ */ jsxDEV10("span", {
938
+ style: {
939
+ color: isUser ? "#64748b" : "#2d3f53",
940
+ fontSize: "10px",
941
+ minWidth: "10px",
942
+ textAlign: "left",
943
+ flexShrink: 0,
944
+ fontVariantNumeric: "tabular-nums"
945
+ },
946
+ children: idx + 1
947
+ }, undefined, false, undefined, this),
948
+ /* @__PURE__ */ jsxDEV10("div", {
949
+ style: { display: "flex", flexDirection: "column", gap: "0.15em", lineHeight: 1.2 },
950
+ children: [
951
+ /* @__PURE__ */ jsxDEV10("div", {
952
+ style: { display: "flex", alignItems: "center" },
953
+ children: /* @__PURE__ */ jsxDEV10("span", {
954
+ style: {
955
+ color: isUser ? "#e2e8f0" : "#50698b",
956
+ fontSize: "12px",
957
+ fontWeight: 500,
958
+ overflow: "hidden",
959
+ textOverflow: "ellipsis",
960
+ whiteSpace: "nowrap"
961
+ },
962
+ children: frame.fn ?? "(anonymous)"
963
+ }, undefined, false, undefined, this)
964
+ }, undefined, false, undefined, this),
965
+ /* @__PURE__ */ jsxDEV10("div", {
966
+ style: { display: "flex", alignItems: "baseline", overflow: "hidden" },
967
+ children: [
968
+ folderPrefix !== "" && /* @__PURE__ */ jsxDEV10("span", {
969
+ style: {
970
+ color: isUser ? "#596b83" : "#2d3f53",
971
+ fontSize: "10px",
972
+ overflow: "hidden",
973
+ textOverflow: "ellipsis",
974
+ whiteSpace: "nowrap",
975
+ flexShrink: 1,
976
+ minWidth: 0
977
+ },
978
+ children: folderPrefix
979
+ }, undefined, false, undefined, this),
980
+ /* @__PURE__ */ jsxDEV10("span", {
981
+ style: {
982
+ color: isUser ? "#8a9ebb" : "#425979",
983
+ fontSize: "10px",
984
+ whiteSpace: "nowrap",
985
+ flexShrink: 0
986
+ },
987
+ children: bareFilename
988
+ }, undefined, false, undefined, this)
989
+ ]
990
+ }, undefined, true, undefined, this)
991
+ ]
992
+ }, undefined, true, undefined, this)
993
+ ]
994
+ }, `${frame.fn ?? "anon"}@${frame.file ?? "unknown"}`, true, undefined, this);
995
+ })
1257
996
  }, undefined, false, undefined, this)
1258
997
  ]
1259
998
  }, undefined, true, undefined, this);
1260
999
  }
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);
1000
+
1001
+ // src/devtools/browser/components/ActionDetailPanel.tsx
1002
+ import { jsxDEV as jsxDEV11, Fragment as Fragment3 } from "react/jsx-dev-runtime";
1003
+ function DetailHeader({
1004
+ entry,
1005
+ isActive,
1006
+ onClick,
1007
+ childExternalLabels
1008
+ }) {
1009
+ const color = STATUS_COLOR[entry.status];
1010
+ const symbol = STATUS_SYMBOL[entry.status];
1011
+ const timestamp = formatTimestamp(entry.startTime);
1012
+ return /* @__PURE__ */ jsxDEV11("div", {
1013
+ onClick: !isActive ? onClick : undefined,
1014
+ style: {
1015
+ padding: "10px 12px",
1016
+ background: isActive ? "#1e293b" : "#131f35",
1017
+ borderBottom: "1px solid #0f172a",
1018
+ borderLeft: isActive ? "2px solid #60a5fa" : "2px solid transparent",
1019
+ flexShrink: 0,
1020
+ display: "flex",
1021
+ alignItems: "flex-start",
1022
+ gap: "10px",
1023
+ cursor: isActive ? "default" : "pointer"
1024
+ },
1025
+ children: [
1026
+ /* @__PURE__ */ jsxDEV11("span", {
1027
+ style: {
1028
+ color,
1029
+ fontSize: "15px",
1030
+ flexShrink: 0,
1031
+ paddingTop: "1px",
1032
+ animation: entry.status === "running" ? "__nice-action-pulse 1.2s ease-in-out infinite" : undefined
1033
+ },
1034
+ children: symbol
1035
+ }, undefined, false, undefined, this),
1036
+ /* @__PURE__ */ jsxDEV11("div", {
1037
+ style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: "0.5em" },
1038
+ children: [
1039
+ /* @__PURE__ */ jsxDEV11("div", {
1040
+ style: { display: "flex", alignItems: "center", minWidth: 0, gap: "0.4em" },
1041
+ children: [
1042
+ /* @__PURE__ */ jsxDEV11("span", {
1043
+ style: { fontSize: "1.2em" },
1044
+ children: "⚡"
1045
+ }, undefined, false, undefined, this),
1046
+ /* @__PURE__ */ jsxDEV11("span", {
1047
+ style: {
1048
+ color: "#f1f5f9",
1049
+ fontSize: "1.2em",
1050
+ fontWeight: "600",
1051
+ overflow: "hidden",
1052
+ textOverflow: "ellipsis",
1053
+ whiteSpace: "nowrap",
1054
+ flexShrink: 1,
1055
+ minWidth: "24px"
1056
+ },
1057
+ children: entry.actionId
1058
+ }, undefined, false, undefined, this),
1059
+ /* @__PURE__ */ jsxDEV11(DomainChip, {
1060
+ domain: entry.domain,
1061
+ allDomains: entry.allDomains,
1062
+ size: "md"
1063
+ }, undefined, false, undefined, this)
1064
+ ]
1065
+ }, undefined, true, undefined, this),
1066
+ /* @__PURE__ */ jsxDEV11("div", {
1067
+ style: {
1068
+ display: "flex",
1069
+ alignItems: "center",
1070
+ justifyContent: "space-between",
1071
+ gap: "8px"
1072
+ },
1073
+ children: [
1074
+ /* @__PURE__ */ jsxDEV11("div", {
1075
+ style: {
1076
+ display: "flex",
1077
+ alignItems: "center",
1078
+ gap: "6px",
1079
+ minWidth: 0,
1080
+ overflow: "hidden"
1081
+ },
1082
+ children: /* @__PURE__ */ jsxDEV11(HandlerChips, {
1083
+ entry,
1084
+ size: "md"
1085
+ }, undefined, false, undefined, this)
1086
+ }, undefined, false, undefined, this),
1087
+ /* @__PURE__ */ jsxDEV11("div", {
1088
+ style: { display: "flex", alignItems: "center", gap: "8px", flexShrink: 0 },
1089
+ children: [
1090
+ /* @__PURE__ */ jsxDEV11("span", {
1091
+ style: { color: "#334155", fontSize: "10px", letterSpacing: "0.02em" },
1092
+ children: timestamp
1093
+ }, undefined, false, undefined, this),
1094
+ /* @__PURE__ */ jsxDEV11("span", {
1095
+ style: { color, fontSize: "12px", fontWeight: "500" },
1096
+ children: /* @__PURE__ */ jsxDEV11(DurationDisplay, {
1097
+ entry
1098
+ }, undefined, false, undefined, this)
1099
+ }, undefined, false, undefined, this)
1100
+ ]
1101
+ }, undefined, true, undefined, this)
1102
+ ]
1103
+ }, undefined, true, undefined, this)
1104
+ ]
1105
+ }, undefined, true, undefined, this)
1106
+ ]
1107
+ }, undefined, true, undefined, this);
1108
+ }
1109
+ function ActionDetailPanel({
1110
+ entry,
1111
+ parent,
1112
+ childEntries,
1113
+ onSelectEntry
1114
+ }) {
1115
+ const [focusedChildCuid, setFocusedChildCuid] = useState5(null);
1116
+ const focusedEntry = focusedChildCuid != null ? childEntries.find((e) => e.cuid === focusedChildCuid) ?? entry : entry;
1117
+ const maxRoutingHops = Math.max(entry.meta.routing.length, ...childEntries.map((e) => e.meta.routing.length), 0);
1118
+ const childExternalLabels = useMemo(() => {
1119
+ const seen = new Set;
1120
+ const result = [];
1121
+ for (const child of childEntries) {
1122
+ const firstHop = child.meta.routing[0];
1123
+ if (firstHop == null)
1124
+ continue;
1125
+ const label = getExternalLabel(firstHop);
1126
+ if (label == null || seen.has(label))
1127
+ continue;
1128
+ seen.add(label);
1129
+ result.push(label);
1130
+ }
1131
+ return result;
1132
+ }, [childEntries]);
1133
+ const handleFocusChild = (cuid) => {
1134
+ setFocusedChildCuid((prev) => prev === cuid ? null : cuid);
1135
+ };
1136
+ return /* @__PURE__ */ jsxDEV11("div", {
1137
+ style: {
1138
+ flex: 1,
1139
+ display: "flex",
1140
+ flexDirection: "column",
1141
+ overflow: "hidden",
1142
+ minHeight: 0,
1143
+ background: "#0f172a"
1144
+ },
1145
+ children: [
1146
+ /* @__PURE__ */ jsxDEV11(DetailHeader, {
1147
+ entry,
1148
+ isActive: focusedChildCuid === null,
1149
+ onClick: () => setFocusedChildCuid(null),
1150
+ childExternalLabels
1151
+ }, undefined, false, undefined, this),
1152
+ /* @__PURE__ */ jsxDEV11("div", {
1153
+ style: {
1154
+ flex: 1,
1155
+ overflowY: "auto",
1156
+ minHeight: 0,
1157
+ padding: "10px 12px",
1158
+ display: "flex",
1159
+ flexDirection: "column",
1160
+ gap: "8px"
1161
+ },
1162
+ children: [
1163
+ /* @__PURE__ */ jsxDEV11(CallStackSection, {
1164
+ parent,
1165
+ childEntries,
1166
+ focusedChildCuid,
1167
+ onFocusChild: handleFocusChild,
1168
+ onSelectParent: onSelectEntry
1169
+ }, undefined, false, undefined, this),
1170
+ /* @__PURE__ */ jsxDEV11(MetaSection, {
1171
+ entry: focusedEntry
1172
+ }, undefined, false, undefined, this),
1173
+ /* @__PURE__ */ jsxDEV11(RoutingSection, {
1174
+ entry: focusedEntry,
1175
+ minHopCount: maxRoutingHops
1176
+ }, undefined, false, undefined, this),
1177
+ /* @__PURE__ */ jsxDEV11(StackTraceSection, {
1178
+ label: "Dispatch Site",
1179
+ stack: focusedEntry.callSite,
1180
+ color: "#94a3b8"
1181
+ }, undefined, false, undefined, this),
1182
+ /* @__PURE__ */ jsxDEV11(DetailSection, {
1183
+ label: "Input",
1184
+ value: focusedEntry.input
1185
+ }, undefined, false, undefined, this),
1186
+ focusedEntry.status === "success" && /* @__PURE__ */ jsxDEV11(DetailSection, {
1187
+ label: "Output",
1188
+ value: focusedEntry.output,
1189
+ color: "#4ade80"
1190
+ }, undefined, false, undefined, this),
1191
+ focusedEntry.status === "failed" && /* @__PURE__ */ jsxDEV11(Fragment3, {
1192
+ children: [
1193
+ /* @__PURE__ */ jsxDEV11(DetailSection, {
1194
+ label: "Error",
1195
+ value: focusedEntry.error,
1196
+ color: "#f87171"
1197
+ }, undefined, false, undefined, this),
1198
+ /* @__PURE__ */ jsxDEV11(StackTraceSection, {
1199
+ label: "Error Stack",
1200
+ stack: focusedEntry.errorStack,
1201
+ color: "#f87171"
1202
+ }, undefined, false, undefined, this)
1203
+ ]
1204
+ }, undefined, true, undefined, this),
1205
+ focusedEntry.status === "aborted" && /* @__PURE__ */ jsxDEV11(Fragment3, {
1206
+ children: [
1207
+ focusedEntry.abortReason != null && /* @__PURE__ */ jsxDEV11(DetailSection, {
1208
+ label: "Abort Reason",
1209
+ value: focusedEntry.abortReason,
1210
+ color: "#9ca3af"
1211
+ }, undefined, false, undefined, this),
1212
+ /* @__PURE__ */ jsxDEV11(StackTraceSection, {
1213
+ label: "Abort Stack",
1214
+ stack: focusedEntry.errorStack,
1215
+ color: "#9ca3af"
1216
+ }, undefined, false, undefined, this)
1217
+ ]
1218
+ }, undefined, true, undefined, this),
1219
+ focusedEntry.progressUpdates.length > 0 && /* @__PURE__ */ jsxDEV11(DetailSection, {
1220
+ label: `Progress (${focusedEntry.progressUpdates.length})`,
1221
+ value: focusedEntry.progressUpdates
1222
+ }, undefined, false, undefined, this)
1223
+ ]
1224
+ }, undefined, true, undefined, this)
1225
+ ]
1226
+ }, undefined, true, undefined, this);
1227
+ }
1228
+
1229
+ // src/devtools/browser/components/ChildDispatchChips.tsx
1230
+ import { jsxDEV as jsxDEV12, Fragment as Fragment4 } from "react/jsx-dev-runtime";
1231
+ function ChildDispatchChips({
1232
+ labels,
1233
+ size = "sm"
1234
+ }) {
1235
+ if (labels == null || labels.length === 0)
1236
+ return null;
1237
+ const fontSize = size === "md" ? "1em" : "0.8em";
1238
+ const padding = size === "md" ? "1px 4px" : "1px 3px";
1239
+ return /* @__PURE__ */ jsxDEV12(Fragment4, {
1240
+ children: labels.map((label) => /* @__PURE__ */ jsxDEV12(Chip, {
1241
+ color: DEVTOOL_COLOR_HANDLER_EXTERNAL_TEXT,
1242
+ borderColor: DEVTOOL_COLOR_HANDLER_EXTERNAL_BORDER,
1243
+ fontSize,
1244
+ padding,
1245
+ children: [
1246
+ "↳ ",
1247
+ label
1248
+ ]
1249
+ }, label, true, undefined, this))
1250
+ }, undefined, false, undefined, this);
1251
+ }
1252
+
1253
+ // src/devtools/browser/components/ActionEntryRow.tsx
1254
+ import { jsxDEV as jsxDEV13 } from "react/jsx-dev-runtime";
1255
+ function ActionEntryRow({
1256
+ entry,
1257
+ isSelected,
1258
+ onClick,
1259
+ groupCount,
1260
+ isSubEntry = false,
1261
+ isLatest = false,
1262
+ latestTime,
1263
+ childExternalLabels
1264
+ }) {
1265
+ const color = STATUS_COLOR[entry.status];
1266
+ const symbol = STATUS_SYMBOL[entry.status];
1267
+ const timestamp = formatTimestamp(entry.startTime);
1268
+ if (isSubEntry) {
1269
+ return /* @__PURE__ */ jsxDEV13("div", {
1270
+ "data-cuid": entry.cuid,
1271
+ onClick,
1272
+ style: {
1273
+ display: "flex",
1274
+ alignItems: "center",
1275
+ gap: "1em",
1276
+ padding: "4px 10px 4px 26px",
1277
+ cursor: "pointer",
1278
+ background: isSelected ? "#131f35" : "#070d18",
1279
+ borderBottom: "1px solid #0f172a",
1280
+ borderLeft: isSelected ? "2px solid #3b82f6" : "2px solid transparent"
1281
+ },
1282
+ children: [
1283
+ /* @__PURE__ */ jsxDEV13("span", {
1284
+ style: { color: "#334155", fontSize: "10px", flexShrink: 0 },
1285
+ children: symbol
1286
+ }, undefined, false, undefined, this),
1287
+ /* @__PURE__ */ jsxDEV13(DomainChip, {
1288
+ subtle: true,
1289
+ domain: entry.domain,
1290
+ allDomains: entry.allDomains,
1291
+ size: "sm"
1292
+ }, undefined, false, undefined, this),
1293
+ /* @__PURE__ */ jsxDEV13("span", {
1294
+ children: [
1295
+ /* @__PURE__ */ jsxDEV13("span", {
1296
+ style: { color: isSelected ? "#818cf8" : "#3730a3", opacity: 0.5, fontSize: "10px" },
1297
+ children: "⚡"
1298
+ }, undefined, false, undefined, this),
1299
+ /* @__PURE__ */ jsxDEV13("span", {
1300
+ style: {
1301
+ flex: 1,
1302
+ color: "#475569",
1303
+ fontSize: "11px",
1304
+ overflow: "hidden",
1305
+ textOverflow: "ellipsis",
1306
+ whiteSpace: "nowrap",
1307
+ minWidth: 0
1308
+ },
1309
+ children: entry.actionId
1310
+ }, undefined, false, undefined, this)
1311
+ ]
1312
+ }, undefined, true, undefined, this),
1313
+ /* @__PURE__ */ jsxDEV13("span", {
1314
+ style: { color: "#334155", fontSize: "11px", flexShrink: 0 },
1315
+ children: /* @__PURE__ */ jsxDEV13(DurationDisplay, {
1316
+ entry
1317
+ }, undefined, false, undefined, this)
1318
+ }, undefined, false, undefined, this)
1319
+ ]
1320
+ }, undefined, true, undefined, this);
1270
1321
  }
1322
+ return /* @__PURE__ */ jsxDEV13("div", {
1323
+ "data-cuid": entry.cuid,
1324
+ onClick,
1325
+ style: {
1326
+ display: "flex",
1327
+ alignItems: "flex-start",
1328
+ gap: "8px",
1329
+ padding: isSelected ? "6px 12px 6px 10px" : "6px 12px",
1330
+ cursor: "pointer",
1331
+ background: isSelected ? "#131f35" : "transparent",
1332
+ borderBottom: "1px solid #0f172a",
1333
+ borderLeft: isSelected ? "2px solid #60a5fa" : "2px solid transparent"
1334
+ },
1335
+ children: [
1336
+ /* @__PURE__ */ jsxDEV13("span", {
1337
+ style: {
1338
+ flexShrink: 0,
1339
+ minWidth: "3.5em",
1340
+ display: "flex",
1341
+ alignItems: "center",
1342
+ justifyContent: "start"
1343
+ },
1344
+ children: isLatest ? /* @__PURE__ */ jsxDEV13(Chip, {
1345
+ color: "#60a5fa",
1346
+ borderColor: "#1e3a5f",
1347
+ children: "latest"
1348
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV13(Chip, {
1349
+ color: "#475569",
1350
+ borderColor: "#1e293b",
1351
+ children: [
1352
+ "+",
1353
+ latestTime != null ? formatRelativeAge(latestTime - entry.startTime) : "?"
1354
+ ]
1355
+ }, undefined, true, undefined, this)
1356
+ }, undefined, false, undefined, this),
1357
+ /* @__PURE__ */ jsxDEV13("span", {
1358
+ style: {
1359
+ color,
1360
+ fontSize: "10px",
1361
+ flexShrink: 0,
1362
+ paddingTop: "2px",
1363
+ animation: entry.status === "running" ? "__nice-action-pulse 1.2s ease-in-out infinite" : undefined
1364
+ },
1365
+ children: symbol
1366
+ }, undefined, false, undefined, this),
1367
+ /* @__PURE__ */ jsxDEV13("div", {
1368
+ style: { flex: 1, minWidth: 0, display: "flex", flexDirection: "column", gap: "3px" },
1369
+ children: [
1370
+ /* @__PURE__ */ jsxDEV13("div", {
1371
+ style: {
1372
+ display: "flex",
1373
+ alignItems: "center",
1374
+ minWidth: 0,
1375
+ overflow: "hidden",
1376
+ gap: "0.3em"
1377
+ },
1378
+ children: [
1379
+ /* @__PURE__ */ jsxDEV13(DomainChip, {
1380
+ domain: entry.domain,
1381
+ allDomains: entry.allDomains,
1382
+ size: "md"
1383
+ }, undefined, false, undefined, this),
1384
+ /* @__PURE__ */ jsxDEV13("span", {
1385
+ style: { color: isSelected ? "#818cf8" : "#3730a3", fontSize: "1em" },
1386
+ children: "⚡"
1387
+ }, undefined, false, undefined, this),
1388
+ /* @__PURE__ */ jsxDEV13("span", {
1389
+ style: {
1390
+ color: "#cbd5e1",
1391
+ fontSize: "11px",
1392
+ overflow: "hidden",
1393
+ textOverflow: "ellipsis",
1394
+ whiteSpace: "nowrap",
1395
+ flexShrink: 1,
1396
+ minWidth: "24px"
1397
+ },
1398
+ children: entry.actionId
1399
+ }, undefined, false, undefined, this)
1400
+ ]
1401
+ }, undefined, true, undefined, this),
1402
+ /* @__PURE__ */ jsxDEV13("div", {
1403
+ style: {
1404
+ display: "flex",
1405
+ alignItems: "center",
1406
+ justifyContent: "space-between",
1407
+ gap: "6px"
1408
+ },
1409
+ children: [
1410
+ /* @__PURE__ */ jsxDEV13("div", {
1411
+ style: {
1412
+ display: "flex",
1413
+ flexDirection: "row",
1414
+ alignItems: "center",
1415
+ gap: "5px",
1416
+ minWidth: 0,
1417
+ overflow: "hidden"
1418
+ },
1419
+ children: [
1420
+ /* @__PURE__ */ jsxDEV13(HandlerChips, {
1421
+ entry,
1422
+ size: "sm"
1423
+ }, undefined, false, undefined, this),
1424
+ /* @__PURE__ */ jsxDEV13(ChildDispatchChips, {
1425
+ labels: childExternalLabels,
1426
+ size: "sm"
1427
+ }, undefined, false, undefined, this)
1428
+ ]
1429
+ }, undefined, true, undefined, this),
1430
+ /* @__PURE__ */ jsxDEV13("div", {
1431
+ style: { display: "flex", alignItems: "center", gap: "6px", flexShrink: 0 },
1432
+ children: [
1433
+ groupCount != null && /* @__PURE__ */ jsxDEV13(Chip, {
1434
+ color: "#3b82f6",
1435
+ borderColor: "#1e3a5f",
1436
+ fontSize: "9px",
1437
+ padding: "1px 5px",
1438
+ children: [
1439
+ "x",
1440
+ groupCount
1441
+ ]
1442
+ }, undefined, true, undefined, this),
1443
+ /* @__PURE__ */ jsxDEV13("span", {
1444
+ style: { color: "#1e3a5f", fontSize: "10px", letterSpacing: "0.02em" },
1445
+ children: timestamp
1446
+ }, undefined, false, undefined, this),
1447
+ /* @__PURE__ */ jsxDEV13("span", {
1448
+ style: { color: "#475569", fontSize: "11px" },
1449
+ children: /* @__PURE__ */ jsxDEV13(DurationDisplay, {
1450
+ entry
1451
+ }, undefined, false, undefined, this)
1452
+ }, undefined, false, undefined, this)
1453
+ ]
1454
+ }, undefined, true, undefined, this)
1455
+ ]
1456
+ }, undefined, true, undefined, this)
1457
+ ]
1458
+ }, undefined, true, undefined, this)
1459
+ ]
1460
+ }, undefined, true, undefined, this);
1461
+ }
1462
+
1463
+ // src/devtools/browser/components/PanelChrome.tsx
1464
+ import { jsxDEV as jsxDEV14 } from "react/jsx-dev-runtime";
1465
+ var DOCKED_SIZE_MIN = 140;
1466
+ var POSITION_GRID = [
1467
+ ["top-left", "dock-top", "top-right"],
1468
+ ["dock-left", null, "dock-right"],
1469
+ ["bottom-left", "dock-bottom", "bottom-right"]
1470
+ ];
1471
+ function getDockSide(pos) {
1472
+ if (pos === "dock-top")
1473
+ return "top";
1474
+ if (pos === "dock-bottom")
1475
+ return "bottom";
1476
+ if (pos === "dock-left")
1477
+ return "left";
1478
+ if (pos === "dock-right")
1479
+ return "right";
1480
+ return null;
1481
+ }
1482
+ function PanelHeader({
1483
+ position,
1484
+ onPositionChange,
1485
+ onClose,
1486
+ onClear
1487
+ }) {
1488
+ return /* @__PURE__ */ jsxDEV14("div", {
1489
+ style: {
1490
+ display: "flex",
1491
+ alignItems: "center",
1492
+ justifyContent: "space-between",
1493
+ padding: "8px 12px",
1494
+ background: "#1e293b",
1495
+ borderBottom: "1px solid #0f172a",
1496
+ flexShrink: 0
1497
+ },
1498
+ children: [
1499
+ /* @__PURE__ */ jsxDEV14("span", {
1500
+ style: { color: "#60a5fa", fontWeight: "bold", fontSize: "11px" },
1501
+ children: "⚡ nice-action devtools"
1502
+ }, undefined, false, undefined, this),
1503
+ /* @__PURE__ */ jsxDEV14("div", {
1504
+ style: { display: "flex", gap: "10px", alignItems: "center" },
1505
+ children: [
1506
+ /* @__PURE__ */ jsxDEV14(PositionPicker, {
1507
+ position,
1508
+ onChange: onPositionChange
1509
+ }, undefined, false, undefined, this),
1510
+ onClear != null && /* @__PURE__ */ jsxDEV14("button", {
1511
+ onClick: onClear,
1512
+ style: {
1513
+ background: "none",
1514
+ border: "none",
1515
+ color: "#475569",
1516
+ cursor: "pointer",
1517
+ fontSize: "11px",
1518
+ padding: "0"
1519
+ },
1520
+ children: "clear"
1521
+ }, undefined, false, undefined, this),
1522
+ /* @__PURE__ */ jsxDEV14("button", {
1523
+ onClick: onClose,
1524
+ style: {
1525
+ background: "none",
1526
+ border: "none",
1527
+ color: "#475569",
1528
+ cursor: "pointer",
1529
+ fontSize: "16px",
1530
+ padding: "0",
1531
+ lineHeight: "1"
1532
+ },
1533
+ children: "×"
1534
+ }, undefined, false, undefined, this)
1535
+ ]
1536
+ }, undefined, true, undefined, this)
1537
+ ]
1538
+ }, undefined, true, undefined, this);
1539
+ }
1540
+ function PositionPicker({
1541
+ position,
1542
+ onChange
1543
+ }) {
1544
+ return /* @__PURE__ */ jsxDEV14("div", {
1545
+ title: "Move / dock panel",
1546
+ style: { display: "grid", gridTemplateColumns: "repeat(3, 9px)", gap: "2px", padding: "2px" },
1547
+ children: POSITION_GRID.flat().map((pos) => {
1548
+ if (pos == null)
1549
+ return /* @__PURE__ */ jsxDEV14("div", {
1550
+ style: { width: "9px", height: "9px" }
1551
+ }, "center-empty", false, undefined, this);
1552
+ const isDock = pos.startsWith("dock-");
1553
+ const isTopBottom = pos === "dock-top" || pos === "dock-bottom";
1554
+ const isActive = pos === position;
1555
+ return /* @__PURE__ */ jsxDEV14("div", {
1556
+ title: pos,
1557
+ onClick: () => onChange(pos),
1558
+ style: {
1559
+ width: "9px",
1560
+ height: "9px",
1561
+ display: "flex",
1562
+ alignItems: "center",
1563
+ justifyContent: "center",
1564
+ cursor: "pointer"
1565
+ },
1566
+ children: /* @__PURE__ */ jsxDEV14("div", {
1567
+ style: {
1568
+ width: isDock ? isTopBottom ? "9px" : "3px" : "7px",
1569
+ height: isDock ? isTopBottom ? "3px" : "9px" : "7px",
1570
+ borderRadius: isDock ? "1px" : "50%",
1571
+ background: isActive ? "#60a5fa" : "#334155"
1572
+ }
1573
+ }, undefined, false, undefined, this)
1574
+ }, pos, false, undefined, this);
1575
+ })
1576
+ }, undefined, false, undefined, this);
1577
+ }
1578
+ function ResizeHandle({
1579
+ dockSide,
1580
+ dockedSize,
1581
+ onChange
1582
+ }) {
1583
+ const isHoriz = dockSide === "left" || dockSide === "right";
1584
+ const onMouseDown = (e) => {
1585
+ e.preventDefault();
1586
+ const startCoord = isHoriz ? e.clientX : e.clientY;
1587
+ const startSize = dockedSize;
1588
+ const maxSize = isHoriz ? window.innerWidth * 0.85 : window.innerHeight * 0.85;
1589
+ const sign = dockSide === "bottom" || dockSide === "right" ? -1 : 1;
1590
+ const onMove = (me) => {
1591
+ const delta = (isHoriz ? me.clientX : me.clientY) - startCoord;
1592
+ onChange(Math.max(DOCKED_SIZE_MIN, Math.min(maxSize, startSize + sign * delta)));
1593
+ };
1594
+ const onUp = () => {
1595
+ window.removeEventListener("mousemove", onMove);
1596
+ window.removeEventListener("mouseup", onUp);
1597
+ };
1598
+ window.addEventListener("mousemove", onMove);
1599
+ window.addEventListener("mouseup", onUp);
1600
+ };
1601
+ 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" };
1602
+ return /* @__PURE__ */ jsxDEV14("div", {
1603
+ onMouseDown,
1604
+ style: {
1605
+ position: "absolute",
1606
+ zIndex: 10,
1607
+ background: "transparent",
1608
+ ...edgeStyle
1609
+ }
1610
+ }, undefined, false, undefined, this);
1611
+ }
1612
+
1613
+ // src/devtools/browser/NiceActionDevtools.tsx
1614
+ import { jsxDEV as jsxDEV15, Fragment as Fragment5 } from "react/jsx-dev-runtime";
1615
+ if (typeof document !== "undefined" && !document.getElementById("__nice-action-devtools-styles")) {
1616
+ const style = document.createElement("style");
1617
+ style.id = "__nice-action-devtools-styles";
1618
+ style.textContent = `
1619
+ @keyframes __nice-action-pulse {
1620
+ 0%, 100% { opacity: 1; }
1621
+ 50% { opacity: 0.35; }
1622
+ }
1623
+ @keyframes __nice-action-shine {
1624
+ 0% { transform: translateX(-100%); opacity: 0; }
1625
+ 15% { opacity: 1; }
1626
+ 85% { opacity: 1; }
1627
+ 100% { transform: translateX(200%); opacity: 0; }
1628
+ }
1629
+ `;
1630
+ document.head?.appendChild(style);
1631
+ }
1632
+ var PREFS_KEY = "__nice-action-devtools-prefs";
1633
+ var DOCKED_HEIGHT_DEFAULT = 320;
1634
+ var DOCKED_WIDTH_DEFAULT = 420;
1635
+ function readPrefs(defaultPosition, initialOpen) {
1636
+ const fallback = {
1637
+ position: defaultPosition,
1638
+ isOpen: initialOpen,
1639
+ dockedHeight: DOCKED_HEIGHT_DEFAULT,
1640
+ dockedWidth: DOCKED_WIDTH_DEFAULT
1641
+ };
1642
+ try {
1643
+ if (typeof localStorage === "undefined")
1644
+ return fallback;
1645
+ const stored = localStorage.getItem(PREFS_KEY);
1646
+ return stored != null ? { ...fallback, ...JSON.parse(stored) } : fallback;
1647
+ } catch (_e) {
1648
+ return fallback;
1649
+ }
1650
+ }
1651
+ function writePrefs(prefs) {
1652
+ try {
1653
+ localStorage.setItem(PREFS_KEY, JSON.stringify(prefs));
1654
+ } catch (_e) {
1655
+ return;
1656
+ }
1657
+ }
1658
+ function getHandlerKey(entry) {
1659
+ const hop = entry.meta.routing[0];
1660
+ if (hop == null)
1661
+ return "none";
1662
+ if (hop.handlerType === "local")
1663
+ return "local";
1664
+ return `ext:${hop.transport ?? "ext"}`;
1665
+ }
1666
+ function canGroupWith(a, b) {
1667
+ if (a.status === "running" || b.status === "running")
1668
+ return false;
1669
+ const handlerA = getHandlerKey(a);
1670
+ const handlerB = getHandlerKey(b);
1671
+ const handlerConflict = handlerA !== "none" && handlerB !== "none" && handlerA !== handlerB;
1672
+ return a.actionId === b.actionId && a.domain === b.domain && a.status === b.status && !handlerConflict && safeStringify(a.input, 0) === safeStringify(b.input, 0);
1673
+ }
1674
+ function groupEntries(entries) {
1675
+ const groups = [];
1676
+ for (const entry of entries) {
1677
+ const last = groups[groups.length - 1];
1678
+ if (last != null && canGroupWith(entry, last.representative)) {
1679
+ last.rest.push(entry);
1680
+ } else {
1681
+ groups.push({ representative: entry, rest: [] });
1682
+ }
1683
+ }
1684
+ return groups;
1685
+ }
1686
+ function NiceActionDevtools(props) {
1687
+ if (false) {}
1688
+ return /* @__PURE__ */ jsxDEV15(NiceActionDevtools_Panel, {
1689
+ ...props
1690
+ }, undefined, false, undefined, this);
1691
+ }
1692
+ function NiceActionDevtools_Panel({
1693
+ core,
1694
+ position: defaultPosition = "bottom-right",
1695
+ initialOpen = false
1696
+ }) {
1697
+ const [prefs, setPrefsRaw] = useState6(() => readPrefs(defaultPosition, initialOpen));
1698
+ const [entries, setEntries] = useState6([]);
1699
+ const [selectedCuid, setSelectedCuid] = useState6(null);
1700
+ const [expandedGroupCuids, setExpandedGroupCuids] = useState6(new Set);
1701
+ const [domainTooltip, setDomainTooltip] = useState6(null);
1702
+ const showDomainTooltip = useCallback((rect, allDomains) => setDomainTooltip({ rect, allDomains }), []);
1703
+ const hideDomainTooltip = useCallback(() => setDomainTooltip(null), []);
1704
+ const domainTooltipCtx = useMemo2(() => ({ show: showDomainTooltip, hide: hideDomainTooltip }), [showDomainTooltip, hideDomainTooltip]);
1705
+ useEffect2(() => core.subscribe(setEntries), [core]);
1706
+ const groups = useMemo2(() => {
1707
+ const byCuid = new Map(entries.map((e) => [e.cuid, e]));
1708
+ const roots = entries.filter((e) => e.status !== "running" && (e.parentCuid == null || !byCuid.has(e.parentCuid)));
1709
+ return groupEntries(roots);
1710
+ }, [entries]);
1711
+ const childExternalLabelsMap = useMemo2(() => {
1712
+ const map = new Map;
1713
+ for (const entry of entries) {
1714
+ if (entry.parentCuid == null)
1715
+ continue;
1716
+ const firstHop = entry.meta.routing[0];
1717
+ if (firstHop == null)
1718
+ continue;
1719
+ const label = getExternalLabel(firstHop);
1720
+ if (label == null)
1721
+ continue;
1722
+ const existing = map.get(entry.parentCuid) ?? [];
1723
+ if (!existing.includes(label))
1724
+ map.set(entry.parentCuid, [...existing, label]);
1725
+ }
1726
+ return map;
1727
+ }, [entries]);
1728
+ const handleGroupRowClick = (group) => {
1729
+ const repCuid = group.representative.cuid;
1730
+ const allInGroup = [group.representative, ...group.rest];
1731
+ const selectedInGroup = allInGroup.find((e) => e.cuid === selectedCuid) ?? null;
1732
+ setExpandedGroupCuids(new Set);
1733
+ if (selectedInGroup != null && selectedCuid !== repCuid) {
1734
+ setSelectedCuid(repCuid);
1735
+ } else {
1736
+ setSelectedCuid(selectedCuid === repCuid ? null : repCuid);
1737
+ }
1738
+ };
1739
+ const handleExpandGroup = (group) => {
1740
+ const oldestCuid = (group.rest[group.rest.length - 1] ?? group.representative).cuid;
1741
+ setSelectedCuid(null);
1742
+ setExpandedGroupCuids(new Set([oldestCuid]));
1743
+ };
1744
+ const setPrefs = (update) => {
1745
+ setPrefsRaw((prev) => {
1746
+ const next = { ...prev, ...update };
1747
+ writePrefs(next);
1748
+ return next;
1749
+ });
1750
+ };
1751
+ const { position, isOpen, dockedHeight, dockedWidth } = prefs;
1752
+ const dockSide = getDockSide(position);
1753
+ const isHorizDock = dockSide === "top" || dockSide === "bottom";
1754
+ const dockedSize = isHorizDock ? dockedHeight : dockedWidth;
1755
+ const selectedEntry = selectedCuid != null ? entries.find((e) => e.cuid === selectedCuid) : null;
1756
+ const runningCount = entries.filter((e) => e.status === "running").length;
1757
+ useEffect2(() => {
1758
+ const sides = ["top", "bottom", "left", "right"];
1759
+ const clearAll = () => {
1760
+ sides.forEach((s) => {
1761
+ document.body.style.removeProperty(`margin-${s}`);
1762
+ });
1763
+ };
1764
+ if (!isOpen || dockSide == null) {
1765
+ clearAll();
1766
+ return clearAll;
1767
+ }
1768
+ clearAll();
1769
+ document.body.style.setProperty(`margin-${dockSide}`, `${dockedSize}px`);
1770
+ return clearAll;
1771
+ }, [dockSide, isOpen, dockedSize]);
1772
+ const closedAnchor = (() => {
1773
+ switch (position) {
1774
+ case "dock-bottom":
1775
+ return { bottom: "16px", right: "16px" };
1776
+ case "dock-top":
1777
+ return { top: "16px", right: "16px" };
1778
+ case "dock-left":
1779
+ return { top: "16px", left: "16px" };
1780
+ case "dock-right":
1781
+ return { top: "16px", right: "16px" };
1782
+ default:
1783
+ return {
1784
+ ...position.includes("right") ? { right: "16px" } : { left: "16px" },
1785
+ ...position.includes("bottom") ? { bottom: "16px" } : { top: "16px" }
1786
+ };
1787
+ }
1788
+ })();
1789
+ const baseStyle = {
1790
+ position: "fixed",
1791
+ zIndex: 2147483647,
1792
+ fontFamily: "ui-monospace, 'Cascadia Code', 'Source Code Pro', monospace",
1793
+ fontSize: "12px"
1794
+ };
1795
+ if (!isOpen) {
1796
+ return /* @__PURE__ */ jsxDEV15("button", {
1797
+ onClick: () => setPrefs({ isOpen: true }),
1798
+ style: {
1799
+ ...baseStyle,
1800
+ ...closedAnchor,
1801
+ background: "#1e293b",
1802
+ color: "#94a3b8",
1803
+ border: "1px solid #334155",
1804
+ borderRadius: "6px",
1805
+ padding: "5px 10px",
1806
+ cursor: "pointer",
1807
+ lineHeight: "1.5"
1808
+ },
1809
+ children: [
1810
+ "⚡ actions",
1811
+ runningCount > 0 && /* @__PURE__ */ jsxDEV15("span", {
1812
+ style: {
1813
+ marginLeft: "6px",
1814
+ color: "#60a5fa",
1815
+ animation: "__nice-action-pulse 1.2s ease-in-out infinite"
1816
+ },
1817
+ children: [
1818
+ runningCount,
1819
+ " running"
1820
+ ]
1821
+ }, undefined, true, undefined, this)
1822
+ ]
1823
+ }, undefined, true, undefined, this);
1824
+ }
1825
+ const panelStyle = dockSide != null ? {
1826
+ ...baseStyle,
1827
+ background: "#0f172a",
1828
+ border: "1px solid #1e293b",
1829
+ color: "#e2e8f0",
1830
+ display: "flex",
1831
+ flexDirection: "column",
1832
+ boxShadow: "0 -4px 24px rgba(0,0,0,0.4)",
1833
+ overflow: "hidden",
1834
+ ...dockSide === "bottom" ? {
1835
+ bottom: 0,
1836
+ left: 0,
1837
+ right: 0,
1838
+ height: `${dockedSize}px`,
1839
+ borderRadius: "8px 8px 0 0"
1840
+ } : dockSide === "top" ? {
1841
+ top: 0,
1842
+ left: 0,
1843
+ right: 0,
1844
+ height: `${dockedSize}px`,
1845
+ borderRadius: "0 0 8px 8px"
1846
+ } : dockSide === "left" ? {
1847
+ top: 0,
1848
+ left: 0,
1849
+ bottom: 0,
1850
+ width: `${dockedSize}px`,
1851
+ borderRadius: "0 8px 8px 0"
1852
+ } : {
1853
+ top: 0,
1854
+ right: 0,
1855
+ bottom: 0,
1856
+ width: `${dockedSize}px`,
1857
+ borderRadius: "8px 0 0 8px"
1858
+ }
1859
+ } : {
1860
+ ...baseStyle,
1861
+ ...closedAnchor,
1862
+ width: "460px",
1863
+ maxHeight: "560px",
1864
+ background: "#0f172a",
1865
+ border: "1px solid #1e293b",
1866
+ borderRadius: "10px",
1867
+ color: "#e2e8f0",
1868
+ display: "flex",
1869
+ flexDirection: "column",
1870
+ boxShadow: "0 25px 50px rgba(0,0,0,0.5)",
1871
+ overflow: "hidden"
1872
+ };
1873
+ const selectedEntryParent = selectedEntry?.parentCuid != null ? entries.find((e) => e.cuid === selectedEntry.parentCuid) ?? null : null;
1874
+ const selectedEntryChildren = selectedEntry != null ? [...entries].filter((e) => e.parentCuid === selectedEntry.cuid).sort((a, b) => a.startTime - b.startTime) : [];
1875
+ const virtualListProps = {
1876
+ groups,
1877
+ selectedCuid,
1878
+ expandedGroupCuids,
1879
+ onGroupClick: handleGroupRowClick,
1880
+ onSubClick: (cuid, isSelected) => {
1881
+ setSelectedCuid(isSelected ? null : cuid);
1882
+ setExpandedGroupCuids(new Set);
1883
+ },
1884
+ onExpandGroup: handleExpandGroup,
1885
+ childExternalLabelsMap
1886
+ };
1887
+ return /* @__PURE__ */ jsxDEV15(DomainTooltipCtx.Provider, {
1888
+ value: domainTooltipCtx,
1889
+ children: /* @__PURE__ */ jsxDEV15("div", {
1890
+ style: panelStyle,
1891
+ children: [
1892
+ domainTooltip != null && /* @__PURE__ */ jsxDEV15(DomainHierarchyTooltip, {
1893
+ anchor: domainTooltip.rect,
1894
+ allDomains: domainTooltip.allDomains
1895
+ }, undefined, false, undefined, this),
1896
+ dockSide != null && /* @__PURE__ */ jsxDEV15(ResizeHandle, {
1897
+ dockSide,
1898
+ dockedSize,
1899
+ onChange: (size) => setPrefs(isHorizDock ? { dockedHeight: size } : { dockedWidth: size })
1900
+ }, undefined, false, undefined, this),
1901
+ /* @__PURE__ */ jsxDEV15(PanelHeader, {
1902
+ position,
1903
+ onPositionChange: (p) => setPrefs({ position: p }),
1904
+ onClose: () => setPrefs({ isOpen: false }),
1905
+ onClear: entries.length > 0 ? () => {
1906
+ core.clear();
1907
+ setSelectedCuid(null);
1908
+ setExpandedGroupCuids(new Set);
1909
+ } : undefined
1910
+ }, undefined, false, undefined, this),
1911
+ isHorizDock ? /* @__PURE__ */ jsxDEV15("div", {
1912
+ style: { flex: 1, display: "flex", overflow: "hidden" },
1913
+ children: [
1914
+ /* @__PURE__ */ jsxDEV15(ActionList, {
1915
+ ...virtualListProps,
1916
+ style: {
1917
+ width: "340px",
1918
+ flexShrink: 0,
1919
+ overflowY: "auto",
1920
+ borderRight: "1px solid #1e293b"
1921
+ }
1922
+ }, undefined, false, undefined, this),
1923
+ /* @__PURE__ */ jsxDEV15("div", {
1924
+ style: { flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" },
1925
+ children: selectedEntry != null ? /* @__PURE__ */ jsxDEV15(ActionDetailPanel, {
1926
+ entry: selectedEntry,
1927
+ parent: selectedEntryParent,
1928
+ childEntries: selectedEntryChildren,
1929
+ onSelectEntry: (cuid) => setSelectedCuid(cuid)
1930
+ }, selectedEntry.cuid, false, undefined, this) : /* @__PURE__ */ jsxDEV15("div", {
1931
+ style: {
1932
+ padding: "24px",
1933
+ textAlign: "center",
1934
+ color: "#475569",
1935
+ fontSize: "11px"
1936
+ },
1937
+ children: "Select an action to inspect"
1938
+ }, undefined, false, undefined, this)
1939
+ }, undefined, false, undefined, this)
1940
+ ]
1941
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV15(Fragment5, {
1942
+ children: [
1943
+ /* @__PURE__ */ jsxDEV15(ActionList, {
1944
+ ...virtualListProps,
1945
+ style: {
1946
+ overflowY: "auto",
1947
+ flex: 1,
1948
+ minHeight: "80px",
1949
+ borderBottom: selectedEntry != null ? "1px solid #1e293b" : "none"
1950
+ }
1951
+ }, undefined, false, undefined, this),
1952
+ selectedEntry != null && /* @__PURE__ */ jsxDEV15("div", {
1953
+ style: {
1954
+ flexShrink: 0,
1955
+ maxHeight: "45%",
1956
+ display: "flex",
1957
+ flexDirection: "column",
1958
+ overflow: "hidden"
1959
+ },
1960
+ children: /* @__PURE__ */ jsxDEV15(ActionDetailPanel, {
1961
+ entry: selectedEntry,
1962
+ parent: selectedEntryParent,
1963
+ childEntries: selectedEntryChildren,
1964
+ onSelectEntry: (cuid) => setSelectedCuid(cuid)
1965
+ }, selectedEntry.cuid, false, undefined, this)
1966
+ }, undefined, false, undefined, this)
1967
+ ]
1968
+ }, undefined, true, undefined, this)
1969
+ ]
1970
+ }, undefined, true, undefined, this)
1971
+ }, undefined, false, undefined, this);
1972
+ }
1973
+ function getFlatItemKey(item) {
1974
+ const oldestCuid = item.group.rest[item.group.rest.length - 1]?.cuid ?? item.group.representative.cuid;
1975
+ if (item.type === "group")
1976
+ return `g:${oldestCuid}`;
1977
+ if (item.type === "sub")
1978
+ return `s:${item.entry.cuid}`;
1979
+ return `c:${item.position}:${oldestCuid}`;
1980
+ }
1981
+ function ActionList({
1982
+ groups,
1983
+ selectedCuid,
1984
+ expandedGroupCuids,
1985
+ onGroupClick,
1986
+ onSubClick,
1987
+ onExpandGroup,
1988
+ childExternalLabelsMap,
1989
+ style
1990
+ }) {
1991
+ const containerRef = useRef2(null);
1992
+ const latestTime = groups[0]?.representative.startTime;
1993
+ const flatItems = useMemo2(() => {
1994
+ const result = [];
1995
+ for (let gi = 0;gi < groups.length; gi++) {
1996
+ const group = groups[gi];
1997
+ const repCuid = group.representative.cuid;
1998
+ const allInGroup = [group.representative, ...group.rest];
1999
+ const selectedIdx = allInGroup.findIndex((e) => e.cuid === selectedCuid);
2000
+ result.push({ type: "group", group, groupIndex: gi });
2001
+ const oldestCuid = (group.rest[group.rest.length - 1] ?? group.representative).cuid;
2002
+ if (selectedIdx > 0) {
2003
+ const aboveCount = selectedIdx;
2004
+ const belowCount = allInGroup.length - selectedIdx - 1;
2005
+ if (aboveCount > 0)
2006
+ result.push({ type: "group-count", count: aboveCount, position: "above", group });
2007
+ result.push({ type: "sub", entry: allInGroup[selectedIdx], group });
2008
+ if (belowCount > 0)
2009
+ result.push({ type: "group-count", count: belowCount, position: "below", group });
2010
+ } else if (selectedIdx === 0 && group.rest.length > 0) {
2011
+ result.push({ type: "group-count", count: group.rest.length, position: "below", group });
2012
+ } else {
2013
+ const isExpanded = expandedGroupCuids.has(repCuid) || expandedGroupCuids.has(oldestCuid);
2014
+ if (isExpanded) {
2015
+ for (const entry of group.rest) {
2016
+ result.push({ type: "sub", entry, group });
2017
+ }
2018
+ }
2019
+ }
2020
+ }
2021
+ return result;
2022
+ }, [groups, expandedGroupCuids, selectedCuid]);
2023
+ const prevSelectedRef = useRef2(selectedCuid);
2024
+ useEffect2(() => {
2025
+ if (selectedCuid === prevSelectedRef.current)
2026
+ return;
2027
+ prevSelectedRef.current = selectedCuid;
2028
+ if (selectedCuid == null)
2029
+ return;
2030
+ containerRef.current?.querySelector(`[data-cuid="${selectedCuid}"]`)?.scrollIntoView({ block: "nearest" });
2031
+ }, [selectedCuid]);
2032
+ if (groups.length === 0) {
2033
+ return /* @__PURE__ */ jsxDEV15("div", {
2034
+ style,
2035
+ children: /* @__PURE__ */ jsxDEV15("div", {
2036
+ style: { padding: "24px", textAlign: "center", color: "#475569" },
2037
+ children: "No actions recorded yet"
2038
+ }, undefined, false, undefined, this)
2039
+ }, undefined, false, undefined, this);
2040
+ }
2041
+ return /* @__PURE__ */ jsxDEV15("div", {
2042
+ ref: containerRef,
2043
+ style,
2044
+ children: flatItems.map((item) => {
2045
+ const key = getFlatItemKey(item);
2046
+ return /* @__PURE__ */ jsxDEV15("div", {
2047
+ "data-cuid": item.type === "group" ? item.group.representative.cuid : item.type === "sub" ? item.entry.cuid : undefined,
2048
+ style: { borderBottom: "1px solid #101109", position: "relative", overflow: "hidden" },
2049
+ children: [
2050
+ item.type === "group" && /* @__PURE__ */ jsxDEV15("div", {
2051
+ style: {
2052
+ position: "absolute",
2053
+ inset: 0,
2054
+ pointerEvents: "none",
2055
+ background: "linear-gradient(90deg, transparent 0%, rgba(148, 210, 255, 0.13) 50%, transparent 100%)",
2056
+ animation: "__nice-action-shine 0.65s ease-out forwards"
2057
+ }
2058
+ }, item.group.representative.cuid, false, undefined, this),
2059
+ item.type === "group" ? /* @__PURE__ */ jsxDEV15(ActionEntryRow, {
2060
+ entry: item.group.representative,
2061
+ isSelected: selectedCuid === item.group.representative.cuid,
2062
+ groupCount: item.group.rest.length > 0 ? item.group.rest.length + 1 : undefined,
2063
+ isLatest: item.groupIndex === 0,
2064
+ latestTime,
2065
+ childExternalLabels: childExternalLabelsMap.get(item.group.representative.cuid),
2066
+ onClick: () => onGroupClick(item.group)
2067
+ }, undefined, false, undefined, this) : item.type === "group-count" ? /* @__PURE__ */ jsxDEV15("div", {
2068
+ onClick: () => onExpandGroup(item.group),
2069
+ style: {
2070
+ padding: "2px 28px",
2071
+ fontSize: "10px",
2072
+ color: "#475569",
2073
+ display: "flex",
2074
+ alignItems: "center",
2075
+ gap: "5px",
2076
+ background: "#0a1120",
2077
+ cursor: "pointer",
2078
+ userSelect: "none"
2079
+ },
2080
+ children: [
2081
+ /* @__PURE__ */ jsxDEV15("span", {
2082
+ style: { opacity: 0.6 },
2083
+ children: item.position === "above" ? "↑" : "↓"
2084
+ }, undefined, false, undefined, this),
2085
+ /* @__PURE__ */ jsxDEV15("span", {
2086
+ children: [
2087
+ item.count,
2088
+ " ",
2089
+ item.position === "above" ? "newer" : "older",
2090
+ " — click to browse"
2091
+ ]
2092
+ }, undefined, true, undefined, this)
2093
+ ]
2094
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV15(ActionEntryRow, {
2095
+ entry: item.entry,
2096
+ isSelected: selectedCuid === item.entry.cuid,
2097
+ isSubEntry: true,
2098
+ isLatest: false,
2099
+ latestTime,
2100
+ onClick: () => onSubClick(item.entry.cuid, selectedCuid === item.entry.cuid)
2101
+ }, undefined, false, undefined, this)
2102
+ ]
2103
+ }, key, true, undefined, this);
2104
+ })
2105
+ }, undefined, false, undefined, this);
1271
2106
  }
1272
2107
  export {
1273
2108
  NiceActionDevtools,