@workflow/web 5.0.0-beta.15 → 5.0.0-beta.16

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 (20) hide show
  1. package/build/client/assets/{highlighted-body-B3W2YXNL-BQ1pmB9V.js → highlighted-body-B3W2YXNL-QKf7Yrcl.js} +1 -1
  2. package/build/client/assets/{home-DmsdVk2U.js → home-C2tAadK2.js} +2 -2
  3. package/build/client/assets/{manifest-67209c1f.js → manifest-96e6bcc7.js} +1 -1
  4. package/build/client/assets/{mermaid-3ZIDBTTL-BMWEihLr.js → mermaid-3ZIDBTTL-DQJ4rkIZ.js} +933 -276
  5. package/build/client/assets/root-D1iC2mNY.css +1 -0
  6. package/build/client/assets/{root-BABNjrUh.js → root-QCHdCGTF.js} +1 -1
  7. package/build/client/assets/{run-detail-9xQOGhVk.js → run-detail-D4mcR51B.js} +201 -222
  8. package/build/client/assets/server-build-6KQbeuD8.css +1 -0
  9. package/build/client/assets/{workflow-graph-viewer-fgQ2XQ5R.js → workflow-graph-viewer-BEhdopGj.js} +4918 -4917
  10. package/build/server/assets/{app-DM9e_6xn.js → app-BxW1wRWj.js} +1 -1
  11. package/build/server/assets/{highlighted-body-B3W2YXNL-tYGHwGrY.js → highlighted-body-B3W2YXNL-CP6Zp179.js} +2 -2
  12. package/build/server/assets/{index-8Fb8OEQ2.js → index-Cxv7xPiz.js} +3 -3
  13. package/build/server/assets/{mermaid-3ZIDBTTL-EN1JYLRP.js → mermaid-3ZIDBTTL-BMFjZDcW.js} +2 -2
  14. package/build/server/assets/{server-build-CZXlov2m.js → server-build-B4JanZE6.js} +10829 -10028
  15. package/build/server/assets/{token-util-C02bLOPS.js → token-util-Cw2FB_2n.js} +2 -2
  16. package/build/server/assets/{token-CDoC3gHn.js → token-w6r7bnnd.js} +2 -2
  17. package/build/server/index.js +1 -1
  18. package/package.json +5 -5
  19. package/build/client/assets/root-Bqr5evzw.css +0 -1
  20. package/build/client/assets/server-build-Ik-p0gUh.css +0 -1
@@ -1,6 +1,6 @@
1
- import { j as jsxRuntimeExports, r as reactExports, f as reactDomExports, G as ReactDOM, B as useNavigate, C as useSearchParams, A as Link, w as withComponentProps, H as useParams } from "./index-BXZSIDEp.js";
2
- import { q as Check, O as Copy, C as CircleAlert, Q as parseStepName, B as parseWorkflowName, j as ChevronRight, o as ChevronDown, U as ErrorCard, Z as Zap, S as Send, R as ResolveHookModal, V as Circle, p as ChevronUp, X, N as ErrorBoundary, I as unwrapServerActionResult, u as unwrapOrThrow, W as WorkflowWebAPIError, Y as useEscapeKeydown, t as composeEventHandlers, _ as useCallbackRef, $ as useLayoutEffect2, s as useControllableState, a0 as useId, a1 as createContext2, v as Presence, x as createContextScope, l as hideOthers, m as ReactRemoveScroll, a2 as useFocusGuards, a3 as LAYOUT, a4 as wakeUpRun, r as resumeHook, A as Alert, c as AlertTitle, d as AlertDescription, a as Skeleton$1, a5 as RunActionsButtons, F as StatusBadge, e as CopyableText, b as RelativeTime, T as Tabs, K as TabsList, L as TabsTrigger, M as TabsContent, y as cancelRun, a6 as recreateRun } from "./workflow-graph-viewer-fgQ2XQ5R.js";
3
- import { c as createLucideIcon, N as Spinner, O as cn, g as useToast, U as Skeleton, W as DecryptClickContext, Y as Yr, X as isEncryptedMarker, Z as formatDuration, _ as DataInspector, $ as _r, a0 as Button, a1 as Lock, a2 as RunClickContext, a3 as StreamClickContext, a4 as isExpiredMarker, a5 as isDoStreamStep, a6 as extractConversation, a7 as hasEncryptedFields, a8 as EVENT_DATA_REF_FIELDS, a9 as useSidebarDataOptional, aa as clsx, ab as useRowWindow, ac as isSpanDimmedBySearch, ad as ROW_HEIGHT_PX, ae as getSpanDurationMs, af as formatDurationPrecise, ag as TooltipProvider, ah as ActiveSpanProvider, ai as useActiveSpan, aj as useSidebarData, ak as searchSpans, al as computeRootBounds, am as computeTimeMarkers, an as getHighResInMs, ao as TIMELINE_PADDING_PX, ap as Timeline, aq as TimelineHeader, ar as IconButton, as as Tooltip, at as TooltipTrigger, au as TooltipContent, av as SidebarDataProvider, aw as hydrateResourceIOWithKey, ax as hydrateResourceIO, ay as fetchHook, k as fetchEvents, G as fetchRun, az as fetchStep, aA as fetchStreams, aB as Slot, F as useComposedRefs, aC as Slottable, d as cn$1, aD as buttonVariants, aE as fetchEvent, aF as fetchEventsByCorrelationId, aG as isEncryptedData, aH as hydrateData, aI as getWebRevivers, T as Tooltip$1, a as TooltipTrigger$1, b as TooltipContent$1, aJ as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, aK as getEncryptionKeyForRun, t as toast, L as LoaderCircle, aL as StreamViewer } from "./mermaid-3ZIDBTTL-BMWEihLr.js";
1
+ import { r as reactExports, j as jsxRuntimeExports, f as reactDomExports, G as ReactDOM, B as useNavigate, C as useSearchParams, A as Link, w as withComponentProps, H as useParams } from "./index-BXZSIDEp.js";
2
+ import { q as Check, O as Copy, j as ChevronRight, o as ChevronDown, C as CircleAlert, Q as parseStepName, B as parseWorkflowName, U as ErrorCard, V as format, Z as Zap, S as Send, R as ResolveHookModal, Y as Circle, p as ChevronUp, X, N as ErrorBoundary, I as unwrapServerActionResult, u as unwrapOrThrow, W as WorkflowWebAPIError, _ as useEscapeKeydown, t as composeEventHandlers, $ as useCallbackRef, a0 as useLayoutEffect2, s as useControllableState, a1 as useId, a2 as createContext2, v as Presence, x as createContextScope, l as hideOthers, m as ReactRemoveScroll, a3 as useFocusGuards, a4 as LAYOUT, a5 as wakeUpRun, r as resumeHook, A as Alert, c as AlertTitle, d as AlertDescription, a as Skeleton$1, a6 as RunActionsButtons, F as StatusBadge, e as CopyableText, b as RelativeTime, T as Tabs, K as TabsList, L as TabsTrigger, M as TabsContent, y as cancelRun, a7 as recreateRun } from "./workflow-graph-viewer-BEhdopGj.js";
3
+ import { c as createLucideIcon, N as cn, O as DataInspector, U as DecryptClickContext, W as Button, X as Spinner, Y as Lock, Z as RESERVED_ATTRIBUTE_KEY_PREFIX, _ as useHasContextCardProvider, $ as ContextCardProvider, a0 as ContextCardTrigger, g as useToast, a1 as Skeleton, a2 as Yr, a3 as isEncryptedMarker, a4 as formatDuration, a5 as _r, a6 as RunClickContext, a7 as StreamClickContext, a8 as isExpiredMarker, a9 as isDoStreamStep, aa as extractConversation, ab as hasEncryptedFields, ac as EVENT_DATA_REF_FIELDS, ad as useSidebarDataOptional, ae as clsx, af as useRowWindow, ag as isSpanDimmedBySearch, ah as ROW_HEIGHT_PX, ai as getSpanDurationMs, aj as formatDurationPrecise, ak as TooltipProvider, al as ActiveSpanProvider, am as useActiveSpan, an as useSidebarData, ao as searchSpans, ap as computeRootBounds, aq as computeTimeMarkers, ar as getHighResInMs, as as TIMELINE_PADDING_PX, at as Timeline, au as TimelineHeader, av as IconButton, aw as Tooltip, ax as TooltipTrigger, ay as TooltipContent, az as useReducedMotion, aA as SidebarDataProvider, aB as hydrateResourceIOWithKey, aC as hydrateResourceIO, aD as fetchHook, k as fetchEvents, G as fetchRun, aE as fetchStep, aF as fetchStreams, aG as Slot, F as useComposedRefs, aH as Slottable, d as cn$1, aI as buttonVariants, aJ as fetchEvent, aK as fetchEventsByCorrelationId, aL as isEncryptedData, aM as hydrateData, aN as getWebRevivers, T as Tooltip$1, a as TooltipTrigger$1, b as TooltipContent$1, aO as LIVE_UPDATE_INTERVAL_MS$1, u as useServerConfig, aP as getEncryptionKeyForRun, t as toast, L as LoaderCircle, aQ as StreamViewer } from "./mermaid-3ZIDBTTL-DQJ4rkIZ.js";
4
4
  import { decrypt, importKey } from "./encryption-g14N5vQl.js";
