diff --git a/packages/browseros-agent/apps/claw-app/modules/api/replay.hooks.ts b/packages/browseros-agent/apps/claw-app/modules/api/replay.hooks.ts index abd9d68cc1..6002b66c10 100644 --- a/packages/browseros-agent/apps/claw-app/modules/api/replay.hooks.ts +++ b/packages/browseros-agent/apps/claw-app/modules/api/replay.hooks.ts @@ -25,8 +25,16 @@ export type ReplayVerb = export type ReplayKind = 'action' | 'block' | 'done' export interface ReplayFrame { - /** Seconds into the session. */ + /** Seconds into the session, at which this dispatch completed. */ t: number + /** + * How long the tool ran, from the source dispatch row. `session-replay.ts` + * subtracts it from `t` to approximate when the action began, which is when + * the replay starts treating it as current. Absent on rows recorded before + * durations were persisted; negative and non-finite values fall back to the + * completion time. + */ + durationMs?: number | null kind: ReplayKind verb: ReplayVerb /** Short node label, e.g. the page title or a focused element. */ diff --git a/packages/browseros-agent/apps/claw-app/screens/replay/EventTimeline.tsx b/packages/browseros-agent/apps/claw-app/screens/replay/EventTimeline.tsx index 5239cf85d6..901ee7555f 100644 --- a/packages/browseros-agent/apps/claw-app/screens/replay/EventTimeline.tsx +++ b/packages/browseros-agent/apps/claw-app/screens/replay/EventTimeline.tsx @@ -1,24 +1,26 @@ import { Layers } from 'lucide-react' import { cn } from '@/lib/utils' -import type { ReplayFrame } from '@/modules/api/replay.hooks' import { formatTime, KIND_STYLE, VERB_META } from './replay.helpers' +import type { ReplayAction } from './session-replay' interface EventTimelineProps { - frames: readonly ReplayFrame[] - currentFrameIndex: number - onSelectFrame: (frame: ReplayFrame) => void + /** Every tool in the session, globally ordered — not filtered by tab. */ + actions: readonly ReplayAction[] + /** Index of the globally current action; -1 before the first one starts. */ + currentIndex: number + onSelectAction: (action: ReplayAction) => void } /** - * Right-rail vertical event list. Each row corresponds to one frame - * in the recording. Past frames are full-opacity, future frames dim, - * and the row matching the playhead gets an accent-tint background. - * Clicking a row seeks the player to that frame. + * Right-rail vertical list of the session's tools in chronological order. + * Rows are stamped with the action's activity start, which is both where the + * row becomes current and where clicking it seeks. Past rows are full-opacity, + * future rows dim, and the current row gets an accent-tint background. */ export function EventTimeline({ - frames, - currentFrameIndex, - onSelectFrame, + actions, + currentIndex, + onSelectAction, }: EventTimelineProps) { return (