Drop the synchronous getModuleSourceUrl prop so hosts maintain one prop
instead of two. resolveModuleSourceUrl now returns its own best-effort
fallback, so the sync variant is unnecessary; the Module row renders as
plain text until resolved.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an optional async resolveModuleSourceUrl to the trace-viewer sidebar
data. The details-panel "Module" link prefers it over the synchronous
getModuleSourceUrl (falling back when it's absent or returns nothing), so
hosts can resolve the link to the file's real source path and extension
and never render a broken link.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hook timeline bars were amber/yellow via RESOURCE_COLORS; passive
spans should be gray to match the event list icons and minimap.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* Give Metadata Token and Hook ID copy + truncation
Add token to the copyable metadata attributes set and constrain
copyable key-value rows so MiddleTruncate can shrink long IDs.
* Remove AttributePanel copy unit tests
The Metadata Token/Hook ID copy change is small enough that the
dedicated panel render tests are unnecessary.
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
The row is already right-aligned via the parent's justify-between, so
flex-1 was only forcing the value column to stretch. Drop it so values
hug their content.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Anchor trace viewer shortcut helper to the timeline's left edge
Render the shortcut helper inside the timeline column instead of as a
pane-root overlay, so it aligns to the timeline's left edge (tracking
the divider for free) and sticks to the bottom of the viewport while
the pane scrolls. Gate visibility on a container-query width
(`@container` on the timeline column + `@min-[420px]`) rather than the
viewport `md` breakpoint, so it hides based on the timeline's own width.
No SplitPane API change required.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Raise shortcut-helper container-query threshold to 480px
At 420px the helper could still show when the detail panel squeezes the
timeline, colliding with the zoom controls in the bottom-right. 480px
leaves comfortable clearance so it hides once the timeline is narrow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Update trace-viewer.tsx
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Match split-pane divider drag to the detail panel
The trace event-list / timeline split-pane divider now reuses the shared
DraggableBorder component, so it resizes identically to the span detail
panel: a wider invisible hit strip, hover/focus/drag highlight rendered
over the divider, double-click reset, and keyboard/ARIA (role="separator")
resize. Width stays in-memory (not persisted), unlike the detail panel.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Update split-pane.tsx
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The click-to-focus viewport reframe used a weak quadratic ease-out over
150ms, which read as a near-linear snap. Switch to a stronger
easeInOutQuart curve (~cubic-bezier(0.77, 0, 0.175, 1)) over 240ms so the
camera zoom/pan accelerates and decelerates like a smooth move.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* doen
* Fix: Old test file `test/format-duration-precise.test.ts` still asserts two-decimal output ("45.20s", "1m 0.00s") that no longer matches the trimmed-zero output of `formatDurationPrecise`, so `pnpm test`/CI fails.
This commit fixes the issue reported at packages/web-shared/test/format-duration-precise.test.ts:15
## Bug
The PR changed `formatDurationPrecise` (in `packages/web-shared/src/lib/utils.ts`) to trim trailing zeros by wrapping the fractional value in `Number(x.toFixed(fractionDigits))`:
```ts
if (normalizedMs < MS_IN_MINUTE) {
return `${Number((normalizedMs / MS_IN_SECOND).toFixed(fractionDigits))}s`;
}
...
parts.push(`${Number(seconds.toFixed(fractionDigits))}s`);
```
`Number("45.20")` → `45.2`, `Number("0.00")` → `0`, so whole/half seconds now render without padding.
A new test file `packages/web-shared/src/lib/utils.test.ts` reflects this behavior, but the pre-existing `packages/web-shared/test/format-duration-precise.test.ts` was left untouched and still asserts the **old** padded output.
## Concrete trigger
Reproduced the actual function output (integer decomposition + trimmed zeros):
| Input | Old assertion | New actual output |
|-------|---------------|-------------------|
| `45200` | `45.20s` | `45.2s` |
| `999.6` | `1.00s` | `1s` |
| `999.5` | `1.00s` | `1s` |
| `59999` | `1m 0.00s` | `1m 0s` |
| `59995` | `1m 0.00s` | `1m 0s` |
| `119999` | `2m 0.00s` | `2m 0s` |
| `3659999` | `1h 1m 0.00s` | `1h 1m 0s` |
| `86459999` | `1d 1m 0.00s` | `1d 1m 0s` |
The root `vitest.config.ts` uses default include globs, so `test/*.test.ts` runs and these assertions fail, breaking CI. (I couldn't run vitest directly in the sandbox because dev deps weren't installed / `vitest/config` unresolved, so I reproduced the exact function logic in a standalone Node script to confirm the outputs.)
## Fix
Updated the stale assertions in `test/format-duration-precise.test.ts` to the trimmed-zero outputs, and adjusted the file-level doc comment (which referenced `"1m 0.00s"` / `"60.00s"`) to describe the current behavior.
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: mitul-s <mitulxshah@gmail.com>
---------
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
* nice
* refactor(web-shared): simplify resizable detail panel internals
Inline single-use constants in DraggableBorder and make comments
self-contained.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fix compressed workflow data display
* Add OSS web no-key hydration regression
* Scope compression normalization to read paths; tidy hydration
Address review feedback on the compressed-data fix:
- world-vercel: keep gzip/zstd decompression on the o11y/display read
paths (getStep/getRun/getEvent/getWorkflowRunEvents/getHook) but not on
the runtime event-append path (world.events.create, createStep,
updateStep). That path is runtime-only and re-hydrates every payload via
the decompress-aware helpers, so decompressing at the adapter was
redundant work on the TTFB-sensitive run_started/inline-delta path and
skewed the runtime's deserialize compression telemetry to `codec: none`.
deserializeStep is now shape-only; normalizeStepData runs in the read
filter. Adds a regression test pinning the write-path pass-through.
- serialized-data: drop dead `errorRef`/`metadataRef` normalization (refs
are descriptor objects, never compressed byte payloads).
- web: in the wait-entity path, filter events by correlationId before
hydrating so an encryption key doesn't decrypt the whole event page.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Peter Wielander <peter.wielander@vercel.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(web-shared): align metadata panel styling with attributes section
Render hook metadata as key-value rows inside a DetailCard, matching
the Attributes section instead of a raw JSON block with a separate label.
* fix(web-shared): align top detail panel rows with attributes styling
Reuse DetailKeyValueRow for Module, Step ID, timestamps, etc. — same
tighter spacing, typography, and no dividers as the Attributes section.
* fix(web-shared): collapse top detail rows into Metadata with mono values
Wrap Module, Step ID, timestamps, etc. in a Metadata DetailCard and
render all values in monospace, including copyable paths and IDs.
* fix(web-shared): use contained header style for Metadata section
Add a contained DetailCard variant with rounded bg header and drop my-2
in favor of py-2 padding on the section wrapper.
* refactor(web-shared): drop reserved badge and use cn for row classes
Remove ReservedBadge and showReservedBadge; keep reserved-key sorting only.
Use cn() for conditional mono font classes in DetailKeyValueRow.
* refactor(web-shared): drop contained DetailCard variant
Use the default section DetailCard for Metadata, matching Attributes.
* feat(web-shared): extend cn with custom tailwind-merge class groups
Add a dedicated cn module that understands text-heading, text-label,
text-copy, text-button, and material utilities when merging classes.
* chore: note cn tailwind-merge update in changeset
* fix(web-shared): remove my-2 from DetailCard summary rows
Move vertical spacing to py-2 on the section container instead.
* fix(web-shared): scope Metadata spacing override
Restore shared DetailCard summary spacing for Input, Output, Events, and
Attributes while keeping Metadata tighter with a summaryClassName override.
* refactor(web-shared): use CVA variants for detail row value styling
Replace the mono boolean and one-off Metadata summary override with CVA-backed row variants and semantic mono row wrapper.
* fix(web-shared): use section padding for DetailCard spacing
Move spacing from summary margins to section padding and add content top
spacing so collapsed and expanded detail cards both breathe consistently.
* fix(web-shared): remove expanded Metadata content gap
Keep DetailCard's default expanded content spacing for data panels, but let
Metadata rows start directly below the title via contentClassName merge.
* refactor(web-shared): use Tailwind classes for disabled detail card
* refactor(web-shared): use DetailCard compound content
* refactor(web-shared): rebuild DetailCard as a compound component
Replace the monolithic DetailCard (summary/trailing/disabled props plus
child-type reflection for content) with a context-driven compound API:
DetailCard + DetailCard.Trigger + DetailCard.Content. Drop the dead
trailing branch, expose data-slot/data-state, and migrate all call sites.
* refactor(web-shared): rename DetailCard to Collapsible
It's a generic collapsible section, not a card-specific component. Rename
the component, its parts, data-slots, and the file accordingly.
* refactor(web-shared): split Collapsible into all-in-one + parts
Export a batteries-included <Collapsible label> for the common case so
consumers don't recompose the trigger/content every time, plus
CollapsibleRoot/CollapsibleTrigger/CollapsibleContent for the few call
sites that need to override part styling. Drop the dot-notation namespace.
* refactor(web-shared): move Collapsible into ui directory
It's a generic UI primitive, not sidebar-specific.
* refactor(web-shared): import cn from lib/cn directly
Drop the cn re-export from lib/utils; consumers import it from its
actual source instead of routing through utils.
* refactor(web-shared): drop cn tailwind-merge changes from this PR
Move the extended cn (lib/cn) work to a separate PR; this branch keeps
using the existing cn from lib/utils.
* ship it
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* Add selection-driven span-detail primitives
Extract the run/step/hook/sleep fetch+hydrate core out of useWorkflowResourceData
into a plain async fetchSpanDetailResource (no React state), and add a
selection-driven state machine in web-shared:
- deriveSpanDetailView / resourceNeedsFetchedDetail: pure view-model deriver
whose status (idle/loading/ready/error) is a function of (selection, fetched
detail), so it can never lag the selection.
- useSelectedSpanDetail: fetches a selected span's detail directly with a
request-token to drop stale/out-of-order responses.
* Drive trace detail panel from the span-detail state machine
Replace the cross-package selection round-trip (EntityDetailPanel useEffect ->
onSpanSelect -> page spanSelection state -> useWorkflowResourceData -> context)
with a single injected fetchSpanDetail capability:
- EntityDetailPanel consumes useSelectedSpanDetail; its loading state now stays
in phase with the selected span, so Input/Output no longer vanish and pop back
in while navigating.
- SidebarDataContext drops spanDetailData/Loading/Error + onSpanSelect for a
single fetchSpanDetail; RunDetailView injects it and drops the duplicate
spanSelection state.
- WorkflowTraceViewer / RunTraceView take fetchSpanDetail too.
* Test span-detail view-model transitions; add changeset
Cover deriveSpanDetailView (idle/loading/ready/error, stale-detail rejection,
hooks ready inline) and resourceNeedsFetchedDetail.
* Trim redundant/narrative comments in span-detail state machine
Comment-only cleanup: drop PR-narration and cross-file duplication from the
deriveSpanDetailView / useSelectedSpanDetail / EntityDetailPanel / fetchSpanDetail
doc comments, keeping the non-obvious intent (request-token, error scoping,
decrypt closure).
* delete pointless coments
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Move cn to its own lib/cn module that teaches tailwind-merge about the
design-system text-heading/text-label/text-copy/text-button/material
utilities, and import it directly from lib/cn.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* Use text-gray-900 for trace shortcut helper text
Co-authored-by: Mitul Shah <mitulxshah@gmail.com>
* Add changeset for trace shortcut helper text color
Co-authored-by: Mitul Shah <mitulxshah@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix(web-shared): stop data inspector duplicating expanded objects
Expanded objects/arrays now render bracket delimiters ({ … } / [ … ])
instead of repeating the inline preview alongside the child tree.
Co-authored-by: Cursor <cursoragent@cursor.com>
* nice
* fix: sync lockfile after dropping react-inspector
The react-inspector removal landed in package.json but the lockfile was
reverted during cleanup, breaking frozen-lockfile installs in CI.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shared): keep data inspector colors theme-aware
Drop the dark-mode color overrides (and the data-theme/useDarkMode
wiring) and rely on the theme-aware --ds-* tokens, matching front:
strings stay green in both light and dark instead of turning blue.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(web-shared): add data inspector tests; tidy comments
Cover collapseRefs ref/typed-array/Map/Set handling and the rendered
tree (keys, value colors, brackets, commas, collapse/expand, empties,
dates, class/Map/Set prefixes) via jsdom + testing-library.
Co-authored-by: Cursor <cursoragent@cursor.com>
* revert(web-shared): drop data inspector tests
Remove the test suite and its jsdom/@testing-library devDependencies to
avoid adding new packages. Keeps the data inspector code unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(web-shared): extract data inspector styles to a sibling module
Move the class-name map and CSS string out of the component into
data-inspector.styles.ts for readability. Still injected via the
hoistable <style>; no behavior or dependency change.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shared): restore ARIA tree semantics for the data inspector
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shared): render RegExp values as /source/flags
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(web-shared): add unit tests for CopyableDataBlock JSON viewer (#2584)
Export serializeForClipboard and cover its clipboard formatting (strings, primitives, pretty-printed JSON, circular/BigInt fallbacks) plus CopyableDataBlock/EncryptedDataBlock rendering.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* Show pending runs as gray animated stripes in the new trace viewer.
Pending was incorrectly using the blue running indicator; it now has its own segment status and gray stripe styling.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add changeset for pending trace viewer indicator styling.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* [web-shared] Auto-scroll trace viewer on J/K span navigation
Bring the selected span into view when J/K (or the up/down chevrons)
navigate to a span outside the visible area. The event list is windowed
with fixed-height rows, so the target offset is computed from the row
index rather than relying on a DOM node that may not be mounted.
Co-authored-by: Cursor <cursoragent@cursor.com>
* [web-shared] Extract scrollRowIntoView helper from trace viewer
Relocate the J/K auto-scroll geometry math out of the large
NewTraceViewerContent component and into a small pure helper colocated
with the windowing primitives in use-row-window.ts. scrollRowIntoView
reuses the existing getScrollParent walker and takes the row height as a
parameter, so the trace viewer's scrollSpanIntoView is now a thin caller
that finds the span index and delegates.
No behavior change: the off-screen-only condition, one-row margin,
clamp to [0, scrollHeight - clientHeight], and reduced-motion behavior
are all preserved. getScrollParent(#event-list) resolves to the same
SplitPane scroll container the old code measured against directly, so
the net scroll geometry is identical.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Update trace-viewer.tsx
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
When a step emits `step_started` twice in a row (a re-start with no
retrying/failed/completed in between), the interval between the two starts
was shown with the animated blue "running" stripes, implying active
progress. Treat that segment as gray ('retrying') instead.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shared): use solid gray for queued trace segment
The queued span segment used alpha gray tokens for its hatched fill,
making it look washed out. Switch to the solid gray tokens.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix typo in queued trace segment color message
Signed-off-by: Mitul Shah <mitulxshah@gmail.com>
---------
Signed-off-by: Mitul Shah <mitulxshah@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(web-shared): add event markers to the trace timeline
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Update span-markers.tsx
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(core,world): gzip-compress serialized payloads behind specVersion 5
Add a composable 'gzip' format prefix layer to the serialization
pipeline (compress before encrypt: encr(gzip(devl))), cutting stored
payload bytes by ~70-87% on real-world-style workloads. Compression is
gated on run specVersion 5 (new SPEC_VERSION_SUPPORTS_COMPRESSION) and
on target-deployment capabilities for cross-deployment writes; payloads
under 1KB or that don't compress meaningfully are stored unchanged.
Reads dispatch on the format prefix so both compressed and uncompressed
data are always readable. WORKFLOW_DISABLE_COMPRESSION=1 disables
writes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(core): add CPU/perf compression benchmark + shared workloads
Split the compression benchmark into reproducible size and CPU scripts
sharing deterministic workloads (lib/workloads.mjs). The CPU benchmark
measures serialize/deserialize overhead per payload, total CPU across
thousands of events, and compares gzip levels/brotli/deflate. Documents
how to run the size, CPU, and end-to-end (bench.bench.ts) benchmarks
against local and Vercel in scripts/README.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(world-vercel): advertise specVersion 5 to enable compression on Vercel
Now that workflow-server declares spec-5 support (vercel/workflow-server#520),
bump the Vercel world's advertised specVersion from 4 to 5 so new Vercel runs
are stamped spec 5 and become eligible for gzip payload compression. Payloads
stay opaque to the server (compression is client-side); spec 5 is a superset of
spec 4, so initial run attributes still work.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(core): emit OTel span attributes for compression impact
Track gzip payload compression on both the serialize (write) and
deserialize (read) paths via span attributes:
workflow.serialization.{operation,compressed,uncompressed_bytes,
stored_bytes,compression_ratio}. Sizes are measured at the compression
boundary (pre-encryption), so they reflect compression's effect rather
than the at-rest size.
The compression codec stays pure — compress/decompress optionally
populate a CompressionStats sink, threaded through CodecOptions to the
mode serializers and read by the dehydrate/hydrate wrappers, which set
attributes on the active span. Telemetry failures are swallowed so they
can never break the serialize/deserialize data path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(core,web-shared): prefer zstd compression codec (gzip fallback)
Switch the payload compression codec to zstd, which benchmarks 3–7×
faster than gzip at an equal-or-better ratio on representative workloads
(compression runs at every step boundary, so the write CPU is a per-step
tax). zstd uses node:zlib (>= 22.15); gzip via the portable
CompressionStream remains the fallback when zstd is unavailable, and
WORKFLOW_COMPRESSION_CODEC=gzip forces it. Reads dispatch on the format
prefix, so 'zstd' and 'gzip' payloads are both always decodable.
zstd is Node-only (Web CompressionStream has no zstd), so the browser
o11y read path registers a WASM-backed decoder (@tootallnate/zstd-wasm)
via a new registerZstdDecoder hook; node:zlib handles Node-side reads
(runtime replay, CLI, server o11y). A new workflow.serialization.codec
span attribute reports which codec applied. gzip and zstd read support
co-ship, so the existing specVersion-5 capability gate is unchanged.
Verified end-to-end: spec-5 runs store zstd-prefixed payloads on disk
and replay/complete correctly; the WASM decoder round-trips node:zlib
zstd output. Benchmarks updated to compare zstd vs gzip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Teal diamond markers for attr_set events on the trace timeline with
time tooltips (new trace viewer)
- attr_set payloads render changed/removed keys and the writer
(workflow vs step + attempt) in the run sidebar and Events tab
- Run root span selection now shows run-level events (run lifecycle +
attr_set) in the sidebar
- Attributes card on run details renders key-value rows with reserved
$-prefixed keys badged and sorted after user keys
- attr_set added to MARKER_EVENT_TYPES, BOUNDARY_LABELS, event colors
(teal), and the flat events list run-level grouping
- Docs: screenshots on the attributes page, served from docs/public
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(web-shared): RelativeTimeCard with shared ContextCard provider
Add a ContextCard provider/trigger and rebuild the timestamp tooltip as a
RelativeTimeCard, giving animated, collision-aware morphing hover cards.
Mount the shared provider in EventListView and AttributePanel.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Match vercel/front timestamp format for run/activity fields
Render absolute Created/Started/Completed (and sibling) timestamps using
date-fns in vercel/front's request/activity format (e.g.
"JUN 10 10:16:02.69 GMT-4") via the shared formatLocalMillisecondTime helper.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shared): register dark-theme/light-theme Tailwind variants
The context-card arrow tip stroke uses `dark-theme:[--context-card-tip-stroke:#252525]`,
but Tailwind v4 has no built-in `dark-theme` variant, so the utility was silently
dropped and the stroke fell back to its light `#DBDBDB` value — rendering as a white
caret in dark mode. Register the `dark-theme`/`light-theme` custom variants in
styles.css (mirroring vercel/front's geistcn tailwind.css, extended to match the
`.dark`/`[data-theme="dark"]` selectors this package and next-themes use).
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shared): match context card shadow to vercel/front
The --ds-shadow-tooltip token was guessed when added standalone, producing
an oversized/heavy drop shadow. Reproduce front's exact resolved value for
both light and dark themes (including the background-border layer).
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shared): bridge context card hover gap to stop flicker
The card is positioned `sideOffset` away from the trigger, leaving a
transparent un-hoverable gap that caused the hover card to flicker
(open → close → open) when moving the cursor onto it. Add a transparent
hover bridge inside the floating wrapper that extends the hover surface
by `sideOffset` to meet the trigger edge, keeping the visual spacing
while making the hover surface continuous.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Revert "fix(web-shared): bridge context card hover gap to stop flicker"
This reverts commit 2b961b1610.
* docs: simplify changeset description
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs: remove vercel/front references from comments
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shared): only clear active context card when the active trigger unmounts
The unmount cleanup had an inverted guard: an unmounting inactive trigger
would clear the shared active card, hiding another trigger's card (and an
unmounting active trigger left a stale card). Guard on === id instead.
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs: remove theme-variant comment
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* Animate in-progress segments in the timeline
Add an animated diagonal "barber-pole" stripe overlay to in-progress
(running/received) segments in the new trace viewer timeline, so it's
obvious at a glance which work is still live.
The animation lives in a colocated CSS module (timeline.module.css),
imported by the component — web-shared is in consumers' transpilePackages,
so the keyframes ship with the component rather than relying on the global
styles.css (which Geist-using hosts don't import).
Also fixes a latent status bug this surfaced: the run-segment builders
collapsed every non-failed run to "running", so completed runs rendered as
"running" (and, with the new animation, kept animating). They now map to a
new terminal `completed` status (blue, static) via a fail-closed
runSegmentStatus helper — only genuinely in-progress runs animate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Create chatty-walls-appear.md
Signed-off-by: Mitul Shah <mitulxshah@gmail.com>
---------
Signed-off-by: Mitul Shah <mitulxshah@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the filled gray queued box with a tick and horizontal line into the active bar so wait time reads as "waited, then ran."
Co-authored-by: Cursor <cursoragent@cursor.com>
* [web-shared] Show precise durations in the new trace viewer
The events list and timeline bar labels now render two-decimal seconds for
durations over 1s instead of rounding to whole seconds.
Co-authored-by: Cursor <cursoragent@cursor.com>
* [web-shared] Fix duration rounding at unit boundaries
formatDurationPrecise bucketed durations on the raw ms value but only
rounded at display time, so inputs just below a unit boundary carried
into the next unit without re-bucketing (e.g. 59999ms -> "60.00s").
Round to centisecond precision FIRST, then decompose in integer
centisecond space so the seconds component stays in [0.00, 59.99] and
carries re-bucket into the next unit (59999ms -> "1m 0.00s").
Co-authored-by: Cursor <cursoragent@cursor.com>
* [web-shared] Simplify precise duration formatting
Reuse the existing MS_IN_* constants instead of the centisecond decomposition; behavior is unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* Move run attributes into their own detail card
Render the run's `attributes` field as a dedicated collapsible
DetailCard in the detail panel instead of as a cramped JSON value
inside the top metadata key/value list.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Create empty-worlds-throw.md
Signed-off-by: Mitul Shah <mitulxshah@gmail.com>
* Render attributes card after Input/Output
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Signed-off-by: Mitul Shah <mitulxshah@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>