5
5
  import "./index-B6-SzLmT.js";
6
6
  /**
@@ -104,10 +104,6 @@ function looksLikeWorkflowIdSearchInput(query) {
104
104
  }
105
105
  return /\d/.test(trimmed);
106
106
  }
107
- const STYLES$2 = `.wf-decrypt-btn{appearance:none;-webkit-appearance:none;border:none;display:inline-flex;align-items:center;justify-content:center;height:40px;padding:0 12px;border-radius:6px;font-size:14px;font-weight:500;line-height:20px;cursor:pointer;white-space:nowrap;gap:6px;transition:background 150ms}.wf-decrypt-idle{color:var(--ds-gray-1000);background:var(--ds-background-100);box-shadow:0 0 0 1px var(--ds-gray-400)}.wf-decrypt-idle:hover{background:var(--ds-gray-alpha-200)}.wf-decrypt-done{color:var(--ds-green-900);background:var(--ds-green-100);box-shadow:0 0 0 1px var(--ds-green-400);cursor:default}`;
108
- function DecryptButton({ decrypted = false, loading = false, onClick }) {
109
- return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { dangerouslySetInnerHTML: { __html: STYLES$2 } }), jsxRuntimeExports.jsxs("button", { type: "button", onClick: decrypted ? void 0 : onClick, disabled: decrypted || loading, className: `wf-decrypt-btn ${decrypted ? "wf-decrypt-done" : "wf-decrypt-idle"}`, children: [loading ? jsxRuntimeExports.jsx(Spinner, { size: 14 }) : decrypted ? jsxRuntimeExports.jsxs("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }), jsxRuntimeExports.jsx("path", { d: "M7 11V7a5 5 0 0 1 9.9-1" })] }) : jsxRuntimeExports.jsxs("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }), jsxRuntimeExports.jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })] }), loading ? "Decrypting…" : decrypted ? "Decrypted" : "Decrypt"] })] });
110
- }
111
107
  function CopyButton({ copyText, ariaLabel, className }) {
112
108
  const [copied, setCopied] = reactExports.useState(false);
113
109
  const timeoutRef = reactExports.useRef(null);
@@ -129,6 +125,112 @@ function CopyButton({ copyText, ariaLabel, className }) {
129
125
  });
130
126
  }, children: jsxRuntimeExports.jsxs("div", { className: "relative w-3 h-3", children: [jsxRuntimeExports.jsx("div", { className: cn("absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out", copied ? "scale-100 opacity-100" : "scale-0 opacity-0"), children: jsxRuntimeExports.jsx(Check, { className: "w-3 h-3" }) }), jsxRuntimeExports.jsx("div", { className: cn("absolute inset-0 flex items-center justify-center transition-all duration-150 ease-out", copied ? "scale-0 opacity-0" : "scale-100 opacity-100"), children: jsxRuntimeExports.jsx(Copy, { className: "w-3 h-3" }) })] }) });
131
127
  }
128
+ const encryptedPlaceholderPreview = `{
129
+ "input": "[encrypted]",
130
+ "result": "[encrypted]"
131
+ }`;
132
+ function EncryptedDataBlock() {
133
+ const ctx = reactExports.useContext(DecryptClickContext);
134
+ return jsxRuntimeExports.jsxs("div", { className: "relative min-h-20 overflow-hidden rounded-md border border-gray-alpha-400 bg-background-100", children: [jsxRuntimeExports.jsx("pre", { "aria-hidden": "true", className: "pointer-events-none m-0 select-none p-3 font-mono text-label-12 text-gray-900 blur-[4px]", children: encryptedPlaceholderPreview }), jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: ctx ? jsxRuntimeExports.jsxs(Button, { onClick: ctx.onDecrypt, disabled: ctx.isDecrypting, size: "xs", children: [ctx.isDecrypting ? jsxRuntimeExports.jsx(Spinner, { size: 10 }) : jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), jsxRuntimeExports.jsx("span", { children: "Decrypt" })] }) : jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 rounded border border-gray-alpha-400 bg-gray-100 px-1.5 py-0.5 text-button-12 font-medium text-gray-700", children: [jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), "Encrypted"] }) })] });
135
+ }
136
+ const serializeForClipboard = (value) => {
137
+ if (typeof value === "string")
138
+ return value;
139
+ if (typeof value === "number" || typeof value === "boolean" || value === null) {
140
+ return String(value);
141
+ }
142
+ try {
143
+ return JSON.stringify(value, null, 2);
144
+ } catch {
145
+ return String(value);
146
+ }
147
+ };
148
+ function CopyableDataBlock({ data }) {
149
+ return jsxRuntimeExports.jsxs("div", { className: "relative overflow-x-auto rounded-md border border-gray-alpha-400 p-3", children: [jsxRuntimeExports.jsx(CopyButton, { copyText: serializeForClipboard(data), ariaLabel: "Copy data", className: "absolute right-2 top-2 z-10 flex h-6 w-6 items-center justify-center rounded-md border border-gray-alpha-400 !bg-background-100 p-0 text-gray-900 transition-transform transition-colors duration-100 hover:bg-gray-200 active:scale-95 active:bg-gray-300" }), jsxRuntimeExports.jsx(DataInspector, { data })] });
150
+ }
151
+ function DetailCard({ summary, children, onToggle, disabled = false, defaultOpen = false, variant = "section", trailing, summaryClassName, contentClassName }) {
152
+ const [open, setOpen] = reactExports.useState(defaultOpen);
153
+ const handleToggle = (e) => {
154
+ if (e.target !== e.currentTarget)
155
+ return;
156
+ const next = e.currentTarget.open;
157
+ setOpen(next);
158
+ onToggle == null ? void 0 : onToggle(next);
159
+ };
160
+ if (variant === "card") {
161
+ if (disabled) {
162
+ return jsxRuntimeExports.jsx("div", { className: cn("list-none px-3 py-4 bg-background-200 [&::-webkit-details-marker]:hidden", summaryClassName), style: { cursor: "not-allowed", opacity: 0.8 }, children: summary });
163
+ }
164
+ return jsxRuntimeExports.jsxs("details", { className: "group/card last:border-b border-gray-alpha-400", open, onToggle: handleToggle, children: [jsxRuntimeExports.jsx("summary", { className: cn("list-none cursor-pointer px-3 py-4 border-t border-gray-alpha-400 bg-background-200 hover:bg-gray-100 [&::-webkit-details-marker]:hidden", summaryClassName), children: jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5", children: [jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: cn("shrink-0 text-gray-700 group-hover/card:text-gray-1000", open && "rotate-90") }), summary] }) }), jsxRuntimeExports.jsx("div", { className: contentClassName, children })] });
165
+ }
166
+ const rowClasses = "flex h-9 items-center gap-2 px-2 -mx-2 text-heading-14 font-medium my-2";
167
+ if (trailing) {
168
+ return jsxRuntimeExports.jsx("section", { className: "-mx-4 border-t px-4 border-gray-alpha-400", children: jsxRuntimeExports.jsxs("div", { className: cn(rowClasses, summaryClassName), children: [jsxRuntimeExports.jsx("div", { className: "isolate relative shrink-0 w-3.5 h-3.5 text-gray-700", children: jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" }) }), jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1", children: summary }), jsxRuntimeExports.jsx("div", { className: "shrink-0 pr-1", children: trailing })] }) });
169
+ }
170
+ if (disabled) {
171
+ return jsxRuntimeExports.jsx("section", { className: "-mx-4 border-t px-4 border-gray-alpha-400", children: jsxRuntimeExports.jsx("div", { className: cn(rowClasses, summaryClassName), style: { color: "var(--ds-gray-700)", cursor: "not-allowed" }, children: jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1", children: summary }) }) });
172
+ }
173
+ return jsxRuntimeExports.jsx("section", { className: "-mx-4 border-t px-4 border-gray-alpha-400", children: jsxRuntimeExports.jsxs("details", { className: "group", open, onToggle: handleToggle, children: [jsxRuntimeExports.jsxs("summary", { className: cn("group/trigger list-none cursor-pointer rounded hover:bg-gray-alpha-100 [&::-webkit-details-marker]:hidden", rowClasses, summaryClassName), children: [jsxRuntimeExports.jsxs("div", { className: "isolate relative shrink-0 text-gray-700 group-hover/trigger:text-gray-1000 w-3.5 h-3.5", children: [jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-100 group-open:opacity-0" }), jsxRuntimeExports.jsx(ChevronDown, { size: 14, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0 group-open:opacity-100" })] }), jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1", children: summary })] }), jsxRuntimeExports.jsx("div", { className: cn("mb-3", contentClassName), children })] }) });
174
+ }
175
+ const isReservedAttributeKey = (key) => key.startsWith(RESERVED_ATTRIBUTE_KEY_PREFIX);
176
+ function ReservedBadge() {
177
+ return jsxRuntimeExports.jsx("span", { className: "shrink-0 rounded border px-1 py-px text-[10px] font-medium leading-3", style: {
178
+ borderColor: "var(--ds-gray-alpha-400)",
179
+ backgroundColor: "var(--ds-gray-100)",
180
+ color: "var(--ds-gray-700)"
181
+ }, title: `Keys prefixed with "${RESERVED_ATTRIBUTE_KEY_PREFIX}" are reserved for framework and library code`, children: "Reserved" });
182
+ }
183
+ function AttributeRow({ attributeKey, value, removed = false }) {
184
+ const reserved = isReservedAttributeKey(attributeKey);
185
+ return jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-3 py-1.5", children: [jsxRuntimeExports.jsxs("span", { className: "flex min-w-0 items-center gap-1.5 text-label-12 font-mono", style: {
186
+ color: reserved ? "var(--ds-gray-700)" : "var(--ds-gray-900)"
187
+ }, children: [jsxRuntimeExports.jsx("span", { className: "truncate", children: attributeKey }), reserved && jsxRuntimeExports.jsx(ReservedBadge, {})] }), removed ? jsxRuntimeExports.jsx("span", { className: "shrink-0 text-label-12 italic", style: { color: "var(--ds-gray-700)" }, children: "removed" }) : jsxRuntimeExports.jsx("span", { className: "max-w-[60%] truncate text-right text-label-12 font-mono text-gray-1000", title: value, children: value })] });
188
+ }
189
+ function sortAttributeKeys(keys) {
190
+ return [...keys].sort((a, b) => {
191
+ const aReserved = isReservedAttributeKey(a);
192
+ const bReserved = isReservedAttributeKey(b);
193
+ if (aReserved !== bReserved)
194
+ return aReserved ? 1 : -1;
195
+ return a.localeCompare(b);
196
+ });
197
+ }
198
+ function RunAttributesCard({ attributes }) {
199
+ const keys = sortAttributeKeys(Object.keys(attributes));
200
+ if (keys.length === 0)
201
+ return null;
202
+ return jsxRuntimeExports.jsx(DetailCard, { summary: `Attributes (${keys.length})`, defaultOpen: true, contentClassName: "mb-0", children: jsxRuntimeExports.jsx("div", { className: "flex flex-col divide-y divide-gray-alpha-400", children: keys.map((key) => jsxRuntimeExports.jsx(AttributeRow, { attributeKey: key, value: attributes[key] }, key)) }) });
203
+ }
204
+ function isAttrSetEventData(data) {
205
+ if (data === null || typeof data !== "object")
206
+ return false;
207
+ const record = data;
208
+ return Array.isArray(record.changes) && record.changes.every((c) => c !== null && typeof c === "object" && typeof c.key === "string");
209
+ }
210
+ function describeWriter(writer) {
211
+ if (!writer)
212
+ return null;
213
+ if (writer.type === "workflow")
214
+ return "Set by workflow";
215
+ if (writer.type === "step") {
216
+ return `Set by step ${writer.stepId} (attempt ${writer.attempt})`;
217
+ }
218
+ return null;
219
+ }
220
+ function AttrSetEventBlock({ data }) {
221
+ if (!isAttrSetEventData(data)) {
222
+ return jsxRuntimeExports.jsx(CopyableDataBlock, { data });
223
+ }
224
+ const writerLabel = describeWriter(data.writer);
225
+ return jsxRuntimeExports.jsxs("div", { className: "flex flex-col px-3 py-1", children: [jsxRuntimeExports.jsx("div", { className: "flex flex-col divide-y divide-gray-alpha-400", children: data.changes.map((change, index) => jsxRuntimeExports.jsx(AttributeRow, { attributeKey: change.key, removed: change.value === null, value: change.value ?? void 0 }, `${change.key}:${index}`)) }), writerLabel && jsxRuntimeExports.jsx("div", { className: "border-t py-1.5 text-label-12", style: {
226
+ borderColor: "var(--ds-gray-alpha-400)",
227
+ color: "var(--ds-gray-700)"
228
+ }, children: writerLabel })] });
229
+ }
230
+ const STYLES$2 = `.wf-decrypt-btn{appearance:none;-webkit-appearance:none;border:none;display:inline-flex;align-items:center;justify-content:center;height:40px;padding:0 12px;border-radius:6px;font-size:14px;font-weight:500;line-height:20px;cursor:pointer;white-space:nowrap;gap:6px;transition:background 150ms}.wf-decrypt-idle{color:var(--ds-gray-1000);background:var(--ds-background-100);box-shadow:0 0 0 1px var(--ds-gray-400)}.wf-decrypt-idle:hover{background:var(--ds-gray-alpha-200)}.wf-decrypt-done{color:var(--ds-green-900);background:var(--ds-green-100);box-shadow:0 0 0 1px var(--ds-green-400);cursor:default}`;
231
+ function DecryptButton({ decrypted = false, loading = false, onClick }) {
232
+ return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("style", { dangerouslySetInnerHTML: { __html: STYLES$2 } }), jsxRuntimeExports.jsxs("button", { type: "button", onClick: decrypted ? void 0 : onClick, disabled: decrypted || loading, className: `wf-decrypt-btn ${decrypted ? "wf-decrypt-done" : "wf-decrypt-idle"}`, children: [loading ? jsxRuntimeExports.jsx(Spinner, { size: 14 }) : decrypted ? jsxRuntimeExports.jsxs("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }), jsxRuntimeExports.jsx("path", { d: "M7 11V7a5 5 0 0 1 9.9-1" })] }) : jsxRuntimeExports.jsxs("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("rect", { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }), jsxRuntimeExports.jsx("path", { d: "M7 11V7a5 5 0 0 1 10 0v4" })] }), loading ? "Decrypting…" : decrypted ? "Decrypted" : "Decrypt"] })] });
233
+ }
132
234
  function isStructuredError(value) {
133
235
  return value != null && typeof value === "object" && (typeof value.message === "string" || typeof value.stack === "string");
134
236
  }
@@ -231,17 +333,45 @@ function formatTimeDifference(diff) {
231
333
  function useTimeAgo(date) {
232
334
  const [timeAgo, setTimeAgo] = reactExports.useState("");
233
335
  reactExports.useEffect(() => {
234
- const update = () => {
336
+ const updateTimeAgo = () => {
235
337
  const diff = Date.now() - date;
236
- const formatted = formatTimeDifference(diff);
237
- setTimeAgo(formatted ? `${formatted} ago` : "Just now");
338
+ const formattedDiff = formatTimeDifference(diff);
339
+ setTimeAgo(formattedDiff ? `${formattedDiff} ago` : "Just now");
238
340
  };
239
- update();
240
- const timer = setInterval(update, 1e3);
341
+ updateTimeAgo();
342
+ const timer = setInterval(updateTimeAgo, 1e3);
241
343
  return () => clearInterval(timer);
242
344
  }, [date]);
243
345
  return timeAgo;
244
346
  }
347
+ function useShortTimeAgo(date) {
348
+ const [shortTimeAgo, setShortTimeAgo] = reactExports.useState("");
349
+ reactExports.useEffect(() => {
350
+ if (!date) {
351
+ setShortTimeAgo("");
352
+ return;
353
+ }
354
+ const updateShortTimeAgo = () => {
355
+ const diff = Date.now() - date;
356
+ const days = Math.floor(diff / (1e3 * 60 * 60 * 24));
357
+ const hours = Math.floor(diff / (1e3 * 60 * 60));
358
+ const minutes = Math.floor(diff / (1e3 * 60));
359
+ if (days > 0) {
360
+ setShortTimeAgo(`${days} day${days > 1 ? "s" : ""} ago`);
361
+ } else if (hours > 0) {
362
+ setShortTimeAgo(`${hours} hour${hours > 1 ? "s" : ""} ago`);
363
+ } else if (minutes > 0) {
364
+ setShortTimeAgo(`${minutes} minute${minutes > 1 ? "s" : ""} ago`);
365
+ } else {
366
+ setShortTimeAgo("Just now");
367
+ }
368
+ };
369
+ updateShortTimeAgo();
370
+ const timer = setInterval(updateShortTimeAgo, 6e4);
371
+ return () => clearInterval(timer);
372
+ }, [date]);
373
+ return shortTimeAgo;
374
+ }
245
375
  function ZoneDateTimeRow({ date, zone }) {
246
376
  var _a;
247
377
  const dateObj = new Date(date);
@@ -261,133 +391,30 @@ function ZoneDateTimeRow({ date, zone }) {
261
391
  minute: "2-digit",
262
392
  second: "2-digit"
263
393
  });
264
- return jsxRuntimeExports.jsxs("div", { style: {
265
- display: "flex",
266
- alignItems: "center",
267
- justifyContent: "space-between",
268
- gap: 12
269
- }, children: [jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [jsxRuntimeExports.jsx("div", { style: {
270
- display: "inline-flex",
271
- alignItems: "center",
272
- justifyContent: "center",
273
- height: 16,
274
- padding: "0 6px",
275
- backgroundColor: "var(--ds-gray-200)",
276
- borderRadius: 3,
277
- fontSize: 11,
278
- fontFamily: "var(--font-mono, monospace)",
279
- fontWeight: 500,
280
- color: "var(--ds-gray-900)",
281
- whiteSpace: "nowrap"
282
- }, children: formattedZone }), jsxRuntimeExports.jsx("span", { style: {
283
- fontSize: 13,
284
- color: "var(--ds-gray-1000)",
285
- whiteSpace: "nowrap"
286
- }, children: formattedDate })] }), jsxRuntimeExports.jsx("span", { style: {
287
- fontSize: 11,
288
- fontFamily: "var(--font-mono, monospace)",
289
- fontVariantNumeric: "tabular-nums",
290
- color: "var(--ds-gray-900)",
291
- whiteSpace: "nowrap"
292
- }, children: formattedTime })] });
394
+ return jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-3", children: [jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-4 px-1.5 bg-gray-200 rounded-xs", children: jsxRuntimeExports.jsx("span", { className: "text-[12px] font-mono text-gray-900", children: formattedZone }) }), jsxRuntimeExports.jsx("span", { className: "text-[13px] text-gray-1000", children: formattedDate })] }), jsxRuntimeExports.jsx("span", { className: "tabular-nums text-[12px] font-mono text-gray-900", children: formattedTime })] });
293
395
  }
294
- function TimestampTooltipContent({ date }) {
396
+ function RelativeTimeContextCardContent({ date }) {
295
397
  const localTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
296
398
  const timeAgo = useTimeAgo(date);
297
- return jsxRuntimeExports.jsxs("div", { style: {
298
- display: "flex",
299
- flexDirection: "column",
300
- gap: 12,
301
- minWidth: 300,
302
- padding: "12px 14px"
303
- }, children: [jsxRuntimeExports.jsx("span", { style: {
304
- fontSize: 13,
305
- fontVariantNumeric: "tabular-nums",
306
- color: "var(--ds-gray-900)"
307
- }, children: timeAgo }), jsxRuntimeExports.jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [jsxRuntimeExports.jsx(ZoneDateTimeRow, { date, zone: "UTC" }), jsxRuntimeExports.jsx(ZoneDateTimeRow, { date, zone: localTimezone })] })] });
308
- }
309
- const TOOLTIP_WIDTH = 330;
310
- const VIEWPORT_PAD = 8;
311
- function TooltipPortal({ triggerRect, onMouseEnter, onMouseLeave, date }) {
312
- const tooltipRef = reactExports.useRef(null);
313
- const [style, setStyle] = reactExports.useState({
314
- position: "fixed",
315
- zIndex: 9999,
316
- visibility: "hidden"
317
- });
318
- reactExports.useEffect(() => {
319
- const placement = triggerRect.top > 240 ? "above" : "below";
320
- const centerX = triggerRect.left + triggerRect.width / 2;
321
- const el = tooltipRef.current;
322
- const w = el ? el.offsetWidth : TOOLTIP_WIDTH;
323
- const h = el ? el.offsetHeight : 100;
324
- let left = centerX - w / 2;
325
- left = Math.max(VIEWPORT_PAD, Math.min(left, window.innerWidth - w - VIEWPORT_PAD));
326
- let top;
327
- if (placement === "above") {
328
- top = triggerRect.top - h - 6;
329
- if (top < VIEWPORT_PAD) {
330
- top = triggerRect.bottom + 6;
331
- }
332
- } else {
333
- top = triggerRect.bottom + 6;
334
- if (top + h > window.innerHeight - VIEWPORT_PAD) {
335
- top = triggerRect.top - h - 6;
336
- }
337
- }
338
- setStyle({
339
- position: "fixed",
340
- left,
341
- top,
342
- zIndex: 9999,
343
- borderRadius: 10,
344
- border: "1px solid var(--ds-gray-alpha-200)",
345
- backgroundColor: "var(--ds-background-100)",
346
- boxShadow: "0 4px 12px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.06)",
347
- visibility: "visible"
348
- });
349
- }, [triggerRect]);
350
- return reactDomExports.createPortal(
351
- // biome-ignore lint/a11y/noStaticElementInteractions: tooltip hover zone
352
- jsxRuntimeExports.jsx("div", { ref: tooltipRef, onMouseEnter, onMouseLeave, style, children: jsxRuntimeExports.jsx(TimestampTooltipContent, { date }) }),
353
- document.body
354
- );
399
+ return jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 min-w-[300px]", children: [jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-3", children: jsxRuntimeExports.jsx("span", { className: "tabular-nums text-[13px] text-gray-900", children: timeAgo }) }), jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntimeExports.jsx(ZoneDateTimeRow, { date, zone: "UTC" }), jsxRuntimeExports.jsx(ZoneDateTimeRow, { date, zone: localTimezone })] })] });
355
400
  }
356
- function TimestampTooltip({ date, children }) {
357
- const [open, setOpen] = reactExports.useState(false);
358
- const [triggerRect, setTriggerRect] = reactExports.useState(null);
359
- const triggerRef = reactExports.useRef(null);
360
- const closeTimer = reactExports.useRef(null);
361
- reactExports.useEffect(() => {
362
- return () => {
363
- if (closeTimer.current)
364
- clearTimeout(closeTimer.current);
365
- };
366
- }, []);
401
+ function DefaultTimeText({ date }) {
402
+ const shortTimeAgo = useShortTimeAgo(date);
403
+ return jsxRuntimeExports.jsx("span", { className: "text-label-14 text-gray-900", children: shortTimeAgo });
404
+ }
405
+ function RelativeTimeCard({ date, children: _children, ...props }) {
406
+ const children = _children === void 0 ? jsxRuntimeExports.jsx(DefaultTimeText, { date }) : _children;
407
+ if (!date)
408
+ return children;
409
+ return jsxRuntimeExports.jsx(ContextCardTrigger, { content: jsxRuntimeExports.jsx(RelativeTimeContextCardContent, { date }), ...props, children });
410
+ }
411
+ function TimestampTooltip({ date, children, side = "top" }) {
412
+ const hasProvider = useHasContextCardProvider();
367
413
  const ts = date == null ? null : typeof date === "number" ? date : new Date(date).getTime();
368
414
  if (ts == null || Number.isNaN(ts))
369
415
  return jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children });
370
- const cancelClose = () => {
371
- if (closeTimer.current) {
372
- clearTimeout(closeTimer.current);
373
- closeTimer.current = null;
374
- }
375
- };
376
- const scheduleClose = () => {
377
- cancelClose();
378
- closeTimer.current = setTimeout(() => setOpen(false), 120);
379
- };
380
- const handleOpen = () => {
381
- cancelClose();
382
- if (triggerRef.current) {
383
- setTriggerRect(triggerRef.current.getBoundingClientRect());
384
- }
385
- setOpen(true);
386
- };
387
- return (
388
- // biome-ignore lint/a11y/noStaticElementInteractions: tooltip trigger
389
- jsxRuntimeExports.jsxs("span", { ref: triggerRef, onMouseEnter: handleOpen, onMouseLeave: scheduleClose, style: { display: "inline-flex" }, children: [children, open && triggerRect && jsxRuntimeExports.jsx(TooltipPortal, { triggerRect, onMouseEnter: cancelClose, onMouseLeave: scheduleClose, date: ts })] })
390
- );
416
+ const card = jsxRuntimeExports.jsx(RelativeTimeCard, { date: ts, side, asChild: true, children });
417
+ return hasProvider ? card : jsxRuntimeExports.jsx(ContextCardProvider, { children: card });
391
418
  }
392
419
  const ERROR_EVENT_TYPES$1 = /* @__PURE__ */ new Set([
393
420
  "step_failed",
@@ -423,6 +450,9 @@ function getStatusDotColor(eventType) {
423
450
  if (eventType === "step_retrying") {
424
451
  return "var(--ds-amber-700)";
425
452
  }
453
+ if (eventType === "attr_set") {
454
+ return "var(--ds-teal-900)";
455
+ }
426
456
  if (eventType === "step_completed" || eventType === "run_completed" || eventType === "workflow_completed" || eventType === "hook_disposed" || eventType === "wait_completed") {
427
457
  return "var(--ds-green-700)";
428
458
  }
@@ -497,7 +527,9 @@ function hasEncryptedValues(data) {
497
527
  return false;
498
528
  }
499
529
  function isRunLevel(eventType) {
500
- return eventType === "run_created" || eventType === "run_started" || eventType === "run_completed" || eventType === "run_failed" || eventType === "run_cancelled" || eventType === "workflow_started" || eventType === "workflow_completed" || eventType === "workflow_failed";
530
+ return eventType === "run_created" || eventType === "run_started" || eventType === "run_completed" || eventType === "run_failed" || eventType === "run_cancelled" || eventType === "workflow_started" || eventType === "workflow_completed" || eventType === "workflow_failed" || // attr_set carries a dedup correlationId rather than a child entity ID,
531
+ // so it groups and labels with the run itself.
532
+ eventType === "attr_set";
501
533
  }
502
534
  const GUTTER_WIDTH = 36;
503
535
  const LANE_X = 20;
@@ -665,6 +697,9 @@ function PayloadBlock({ data, eventType }) {
665
697
  if (structuredError) {
666
698
  return jsxRuntimeExports.jsx("div", { className: "p-2", children: jsxRuntimeExports.jsx(ErrorStackBlock, { value: structuredError }) });
667
699
  }
700
+ if (eventType === "attr_set") {
701
+ return jsxRuntimeExports.jsx(AttrSetEventBlock, { data: cleaned });
702
+ }
668
703
  return jsxRuntimeExports.jsxs("div", { className: "relative group/payload", children: [jsxRuntimeExports.jsx("div", { className: "overflow-x-auto p-2 text-[11px]", style: { color: "var(--ds-gray-1000)" }, children: jsxRuntimeExports.jsx(DataInspector, { data: cleaned, expandLevel: 2 }) }), jsxRuntimeExports.jsx("button", { type: "button", onClick: handleCopy, className: "absolute bottom-2 right-2 opacity-0 group-hover/payload:opacity-100 transition-opacity flex items-center gap-1 px-2 py-1 rounded-md text-xs hover:bg-[var(--ds-gray-alpha-200)]", style: { ...BUTTON_RESET_STYLE, color: "var(--ds-gray-700)" }, "aria-label": "Copy payload", children: copied ? jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(Check, { className: "h-3 w-3", style: { color: "var(--ds-green-700)" } }), jsxRuntimeExports.jsx("span", { style: { color: "var(--ds-green-700)" }, children: "Copied" })] }) : jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(Copy, { className: "h-3 w-3" }), jsxRuntimeExports.jsx("span", { children: "Copy" })] }) })] });
669
704
  }
670
705
  const SORT_OPTIONS = [
@@ -830,7 +865,7 @@ function EventRow$1({ event, index, isFirst, isLast, isExpanded, onToggleExpand,
830
865
  color: "var(--ds-red-900)"
831
866
  }, children: loadError }) : isLoading || loadedEventData === null && !hasAttemptedLoad && event.correlationId ? jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 p-3", children: [jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "75%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "50%" } }), jsxRuntimeExports.jsx(Skeleton, { className: "h-3", style: { width: "60%" } })] }) : jsxRuntimeExports.jsx("div", { className: "p-2 text-xs", style: { color: "var(--ds-gray-900)" }, children: "No data" })] })] })] });
832
867
  }
833
- function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, isLoadingMoreEvents = false, onLoadMoreEvents, encryptionKey, isLoading = false, sortOrder: sortOrderProp, onSortOrderChange, onDecrypt, isDecrypting = false, hasEncryptedData: hasEncryptedDataProp = false, onExactIdSearch }) {
868
+ function EventListViewInner({ events, run, onLoadEventData, hasMoreEvents = false, isLoadingMoreEvents = false, onLoadMoreEvents, encryptionKey, isLoading = false, sortOrder: sortOrderProp, onSortOrderChange, onDecrypt, isDecrypting = false, hasEncryptedData: hasEncryptedDataProp = false, onExactIdSearch }) {
834
869
  const toast2 = useToast();
835
870
  const [internalSortOrder, setInternalSortOrder] = reactExports.useState("asc");
836
871
  const effectiveSortOrder = sortOrderProp ?? internalSortOrder;
@@ -1098,6 +1133,9 @@ function EventListView({ events, run, onLoadEventData, hasMoreEvents = false, is
1098
1133
  backgroundColor: "var(--ds-background-100)"
1099
1134
  }, children: [jsxRuntimeExports.jsx("span", { children: isExactSearchActive ? searchError ? searchError : searchNotFound ? `No events found for ${searchQuery.trim()}` : `${sortedEvents.length} event${sortedEvents.length !== 1 ? "s" : ""} for ${searchQuery.trim()}${searchResultsTruncated ? " (results may be truncated)" : ""}` : `${sortedEvents.length} event${sortedEvents.length !== 1 ? "s" : ""} loaded` }), !isExactSearchActive && hasMoreEvents && jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: jsxRuntimeExports.jsx("div", { className: "pointer-events-auto", children: jsxRuntimeExports.jsx(LoadMoreButton, { loading: isLoadingMoreEvents, onClick: () => void (onLoadMoreEvents == null ? void 0 : onLoadMoreEvents()) }) }) })] })] }) });
1100
1135
  }
1136
+ function EventListView(props) {
1137
+ return jsxRuntimeExports.jsx(ContextCardProvider, { children: jsxRuntimeExports.jsx(EventListViewInner, { ...props }) });
1138
+ }
1101
1139
  function shouldShowVerticalLine(eventType) {
1102
1140
  if (eventType === "hook_created" || eventType === "hook_received" || eventType === "hook_disposed") {
1103
1141
  return true;
@@ -1150,7 +1188,8 @@ const MARKER_EVENT_TYPES = /* @__PURE__ */ new Set([
1150
1188
  "step_failed",
1151
1189
  "run_failed",
1152
1190
  "wait_created",
1153
- "wait_completed"
1191
+ "wait_completed",
1192
+ "attr_set"
1154
1193
  ]);
1155
1194
  function convertEventsToSpanEvents(events, filterTypes = true) {
1156
1195
  return events.filter((event) => filterTypes ? MARKER_EVENT_TYPES.has(event.eventType) : true).map((event) => ({
@@ -1385,6 +1424,15 @@ function runToSpan(run, runEvents, nowTime) {
1385
1424
  const isStepEvent = (eventType) => eventType.startsWith("step_");
1386
1425
  const isTimerEvent = (eventType) => eventType === "wait_created" || eventType === "wait_completed";
1387
1426
  const isHookLifecycleEvent = (eventType) => eventType === "hook_received" || eventType === "hook_created" || eventType === "hook_disposed";
1427
+ const isRunLevelEvent = (event) => !event.correlationId || !isTimerEvent(event.eventType) && !isHookLifecycleEvent(event.eventType) && !isStepEvent(event.eventType);
1428
+ function filterSpanRawEvents(events, resource, spanId) {
1429
+ if (resource === "run") {
1430
+ return events.filter(isRunLevelEvent);
1431
+ }
1432
+ if (!spanId)
1433
+ return [];
1434
+ return events.filter((e) => e.correlationId === spanId);
1435
+ }
1388
1436
  function pushEvent(map, correlationId, event) {
1389
1437
  const existing = map.get(correlationId);
1390
1438
  if (existing) {
@@ -1865,53 +1913,6 @@ function parseContent(content) {
1865
1913
  }
1866
1914
  return [];
1867
1915
  }
1868
- const encryptedPlaceholderPreview = `{
1869
- "input": "[encrypted]",
1870
- "result": "[encrypted]"
1871
- }`;
1872
- function EncryptedDataBlock() {
1873
- const ctx = reactExports.useContext(DecryptClickContext);
1874
- return jsxRuntimeExports.jsxs("div", { className: "relative min-h-20 overflow-hidden rounded-md border border-gray-alpha-400 bg-background-100", children: [jsxRuntimeExports.jsx("pre", { "aria-hidden": "true", className: "pointer-events-none m-0 select-none p-3 font-mono text-label-12 text-gray-900 blur-[4px]", children: encryptedPlaceholderPreview }), jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: ctx ? jsxRuntimeExports.jsxs(Button, { onClick: ctx.onDecrypt, disabled: ctx.isDecrypting, size: "xs", children: [ctx.isDecrypting ? jsxRuntimeExports.jsx(Spinner, { size: 10 }) : jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), jsxRuntimeExports.jsx("span", { children: "Decrypt" })] }) : jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 rounded border border-gray-alpha-400 bg-gray-100 px-1.5 py-0.5 text-button-12 font-medium text-gray-700", children: [jsxRuntimeExports.jsx(Lock, { className: "h-3 w-3" }), "Encrypted"] }) })] });
1875
- }
1876
- const serializeForClipboard = (value) => {
1877
- if (typeof value === "string")
1878
- return value;
1879
- if (typeof value === "number" || typeof value === "boolean" || value === null) {
1880
- return String(value);
1881
- }
1882
- try {
1883
- return JSON.stringify(value, null, 2);
1884
- } catch {
1885
- return String(value);
1886
- }
1887
- };
1888
- function CopyableDataBlock({ data }) {
1889
- return jsxRuntimeExports.jsxs("div", { className: "relative overflow-x-auto rounded-md border border-gray-alpha-400 p-3", children: [jsxRuntimeExports.jsx(CopyButton, { copyText: serializeForClipboard(data), ariaLabel: "Copy data", className: "absolute right-2 top-2 z-10 flex h-6 w-6 items-center justify-center rounded-md border border-gray-alpha-400 !bg-background-100 p-0 text-gray-900 transition-transform transition-colors duration-100 hover:bg-gray-200 active:scale-95 active:bg-gray-300" }), jsxRuntimeExports.jsx(DataInspector, { data })] });
1890
- }
1891
- function DetailCard({ summary, children, onToggle, disabled = false, defaultOpen = false, variant = "section", trailing, summaryClassName, contentClassName }) {
1892
- const [open, setOpen] = reactExports.useState(defaultOpen);
1893
- const handleToggle = (e) => {
1894
- if (e.target !== e.currentTarget)
1895
- return;
1896
- const next = e.currentTarget.open;
1897
- setOpen(next);
1898
- onToggle == null ? void 0 : onToggle(next);
1899
- };
1900
- if (variant === "card") {
1901
- if (disabled) {
1902
- return jsxRuntimeExports.jsx("div", { className: cn("list-none px-3 py-4 bg-background-200 [&::-webkit-details-marker]:hidden", summaryClassName), style: { cursor: "not-allowed", opacity: 0.8 }, children: summary });
1903
- }
1904
- return jsxRuntimeExports.jsxs("details", { className: "group/card last:border-b border-gray-alpha-400", open, onToggle: handleToggle, children: [jsxRuntimeExports.jsx("summary", { className: cn("list-none cursor-pointer px-3 py-4 border-t border-gray-alpha-400 bg-background-200 hover:bg-gray-100 [&::-webkit-details-marker]:hidden", summaryClassName), children: jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5", children: [jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: cn("shrink-0 text-gray-700 group-hover/card:text-gray-1000", open && "rotate-90") }), summary] }) }), jsxRuntimeExports.jsx("div", { className: contentClassName, children })] });
1905
- }
1906
- const rowClasses = "flex h-9 items-center gap-2 px-2 -mx-2 text-heading-14 font-medium my-2";
1907
- if (trailing) {
1908
- return jsxRuntimeExports.jsx("section", { className: "-mx-4 border-t px-4 border-gray-alpha-400", children: jsxRuntimeExports.jsxs("div", { className: cn(rowClasses, summaryClassName), children: [jsxRuntimeExports.jsx("div", { className: "isolate relative shrink-0 w-3.5 h-3.5 text-gray-700", children: jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" }) }), jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1", children: summary }), jsxRuntimeExports.jsx("div", { className: "shrink-0 pr-1", children: trailing })] }) });
1909
- }
1910
- if (disabled) {
1911
- return jsxRuntimeExports.jsx("section", { className: "-mx-4 border-t px-4 border-gray-alpha-400", children: jsxRuntimeExports.jsx("div", { className: cn(rowClasses, summaryClassName), style: { color: "var(--ds-gray-700)", cursor: "not-allowed" }, children: jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1", children: summary }) }) });
1912
- }
1913
- return jsxRuntimeExports.jsx("section", { className: "-mx-4 border-t px-4 border-gray-alpha-400", children: jsxRuntimeExports.jsxs("details", { className: "group", open, onToggle: handleToggle, children: [jsxRuntimeExports.jsxs("summary", { className: cn("group/trigger list-none cursor-pointer rounded hover:bg-gray-alpha-100 [&::-webkit-details-marker]:hidden", rowClasses, summaryClassName), children: [jsxRuntimeExports.jsxs("div", { className: "isolate relative shrink-0 text-gray-700 group-hover/trigger:text-gray-1000 w-3.5 h-3.5", children: [jsxRuntimeExports.jsx(ChevronRight, { size: 14, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-100 group-open:opacity-0" }), jsxRuntimeExports.jsx(ChevronDown, { size: 14, className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-0 group-open:opacity-100" })] }), jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1", children: summary })] }), jsxRuntimeExports.jsx("div", { className: cn("mb-3", contentClassName), children })] }) });
1914
- }
1915
1916
  function TabButton({ active, onClick, children }) {
1916
1917
  return jsxRuntimeExports.jsx("button", { type: "button", role: "tab", "aria-selected": active, tabIndex: active ? 0 : -1, onClick, className: "px-3 py-1.5 text-[11px] font-medium transition-colors -mb-px", style: {
1917
1918
  // Explicit styles to prevent app-level button overrides when web-shared
@@ -2074,15 +2075,7 @@ const parseDateValue = (value) => {
2074
2075
  const date = typeof value === "number" ? new Date(value) : new Date(String(value));
2075
2076
  return Number.isNaN(date.getTime()) ? null : date;
2076
2077
  };
2077
- const formatLocalMillisecondTime = (date) => date.toLocaleString(void 0, {
2078
- year: "numeric",
2079
- month: "numeric",
2080
- day: "numeric",
2081
- hour: "numeric",
2082
- minute: "numeric",
2083
- second: "numeric",
2084
- fractionalSecondDigits: 3
2085
- });
2078
+ const formatLocalMillisecondTime = (date) => format(date, "MMM dd HH:mm:ss.SS OO").toUpperCase();
2086
2079
  const localMillisecondTimeOrNull = (value) => {
2087
2080
  const date = parseDateValue(value);
2088
2081
  if (!date) {
@@ -2128,13 +2121,13 @@ const attributeToDisplayFn = {
2128
2121
  projectId: (_value) => null,
2129
2122
  environment: (_value) => null,
2130
2123
  executionContext: (_value) => null,
2131
- // Attributes MVP — string-string metadata attached to the run.
2132
- // Rendered in its own collapsible DetailCard; if empty/missing, hidden
2133
- // by the hasDisplayContent gate.
2124
+ // Attributes — string-string metadata attached to the run.
2125
+ // Rendered as key-value rows in its own collapsible DetailCard;
2126
+ // if empty/missing, hidden by the hasDisplayContent gate.
2134
2127
  attributes: (value) => {
2135
2128
  if (!hasDisplayContent(value))
2136
2129
  return null;
2137
- return jsxRuntimeExports.jsx(DetailCard, { summary: "Attributes", children: JsonBlock(value) });
2130
+ return jsxRuntimeExports.jsx(RunAttributesCard, { attributes: value });
2138
2131
  },
2139
2132
  // Dates — wrapped with TimestampTooltip showing UTC/local + relative time
2140
2133
  createdAt: timestampWithTooltipOrNull,
@@ -2348,7 +2341,7 @@ const AttributePanel = ({ data, moduleSpecifier, isLoading, error, expiredAt, on
2348
2341
  isDecrypting,
2349
2342
  hasEncryptedData: outerDecryptCtx == null ? void 0 : outerDecryptCtx.hasEncryptedData
2350
2343
  } : outerDecryptCtx;
2351
- return jsxRuntimeExports.jsx(RunClickContext.Provider, { value: onRunClick, children: jsxRuntimeExports.jsx(StreamClickContext.Provider, { value: onStreamClick, children: jsxRuntimeExports.jsxs(DecryptClickContext.Provider, { value: decryptValue, children: [visibleBasicAttributes.length > 0 && jsxRuntimeExports.jsxs("div", { className: "flex flex-col overflow-hidden divide-y divide-gray-alpha-400 mb-3", children: [orderedBasicAttributes.map((attribute) => {
2344
+ return jsxRuntimeExports.jsx(ContextCardProvider, { children: jsxRuntimeExports.jsx(RunClickContext.Provider, { value: onRunClick, children: jsxRuntimeExports.jsx(StreamClickContext.Provider, { value: onStreamClick, children: jsxRuntimeExports.jsxs(DecryptClickContext.Provider, { value: decryptValue, children: [visibleBasicAttributes.length > 0 && jsxRuntimeExports.jsxs("div", { className: "flex flex-col overflow-hidden divide-y divide-gray-alpha-400 mb-3", children: [orderedBasicAttributes.map((attribute) => {
2352
2345
  var _a;
2353
2346
  const displayValue = (_a = attributeToDisplayFn[attribute]) == null ? void 0 : _a.call(attributeToDisplayFn, displayData[attribute]);
2354
2347
  const isModuleSpecifier = attribute === "moduleSpecifier";
@@ -2362,7 +2355,7 @@ const AttributePanel = ({ data, moduleSpecifier, isLoading, error, expiredAt, on
2362
2355
  }, title: moduleSpecifierValue, onClick: () => handleCopyModuleSpecifier(moduleSpecifierValue), children: moduleSpecifierValue }) : isCopyableBasicAttribute ? jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 max-w-[70%] items-center justify-end gap-1 text-right text-[13px] font-mono", style: {
2363
2356
  color: "var(--ds-gray-1000)"
2364
2357
  }, title: displayValue, children: [jsxRuntimeExports.jsx(MiddleTruncate, { value: displayValue, className: "flex-1" }), jsxRuntimeExports.jsx(CopyButton, { copyText: displayValue, ariaLabel: `Copy ${getAttributeDisplayName(attribute)}`, className: "shrink-0 -mr-1" })] }) : jsxRuntimeExports.jsx("span", { className: "text-right text-label-13 font-mono", children: displayValue })] }, attribute);
2365
- }), isLoading && resource === "sleep" && !displayData.resumeAt && jsxRuntimeExports.jsx("div", { className: "py-1", children: jsxRuntimeExports.jsxs("div", { className: "flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1", children: [jsxRuntimeExports.jsx("span", { className: "text-[14px] first-letter:uppercase", style: { color: "var(--ds-gray-700)" }, children: "resumeAt" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-[55%]" })] }) })] }), error ? jsxRuntimeExports.jsx(ErrorCard, { title: "Failed to load resource details", details: error.message, className: "my-4" }) : hasExpired ? jsxRuntimeExports.jsx(ExpiredDataMessage, {}) : resolvedAttributes.length > 0 ? jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: resolvedAttributes.map((attribute) => jsxRuntimeExports.jsx(AttributeBlock, { isLoading, attribute, value: displayData[attribute], context: displayContext }, attribute)) }) : null] }) }) });
2358
+ }), isLoading && resource === "sleep" && !displayData.resumeAt && jsxRuntimeExports.jsx("div", { className: "py-1", children: jsxRuntimeExports.jsxs("div", { className: "flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1", children: [jsxRuntimeExports.jsx("span", { className: "text-[14px] first-letter:uppercase", style: { color: "var(--ds-gray-700)" }, children: "resumeAt" }), jsxRuntimeExports.jsx(Skeleton, { className: "h-4 w-[55%]" })] }) })] }), error ? jsxRuntimeExports.jsx(ErrorCard, { title: "Failed to load resource details", details: error.message, className: "my-4" }) : hasExpired ? jsxRuntimeExports.jsx(ExpiredDataMessage, {}) : resolvedAttributes.length > 0 ? jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: resolvedAttributes.map((attribute) => jsxRuntimeExports.jsx(AttributeBlock, { isLoading, attribute, value: displayData[attribute], context: displayContext }, attribute)) }) : null] }) }) }) });
2366
2359
  };
2367
2360
  const ERROR_EVENT_TYPES = /* @__PURE__ */ new Set(["step_failed", "step_retrying"]);
2368
2361
  const DATA_EVENT_TYPES = /* @__PURE__ */ new Set([
@@ -2376,7 +2369,8 @@ const DATA_EVENT_TYPES = /* @__PURE__ */ new Set([
2376
2369
  "run_completed",
2377
2370
  "run_failed",
2378
2371
  "wait_created",
2379
- "wait_completed"
2372
+ "wait_completed",
2373
+ "attr_set"
2380
2374
  ]);
2381
2375
  function EventItem({ event, onLoadEventData, encryptionKey }) {
2382
2376
  const [loadedData, setLoadedData] = reactExports.useState(null);
@@ -2450,6 +2444,9 @@ function EventDataBlock({ eventType, data }) {
2450
2444
  if (hasEncryptedFields({ eventType, eventData: data })) {
2451
2445
  return jsxRuntimeExports.jsx(EncryptedDataBlock, {});
2452
2446
  }
2447
+ if (eventType === "attr_set") {
2448
+ return jsxRuntimeExports.jsx(AttrSetEventBlock, { data });
2449
+ }
2453
2450
  if (ERROR_EVENT_TYPES.has(eventType) && data != null && typeof data === "object") {
2454
2451
  const record = data;
2455
2452
  if (isStructuredError(record.error)) {
@@ -2705,7 +2702,7 @@ function EntityDetailPanel({ run, onStreamClick, onRunClick, spanDetailData, spa
2705
2702
  }, children: [jsxRuntimeExports.jsx(Zap, { className: "h-4 w-4" }), stoppingSleep ? "Waking up..." : "Wake Up Sleep"] }), resource === "hook" && canResolveHook && jsxRuntimeExports.jsxs("button", { type: "button", onClick: () => setShowResolveHookModal(true), disabled: resolvingHook, className: clsx("flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium", "disabled:opacity-50 disabled:cursor-not-allowed transition-colors", resolvingHook ? "opacity-50 cursor-not-allowed" : "cursor-pointer"), style: {
2706
2703
  background: "var(--ds-gray-1000)",
2707
2704
  color: "var(--ds-background-100)"
2708
- }, children: [jsxRuntimeExports.jsx(Send, { className: "h-4 w-4" }), "Resolve Hook"] })] })] }), jsxRuntimeExports.jsx(AttributePanel, { data: displayData, moduleSpecifier, expiredAt: run.expiredAt, isLoading: loading, error: error ?? void 0, onStreamClick, onRunClick, onDecrypt, isDecrypting, resource }), resource !== "run" && rawEvents && jsxRuntimeExports.jsx(EventsList, { events: rawEvents, onLoadEventData, onStreamClick, onRunClick, encryptionKey })] }) }), jsxRuntimeExports.jsx(ResolveHookModal, { isOpen: showResolveHookModal, onClose: () => setShowResolveHookModal(false), onSubmit: handleResolveHook, isSubmitting: resolvingHook })] });
2705
+ }, children: [jsxRuntimeExports.jsx(Send, { className: "h-4 w-4" }), "Resolve Hook"] })] })] }), jsxRuntimeExports.jsx(AttributePanel, { data: displayData, moduleSpecifier, expiredAt: run.expiredAt, isLoading: loading, error: error ?? void 0, onStreamClick, onRunClick, onDecrypt, isDecrypting, resource }), rawEvents && jsxRuntimeExports.jsx(EventsList, { events: rawEvents, onLoadEventData, onStreamClick, onRunClick, encryptionKey })] }) }), jsxRuntimeExports.jsx(ResolveHookModal, { isOpen: showResolveHookModal, onClose: () => setShowResolveHookModal(false), onSubmit: handleResolveHook, isSubmitting: resolvingHook })] });
2709
2706
  }
2710
2707
  const COL_TEMPLATE = "340px 1px minmax(50px, 1fr)";
2711
2708
  const ROWS = [
@@ -2758,24 +2755,6 @@ function useLoadMoreOnScroll(loadMore, { hasMore, isLoadingMore, rootRef, rootMa
2758
2755
  }, [entry == null ? void 0 : entry.isIntersecting, hasMore, isLoadingMore]);
2759
2756
  return sentinelRef;
2760
2757
  }
2761
- const QUERY = "(prefers-reduced-motion: reduce)";
2762
- const useReducedMotion = () => {
2763
- const [reduced, setReduced] = reactExports.useState(() => {
2764
- if (typeof window === "undefined" || !window.matchMedia)
2765
- return false;
2766
- return window.matchMedia(QUERY).matches;
2767
- });
2768
- reactExports.useEffect(() => {
2769
- if (typeof window === "undefined" || !window.matchMedia)
2770
- return;
2771
- const media = window.matchMedia(QUERY);
2772
- const onChange = () => setReduced(media.matches);
2773
- media.addEventListener("change", onChange);
2774
- onChange();
2775
- return () => media.removeEventListener("change", onChange);
2776
- }, []);
2777
- return reduced;
2778
- };
2779
2758
  function Kbd({ children, className }) {
2780
2759
  return jsxRuntimeExports.jsx("kbd", { className: cn("inline-flex h-5 min-w-5 items-center justify-center rounded bg-background-100/20 px-1 text-center font-sans text-xs leading-none", className), children });
2781
2760
  }
@@ -2982,11 +2961,11 @@ function useSelectedSpanInfo() {
2982
2961
  var _a, _b;
2983
2962
  if (!activeSpan)
2984
2963
  return null;
2985
- const correlationId = activeSpan.spanId;
2986
- const rawEvents = correlationId ? sidebar.events.filter((e) => e.correlationId === correlationId) : [];
2964
+ const resource = (_a = activeSpan.attributes) == null ? void 0 : _a.resource;
2965
+ const rawEvents = filterSpanRawEvents(sidebar.events, resource, activeSpan.spanId);
2987
2966
  return {
2988
- data: (_a = activeSpan.attributes) == null ? void 0 : _a.data,
2989
- resource: (_b = activeSpan.attributes) == null ? void 0 : _b.resource,
2967
+ data: (_b = activeSpan.attributes) == null ? void 0 : _b.data,
2968
+ resource,
2990
2969
  spanId: activeSpan.spanId,
2991
2970
  rawEvents
2992
2971
  };
@@ -3194,7 +3173,7 @@ function NewTraceViewerContent({ trace, onLoadMore, hasMore, isLoadingMore }) {
3194
3173
  dy *= 16;
3195
3174
  const cursorFraction = Math.max(0, Math.min(1, (e.clientX - rect.left - TIMELINE_PADDING_PX) / contentWidth));
3196
3175
  const isMouseWheel = e.deltaMode === 1 || Math.abs(e.deltaY) >= 50;
3197
- const scaleFactor = Math.pow(2, dy / (isMouseWheel ? 200 : 60));
3176
+ const scaleFactor = 2 ** (dy / (isMouseWheel ? 200 : 60));
3198
3177
  setViewport((prev) => {
3199
3178
  const prevDuration = prev.end - prev.start;
3200
3179
  const cursorTime = prev.start + cursorFraction * prevDuration;