@dxos/react-ui-trace 0.11.1 → 0.14.0

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 (115) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/index.mjs +1722 -561
  3. package/dist/lib/index.mjs.map +1 -1
  4. package/dist/lib/testing.mjs +9 -8
  5. package/dist/lib/testing.mjs.map +1 -1
  6. package/dist/lib/translations.mjs +5 -0
  7. package/dist/lib/translations.mjs.map +1 -1
  8. package/dist/types/src/components/Gantt/Gantt.d.ts +109 -24
  9. package/dist/types/src/components/Gantt/Gantt.d.ts.map +1 -1
  10. package/dist/types/src/components/Gantt/Gantt.stories.d.ts +73 -3
  11. package/dist/types/src/components/Gantt/Gantt.stories.d.ts.map +1 -1
  12. package/dist/types/src/components/Gantt/gantt-rows.d.ts +26 -0
  13. package/dist/types/src/components/Gantt/gantt-rows.d.ts.map +1 -0
  14. package/dist/types/src/components/Gantt/gantt-rows.test.d.ts +2 -0
  15. package/dist/types/src/components/Gantt/gantt-rows.test.d.ts.map +1 -0
  16. package/dist/types/src/components/Gantt/gantt-scale.d.ts +57 -0
  17. package/dist/types/src/components/Gantt/gantt-scale.d.ts.map +1 -0
  18. package/dist/types/src/components/Gantt/gantt-scale.test.d.ts +2 -0
  19. package/dist/types/src/components/Gantt/gantt-scale.test.d.ts.map +1 -0
  20. package/dist/types/src/components/Gantt/index.d.ts +2 -0
  21. package/dist/types/src/components/Gantt/index.d.ts.map +1 -1
  22. package/dist/types/src/components/Gantt/useEnter.d.ts +13 -0
  23. package/dist/types/src/components/Gantt/useEnter.d.ts.map +1 -0
  24. package/dist/types/src/components/Gantt/useRangeTween.d.ts +12 -0
  25. package/dist/types/src/components/Gantt/useRangeTween.d.ts.map +1 -0
  26. package/dist/types/src/components/ProcessTree/ProcessTree.d.ts +3 -3
  27. package/dist/types/src/components/ProcessTree/ProcessTree.d.ts.map +1 -1
  28. package/dist/types/src/components/ProcessTree/ProcessTree.stories.d.ts.map +1 -1
  29. package/dist/types/src/components/Timeline/Timeline.d.ts +10 -2
  30. package/dist/types/src/components/Timeline/Timeline.d.ts.map +1 -1
  31. package/dist/types/src/components/Timeline/Timeline.stories.d.ts +8 -4
  32. package/dist/types/src/components/Timeline/Timeline.stories.d.ts.map +1 -1
  33. package/dist/types/src/components/Timeline/timeline-layout.d.ts +35 -0
  34. package/dist/types/src/components/Timeline/timeline-layout.d.ts.map +1 -0
  35. package/dist/types/src/components/Timeline/timeline-layout.test.d.ts +2 -0
  36. package/dist/types/src/components/Timeline/timeline-layout.test.d.ts.map +1 -0
  37. package/dist/types/src/components/TracePanel/SpanTreeView.d.ts +15 -0
  38. package/dist/types/src/components/TracePanel/SpanTreeView.d.ts.map +1 -0
  39. package/dist/types/src/components/TracePanel/TracePanel.d.ts +3 -3
  40. package/dist/types/src/components/TracePanel/TracePanel.d.ts.map +1 -1
  41. package/dist/types/src/components/TracePanel/TracePanel.stories.d.ts +46 -0
  42. package/dist/types/src/components/TracePanel/TracePanel.stories.d.ts.map +1 -0
  43. package/dist/types/src/components/TracePanel/trace-filter.d.ts +7 -2
  44. package/dist/types/src/components/TracePanel/trace-filter.d.ts.map +1 -1
  45. package/dist/types/src/components/TracePanel/useTraceMenu.d.ts.map +1 -1
  46. package/dist/types/src/execution-graph/execution-graph.d.ts +1 -1
  47. package/dist/types/src/execution-graph/execution-graph.d.ts.map +1 -1
  48. package/dist/types/src/hooks/useExecutionGraph.d.ts +2 -2
  49. package/dist/types/src/hooks/useExecutionGraph.d.ts.map +1 -1
  50. package/dist/types/src/hooks/useSessionTimeline.d.ts +1 -1
  51. package/dist/types/src/hooks/useSessionTimeline.d.ts.map +1 -1
  52. package/dist/types/src/hooks/useTraceMessages.d.ts +1 -1
  53. package/dist/types/src/hooks/useTraceMessages.d.ts.map +1 -1
  54. package/dist/types/src/session-timeline/TaskHistory.stories.d.ts +12 -0
  55. package/dist/types/src/session-timeline/TaskHistory.stories.d.ts.map +1 -0
  56. package/dist/types/src/session-timeline/gantt-mapping.d.ts +14 -0
  57. package/dist/types/src/session-timeline/gantt-mapping.d.ts.map +1 -0
  58. package/dist/types/src/session-timeline/gantt-mapping.test.d.ts +2 -0
  59. package/dist/types/src/session-timeline/gantt-mapping.test.d.ts.map +1 -0
  60. package/dist/types/src/session-timeline/index.d.ts +1 -0
  61. package/dist/types/src/session-timeline/index.d.ts.map +1 -1
  62. package/dist/types/src/session-timeline/session-timeline.d.ts +17 -2
  63. package/dist/types/src/session-timeline/session-timeline.d.ts.map +1 -1
  64. package/dist/types/src/session-timeline/types.d.ts +32 -0
  65. package/dist/types/src/session-timeline/types.d.ts.map +1 -1
  66. package/dist/types/src/testing/simulated-agent.d.ts +5 -4
  67. package/dist/types/src/testing/simulated-agent.d.ts.map +1 -1
  68. package/dist/types/src/testing/test-trace.d.ts +2 -2
  69. package/dist/types/src/testing/test-trace.d.ts.map +1 -1
  70. package/dist/types/src/translations.d.ts +5 -0
  71. package/dist/types/src/translations.d.ts.map +1 -1
  72. package/dist/types/tsconfig.tsbuildinfo +1 -1
  73. package/package.json +30 -26
  74. package/src/components/Gantt/Gantt.stories.tsx +914 -96
  75. package/src/components/Gantt/Gantt.tsx +964 -261
  76. package/src/components/Gantt/gantt-rows.test.ts +123 -0
  77. package/src/components/Gantt/gantt-rows.ts +71 -0
  78. package/src/components/Gantt/gantt-scale.test.ts +105 -0
  79. package/src/components/Gantt/gantt-scale.ts +143 -0
  80. package/src/components/Gantt/index.ts +2 -0
  81. package/src/components/Gantt/useEnter.ts +33 -0
  82. package/src/components/Gantt/useRangeTween.ts +61 -0
  83. package/src/components/ProcessTree/ProcessTree.stories.tsx +2 -3
  84. package/src/components/ProcessTree/ProcessTree.tsx +99 -90
  85. package/src/components/Timeline/Timeline.stories.tsx +110 -22
  86. package/src/components/Timeline/Timeline.tsx +319 -271
  87. package/src/components/Timeline/timeline-layout.test.ts +177 -0
  88. package/src/components/Timeline/timeline-layout.ts +153 -0
  89. package/src/components/TracePanel/SpanTreeView.tsx +39 -0
  90. package/src/components/TracePanel/TracePanel.stories.tsx +106 -0
  91. package/src/components/TracePanel/TracePanel.tsx +113 -106
  92. package/src/components/TracePanel/trace-filter.test.ts +31 -2
  93. package/src/components/TracePanel/trace-filter.ts +28 -3
  94. package/src/components/TracePanel/useTraceMenu.ts +0 -1
  95. package/src/execution-graph/SPEC.md +10 -10
  96. package/src/execution-graph/execution-graph.test.ts +16 -15
  97. package/src/execution-graph/execution-graph.ts +108 -60
  98. package/src/execution-graph/pending-block-status.ts +1 -1
  99. package/src/execution-graph/sub-agent-delegation.test.ts +1 -1
  100. package/src/hooks/useExecutionGraph.ts +14 -11
  101. package/src/hooks/useSessionTimeline.ts +35 -9
  102. package/src/hooks/useTraceMessages.ts +1 -1
  103. package/src/session-timeline/TaskHistory.stories.tsx +142 -0
  104. package/src/session-timeline/gantt-mapping.test.ts +118 -0
  105. package/src/session-timeline/gantt-mapping.ts +158 -0
  106. package/src/session-timeline/index.ts +1 -0
  107. package/src/session-timeline/session-timeline.test.ts +585 -35
  108. package/src/session-timeline/session-timeline.ts +433 -62
  109. package/src/session-timeline/types.ts +14 -0
  110. package/src/testing/simulated-agent.ts +17 -16
  111. package/src/testing/test-trace.ts +14 -12
  112. package/src/translations.ts +8 -2
  113. package/dist/types/src/execution-graph/remote-snapshot.test.d.ts +0 -2
  114. package/dist/types/src/execution-graph/remote-snapshot.test.d.ts.map +0 -1
  115. package/src/execution-graph/remote-snapshot.test.ts +0 -116
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/components/Gantt/Gantt.tsx","../../src/components/ProcessTree/ProcessTree.tsx","../../src/components/Timeline/timeline-options.ts","../../src/components/Timeline/Timeline.tsx","../../src/components/Timeline/timeline-printer.ts","../../src/components/TracePanel/trace-filter.ts","../../src/components/TracePanel/useTraceMenu.ts","../../src/components/TracePanel/TracePanel.tsx","../../src/execution-graph/span-tree.ts","../../src/execution-graph/execution-graph.ts","../../src/execution-graph/pending-block-status.ts","../../src/hooks/useTraceMessages.ts","../../src/hooks/useExecutionGraph.ts","../../src/session-timeline/session-timeline.ts","../../src/session-timeline/types.ts","../../src/hooks/useSessionTimeline.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { format } from 'date-fns';\nimport React, { type KeyboardEvent, type ReactNode, forwardRef, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { createContext, useComposedRefs } from '@dxos/react-hooks';\nimport { HoverCard, type ThemedClassName, composable, composableProps } from '@dxos/react-ui';\nimport { mx } from '@dxos/ui-theme';\nimport { Unit } from '@dxos/util';\n\nexport type GanttLaneKind = 'session' | 'task';\nexport type GanttLaneStatus = 'pending' | 'blocked' | 'running' | 'review' | 'done' | 'failed';\nexport type GanttMarkerKind = 'request' | 'operation' | 'tool' | 'message' | 'error' | 'delegation' | 'task';\n\nexport type GanttLane = {\n id: string;\n kind: GanttLaneKind;\n label: string;\n status: GanttLaneStatus;\n start?: number;\n end?: number;\n parentId?: string;\n taskId?: string;\n blockedOn?: readonly string[];\n delegatedFrom?: { laneId: string; markerId: string };\n tokens?: { input: number; output: number; total: number };\n toolCalls?: number;\n};\n\nexport type GanttMarker = {\n id: string;\n laneId: string;\n kind: GanttMarkerKind;\n timestamp: number;\n label: string;\n level?: 'info' | 'warn' | 'error';\n};\n\nconst ROW_HEIGHT = 28;\nconst HEADER_HEIGHT = 20;\nconst PAD_X = 12;\nconst NODE_RADIUS = 5;\n/** Upper bound on axis ticks; the count shrinks with the width so `HH:mm:ss` labels never overlap. */\nconst MAX_TICKS = 5;\nconst TICK_MIN_WIDTH = 72;\n\nconst BAR_HEIGHT = 15;\n/**\n * A bar reaches half its height past its first and last instant, so a node sitting on either one is\n * as far from the bar's end as it is from its top and bottom.\n */\nconst BAR_OVERHANG = BAR_HEIGHT / 2;\n/** Gap between adjacent session rectangles, halved on each. */\nconst GROUP_INSET = 2;\n/** The rectangle's clearance around its bars, the same on every side, so its corners stay concentric with theirs. */\nconst GROUP_PAD = ROW_HEIGHT / 2 - BAR_HEIGHT / 2 - GROUP_INSET;\nconst GROUP_RADIUS = BAR_HEIGHT / 2 + GROUP_PAD;\n/** Radius of the delegation connector's bend from the drop into the child bar. */\nconst BEND_RADIUS = BAR_HEIGHT / 2;\n\n/**\n * Bar, node, thread and label colours per status: nodes and the thread through them are the bar's\n * hue in a lighter shade.\n */\nconst STATUS_COLOR: Record<GanttLaneStatus, { fill: string; node: string; thread: string; text: string }> = {\n pending: {\n fill: 'fill-neutral-500/40',\n node: 'fill-neutral-300',\n thread: 'stroke-neutral-300',\n text: 'text-neutral-400',\n },\n blocked: {\n fill: 'fill-orange-500/40',\n node: 'fill-orange-300',\n thread: 'stroke-orange-300',\n text: 'text-orange-500',\n },\n running: {\n fill: 'fill-sky-500/40',\n node: 'fill-sky-300',\n thread: 'stroke-sky-300',\n text: 'text-sky-500',\n },\n review: {\n fill: 'fill-cyan-500/40',\n node: 'fill-cyan-300',\n thread: 'stroke-cyan-300',\n text: 'text-cyan-500',\n },\n done: {\n fill: 'fill-green-500/40',\n node: 'fill-green-300',\n thread: 'stroke-green-300',\n text: 'text-green-500',\n },\n failed: {\n fill: 'fill-red-500/40',\n node: 'fill-red-300',\n thread: 'stroke-red-300',\n text: 'text-red-500',\n },\n};\n\ntype Row = {\n lane: GanttLane;\n depth: number;\n index: number;\n sessionId: string | undefined;\n};\n\n/** A session's rows: the session itself followed by every task it works in-session, contiguous. */\ntype SessionGroup = {\n session: GanttLane;\n first: number;\n last: number;\n};\n\n/**\n * Rows grouped by the session that processes them: a session, then the tasks (and subtasks) it\n * works itself, then — after that block — every session those tasks spawned, recursively. Keeping a\n * session's own rows contiguous is what lets one rectangle enclose them.\n */\nconst orderRows = (lanes: readonly GanttLane[]): { rows: Row[]; groups: SessionGroup[] } => {\n const rows: Row[] = [];\n const groups: SessionGroup[] = [];\n const childrenOf = (parentId: string | undefined): GanttLane[] => lanes.filter((lane) => lane.parentId === parentId);\n\n const visitSession = (session: GanttLane, depth: number): void => {\n const first = rows.length;\n rows.push({ lane: session, depth, index: rows.length, sessionId: session.id });\n const spawned: { lane: GanttLane; depth: number }[] = [];\n const visitTasks = (parentId: string, taskDepth: number): void => {\n for (const child of childrenOf(parentId)) {\n if (child.kind === 'task') {\n rows.push({ lane: child, depth: taskDepth, index: rows.length, sessionId: session.id });\n visitTasks(child.id, taskDepth + 1);\n } else {\n spawned.push({ lane: child, depth: taskDepth });\n }\n }\n };\n visitTasks(session.id, depth + 1);\n groups.push({ session, first, last: rows.length - 1 });\n for (const child of spawned) {\n visitSession(child.lane, child.depth);\n }\n };\n\n for (const lane of childrenOf(undefined)) {\n if (lane.kind === 'session') {\n visitSession(lane, 0);\n } else {\n rows.push({ lane, depth: 0, index: rows.length, sessionId: undefined });\n }\n }\n return { rows, groups };\n};\n\nconst formatTokens = (tokens: NonNullable<GanttLane['tokens']>): string =>\n tokens.total >= 1_000 ? Unit.Thousand(tokens.total).toString() : String(tokens.total);\n\nexport type GanttData = {\n lanes: readonly GanttLane[];\n markers?: readonly GanttMarker[];\n range?: { start: number; end: number };\n now?: number;\n showNow?: boolean;\n onLaneSelect?: (lane: GanttLane) => void;\n onMarkerSelect?: (marker: GanttMarker) => void;\n};\n\n/** What every part reads: the ordered rows and the shared time axis, resolved once by the root. */\ntype GanttContextValue = {\n rows: Row[];\n groups: SessionGroup[];\n rowById: Map<string, Row>;\n markers: readonly GanttMarker[];\n markerById: Map<string, GanttMarker>;\n range: { start: number; end: number };\n} & Pick<GanttData, 'onLaneSelect' | 'onMarkerSelect' | 'now' | 'showNow'>;\n\nconst [GanttProvider, useGanttContext] = createContext<GanttContextValue>('Gantt');\n\n//\n// Root\n//\n\ntype GanttRootProps = ThemedClassName<GanttData & { children?: ReactNode }>;\n\n/**\n * Gantt view of sessions and tasks on a shared time axis. The root resolves the rows and the axis;\n * the parts lay out side by side in the order given, sharing one row grid: `Legend` names the\n * lanes, `Chart` draws them, `Meta` shows per-lane totals. A host that already lists the lanes\n * renders the chart alone.\n */\nconst GanttRoot = composable<HTMLDivElement, GanttRootProps>(\n (\n { lanes, markers = [], range: rangeProp, now, showNow, onLaneSelect, onMarkerSelect, children, ...props },\n forwardedRef,\n ) => {\n const { rows, groups } = useMemo(() => orderRows(lanes), [lanes]);\n const rowById = useMemo(() => new Map(rows.map((row) => [row.lane.id, row])), [rows]);\n const markerById = useMemo(() => new Map(markers.map((marker) => [marker.id, marker])), [markers]);\n const range = useMemo(() => {\n if (rangeProp) {\n return rangeProp;\n }\n const times = [...lanes.flatMap((lane) => [lane.start, lane.end]), ...markers.map((marker) => marker.timestamp)]\n .filter((time): time is number => time !== undefined)\n .concat(now === undefined ? [] : [now]);\n const start = times.length > 0 ? Math.min(...times) : 0;\n return { start, end: times.length > 0 ? Math.max(...times) : start };\n }, [rangeProp, lanes, markers, now]);\n\n return (\n <GanttProvider\n rows={rows}\n groups={groups}\n rowById={rowById}\n markers={markers}\n markerById={markerById}\n range={range}\n now={now}\n showNow={showNow}\n onLaneSelect={onLaneSelect}\n onMarkerSelect={onMarkerSelect}\n >\n <div\n {...composableProps(props, {\n // `items-start`: the parts are drawn in pixel rows, so a stretching host must not spread them.\n classNames: 'flex w-full items-start text-xs font-mono overflow-hidden',\n })}\n ref={forwardedRef}\n >\n {children}\n </div>\n </GanttProvider>\n );\n },\n);\n\nGanttRoot.displayName = 'Gantt.Root';\n\n//\n// Legend\n//\n\ntype GanttLegendProps = ThemedClassName<{}>;\n\n/** The lane names, one per row, indented by depth; each row is the lane's keyboard path. */\nconst GanttLegend = composable<HTMLDivElement, GanttLegendProps>((props, forwardedRef) => {\n const { rows, onLaneSelect } = useGanttContext('Gantt.Legend');\n return (\n <div\n {...composableProps(props, { classNames: 'shrink-0 w-[min(20rem,40%)] min-w-40 flex flex-col' })}\n ref={forwardedRef}\n >\n <div style={{ height: HEADER_HEIGHT }} />\n {rows.map(({ lane, depth }) => (\n <div\n key={lane.id}\n className={mx(\n 'flex items-center gap-2 truncate',\n onLaneSelect && 'cursor-pointer hover:bg-hover-surface-subtle',\n )}\n style={{ height: ROW_HEIGHT, paddingInlineStart: `${0.5 + depth}rem` }}\n // Button semantics only when there is something to select: the label row is the lane's\n // keyboard path, and an inert focus stop would be noise.\n {...(onLaneSelect && {\n role: 'button',\n tabIndex: 0,\n onClick: () => onLaneSelect(lane),\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n onLaneSelect(lane);\n }\n },\n })}\n >\n <span className={mx('shrink-0 w-2 h-2 rounded-full bg-current', STATUS_COLOR[lane.status].text)} />\n <span className='truncate text-base-fg'>{lane.label}</span>\n </div>\n ))}\n </div>\n );\n});\n\nGanttLegend.displayName = 'Gantt.Legend';\n\n//\n// Meta\n//\n\ntype GanttMetaProps = ThemedClassName<{}>;\n\n/** Per-lane totals — tokens and tool calls — aligned to the rows. */\nconst GanttMeta = composable<HTMLDivElement, GanttMetaProps>((props, forwardedRef) => {\n const { rows } = useGanttContext('Gantt.Meta');\n return (\n <div {...composableProps(props, { classNames: 'shrink-0 flex flex-col' })} ref={forwardedRef}>\n <div style={{ height: HEADER_HEIGHT }} />\n {rows.map(({ lane }) => (\n <div\n key={lane.id}\n className='flex items-center justify-end gap-2 px-2 text-subdued whitespace-nowrap'\n style={{ height: ROW_HEIGHT }}\n >\n {lane.tokens && (\n <span title={`${lane.tokens.input} in / ${lane.tokens.output} out`}>{formatTokens(lane.tokens)}</span>\n )}\n {lane.toolCalls !== undefined && <span>{lane.toolCalls} tools</span>}\n </div>\n ))}\n </div>\n );\n});\n\nGanttMeta.displayName = 'Gantt.Meta';\n\n//\n// Chart\n//\n\ntype GanttChartProps = ThemedClassName<{}>;\n\n/**\n * The drawing: every lane is a rounded bar with its markers threaded through it as nodes, a session's\n * rectangle encloses the tasks it works, and connectors draw dependencies and delegations.\n */\n// `forwardRef` rather than `composable`: the drawing is an `svg`, which the HTML-element helpers do not type.\nconst GanttChart = forwardRef<SVGSVGElement, GanttChartProps>(({ classNames }, forwardedRef) => {\n const { rows, groups, rowById, markers, markerById, range, now, showNow, onLaneSelect, onMarkerSelect } =\n useGanttContext('Gantt.Chart');\n const svgRef = useRef<SVGSVGElement | null>(null);\n const ref = useComposedRefs(svgRef, forwardedRef);\n const [width, setWidth] = useState(600);\n useEffect(() => {\n const element = svgRef.current;\n if (!element) {\n return;\n }\n const observer = new ResizeObserver(([entry]) => entry && setWidth(entry.contentRect.width));\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n\n const span = Math.max(range.end - range.start, 1);\n const x = (time: number): number => PAD_X + ((time - range.start) / span) * (width - 2 * PAD_X);\n const rowY = (index: number): number => HEADER_HEIGHT + index * ROW_HEIGHT + ROW_HEIGHT / 2;\n const laneTimes = (lane: GanttLane): number[] =>\n markers.filter((marker) => marker.laneId === lane.id).map((marker) => marker.timestamp);\n // A bar reaches its last node, not `now`: a lane without a fresh event is not shown as still\n // busy, and a terminated one ends where its last event did.\n const laneEnd = (lane: GanttLane): number | undefined => {\n const times = laneTimes(lane);\n return times.length > 0 ? Math.max(...times) : (lane.end ?? now);\n };\n const delegationSource = (lane: GanttLane): GanttMarker | undefined =>\n lane.delegatedFrom && markerById.get(lane.delegatedFrom.markerId);\n // A delegated lane's bar begins where the connector's bend lands, never under the drop from the\n // parent node: the drop is at the spawn instant and the child starts at or after it.\n const barStart = (lane: GanttLane, start: number): number => {\n const source = delegationSource(lane);\n const edge = x(start) - BAR_OVERHANG;\n // Past the bend the connector runs level for one more radius before the bar begins.\n return source ? Math.max(edge, x(source.timestamp) + 2 * BEND_RADIUS) : edge;\n };\n // A node never sits outside its bar: a delegated lane's first event is the spawn instant itself,\n // which is where the connector drops, so that node is nudged in past the bar's edge.\n const nodeX = (lane: GanttLane, time: number): number =>\n lane.start === undefined ? x(time) : Math.max(x(time), barStart(lane, lane.start) + BAR_OVERHANG);\n const height = HEADER_HEIGHT + rows.length * ROW_HEIGHT;\n const tickCount = Math.max(2, Math.min(MAX_TICKS, Math.floor((width - 2 * PAD_X) / TICK_MIN_WIDTH)));\n const ticks = Array.from({ length: tickCount }, (_, index) => range.start + (span * index) / (tickCount - 1));\n\n return (\n <svg\n className={mx('flex-1 min-w-0', classNames)}\n ref={ref}\n // Pixel coordinates against the measured width, with no viewBox: a viewBox would letterbox\n // the drawing to the column's aspect ratio and shrink every node with it.\n style={{ height }}\n >\n {ticks.map((tick, index) => (\n <g key={index}>\n <line x1={x(tick)} x2={x(tick)} y1={HEADER_HEIGHT} y2={height} className='stroke-separator' />\n <text\n x={x(tick)}\n y={HEADER_HEIGHT - 6}\n textAnchor={index === 0 ? 'start' : index === tickCount - 1 ? 'end' : 'middle'}\n className='fill-current text-subdued'\n >\n {format(tick, 'HH:mm:ss')}\n </text>\n </g>\n ))}\n\n {/* Under the lanes and connectors: a dependency on a still-running lane anchors at `now`\n and would otherwise be hidden by this line. */}\n {now !== undefined && showNow && (\n <line\n x1={x(now)}\n x2={x(now)}\n y1={0}\n y2={height}\n strokeDasharray='3 3'\n className={STATUS_COLOR.running.thread}\n />\n )}\n\n {/* A session's rectangle encloses its own bar and the tasks it works in-session; a task it\n spawned is a session of its own, drawn as a rectangle further down. */}\n {groups.flatMap(({ session, first, last }) => {\n const members = rows.slice(first, last + 1).map((row) => row.lane);\n const starts = members.flatMap((lane) => (lane.start === undefined ? [] : [barStart(lane, lane.start)]));\n // Only lanes with a bar bound the rectangle: a task not yet started has no extent.\n const ends = members.flatMap((lane) => {\n const end = lane.start === undefined ? undefined : laneEnd(lane);\n return end === undefined ? [] : [x(end) + BAR_OVERHANG];\n });\n if (starts.length === 0 || ends.length === 0) {\n return [];\n }\n const left = Math.min(...starts) - GROUP_PAD;\n const right = Math.max(...ends) + GROUP_PAD;\n return [\n <rect\n key={`group:${session.id}`}\n x={left}\n y={rowY(first) - ROW_HEIGHT / 2 + GROUP_INSET}\n width={Math.max(right - left, ROW_HEIGHT)}\n height={(last - first + 1) * ROW_HEIGHT - 2 * GROUP_INSET}\n rx={GROUP_RADIUS}\n className='fill-input-surface'\n />,\n ];\n })}\n\n {/* Connectors next, so the drop to a child passes beneath any bar it crosses. */}\n {rows.flatMap(({ lane, index }) =>\n (lane.blockedOn ?? []).flatMap((depId) => {\n const dep = rowById.get(depId);\n // Anchored on the dependency's last node, so the line meets a node rather than a bar edge.\n const anchor = dep && (laneEnd(dep.lane) ?? dep.lane.start);\n if (!dep || anchor === undefined) {\n return [];\n }\n const anchorX = nodeX(dep.lane, anchor);\n return [\n <line\n key={`${lane.id}:${depId}`}\n x1={anchorX}\n x2={anchorX}\n y1={rowY(dep.index)}\n y2={rowY(index)}\n strokeDasharray='2 2'\n className={STATUS_COLOR.blocked.thread}\n />,\n // A waiter with no bar has nothing on its row for the line to reach, so it ends on a\n // hollow node: the point the waiter is held at until the dependency resolves.\n ...(lane.start === undefined\n ? [\n <circle\n key={`${lane.id}:${depId}:hold`}\n cx={anchorX}\n cy={rowY(index)}\n r={NODE_RADIUS}\n strokeDasharray='2 2'\n className={mx('fill-base-surface', STATUS_COLOR.blocked.thread)}\n />,\n ]\n : []),\n ];\n }),\n )}\n\n {/* Down from the parent node, a quarter bend, then right to the centre of the child's first node. */}\n {rows.flatMap(({ lane, index }) => {\n const source = delegationSource(lane);\n const sourceRow = lane.delegatedFrom && rowById.get(lane.delegatedFrom.laneId);\n if (!source || !sourceRow || lane.start === undefined) {\n return [];\n }\n const sourceX = x(source.timestamp);\n const y = rowY(index);\n const firstNode = Math.min(...laneTimes(lane));\n const targetX = Number.isFinite(firstNode) ? nodeX(lane, firstNode) : barStart(lane, lane.start) + BAR_OVERHANG;\n return [\n <path\n key={`delegation:${lane.id}`}\n d={`M ${sourceX} ${rowY(sourceRow.index)} V ${y - BEND_RADIUS} Q ${sourceX} ${y} ${sourceX + BEND_RADIUS} ${y} H ${targetX}`}\n fill='none'\n className='stroke-fuchsia-500'\n />,\n ];\n })}\n\n {rows.map(({ lane, index }) => {\n const end = laneEnd(lane);\n if (lane.start === undefined || end === undefined) {\n return null;\n }\n const bar = {\n x: barStart(lane, lane.start),\n y: rowY(index) - BAR_HEIGHT / 2,\n width: Math.max(x(end) + BAR_OVERHANG - barStart(lane, lane.start), BAR_HEIGHT),\n height: BAR_HEIGHT,\n rx: BAR_HEIGHT / 2,\n };\n // An opaque backing under the translucent tint: the connectors pass beneath the bars, and\n // without it they would show through.\n return (\n <g key={lane.id} className='cursor-pointer' onClick={() => onLaneSelect?.(lane)}>\n <rect {...bar} className='fill-base-surface' />\n <rect {...bar} className={STATUS_COLOR[lane.status].fill} />\n </g>\n );\n })}\n\n {/* The thread through a lane's nodes, so a row reads as a sequence rather than scattered dots. */}\n {rows.map(({ lane, index }) => {\n const times = laneTimes(lane);\n if (times.length < 2) {\n return null;\n }\n return (\n <line\n key={`thread:${lane.id}`}\n x1={nodeX(lane, Math.min(...times))}\n x2={nodeX(lane, Math.max(...times))}\n y1={rowY(index)}\n y2={rowY(index)}\n className={STATUS_COLOR[lane.status].thread}\n />\n );\n })}\n\n {/* Nodes last, over the bars and every line, so a line reads as ending at a node's centre. */}\n {markers.map((marker) => {\n const row = rowById.get(marker.laneId);\n return row ? (\n <HoverCard.Root key={marker.id}>\n <HoverCard.Trigger asChild>\n <circle\n cx={nodeX(row.lane, marker.timestamp)}\n cy={rowY(row.index)}\n r={NODE_RADIUS}\n className={mx(\n 'cursor-pointer stroke-base-surface transition-[stroke-width] hover:stroke-[3px] hover:stroke-base-fg',\n STATUS_COLOR[row.lane.status].node,\n )}\n onClick={() => onMarkerSelect?.(marker)}\n />\n </HoverCard.Trigger>\n <HoverCard.Portal>\n <HoverCard.Content classNames='p-2 max-w-72 text-xs font-mono'>\n <div className='font-medium truncate'>{marker.label}</div>\n <div className='text-description'>\n {marker.kind} · {format(marker.timestamp, 'HH:mm:ss.SSS')}\n {marker.level && marker.level !== 'info' && (\n <span className={mx('ms-2', marker.level === 'error' ? 'text-error-text' : 'text-warning-text')}>\n {marker.level}\n </span>\n )}\n </div>\n <div className='text-description truncate'>{row.lane.label}</div>\n <HoverCard.Arrow />\n </HoverCard.Content>\n </HoverCard.Portal>\n </HoverCard.Root>\n ) : null;\n })}\n </svg>\n );\n});\n\nGanttChart.displayName = 'Gantt.Chart';\n\nexport const Gantt = {\n Root: GanttRoot,\n Legend: GanttLegend,\n Chart: GanttChart,\n Meta: GanttMeta,\n};\n\nexport type { GanttChartProps, GanttLegendProps, GanttMetaProps, GanttRootProps };\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { RegistryContext } from '@effect/atom-react/RegistryContext';\nimport * as Match from 'effect/Match';\nimport * as Option from 'effect/Option';\nimport React, { useCallback, useContext, useMemo, useRef } from 'react';\n\nimport * as Process from '@dxos/compute/Process';\nimport { Icon, IconButton, ScrollArea, Tooltip, composable, composableProps } from '@dxos/react-ui';\nimport { type ColumnRenderer, type IconRenderer, Tree, createStaticTreeModel } from '@dxos/react-ui-list';\nimport { mx } from '@dxos/ui-theme';\nimport { Unit } from '@dxos/util';\n\nconst DEFAULT_DEPTH = 1;\n/** Nested subprocess rows (level > 1) only surface still-active processes. */\nconst NESTED_ACTIVE_STATES = new Set<Process.State>([\n Process.State.RUNNING,\n Process.State.HYBERNATING,\n Process.State.TERMINATING,\n]);\n\nexport type ProcessTreeProps = {\n // TODO(burdon): Atom.\n processes: readonly Process.Info[];\n /**\n * Maximum nesting depth from the root (1 = top-level processes only).\n *\n * @default 1\n */\n depth?: number;\n /**\n * Overrides the row label for a process (e.g. the name of the chat it is serving), falling back to\n * the process name when it returns `undefined`.\n *\n * Must be referentially stable — `ProcessTree` is memoized on its props.\n */\n resolveLabel?: (process: Process.Info) => string | undefined;\n /** Pids drawn as selected; the tree is controlled, so a click reports through `onSelectedChange`. */\n selected?: readonly string[];\n /** The selection after a click: the clicked pid alone, or toggled among the others on a meta-click. */\n onSelectedChange?: (selected: string[]) => void;\n onProcessTerminate?: (process: Process.Info) => void;\n};\n\n/** Node of the pruned process forest handed to the tree model. */\ntype ProcessNode = {\n id: string;\n /** Absent on the synthetic root, which anchors the top-level processes and is never rendered. */\n process?: Process.Info;\n children: ProcessNode[];\n};\n\n/** Synthetic root; the tree renders its children, never the root itself. */\nconst ROOT_ID = 'processes';\n\nconst NO_SELECTION: readonly string[] = [];\n\n/**\n * The agent's running processes as a tree, one row per process with its status glyph and metrics\n * in trailing columns. The forest is rebuilt on every metrics tick, so open state lives outside the\n * model and is re-seeded — a collapse must survive the next tick. Renders through `Tree`.\n */\nexport const ProcessTree = React.memo(\n composable<HTMLDivElement, ProcessTreeProps>(\n (\n {\n processes,\n depth = DEFAULT_DEPTH,\n resolveLabel,\n selected = NO_SELECTION,\n onSelectedChange,\n onProcessTerminate,\n ...props\n },\n forwardedRef,\n ) => {\n // Open state lives outside the model: `processes` carries live metrics, so the forest (and with\n // it the model) is rebuilt on every tick, and a collapse held only inside the model would be\n // undone by the next one.\n const openRef = useRef(new Map<string, boolean>());\n const registry = useContext(RegistryContext);\n const root = useMemo(() => buildProcessForest(processes, depth), [processes, depth]);\n\n const model = useMemo(\n () =>\n createStaticTreeModel<ProcessNode>(root, {\n getChildren: (node) => node.children,\n getProps: (node) => ({\n label: (node.process && resolveLabel?.(node.process)) ?? node.process?.params.name ?? node.id,\n }),\n // Expanded by default, matching the flattened view this replaced.\n isOpen: (_node, path) => openRef.current.get(path.join('/')) ?? true,\n isCurrent: (node) => node.process !== undefined && selected.includes(node.process.pid),\n }),\n [root, resolveLabel, selected],\n );\n\n // The ref survives model rebuilds; the atom is what the controlled tree actually reads, so a\n // toggle has to land in both.\n const handleOpenChange = useCallback(\n ({ path, open }: { path: string[]; open: boolean }) => {\n openRef.current.set(path.join('/'), open);\n const atom = model.stateAtom(path);\n registry.set(atom, { ...registry.get(atom), open });\n },\n [model, registry],\n );\n\n const handleSelect = useCallback(\n ({ item, current, meta }: { item: ProcessNode; current: boolean; meta: boolean }) => {\n if (!item.process) {\n return;\n }\n const pid = item.process.pid.toString();\n onSelectedChange?.(\n !meta ? [pid] : current ? [...selected, pid] : selected.filter((candidate) => candidate !== pid),\n );\n },\n [selected, onSelectedChange],\n );\n\n const renderIcon = useMemo(() => makeIconRenderer(), []);\n const renderColumns = useMemo(() => makeColumnRenderer(onProcessTerminate), [onProcessTerminate]);\n\n return (\n <ScrollArea.Root {...composableProps(props)} thin ref={forwardedRef}>\n <ScrollArea.Viewport>\n <Tree<ProcessNode>\n id={ROOT_ID}\n model={model}\n density='sm'\n selectionMode='multiple'\n classNames='text-sm tabular-nums font-thin'\n gridTemplateColumns='[tree-row-start] var(--dx-control) minmax(0, 1fr) min-content min-content [tree-row-end]'\n renderIcon={renderIcon}\n renderColumns={renderColumns}\n onOpenChange={handleOpenChange}\n onSelect={handleSelect}\n />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n );\n },\n ),\n);\n\n/** Status glyph — animated, coloured and tooltipped per state, which `TreeItemDataProps.icon` cannot express. */\nconst makeIconRenderer =\n (): IconRenderer<ProcessNode> =>\n ({ item: { process } }) =>\n process === undefined ? null : (\n <Tooltip.Trigger content={process.state.toString()}>\n <Icon\n size={4}\n synchronized\n classNames={mx(\n 'shrink-0',\n process.state === Process.State.RUNNING && 'animate-spin',\n process.state === Process.State.FAILED && 'text-error-text',\n process.state === Process.State.SUCCEEDED && 'text-success-text',\n )}\n icon={Match.value(process.state).pipe(\n Match.when(Process.State.RUNNING, () => 'ph--spinner-gap--regular'),\n Match.when(Process.State.SUCCEEDED, () => 'ph--check-circle--regular'),\n Match.when(Process.State.FAILED, () => 'ph--warning--regular'),\n Match.when(Process.State.HYBERNATING, () => 'ph--spinner--regular'),\n Match.when(Process.State.IDLE, () => 'ph--moon-stars--regular'),\n Match.when(Process.State.TERMINATING, () => 'ph--x-circle--regular'),\n Match.when(Process.State.TERMINATED, () => 'ph--x-circle--regular'),\n Match.orElse(() => 'ph--spinner-gap--regular'),\n )}\n />\n </Tooltip.Trigger>\n );\n\n/** Trailing columns: elapsed time for finished processes, and the terminate control. */\nconst makeColumnRenderer =\n (onProcessTerminate?: (process: Process.Info) => void): ColumnRenderer<ProcessNode> =>\n ({ item: { process } }) =>\n process === undefined ? null : (\n <>\n <div className='flex items-center justify-end text-xs text-description tabular-nums'>\n {[Process.State.FAILED, Process.State.SUCCEEDED].includes(process.state) && (\n <span className='whitespace-nowrap'>{Unit.Duration(process.metrics.wallTime).toString()}</span>\n )}\n </div>\n <div className='flex items-center'>\n {onProcessTerminate && (\n <IconButton\n classNames='min-h-0 p-1'\n icon='ph--x--regular'\n iconOnly\n density='sm'\n variant='ghost'\n label='Actions'\n onClick={(event) => {\n event.stopPropagation();\n onProcessTerminate(process);\n }}\n />\n )}\n </div>\n </>\n );\n\nconst sortProcesses = (processes: readonly Process.Info[]): Process.Info[] => {\n return [\n ...processes.filter((process) => [Process.State.RUNNING, Process.State.HYBERNATING].includes(process.state)),\n ...processes.filter((process) => [Process.State.IDLE].includes(process.state)).slice(0, 3),\n ...processes.filter((process) =>\n [Process.State.SUCCEEDED, Process.State.FAILED, Process.State.TERMINATED].includes(process.state),\n ),\n ].sort((left, right) => {\n const leftCompletedAt = Option.getOrElse(left.completedAt, () => Infinity);\n const rightCompletedAt = Option.getOrElse(right.completedAt, () => Infinity);\n return rightCompletedAt - leftCompletedAt;\n });\n};\n\nconst sortNestedActive = (processes: readonly Process.Info[]): Process.Info[] =>\n processes\n .filter((process) => NESTED_ACTIVE_STATES.has(process.state))\n .sort((left, right) => {\n const priority = (state: Process.State) =>\n state === Process.State.RUNNING ? 0 : state === Process.State.HYBERNATING ? 1 : 2;\n return priority(left.state) - priority(right.state);\n });\n\n/**\n * Builds the process forest, pruned to `maxDepth` from each root. Nested levels surface only still-\n * active processes, so a deep tree stays readable while completed work collapses out of view.\n */\nconst buildProcessForest = (processes: readonly Process.Info[], maxDepth: number): ProcessNode => {\n const pidSet = new Set(processes.map((process) => String(process.pid)));\n const childrenByParent = new Map<string, Process.Info[]>();\n const roots: Process.Info[] = [];\n\n for (const process of processes) {\n const parent = process.parentPid;\n if (parent === null || !pidSet.has(String(parent))) {\n roots.push(process);\n continue;\n }\n const key = String(parent);\n const siblings = childrenByParent.get(key) ?? [];\n siblings.push(process);\n childrenByParent.set(key, siblings);\n }\n\n const visit = (process: Process.Info, level: number): ProcessNode => {\n const children = level >= maxDepth ? [] : sortNestedActive(childrenByParent.get(String(process.pid)) ?? []);\n return {\n id: String(process.pid),\n process,\n children: children.map((child) => visit(child, level + 1)),\n };\n };\n\n return {\n id: ROOT_ID,\n children: sortProcesses(roots).map((process) => visit(process, 1)),\n };\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\n// Kept out of `Timeline.tsx`: react-refresh only fast-refreshes a module whose exports are all\n// components, so constants exported beside them force a full page reload on every edit.\n\nexport type TimelineOptions = {\n lineHeight: number;\n columnWidth: number;\n nodeRadius: number;\n lineStyle: string;\n};\n\nexport const defaultOptions: TimelineOptions = {\n lineHeight: 24,\n columnWidth: 14,\n nodeRadius: 5,\n lineStyle: 'stroke-1',\n};\n\nexport const compactOptions: TimelineOptions = {\n lineHeight: 20,\n columnWidth: 12,\n nodeRadius: 4,\n lineStyle: 'stroke-1',\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { format } from 'date-fns';\nimport React, { memo, useEffect, useMemo, useState } from 'react';\n\nimport { addEventListener } from '@dxos/async';\nimport { LogLevel } from '@dxos/log';\nimport { Icon, type ThemedClassName, useDynamicRef, useForwardedRef, useTranslation } from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { Shimmer } from '@dxos/react-ui-components';\nimport { mx } from '@dxos/ui-theme';\nimport { trim } from '@dxos/util';\n\nimport { translationKey } from '../../translations.ts';\n\nimport { type TimelineOptions, compactOptions, defaultOptions } from './timeline-options.ts';\n\n/**\n * Mercurial-style Commit.\n */\nexport type Commit = {\n id: string;\n timestamp?: Date; // TODO(burdon): Unix time?\n parents?: string[];\n branch: string;\n icon?: string;\n level?: LogLevel;\n message: string;\n tags?: string[];\n /** DXN link for navigation to referenced objects. */\n link?: string;\n};\n\nconst SHIMMER_EFFECT_TAG = 'effect:shimmer';\n\n/** Wall-clock to the second: a trace line is read against its neighbours, and milliseconds only widen the column. */\nconst TIMESTAMP_FORMAT = 'HH:mm:ss';\n\nconst hasShimmerEffect = (commit: Commit): boolean => commit.tags?.includes(SHIMMER_EFFECT_TAG) ?? false;\n\nconst empty = Object.freeze([]);\n\nexport type TimelineProps = ThemedClassName<{\n /** Optional whitelist. */\n branches?: string[];\n /**\n * Controlled value for the highlighted branch.\n * When provided, takes precedence over the branch derived from the currently selected commit.\n */\n branch?: string | null;\n commits?: Commit[];\n showTimestamp?: boolean;\n showIcon?: boolean;\n compact?: boolean;\n options?: TimelineOptions;\n debug?: boolean;\n onChange?: (props: { current?: number; commit?: Commit }) => void;\n /**\n * Callback when a commit with a link is clicked.\n * If provided, commits with links will be navigable.\n */\n onSelect?: (commit: Commit | undefined) => void;\n}>;\n\n/**\n * GitGraph-style timeline.\n */\n// TODO(burdon): Virtualize.\nexport const Timeline = memo(\n composable<HTMLDivElement, TimelineProps>(\n (\n {\n branches: branchesProp,\n branch,\n commits = empty,\n showTimestamp = false,\n showIcon = true,\n compact = false,\n options = compact ? compactOptions : defaultOptions,\n debug = false,\n onChange,\n onSelect,\n ...props\n },\n forwardedRef,\n ) => {\n const { t } = useTranslation(translationKey);\n const containerRef = useForwardedRef(forwardedRef);\n\n // Auto-discover branches if not provided.\n const branches = useMemo(() => {\n if (branchesProp) {\n return branchesProp;\n }\n\n return commits.reduce((branches, commit) => {\n if (!branches.includes(commit.branch)) {\n branches.push(commit.branch);\n }\n\n return branches;\n }, [] as string[]);\n }, [branchesProp, commits]);\n\n // NOTE: Assumes commits are in topological order.\n const getCommitIndex = (id: string) => commits.findIndex((c) => c.id === id);\n const getBranch = (id: string) => commits.find((c) => c.id === id)?.branch;\n\n /**\n * Assign branches to lanes, reusing lanes once a branch has been merged.\n * Unmerged branches keep their lane active (they may still be in progress).\n */\n const { branchLane, laneCount } = useMemo(() => {\n const visibleBranches = new Set(branches);\n\n const commitBranch = new Map<string, string>();\n for (const commit of commits) {\n commitBranch.set(commit.id, commit.branch);\n }\n\n // Find the row at which each branch is merged by another branch.\n const mergeRow = new Map<string, number>();\n for (let row = 0; row < commits.length; row++) {\n const commit = commits[row]!;\n for (const parentId of commit.parents ?? []) {\n const parentBranch = commitBranch.get(parentId);\n if (parentBranch && parentBranch !== commit.branch && visibleBranches.has(parentBranch)) {\n mergeRow.set(parentBranch, Math.max(mergeRow.get(parentBranch) ?? row, row));\n }\n }\n }\n\n const branchLane = new Map<string, number>();\n if (branches.length > 0) {\n branchLane.set(branches[0]!, 0);\n }\n\n const activeLanes = new Set<number>([0]);\n let maxLane = 0;\n\n for (let row = 0; row < commits.length; row++) {\n const commit = commits[row]!;\n if (visibleBranches.has(commit.branch) && !branchLane.has(commit.branch)) {\n let lane = 1;\n while (activeLanes.has(lane)) {\n lane++;\n }\n branchLane.set(commit.branch, lane);\n activeLanes.add(lane);\n maxLane = Math.max(maxLane, lane);\n }\n\n // Release lanes for branches that have been merged at this row.\n for (const [branch, endRow] of mergeRow) {\n if (endRow === row && branch !== branches[0] && branchLane.has(branch)) {\n activeLanes.delete(branchLane.get(branch)!);\n }\n }\n }\n\n return { branchLane, laneCount: maxLane + 1 };\n }, [commits, branches]);\n\n const getBranchIndex = (branch: string): number => branchLane.get(branch) ?? -1;\n\n /**\n * Create spans for each branch.\n */\n const spans = useMemo(() => {\n const spans = new Map<string, Span>();\n commits.forEach((commit, index) => {\n let span = spans.get(commit.branch);\n if (!span) {\n span = { start: index, end: index };\n spans.set(commit.branch, span);\n } else {\n span.end = index;\n }\n\n const parents = commit.parents ?? [];\n for (const parent of parents) {\n const branch = getBranch(parent);\n if (branch && branch !== commit.branch) {\n span.start = Math.min(span.start, getCommitIndex(parent));\n\n // Detect merge.\n if (parents.length > 1) {\n const parentSpan = spans.get(branch);\n if (parentSpan) {\n parentSpan.end = Math.max(parentSpan.end, index);\n }\n }\n }\n }\n });\n\n return spans;\n }, [commits, branches]);\n\n // Navigation.\n const [current, setCurrent] = useState<number | undefined>(undefined);\n const currentRef = useDynamicRef<number | undefined>(current);\n const selectedRef = useDynamicRef<number | undefined>(undefined);\n const currentCommit = useMemo(() => (current !== undefined ? commits[current] : undefined), [current, commits]);\n\n // Controlled `branch` takes precedence over the branch derived from the selected commit.\n const highlightedBranch = branch ?? currentCommit?.branch;\n\n useEffect(() => {\n onChange?.({ current, commit: current === undefined ? undefined : commits[current] });\n const el = containerRef.current?.querySelector(`[data-index=\"${current}\"]`);\n el?.scrollIntoView({ behavior: 'instant', block: 'nearest' });\n }, [onChange, current]);\n\n // When the controlled `branch` changes, jump to the first commit on that branch — but\n // never override an explicit commit selection that already sits on that branch. Otherwise a\n // click that selects a commit (and drives `branch` via the parent) would be snapped\n // back to the branch's first commit.\n useEffect(() => {\n if (!branch) {\n return;\n }\n if (currentRef.current !== undefined && commits[currentRef.current]?.branch === branch) {\n return;\n }\n\n const index = commits.findIndex((commit) => commit.branch === branch);\n if (index >= 0) {\n setCurrent(index);\n }\n }, [branch]);\n\n useEffect(() => {\n if (!containerRef.current) {\n return;\n }\n\n return addEventListener(containerRef.current, 'keydown', (event) => {\n switch (event.key) {\n case 'ArrowUp': {\n event.preventDefault(); // Prevent implicit scrolling.\n if (event.metaKey || currentRef.current === undefined) {\n setCurrent(0);\n } else {\n setCurrent((selected) => {\n if (event.shiftKey && selected !== undefined) {\n const branch = commits[selected].branch;\n for (let i = selected - 1; i >= 0; i--) {\n if (commits[i].branch === branch) {\n return i;\n }\n }\n\n return selected;\n } else {\n return selected === undefined ? commits.length - 1 : Math.max(0, selected - 1);\n }\n });\n }\n break;\n }\n case 'ArrowDown': {\n event.preventDefault(); // Prevent implicit scrolling.\n if (event.metaKey || currentRef.current === undefined) {\n setCurrent(commits.length - 1);\n } else {\n setCurrent((selected) => {\n if (event.shiftKey && selected !== undefined) {\n const branch = commits[selected].branch;\n for (let i = selected + 1; i <= commits.length - 1; i++) {\n if (commits[i].branch === branch) {\n return i;\n }\n }\n return selected;\n } else {\n return selected === undefined ? 0 : Math.min(commits.length - 1, selected + 1);\n }\n });\n }\n break;\n }\n case 'Enter': {\n event.preventDefault();\n if (currentRef.current !== undefined) {\n selectedRef.current = currentRef.current === selectedRef.current ? undefined : currentRef.current;\n onSelect?.(selectedRef.current !== undefined ? commits[selectedRef.current] : undefined);\n }\n break;\n }\n }\n });\n }, [commits, containerRef.current]);\n\n return (\n <div\n {...composableProps(props, { classNames: 'grid auto-rows-min outline-none' })}\n tabIndex={0}\n style={{\n gridTemplateColumns: ['min-content', showIcon && '1.25rem', '1fr', showTimestamp && 'max-content']\n .filter(Boolean)\n .join(' '),\n }}\n ref={containerRef}\n >\n {commits.length < 1 ? (\n <p className='col-span-full text-description p-trim-md'>{t('no-commits.message')}</p>\n ) : (\n commits.map((commit, index) => {\n // Skip branches that are not whitelisted.\n const idx = getBranchIndex(commit.branch);\n if (idx === -1) {\n return null;\n }\n\n const hasLink = !!commit.link && !!onSelect;\n // Clicking the selected commit clears the selection, as Enter does.\n const handleClick = () => {\n if (selectedRef.current === index) {\n selectedRef.current = undefined;\n setCurrent(undefined);\n onSelect?.(undefined);\n return;\n }\n setCurrent(index);\n selectedRef.current = index;\n onSelect?.(commit);\n };\n\n const message = debug ? JSON.stringify({ id: commit.id, parents: commit.parents }) : commit.message;\n\n return (\n <div\n key={commit.id}\n data-index={index}\n aria-current={current === index}\n className={mx(\n 'group/row col-span-full grid grid-cols-subgrid gap-1 px-[2px] overflow-hidden items-center cursor-pointer pe-2',\n 'aria-current:bg-current-surface! hover:bg-hover-surface-subtle',\n )}\n style={{ height: `${options.lineHeight}px` }}\n onClick={handleClick}\n >\n <div className='px-2'>\n <LineVector\n branchLane={branchLane}\n laneCount={laneCount}\n spans={spans}\n index={index}\n commit={commit}\n highlightedBranch={highlightedBranch}\n options={options}\n />\n </div>\n {showIcon && <CommitIcon commit={commit} />}\n <div\n className={mx(\n 'text-sm truncate cursor-pointer text-description font-thin group-aria-current/row:text-current-fg hover:text-current-fg',\n hasLink && 'underline decoration-dotted underline-offset-2',\n )}\n >\n {hasShimmerEffect(commit) ? <Shimmer>{message}</Shimmer> : message}\n </div>\n {showTimestamp && (\n <div className='text-xs tabular-nums items-center text-description font-thin'>\n {commit.timestamp && format(commit.timestamp, TIMESTAMP_FORMAT)}\n </div>\n )}\n </div>\n );\n })\n )}\n </div>\n );\n },\n ),\n);\n\nTimeline.displayName = 'Timeline';\n\nconst CommitIcon = memo(({ commit }: { commit: Commit }) => {\n if (!commit.icon) {\n return <div />;\n }\n\n return (\n <Icon\n icon={commit.icon}\n size={4}\n synchronized\n classNames={mx(\n commit.icon === 'ph--spinner-gap--regular' && 'animate-spin',\n commit.level !== undefined && levelColors[commit.level],\n )}\n />\n );\n});\n\ntype Span = {\n start: number;\n end: number;\n};\n\ntype Color = {\n stroke: string;\n fill: string;\n};\n\nconst defaultColor: Color = { stroke: 'stroke-neutral-surface', fill: 'fill-neutral-surface' };\n\nconst colors: Color[] = [\n { stroke: 'stroke-orange-500', fill: 'group-aria-[current=true]:fill-orange-500' },\n { stroke: 'stroke-sky-500', fill: 'group-aria-[current=true]:fill-sky-500' },\n { stroke: 'stroke-green-500', fill: 'group-aria-[current=true]:fill-green-500' },\n { stroke: 'stroke-fuchsia-500', fill: 'group-aria-[current=true]:fill-fuchsia-500' },\n { stroke: 'stroke-cyan-500', fill: 'group-aria-[current=true]:fill-cyan-500' },\n { stroke: 'stroke-emerald-500', fill: 'group-aria-[current=true]:fill-emerald-500' },\n { stroke: 'stroke-violet-500', fill: 'group-aria-[current=true]:fill-violet-500' },\n { stroke: 'stroke-teal-500', fill: 'group-aria-[current=true]:fill-teal-500' },\n];\n\nconst levelColors: Record<LogLevel, string> = {\n [LogLevel.TRACE]: 'text-gray-500',\n [LogLevel.DEBUG]: 'text-gray-500',\n [LogLevel.VERBOSE]: 'text-gray-500',\n [LogLevel.INFO]: 'text-green-500',\n [LogLevel.WARN]: 'text-orange-500',\n [LogLevel.ERROR]: 'text-red-500',\n};\n\ntype LineVectorProps = {\n branchLane: Map<string, number>;\n laneCount: number;\n spans: Map<string, Span>;\n index: number;\n commit: Commit;\n highlightedBranch: string | undefined;\n options: TimelineOptions;\n};\n\n/**\n * SVG for node and connector paths.\n */\nconst LineVector = memo(\n ({ branchLane, laneCount, spans, index, commit, highlightedBranch, options }: LineVectorProps) => {\n const halfHeight = options.lineHeight / 2;\n const cx = (c: number) => c * options.columnWidth + options.columnWidth / 2;\n const getBranchIndex = (branch: string): number => branchLane.get(branch) ?? -1;\n\n // Create connector path.\n const createPath = (index: number, commit: Commit, branch: string, span: Span): string | undefined => {\n const parents = commit.parents ?? [];\n const commitIndex = getBranchIndex(commit.branch);\n const branchIndex = getBranchIndex(branch);\n\n // Vertical connectors.\n if (span.start < index && index < span.end) {\n return `M ${cx(branchIndex)} 0 l 0 ${options.lineHeight}`;\n } else if (commit.branch === branch && parents.length > 0) {\n return `M ${cx(branchIndex)} 0 l 0 ${halfHeight}`;\n } else if (commit.branch === branch && index < span.end) {\n return `M ${cx(branchIndex)} ${halfHeight} l 0 ${options.lineHeight}`;\n }\n\n // Branch.\n // TODO(burdon): Assumes can only branch to the right.\n if (commit.branch !== branch && index === span.start) {\n return trim`\n M ${cx(commitIndex)} ${halfHeight}\n L ${cx(branchIndex) - halfHeight} ${halfHeight}\n a ${halfHeight} ${halfHeight} 0 0 1 ${halfHeight} ${halfHeight}\n `;\n }\n\n // Merge.\n if (commit.branch !== branch && index === span.end) {\n return trim`\n M ${cx(commitIndex)} ${halfHeight}\n L ${cx(branchIndex) - halfHeight} ${halfHeight}\n a ${halfHeight} ${halfHeight} -90 0 0 ${halfHeight} ${-halfHeight}\n `;\n }\n };\n\n const col = getBranchIndex(commit.branch);\n const color = colors[col % colors.length];\n const opacity = (branch: string | undefined) => [\n 'duration-500 transition-opacity',\n highlightedBranch === undefined || branch === highlightedBranch ? 'opacity-100' : 'opacity-50',\n ];\n\n return (\n <svg width={laneCount * options.columnWidth} height={options.lineHeight}>\n {/* Connectors */}\n {[...spans.entries()].map(([branch, span]) => {\n const lane = getBranchIndex(branch);\n if (lane < 0) {\n return null;\n }\n\n const color = colors[lane % colors.length];\n const path = createPath(index, commit, branch, span);\n if (!path) {\n return null;\n }\n\n return (\n <path\n key={branch}\n d={path}\n fill='none'\n className={mx(options.lineStyle, color.stroke, color.fill, opacity(branch))}\n />\n );\n })}\n\n <circle\n cx={cx(col)}\n cy={halfHeight}\n r={options.nodeRadius}\n className={mx('fill-base-surface stroke-base-surface')}\n />\n <circle\n cx={cx(col)}\n cy={halfHeight}\n r={options.nodeRadius}\n className={mx('fill-base-surface', options.lineStyle, color?.stroke, color?.fill, opacity(commit.branch))}\n />\n </svg>\n );\n },\n);\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Commit } from './Timeline.tsx';\n\nconst NODE = '●';\nconst MERGE_NODE = '◆';\nconst RAIL = '│';\nconst HORIZ = '─';\nconst COL_WIDTH = 3;\n\n/**\n * Renders commits as a monospace ASCII graph with rounded box-drawing arcs and vertical rails.\n * Commits must be ordered chronologically (oldest first, newest last). Parents must refer to older commits.\n */\nexport const renderTimelineAscii = (commits: Commit[], branches: string[]): string => {\n if (commits.length === 0) {\n return '';\n }\n\n const laneById = assignLanes(commits, branches);\n const lanes = commits.map((commit) => laneById.get(commit.id)!);\n const maxLane = Math.max(...lanes);\n\n if (maxLane === 0) {\n return commits.map((commit) => `${NODE} ${formatLabel(commit)}`).join('\\n');\n }\n\n const active = computeActiveColumns(commits, lanes, laneById);\n\n const graphParts = commits.map((commit, row) => renderRow(commit, lanes[row]!, maxLane, active[row]!, laneById));\n\n const maxGraphWidth = Math.max(...graphParts.map((part) => part.length));\n return commits.map((commit, row) => `${graphParts[row]!.padEnd(maxGraphWidth)} ${formatLabel(commit)}`).join('\\n');\n};\n\nconst renderRow = (\n commit: Commit,\n commitLane: number,\n maxLane: number,\n activeRow: boolean[],\n laneById: Map<string, number>,\n): string => {\n const totalChars = (maxLane + 1) * COL_WIDTH;\n const chars: string[] = Array(totalChars).fill(' ');\n\n const merge = isMergeCommit(commit);\n const fork = !merge && isForkCommit(commit, laneById, commitLane);\n\n let connectLane = -1;\n if (fork) {\n const parentLane = laneById.get(commit.parents![0]!);\n if (parentLane !== undefined) {\n connectLane = parentLane;\n }\n } else if (merge) {\n for (const parentId of commit.parents ?? []) {\n const parentLane = laneById.get(parentId);\n if (parentLane !== undefined && parentLane !== commitLane) {\n connectLane = parentLane;\n break;\n }\n }\n }\n\n for (let col = 0; col <= maxLane; col++) {\n if (col === commitLane) {\n continue;\n }\n if (activeRow[col]) {\n chars[col * COL_WIDTH] = RAIL;\n }\n }\n\n chars[commitLane * COL_WIDTH] = merge ? MERGE_NODE : NODE;\n if (connectLane >= 0) {\n const connectPos = connectLane * COL_WIDTH;\n if (fork) {\n chars[connectPos] = connectLane < commitLane ? '├' : '┤';\n } else {\n chars[connectPos] = connectLane > commitLane ? '╯' : '╰';\n }\n\n const minCol = Math.min(commitLane, connectLane);\n const maxCol = Math.max(commitLane, connectLane);\n for (let pos = minCol * COL_WIDTH + 1; pos < maxCol * COL_WIDTH; pos++) {\n if (pos % COL_WIDTH === 0) {\n const col = pos / COL_WIDTH;\n if (activeRow[col]) {\n chars[pos] = '┼';\n } else {\n chars[pos] = HORIZ;\n }\n } else {\n chars[pos] = HORIZ;\n }\n }\n }\n\n return chars.join('').trimEnd();\n};\n\nconst formatLabel = (commit: Commit): string => {\n const icon = commit.icon\n ?.replace(/^ph--/, '')\n .replace(/--regular$/, '')\n .replace(/--bold$/, '')\n .replace(/--fill$/, '');\n return icon ? `[${icon}] ${commit.message}` : commit.message;\n};\n\n/**\n * Assigns each commit to a lane (column), reusing lanes once a branch has been merged.\n * A branch is considered \"merged\" when a commit on another branch references it as a parent.\n * Unmerged branches keep their lane active (they may still be in progress).\n * Lane 0 is reserved for the first branch (typically 'main').\n */\nconst assignLanes = (commits: Commit[], branches: string[]): Map<string, number> => {\n // Build commit-id to branch lookup.\n const commitBranch = new Map<string, string>();\n for (const commit of commits) {\n commitBranch.set(commit.id, commit.branch);\n }\n\n // Find the row at which each branch is merged (closed) by another branch.\n const mergeRow = new Map<string, number>();\n for (let row = 0; row < commits.length; row++) {\n const commit = commits[row]!;\n for (const parentId of commit.parents ?? []) {\n const parentBranch = commitBranch.get(parentId);\n if (parentBranch && parentBranch !== commit.branch) {\n mergeRow.set(parentBranch, Math.max(mergeRow.get(parentBranch) ?? row, row));\n }\n }\n }\n\n const branchLane = new Map<string, number>();\n if (branches.length > 0) {\n branchLane.set(branches[0]!, 0);\n }\n\n const activeLanes = new Set<number>([0]);\n const laneById = new Map<string, number>();\n\n for (let row = 0; row < commits.length; row++) {\n const commit = commits[row]!;\n\n if (!branchLane.has(commit.branch)) {\n let lane = 1;\n while (activeLanes.has(lane)) {\n lane++;\n }\n branchLane.set(commit.branch, lane);\n activeLanes.add(lane);\n }\n\n laneById.set(commit.id, branchLane.get(commit.branch)!);\n\n // Release lanes for branches that have been merged at this row.\n for (const [branch, endRow] of mergeRow) {\n if (endRow === row && branch !== branches[0] && branchLane.has(branch)) {\n activeLanes.delete(branchLane.get(branch)!);\n }\n }\n }\n\n return laneById;\n};\n\nconst isMergeCommit = (commit: Commit): boolean => (commit.parents?.length ?? 0) > 1;\n\nconst isForkCommit = (commit: Commit, laneById: Map<string, number>, lane: number): boolean => {\n const parents = commit.parents;\n if (!parents || parents.length !== 1) {\n return false;\n }\n const parentLane = laneById.get(parents[0]!);\n return parentLane !== undefined && parentLane !== lane;\n};\n\n/**\n * Column `col` is active on `row` when `row` falls inside the vertical span\n * of that column (the range of rows that include commits on that lane plus\n * merge rows referencing parents on that lane) AND the row's own commit\n * is not on that column.\n */\nconst computeActiveColumns = (commits: Commit[], lanes: number[], laneById: Map<string, number>): boolean[][] => {\n const rows = commits.length;\n const cols = Math.max(...lanes, 0) + 1;\n const rowIndicesByCol: number[][] = Array.from({ length: cols }, () => []);\n\n for (let row = 0; row < rows; row++) {\n rowIndicesByCol[lanes[row]!]!.push(row);\n }\n\n for (let row = 0; row < rows; row++) {\n for (const parentId of commits[row]?.parents ?? []) {\n const parentLane = laneById.get(parentId);\n if (parentLane === undefined) {\n continue;\n }\n rowIndicesByCol[parentLane]!.push(row);\n }\n }\n\n const active: boolean[][] = Array.from({ length: rows }, () => Array(cols).fill(false));\n for (let col = 0; col < cols; col++) {\n const indices = rowIndicesByCol[col]!;\n if (indices.length === 0) {\n continue;\n }\n const minR = Math.min(...indices);\n const maxR = Math.max(...indices);\n for (let row = minR; row <= maxR; row++) {\n if (lanes[row] !== col) {\n active[row]![col] = true;\n }\n }\n }\n\n return active;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as Process from '@dxos/compute/Process';\nimport type * as Trace from '@dxos/compute/Trace';\n\n/**\n * What a running process is working on behalf of, as a single bucket.\n *\n * Bucketed from the inherited {@link Process.Environment}, so filtering keeps whole subtrees together.\n */\nexport const ProcessEnvironment = {\n /** Not scoped to a space: layout, navigation, identity, settings, space lifecycle. */\n App: 'app',\n /** Scoped to a space, but not to a conversation within it. */\n Space: 'space',\n /** Serving a conversation: an agent's turn and every tool call it spawns. */\n Conversation: 'conversation',\n} as const;\n\nexport type ProcessEnvironment = (typeof ProcessEnvironment)[keyof typeof ProcessEnvironment];\n\n/** Every environment, in menu order — widening scope, so the filter reads the same on every trace. */\nexport const ALL_PROCESS_ENVIRONMENTS: readonly ProcessEnvironment[] = [\n ProcessEnvironment.App,\n ProcessEnvironment.Space,\n ProcessEnvironment.Conversation,\n];\n\n/** App-level processes start hidden: that bucket fires on every click, whatever the user is watching. */\nexport const DEFAULT_PROCESS_ENVIRONMENTS: readonly ProcessEnvironment[] = [\n ProcessEnvironment.Space,\n ProcessEnvironment.Conversation,\n];\n\nconst ENVIRONMENT_ICONS: Record<ProcessEnvironment, string> = {\n [ProcessEnvironment.App]: 'ph--app-window--regular',\n [ProcessEnvironment.Space]: 'ph--planet--regular',\n [ProcessEnvironment.Conversation]: 'ph--chat-teardrop-text--regular',\n};\n\nexport const environmentIcon = (environment: ProcessEnvironment): string => ENVIRONMENT_ICONS[environment];\n\n/** `conversation` outranks `space`, since a conversation always runs inside one. */\nexport const processEnvironment = (process: Process.Info): ProcessEnvironment => {\n if (process.environment.conversation !== undefined) {\n return ProcessEnvironment.Conversation;\n }\n if (process.environment.space !== undefined) {\n return ProcessEnvironment.Space;\n }\n return ProcessEnvironment.App;\n};\n\nexport const filterProcesses = (\n processes: readonly Process.Info[],\n selected: readonly ProcessEnvironment[],\n): readonly Process.Info[] => {\n // Identity when nothing is excluded, so `ProcessTree`'s `React.memo` still holds.\n if (selected.length === ALL_PROCESS_ENVIRONMENTS.length) {\n return processes;\n }\n const selection = new Set(selected);\n return processes.filter((process) => selection.has(processEnvironment(process)));\n};\n\n/** Toggles an environment, preserving the canonical order. */\nexport const toggleProcessEnvironment = (\n selected: readonly ProcessEnvironment[],\n environment: ProcessEnvironment,\n): ProcessEnvironment[] =>\n ALL_PROCESS_ENVIRONMENTS.filter((candidate) =>\n candidate === environment ? !selected.includes(environment) : selected.includes(candidate),\n );\n\n/**\n * Narrows a persisted selection to the known environments, in canonical order.\n *\n * Settings outlive the vocabulary that wrote them; an unrecognized value would filter the panel to nothing.\n */\nexport const parseProcessEnvironments = (selected: readonly string[] | undefined): readonly ProcessEnvironment[] =>\n selected === undefined\n ? DEFAULT_PROCESS_ENVIRONMENTS\n : ALL_PROCESS_ENVIRONMENTS.filter((environment) => selected.includes(environment));\n\n/**\n * Narrows trace messages to the selected processes and their descendants: a tool call or sub-agent\n * runs as a child of the process it serves, so its events are that process's work. An empty\n * selection is no filter.\n */\nexport const filterTraceMessages = (\n messages: readonly Trace.Message[],\n selected: readonly string[],\n): readonly Trace.Message[] => {\n if (selected.length === 0) {\n return messages;\n }\n const parentByPid = new Map<string, string | undefined>();\n for (const message of messages) {\n if (message.meta.pid !== undefined) {\n parentByPid.set(message.meta.pid, message.meta.parentPid);\n }\n }\n const selection = new Set(selected);\n const matches = new Map<string, boolean>();\n const isSelected = (pid: string): boolean => {\n const known = matches.get(pid);\n if (known !== undefined) {\n return known;\n }\n // Pinned before the walk so a cyclic parent chain (a corrupt trace) terminates.\n matches.set(pid, false);\n const parent = parentByPid.get(pid);\n const result = selection.has(pid) || (parent !== undefined && isSelected(parent));\n matches.set(pid, result);\n return result;\n };\n return messages.filter((message) => message.meta.pid !== undefined && isSelected(message.meta.pid));\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useCallback } from 'react';\n\nimport { MenuBuilder, useMenuBuilder } from '@dxos/react-ui-menu';\n\nimport { translationKey } from '../../translations.ts';\n\nimport {\n ALL_PROCESS_ENVIRONMENTS,\n type ProcessEnvironment,\n environmentIcon,\n toggleProcessEnvironment,\n} from './trace-filter.ts';\n\nexport type UseTraceMenuOptions = {\n /** Process environments currently shown. */\n selected: readonly ProcessEnvironment[];\n onSelectedChange: (environments: ProcessEnvironment[]) => void;\n /** How many processes are picked; the clear action shows only while there are some. */\n selectionCount?: number;\n onClearSelection?: () => void;\n};\n\n/**\n * Environment filter menu for the trace panel's toolbar.\n * The group collapses to a funnel trigger, so the panel's own rows keep the width.\n */\nexport const useTraceMenu = ({\n selected,\n onSelectedChange,\n selectionCount = 0,\n onClearSelection,\n}: UseTraceMenuOptions) => {\n const handleToggle = useCallback(\n (environment: ProcessEnvironment) => onSelectedChange(toggleProcessEnvironment(selected, environment)),\n [selected, onSelectedChange],\n );\n\n return useMenuBuilder(\n () =>\n MenuBuilder.make()\n .action(\n 'clearSelection',\n {\n label: ['trace-clear-selection.label', { ns: translationKey }],\n icon: 'ph--selection-slash--regular',\n iconOnly: true,\n hidden: selectionCount === 0,\n testId: 'tracePanel.clearSelection',\n },\n () => onClearSelection?.(),\n )\n .group(\n 'processEnvironments',\n {\n label: ['trace-filter.menu', { ns: translationKey }],\n icon: 'ph--funnel--regular',\n iconOnly: true,\n variant: 'dropdownMenu',\n selectCardinality: 'multiple',\n value: [...selected],\n testId: 'tracePanel.filter',\n },\n (group) => {\n for (const environment of ALL_PROCESS_ENVIRONMENTS) {\n group.action(\n environment,\n {\n label: [`trace-environment-${environment}.label`, { ns: translationKey }],\n icon: environmentIcon(environment),\n checked: selected.includes(environment),\n },\n () => handleToggle(environment),\n );\n }\n group.separator('line');\n group.action(\n 'all',\n { label: ['trace-filter-all.label', { ns: translationKey }], icon: 'ph--list-checks--regular' },\n () => onSelectedChange([...ALL_PROCESS_ENVIRONMENTS]),\n );\n group.action(\n 'none',\n { label: ['trace-filter-none.label', { ns: translationKey }], icon: 'ph--prohibit--regular' },\n () => onSelectedChange([]),\n );\n },\n )\n .build(),\n [handleToggle, selected, onSelectedChange, selectionCount, onClearSelection],\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useCallback, useDeferredValue, useMemo, useState } from 'react';\n\nimport type * as Process from '@dxos/compute/Process';\nimport {\n Accordion,\n Panel,\n ScrollContainer,\n type ThemedClassName,\n composable,\n composableProps,\n useTranslation,\n} from '@dxos/react-ui';\nimport { ActionToolbar } from '@dxos/react-ui-menu';\nimport { JsonHighlighter } from '@dxos/react-ui-syntax-highlighter';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type ExecutionGraph } from '../../execution-graph/index.ts';\nimport { translationKey } from '../../translations.ts';\nimport { ProcessTree, type ProcessTreeProps } from '../ProcessTree/index.ts';\nimport { type Commit, Timeline } from '../Timeline/index.ts';\n\nimport { type ProcessEnvironment, filterProcesses } from './trace-filter.ts';\nimport { useTraceMenu } from './useTraceMenu.ts';\n\nexport type TracePanelProps = ThemedClassName<\n Pick<ProcessTreeProps, 'resolveLabel' | 'selected' | 'onSelectedChange' | 'onProcessTerminate'> & {\n /** The live process tree; narrowed here by `environments`. */\n processes: readonly Process.Info[];\n /** The trace as a commit graph, built by `useExecutionGraph` (already narrowed to `selected`). */\n graph: ExecutionGraph;\n /** Process environments shown; the toolbar's funnel edits it. */\n environments: readonly ProcessEnvironment[];\n onEnvironmentsChange: (environments: ProcessEnvironment[]) => void;\n /** Shows the span tree as JSON in place of the timeline. */\n debug?: boolean;\n /** A commit whose message links an object was picked; the host decides what opening it means. */\n onOpenLink?: (uri: string) => void;\n }\n>;\n\n/**\n * A space's runtime: its processes as a tree, its trace as a commit graph, and the picked commit's\n * event. Presentation only — the host resolves the process monitor, the trace feed, settings and\n * navigation and hands them in as props.\n */\nexport const TracePanel = composable<HTMLDivElement, TracePanelProps>(\n (\n {\n classNames,\n processes,\n graph,\n environments,\n onEnvironmentsChange,\n debug = false,\n resolveLabel,\n selected = NO_SELECTION,\n onSelectedChange,\n onProcessTerminate,\n onOpenLink,\n ...props\n },\n forwardedRef,\n ) => {\n const { t } = useTranslation(translationKey);\n const handleClearSelection = useCallback(() => onSelectedChange?.([]), [onSelectedChange]);\n const menu = useTraceMenu({\n selected: environments,\n onSelectedChange: onEnvironmentsChange,\n selectionCount: selected.length,\n onClearSelection: handleClearSelection,\n });\n\n // `useDeferredValue` batches update bursts, works together with `React.memo`.\n // See the comment in `ProcessTreeContainer` for more details.\n const { branches, commits, spanTree, details } = useDeferredValue(graph);\n\n const [selectedCommit, setSelectedCommit] = useState<Commit | undefined>();\n // Remembered across selections, so collapsing a section once keeps it collapsed.\n const [openSections, setOpenSections] = useState<string[]>(SECTIONS.map((section) => section.id));\n const handleCommitSelect = useCallback(\n (commit: Commit | undefined) => {\n setSelectedCommit(commit);\n if (commit?.link) {\n onOpenLink?.(commit.link);\n }\n },\n [onOpenLink],\n );\n\n // The most recently picked process is the highlighted branch, while it is still picked.\n const currentBranch = useMemo(() => {\n const last = selected.at(-1);\n return last !== undefined && branches.includes(last) ? last : null;\n }, [selected, branches]);\n\n return (\n <Panel.Root {...composableProps(props, { classNames: ['h-full', classNames] })} ref={forwardedRef}>\n <Panel.Toolbar asChild>\n <ActionToolbar {...menu} alwaysActive classNames='justify-end' />\n </Panel.Toolbar>\n\n <Panel.Content>\n <Accordion.Root<TraceSection>\n items={SECTIONS}\n value={openSections}\n onValueChange={setOpenSections}\n classNames='h-full min-h-0 rounded-none border-y-0'\n >\n {({ items }) =>\n items.map((section) => {\n switch (section.id) {\n case 'processes':\n return (\n <Accordion.Item key={section.id} item={section} classNames='border-x-0'>\n <Accordion.ItemHeader hover>\n <span className='text-sm text-description'>{t('trace-processes.label')}</span>\n </Accordion.ItemHeader>\n <Accordion.ItemBody classNames='p-0'>\n <ProcessTreeContainer\n classNames='max-h-[8lh]'\n processes={processes}\n environments={environments}\n resolveLabel={resolveLabel}\n selected={selected}\n onSelectedChange={onSelectedChange}\n onProcessTerminate={onProcessTerminate}\n />\n </Accordion.ItemBody>\n </Accordion.Item>\n );\n case 'trace':\n return (\n // The trace takes the slack: item and body are flex columns so the scroll\n // container inside gets a definite height to scroll within. The body's slide\n // animation is off here — it ramps to a measured height, and this body's height\n // comes from the flex slack, not its content.\n <Accordion.Item\n key={section.id}\n item={section}\n classNames={mx(\n 'border-x-0 dx-grow flex flex-col',\n '[&>[data-part=item-content]]:dx-grow [&>[data-part=item-content]]:flex [&>[data-part=item-content]]:flex-col [&>[data-part=item-content]]:animate-none',\n )}\n >\n <Accordion.ItemHeader hover>\n <span className='text-sm text-description'>{t('trace.label')}</span>\n </Accordion.ItemHeader>\n <Accordion.ItemBody classNames='dx-grow grid grid-rows-[minmax(0,1fr)]'>\n <ScrollContainer.Root pin>\n <ScrollContainer.Content thin>\n <ScrollContainer.Fade />\n <ScrollContainer.Viewport>\n {debug ? (\n <JsonHighlighter data={spanTree} classNames='text-xs' />\n ) : (\n <Timeline\n branches={branches}\n branch={currentBranch}\n commits={commits}\n showTimestamp\n onSelect={handleCommitSelect}\n />\n )}\n </ScrollContainer.Viewport>\n <ScrollContainer.ScrollDownButton />\n </ScrollContainer.Content>\n </ScrollContainer.Root>\n </Accordion.ItemBody>\n </Accordion.Item>\n );\n case 'details': {\n const commit = debug ? undefined : selectedCommit;\n return (\n // With nothing selected the section stays as a plain, closed row.\n <Accordion.Item key={section.id} item={section} disabled={!commit} classNames='border-x-0'>\n <Accordion.ItemHeader hover>\n <span className='block truncate text-sm text-description'>\n {commit?.message ?? t('trace-details.label')}\n </span>\n </Accordion.ItemHeader>\n {commit && (\n <Accordion.ItemBody classNames='p-0'>\n <JsonHighlighter data={details[commit.id] ?? commit} classNames='max-h-[20lh] text-xs' />\n </Accordion.ItemBody>\n )}\n </Accordion.Item>\n );\n }\n }\n })\n }\n </Accordion.Root>\n </Panel.Content>\n </Panel.Root>\n );\n },\n);\n\nTracePanel.displayName = 'TracePanel';\n\ntype TraceSection = { id: 'processes' | 'trace' | 'details' };\n\nconst SECTIONS: TraceSection[] = [{ id: 'processes' }, { id: 'trace' }, { id: 'details' }];\n\nconst NO_SELECTION: readonly string[] = [];\n\ntype ProcessTreeContainerProps = ThemedClassName<\n Pick<ProcessTreeProps, 'resolveLabel' | 'selected' | 'onSelectedChange' | 'onProcessTerminate'> & {\n processes: readonly Process.Info[];\n environments: readonly ProcessEnvironment[];\n }\n>;\n\n// Isolate `ProcessTree` updates from the rest of the panel.\nconst ProcessTreeContainer = ({\n classNames,\n processes,\n environments,\n resolveLabel,\n selected,\n onSelectedChange,\n onProcessTerminate,\n}: ProcessTreeContainerProps) => {\n // `processes` updates in bursts (about 14 updates per navigation).\n // `useDeferredValue` will debounce update propagation, returning stale value for short periods.\n // NOTE: `ProcessTree` MUST use `React.memo`, otherwise this will not work.\n const processesDeferred = useDeferredValue(processes);\n const visibleProcesses = useMemo(\n () => filterProcesses(processesDeferred, environments),\n [processesDeferred, environments],\n );\n\n return (\n <ProcessTree\n classNames={classNames}\n depth={3}\n processes={visibleProcesses}\n resolveLabel={resolveLabel}\n selected={selected}\n onSelectedChange={onSelectedChange}\n onProcessTerminate={onProcessTerminate}\n />\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Option from 'effect/Option';\nimport * as Schema from 'effect/Schema';\n\nimport * as Trace from '@dxos/compute/Trace';\nimport { EID } from '@dxos/keys';\n\n/**\n * Default duration a span may sit open with no new events before it's considered abandoned\n * (the runtime crashed, lost connectivity, or otherwise never wrote the closing event).\n */\nexport const DEFAULT_SPAN_TIMEOUT_MS = 20 * 60 * 1_000;\n\n/**\n * Synthetic id assigned to the root span.\n * The root is a virtual container for top-level spans (those without a parent in the captured trace).\n */\nexport const ROOT_SPAN_ID = '<main>';\n\n/**\n * Computed metadata for a span.\n * Derived from the meta of the begin event that opened the span.\n */\nexport interface SpanMeta {\n readonly pid?: string;\n readonly parentPid?: string;\n readonly processName?: string;\n readonly conversationId?: string;\n readonly triggerId?: string;\n readonly toolCallId?: string;\n readonly runtimeName?: string;\n}\n\n/**\n * A span in the trace hierarchy.\n *\n * Each span represents a single bounded unit of work — an operation invocation or an\n * agent request. Spans are opened by `OperationStart` / `Trace.AgentRequestBegin` events and\n * closed by their matching `OperationEnd` / `Trace.AgentRequestEnd` events. A single process\n * (pid) may produce multiple sequential spans (for example, an agent session that serves\n * three prompts produces three sibling spans sharing the agent's pid).\n *\n * `events` contains the bounded events for this span only — child spans' events are not\n * duplicated here. `children` contains sub-spans that opened while this span was active.\n */\nexport interface Span {\n readonly id: string;\n readonly meta: SpanMeta;\n readonly events: Trace.FlatEvent[];\n readonly children: Span[];\n}\n\nexport const BEGIN_EVENT_TYPES = new Set<string>([Trace.OperationStart.key, Trace.AgentRequestBegin.key]);\nexport const END_EVENT_TYPES = new Set<string>([Trace.OperationEnd.key, Trace.AgentRequestEnd.key]);\n\nexport const isSpanBeginEvent = (event: Trace.FlatEvent): boolean => BEGIN_EVENT_TYPES.has(event.type);\nexport const isSpanEndEvent = (event: Trace.FlatEvent): boolean => END_EVENT_TYPES.has(event.type);\n\nconst computeMeta = (rawMeta: Trace.Meta): SpanMeta => ({\n pid: rawMeta.pid,\n parentPid: rawMeta.parentPid,\n processName: rawMeta.processName,\n conversationId: rawMeta.conversation ? EID.getEntityId(EID.parse(rawMeta.conversation.uri)) : undefined,\n triggerId: rawMeta.trigger ? EID.getEntityId(EID.parse(rawMeta.trigger.uri)) : undefined,\n toolCallId: rawMeta.toolCallId,\n runtimeName: rawMeta.runtimeName,\n});\n\ninterface MutableSpan {\n id: string;\n meta: SpanMeta;\n events: Trace.FlatEvent[];\n children: MutableSpan[];\n firstTimestamp: number;\n}\n\nconst makeMutableSpan = (id: string, meta: SpanMeta): MutableSpan => ({\n id,\n meta,\n events: [],\n children: [],\n firstTimestamp: Number.POSITIVE_INFINITY,\n});\n\nconst freezeSpan = (span: MutableSpan): Span => ({\n id: span.id,\n meta: span.meta,\n events: span.events,\n children: span.children.map(freezeSpan),\n});\n\nexport interface BuildSpanTreeOptions {\n /**\n * If provided, caps how many *non-boundary* events (status updates, partial blocks, etc.)\n * are retained — only the most recent `eventLimit` of them survive. Span boundary events\n * (`OperationStart` / `OperationEnd` / `Trace.AgentRequestBegin` / `Trace.AgentRequestEnd`) are *always*\n * retained regardless of the limit, because dropping them would orphan their child spans\n * and collapse them onto the root branch.\n */\n eventLimit?: number;\n\n /**\n * Duration a span may sit open with no new events before it's force-closed with a synthetic\n * end event. Only takes effect when `now` is also provided. Defaults to\n * `DEFAULT_SPAN_TIMEOUT_MS`.\n */\n spanTimeoutMs?: number;\n\n /**\n * Reference time used to detect abandoned spans. Force-closing is skipped entirely when this\n * is omitted, so callers that don't pass it (tests, deterministic snapshots) keep the prior\n * behavior of leaving unterminated spans open regardless of their fixture timestamps.\n */\n now?: number;\n}\n\n/**\n * Builds a hierarchical span tree from a list of trace messages.\n *\n * Algorithm:\n * 1. Flatten messages into events and sort them chronologically.\n * 2. For each event:\n * - Begin events (`OperationStart`, `Trace.AgentRequestBegin`) open a new span whose parent\n * is the currently-open span of the event's `meta.parentPid`, or the root if there is\n * none. The begin event itself becomes the first event of the new span.\n * - End events (`OperationEnd`, `Trace.AgentRequestEnd`) close the currently-open span for\n * the event's `meta.pid` and become its last event.\n * - Other events attach to the currently-open span for their `meta.pid`, or to the\n * root span if no span is currently open for that pid (or the event has no pid).\n * 3. Sort each span's children by their earliest event timestamp.\n */\nexport const buildSpanTree = (messages: readonly Trace.Message[], options: BuildSpanTreeOptions = {}): Span => {\n const allEvents = messages.flatMap((message) => Trace.flatten(message));\n allEvents.sort((a, b) => a.timestamp - b.timestamp);\n\n // The limit caps verbose middle events (status/partial-block) only. Span boundary events\n // are always retained so the parent/child structure of older spans isn't dropped — losing a\n // begin event detaches every descendant and collapses them onto the root branch.\n const events = applyEventLimit(allEvents, options.eventLimit);\n\n const root = makeMutableSpan(ROOT_SPAN_ID, {});\n\n // Currently-open span for each pid.\n // A process may host multiple sequential spans (e.g. successive agent requests), so we\n // track the active one and start a new span on the next begin event.\n const openSpans = new Map<string, MutableSpan>();\n\n // Most-recent span for each pid, open OR already closed. Used as the parent fallback for a\n // child process whose parent span has already ended — e.g. a delegated sub-agent runs\n // concurrently and its begin event arrives after the supervisor's turn (its parent) closed.\n // Without this the child would nest at the root and render on its own top-level lane, reusing\n // a sibling's released lane instead of forking off its parent.\n const lastSpanByPid = new Map<string, MutableSpan>();\n\n // Every span ever opened, including ones later superseded by a same-pid begin event before\n // getting an end event (§15 \"interleaved same-pid begin/end pairs\"). `openSpans` only tracks\n // the *current* span per pid, so a superseded span — which will never receive an end event —\n // would otherwise be unreachable by the timeout sweep below.\n const allSpans: MutableSpan[] = [];\n\n let spanCounter = 0;\n const allocSpanId = (pid: string): string => {\n const id = `${pid}#${spanCounter}`;\n spanCounter += 1;\n return id;\n };\n\n const noteTimestamp = (span: MutableSpan, timestamp: number): void => {\n if (timestamp < span.firstTimestamp) {\n span.firstTimestamp = timestamp;\n }\n };\n\n for (const event of events) {\n const pid = event.meta.pid;\n\n if (!pid) {\n // Events without a pid attach to the root.\n root.events.push(event);\n noteTimestamp(root, event.timestamp);\n continue;\n }\n\n if (BEGIN_EVENT_TYPES.has(event.type)) {\n const parentPid = event.meta.parentPid;\n // Prefer the parent's currently-open span; fall back to its most-recent (closed) span so a\n // child process whose parent has already ended still nests under it (delegated sub-agents).\n const parent = (parentPid && (openSpans.get(parentPid) ?? lastSpanByPid.get(parentPid))) || root;\n const span = makeMutableSpan(allocSpanId(pid), computeMeta(event.meta));\n span.events.push(event);\n noteTimestamp(span, event.timestamp);\n parent.children.push(span);\n allSpans.push(span);\n // The new span supersedes any previously-open span for this pid.\n openSpans.set(pid, span);\n lastSpanByPid.set(pid, span);\n continue;\n }\n\n if (END_EVENT_TYPES.has(event.type)) {\n const span = openSpans.get(pid);\n if (span) {\n span.events.push(event);\n noteTimestamp(span, event.timestamp);\n openSpans.delete(pid);\n } else {\n // End event without a matching begin — attach to root so the event isn't lost.\n root.events.push(event);\n noteTimestamp(root, event.timestamp);\n }\n continue;\n }\n\n // Non-boundary event: attach to the currently-open span for this pid if any.\n const open = openSpans.get(pid);\n if (open) {\n open.events.push(event);\n noteTimestamp(open, event.timestamp);\n } else {\n root.events.push(event);\n noteTimestamp(root, event.timestamp);\n }\n }\n\n // Force-close spans the runtime never reported the end of (crash, dropped connection, etc.) —\n // otherwise they stay open forever and the UI renders them as stuck mid-flight. Walks every\n // span ever opened (not just `openSpans`) so a span superseded by a later same-pid begin event\n // — which never receives its own end event — is force-closed too. Skipped when `now` isn't\n // supplied so callers that don't care about wall-clock staleness are unaffected.\n if (options.now !== undefined) {\n const now = options.now;\n const spanTimeoutMs = options.spanTimeoutMs ?? DEFAULT_SPAN_TIMEOUT_MS;\n for (const span of allSpans) {\n const lastEvent = span.events[span.events.length - 1]!;\n if (isSpanEndEvent(lastEvent)) {\n continue;\n }\n const timeoutAt = lastEvent.timestamp + spanTimeoutMs;\n if (now < timeoutAt) {\n continue;\n }\n const endEvent = makeTimeoutEndEvent(span, timeoutAt);\n span.events.push(endEvent);\n noteTimestamp(span, endEvent.timestamp);\n }\n }\n\n // Sort children chronologically for deterministic output.\n const sortChildren = (span: MutableSpan): void => {\n span.children.sort((a, b) => a.firstTimestamp - b.firstTimestamp);\n for (const child of span.children) {\n sortChildren(child);\n }\n };\n sortChildren(root);\n\n return freezeSpan(root);\n};\n\n/**\n * Message stamped on synthetic end events produced when a span times out.\n */\nconst SPAN_TIMEOUT_MESSAGE = 'No end event was recorded for this span; it was closed after a timeout.';\n\n/**\n * Synthesizes the end event that closes an abandoned span, matching the event type its begin\n * event opened it with (`OperationStart` → `OperationEnd`, `Trace.AgentRequestBegin` → `Trace.AgentRequestEnd`).\n */\nconst makeTimeoutEndEvent = (span: MutableSpan, timestamp: number): Trace.FlatEvent => {\n const beginEvent = span.events[0]!;\n if (beginEvent.type === Trace.AgentRequestBegin.key) {\n return {\n type: Trace.AgentRequestEnd.key,\n timestamp,\n meta: beginEvent.meta,\n isEphemeral: false,\n data: { status: 'interrupted', error: SPAN_TIMEOUT_MESSAGE },\n };\n }\n\n // `beginEvent.data` is unvalidated wire data; decode defensively rather than trusting its shape.\n const fallback: Schema.Schema.Type<typeof Trace.OperationStart.schema> = { key: 'unknown' };\n const beginData = Option.getOrElse(\n Schema.decodeUnknownOption(Trace.OperationStart.schema)(beginEvent.data),\n () => fallback,\n );\n return {\n type: Trace.OperationEnd.key,\n timestamp,\n meta: beginEvent.meta,\n isEphemeral: false,\n data: {\n key: beginData.key,\n name: beginData.name,\n icon: beginData.icon,\n outcome: 'failure',\n error: SPAN_TIMEOUT_MESSAGE,\n },\n };\n};\n\n/**\n * Caps the number of non-boundary events while retaining every span boundary event.\n *\n * Boundary events define the span tree's structure: dropping a begin event detaches every\n * descendant span (its `parentPid` lookup fails, so children fall back to the root), and\n * dropping an end event leaves a span open and corrupts the open-span map for sibling spans\n * that share a pid. Status/partial-block events are the noisy bulk and the only ones the\n * limit needs to control.\n *\n * The returned array stays in chronological order.\n */\nconst applyEventLimit = (events: readonly Trace.FlatEvent[], eventLimit: number | undefined): Trace.FlatEvent[] => {\n if (eventLimit === undefined) {\n return [...events];\n }\n\n let nonBoundaryCount = 0;\n for (const event of events) {\n if (!isBoundary(event)) {\n nonBoundaryCount += 1;\n }\n }\n if (nonBoundaryCount <= eventLimit) {\n return [...events];\n }\n\n const dropCount = nonBoundaryCount - eventLimit;\n let dropped = 0;\n const result: Trace.FlatEvent[] = [];\n for (const event of events) {\n if (!isBoundary(event) && dropped < dropCount) {\n dropped += 1;\n continue;\n }\n result.push(event);\n }\n return result;\n};\n\nconst isBoundary = (event: Trace.FlatEvent): boolean =>\n BEGIN_EVENT_TYPES.has(event.type) || END_EVENT_TYPES.has(event.type);\n\n/**\n * A single event positioned within the span tree for commit emission.\n */\nexport interface SpanEventCursor {\n readonly span: Span;\n readonly event: Trace.FlatEvent;\n readonly eventIndex: number;\n}\n\n/**\n * Flattens span-tree events in categorical (depth-first) order: each span's begin events, its\n * child subtrees in sibling order, then its remaining events (middle and end).\n */\nexport const collectSpanTreeEventsCategorically = (root: Span): SpanEventCursor[] => {\n const stream: SpanEventCursor[] = [];\n\n const visitSpan = (span: Span): void => {\n for (let eventIndex = 0; eventIndex < span.events.length; eventIndex += 1) {\n const event = span.events[eventIndex]!;\n if (isSpanBeginEvent(event)) {\n stream.push({ span, event, eventIndex });\n }\n }\n\n for (const child of span.children) {\n visitSpan(child);\n }\n\n for (let eventIndex = 0; eventIndex < span.events.length; eventIndex += 1) {\n const event = span.events[eventIndex]!;\n if (!isSpanBeginEvent(event)) {\n stream.push({ span, event, eventIndex });\n }\n }\n };\n\n visitSpan(root);\n return stream;\n};\n\n/**\n * Walks the span tree in depth-first pre-order, invoking `visit` for each span (root included).\n */\nexport const walkSpanTree = (root: Span, visit: (span: Span, depth: number) => void, depth = 0): void => {\n visit(root, depth);\n for (const child of root.children) {\n walkSpanTree(child, visit, depth + 1);\n }\n};\n\n/**\n * Returns all spans in the tree in depth-first pre-order, root first.\n */\nexport const flattenSpanTree = (root: Span): Span[] => {\n const result: Span[] = [];\n walkSpanTree(root, (span) => result.push(span));\n return result;\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Array from 'effect/Array';\nimport { pipe } from 'effect/Function';\nimport * as Option from 'effect/Option';\nimport * as Pipeable from 'effect/Pipeable';\nimport * as Schema from 'effect/Schema';\nimport * as Struct from 'effect/Struct';\n\nimport { RUN_AGAIN_ERROR_CODE, RUN_AGAIN_MESSAGE } from '@dxos/compute';\nimport * as Process from '@dxos/compute/Process';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Annotation } from '@dxos/echo';\nimport { EID } from '@dxos/keys';\nimport { LogLevel, log } from '@dxos/log';\nimport { type Commit } from '../components/Timeline/index.ts';\nimport { type ContentBlock } from '@dxos/types';\n\nimport { ROOT_SPAN_ID, type Span, buildSpanTree, isSpanBeginEvent, isSpanEndEvent, walkSpanTree } from './span-tree.ts';\n\n/**\n * Branch name for top-level operation invocations.\n */\nconst MAIN_BRANCH = 'main';\n\n/** Timeline tag that applies a shimmer message effect. */\nconst SHIMMER_EFFECT_TAG = 'effect:shimmer';\n\nconst ICONS = {\n agentRequestBegin: {\n icon: 'ph--atom--regular',\n level: LogLevel.VERBOSE,\n },\n agentRequestEndSuccess: {\n icon: 'ph--atom--regular',\n level: LogLevel.INFO,\n },\n agentRequestEndError: {\n icon: 'ph--atom--regular',\n level: LogLevel.ERROR,\n },\n agentRequestEndInterrupted: {\n icon: 'ph--atom--regular',\n level: LogLevel.WARN,\n },\n userMessage: {\n icon: 'ph--user--regular',\n level: LogLevel.VERBOSE,\n },\n statusMessage: {\n icon: 'ph--info--regular',\n level: LogLevel.VERBOSE,\n },\n operationStart: {\n icon: 'ph--function--regular',\n level: LogLevel.VERBOSE,\n },\n operationEndSuccess: {\n icon: 'ph--function--regular',\n level: LogLevel.INFO,\n },\n operationEndError: {\n icon: 'ph--function--regular',\n level: LogLevel.ERROR,\n },\n operationEndIncomplete: {\n icon: 'ph--arrows-clockwise--regular',\n level: LogLevel.WARN,\n },\n toolCall: {\n icon: 'ph--wrench--regular',\n level: LogLevel.VERBOSE,\n },\n toolResultSuccess: {\n icon: 'ph--wrench--regular',\n level: LogLevel.INFO,\n },\n toolResultError: {\n icon: 'ph--wrench--regular',\n level: LogLevel.ERROR,\n },\n agentRequestRunning: {\n icon: 'ph--spinner-gap--regular',\n level: LogLevel.VERBOSE,\n },\n processRunning: {\n icon: 'ph--spinner-gap--regular',\n level: LogLevel.VERBOSE,\n },\n} as const;\n\nexport interface BuildExecutionGraphParams {\n traceMessages: readonly Trace.Message[];\n activeProcesses?: readonly Process.Info[];\n collapseCompletedSpans?: boolean;\n eventLimit?: number;\n /**\n * Duration a span may sit open with no new events before it's force-closed with a synthetic\n * end event. Only takes effect when `now` is also provided. Defaults to\n * `DEFAULT_SPAN_TIMEOUT_MS`.\n */\n spanTimeoutMs?: number;\n /**\n * Reference time used to detect abandoned spans. Force-closing is skipped entirely when this\n * is omitted.\n */\n now?: number;\n}\n\n/**\n * Builds a Timeline-compatible execution graph from trace messages and active processes.\n *\n * The conversion runs in two stages:\n * 1. `buildSpanTree` converts the flat list of trace messages into a hierarchical\n * tree of spans grouped by process id (pid). See `./span-tree.ts`.\n * 2. `spanTreeToCommits` walks the tree and emits one commit per event, using the\n * tree structure to decide which branch each commit belongs to and how to wire parents.\n *\n * Pure function — no signals or atoms.\n */\nexport type ExecutionGraph = {\n branches: string[];\n commits: Commit[];\n spanTree: Span;\n /** Commit id -> trace event. */\n details: ExecutionGraphDetailsMap;\n};\n\nexport type ExecutionGraphDetailsMap = Record<string, Trace.FlatEvent | undefined>;\n\nexport const buildExecutionGraph = ({\n traceMessages,\n activeProcesses = [],\n collapseCompletedSpans = false,\n eventLimit = 500,\n spanTimeoutMs,\n now,\n}: BuildExecutionGraphParams): ExecutionGraph => {\n const spanTree = buildSpanTree(traceMessages, { eventLimit, spanTimeoutMs, now });\n const toolCallContext = buildToolCallContext(traceMessages);\n const built = spanTreeToCommits(spanTree, activeProcesses, toolCallContext, collapseCompletedSpans);\n log('trace execution graph', {\n traceMessages: traceMessages.length,\n commits: built.commits.length,\n branches: built.branches.length,\n activeProcesses: activeProcesses.length,\n });\n return { ...built, spanTree };\n};\n\n/**\n * Lookup tables that pair `toolCall` blocks with their matching `toolResult` blocks so the\n * renderer can collapse the two events into a single commit (mirroring how begin/end events of\n * an empty operation span collapse). Indexed by the shared `toolCallId`.\n */\ninterface ToolCallContext {\n callById: Map<string, ContentBlock.ToolCall>;\n resultByCallId: Map<string, ContentBlock.ToolResult>;\n}\n\nconst buildToolCallContext = (messages: readonly Trace.Message[]): ToolCallContext => {\n const callById = new Map<string, ContentBlock.ToolCall>();\n const resultByCallId = new Map<string, ContentBlock.ToolResult>();\n for (const message of messages) {\n for (const event of message.events) {\n if (event.type !== Trace.CompleteBlock.key) {\n continue;\n }\n const data = event.data as { block?: ContentBlock.Any } | undefined;\n const block = data?.block;\n if (!block) {\n continue;\n }\n if (block._tag === 'toolCall') {\n callById.set(block.toolCallId, block);\n } else if (block._tag === 'toolResult') {\n resultByCallId.set(block.toolCallId, block);\n }\n }\n }\n return { callById, resultByCallId };\n};\n\n/**\n * Visual representation of a single trace event — icon, log level, message string.\n * `undefined` indicates that the event should not produce a commit.\n */\ninterface EventPresentation {\n icon: string;\n level: LogLevel;\n message: string;\n idSuffix?: string;\n}\n\ntype AgentRequestEndData = Schema.Schema.Type<typeof Trace.AgentRequestEnd.schema>;\n\n/**\n * Parses `Trace.AgentRequestEnd` payload, accepting legacy traces that omitted `status`.\n */\nconst parseAgentRequestEnd = (data: unknown): AgentRequestEndData | undefined => {\n if (Schema.is(Trace.AgentRequestEnd.schema)(data)) {\n return data;\n }\n // Traces emitted before `status` was added wrote an empty object.\n if (data != null && typeof data === 'object' && Object.keys(data).length === 0) {\n return { status: 'success' };\n }\n log('invalid trace event', { type: Trace.AgentRequestEnd.key });\n return undefined;\n};\n\nconst presentAgentRequestEnd = (data: AgentRequestEndData): EventPresentation => {\n switch (data.status) {\n case 'error':\n return {\n icon: ICONS.agentRequestEndError.icon,\n level: ICONS.agentRequestEndError.level,\n message: data.error ? trimText(`Agent request failed: ${data.error}`) : 'Agent request failed',\n };\n case 'interrupted':\n return {\n icon: ICONS.agentRequestEndInterrupted.icon,\n level: ICONS.agentRequestEndInterrupted.level,\n message: 'Agent request interrupted',\n };\n default:\n return {\n icon: ICONS.agentRequestEndSuccess.icon,\n level: ICONS.agentRequestEndSuccess.level,\n message: 'Agent completed request',\n };\n }\n};\n\nconst presentEvent = (event: Trace.FlatEvent, toolCallContext: ToolCallContext): EventPresentation | undefined => {\n if (Trace.isOfType(Trace.AgentRequestBegin, event)) {\n if (!Schema.is(Trace.AgentRequestBegin.schema)(event.data)) {\n log('invalid trace event', { type: event.type });\n return undefined;\n }\n return {\n icon: ICONS.agentRequestBegin.icon,\n level: ICONS.agentRequestBegin.level,\n message: 'Agent processing request...',\n };\n }\n if (Trace.isOfType(Trace.AgentRequestEnd, event)) {\n const endData = parseAgentRequestEnd(event.data);\n if (!endData) {\n return undefined;\n }\n return presentAgentRequestEnd(endData);\n }\n if (Trace.isOfType(Trace.CompleteBlock, event)) {\n if (!Schema.is(Trace.CompleteBlock.schema)(event.data)) {\n log('invalid trace event', { type: event.type });\n return undefined;\n }\n switch (event.data.block._tag) {\n case 'text':\n return event.data.role === 'user'\n ? {\n icon: ICONS.userMessage.icon,\n level: ICONS.userMessage.level,\n message: trimText(event.data.block.text),\n }\n : undefined;\n case 'status':\n return {\n icon: ICONS.statusMessage.icon,\n level: ICONS.statusMessage.level,\n message: trimText(event.data.block.statusText),\n };\n case 'toolCall': {\n // Operation-backed tool calls already have a dedicated routine span (Trace.OperationStart /\n // Trace.OperationEnd) that produces its own commits — skip the duplicate toolCall commit\n // to avoid double-rendering.\n if (event.data.block.operationKey) {\n return undefined;\n }\n // Collapse the toolCall/toolResult pair: when the matching toolResult has arrived, the\n // result event is the visible commit and carries the success/error state. The toolCall\n // itself only renders while still pending (i.e. no result yet) — same intent as an\n // operation span that collapses to a single end commit once both boundaries are present.\n if (toolCallContext.resultByCallId.has(event.data.block.toolCallId)) {\n return undefined;\n }\n return {\n icon: ICONS.toolCall.icon,\n level: ICONS.toolCall.level,\n message: event.data.block.name,\n idSuffix: `toolCall:${event.data.block.toolCallId}`,\n };\n }\n case 'toolResult': {\n // Suppress results for operation-backed calls — those are covered by the routine span.\n const call = toolCallContext.callById.get(event.data.block.toolCallId);\n if (call?.operationKey) {\n return undefined;\n }\n const success = event.data.block.error === undefined;\n const name = call?.name ?? event.data.block.name;\n return {\n icon: success ? ICONS.toolResultSuccess.icon : ICONS.toolResultError.icon,\n level: success ? ICONS.toolResultSuccess.level : ICONS.toolResultError.level,\n message: `${name}${!success ? ' - Error' : ''}`,\n idSuffix: `toolResult:${event.data.block.toolCallId}`,\n };\n }\n default:\n return undefined;\n }\n }\n if (Trace.isOfType(Trace.OperationStart, event)) {\n if (!Schema.is(Trace.OperationStart.schema)(event.data)) {\n log('invalid trace event', { type: event.type });\n return undefined;\n }\n return {\n icon: event.data.icon ?? ICONS.operationStart.icon,\n level: ICONS.operationStart.level,\n message: event.data.name ?? event.data.key,\n idSuffix: `${event.data.key}:start`,\n };\n }\n if (Trace.isOfType(Trace.OperationEnd, event)) {\n if (!Schema.is(Trace.OperationEnd.schema)(event.data)) {\n log('invalid trace event', { type: event.type });\n return undefined;\n }\n // A `RunAgainError` (Operation.runAgain) is a scheduler yield, not a hard error: the trace records\n // it as a failure tagged with the run-again error code, but it will be re-invoked. Detect it here\n // and present it as a distinct warn-level state rather than folding it into failure. Fall back to\n // the legacy message for events persisted before `errorCode` existed.\n const incomplete =\n event.data.outcome === 'failure' &&\n (event.data.errorCode === RUN_AGAIN_ERROR_CODE ||\n (event.data.errorCode === undefined && event.data.error === RUN_AGAIN_MESSAGE));\n const presentation =\n event.data.outcome === 'success'\n ? { icon: ICONS.operationEndSuccess.icon, level: ICONS.operationEndSuccess.level, suffix: '' }\n : incomplete\n ? {\n icon: ICONS.operationEndIncomplete.icon,\n level: ICONS.operationEndIncomplete.level,\n suffix: ' - Incomplete',\n }\n : { icon: ICONS.operationEndError.icon, level: ICONS.operationEndError.level, suffix: ' - Error' };\n return {\n icon: event.data.icon ?? presentation.icon,\n level: presentation.level,\n message: `${event.data.name ?? event.data.key}${presentation.suffix}`,\n idSuffix: `${event.data.key}:end`,\n };\n }\n return undefined;\n};\n\nexport type CollectProcessActivityOptions = {\n /**\n * When set, messages with a `conversationId` that disagrees are excluded.\n * Messages without `conversationId` still match when their pid is in the subtree.\n */\n conversationId?: string;\n eventLimit?: number;\n};\n\n/**\n * Collects human-readable activity lines for a process subtree (root pid and descendants).\n * Used to surface live sub-agent status in the task list.\n */\nexport const collectProcessActivityLines = (\n messages: readonly Trace.Message[],\n rootPid: string,\n options: CollectProcessActivityOptions = {},\n): string[] => {\n const { conversationId, eventLimit = 50 } = options;\n const descendantPids = collectDescendantPids(messages, rootPid);\n const filtered = messages.filter((message) => {\n const pid = message.meta.pid;\n if (!pid || !descendantPids.has(pid)) {\n return false;\n }\n const metaConvId = message.meta.conversation\n ? EID.getEntityId(EID.parse(message.meta.conversation.uri))\n : undefined;\n if (conversationId && metaConvId !== undefined && metaConvId !== conversationId) {\n return false;\n }\n return true;\n });\n\n const events = filtered\n .flatMap((message) => Trace.flatten(message))\n .sort((left, right) => left.timestamp - right.timestamp)\n .slice(-eventLimit);\n\n const toolCallContext = buildToolCallContext(filtered);\n const lines: string[] = [];\n for (const event of events) {\n const presentation = presentEvent(event, toolCallContext);\n if (presentation) {\n lines.push(presentation.message);\n }\n }\n return lines;\n};\n\n/**\n * Derives a single in-flight status line from durable trace when ephemeral subscription\n * is unavailable (e.g. between partial blocks or while a child operation is running).\n */\nexport const deriveInFlightActivityLine = (\n messages: readonly Trace.Message[],\n rootPid: string,\n options: CollectProcessActivityOptions = {},\n): string | undefined => {\n const { conversationId, eventLimit = 50 } = options;\n const descendantPids = collectDescendantPids(messages, rootPid);\n const filtered = messages.filter((message) => {\n const pid = message.meta.pid;\n if (!pid || !descendantPids.has(pid)) {\n return false;\n }\n const metaConvId = message.meta.conversation\n ? EID.getEntityId(EID.parse(message.meta.conversation.uri))\n : undefined;\n if (conversationId && metaConvId !== undefined && metaConvId !== conversationId) {\n return false;\n }\n return true;\n });\n\n const events = filtered\n .flatMap((message) => Trace.flatten(message))\n .sort((left, right) => left.timestamp - right.timestamp)\n .slice(-eventLimit);\n\n const openOperations = new Map<string, { name: string; timestamp: number }>();\n let agentRequestOpen = false;\n let lastLine: string | undefined;\n\n for (const event of events) {\n const pid = event.meta.pid ?? rootPid;\n if (Trace.isOfType(Trace.OperationStart, event)) {\n const key = `${pid}:${event.data.key}`;\n const name = event.data.name ?? event.data.key;\n openOperations.set(key, { name, timestamp: event.timestamp });\n lastLine = `${name}...`;\n continue;\n }\n if (Trace.isOfType(Trace.OperationEnd, event)) {\n openOperations.delete(`${pid}:${event.data.key}`);\n continue;\n }\n if (Trace.isOfType(Trace.AgentRequestBegin, event)) {\n agentRequestOpen = true;\n lastLine = 'Generating...';\n continue;\n }\n if (Trace.isOfType(Trace.AgentRequestEnd, event)) {\n agentRequestOpen = false;\n }\n }\n\n if (agentRequestOpen) {\n return 'Generating...';\n }\n\n const latestOperation = [...openOperations.values()].sort((left, right) => right.timestamp - left.timestamp)[0];\n if (latestOperation) {\n return `${latestOperation.name}...`;\n }\n\n return lastLine;\n};\n\nconst collectDescendantPids = (messages: readonly Trace.Message[], rootPid: string): Set<string> => {\n const pids = new Set([rootPid]);\n let expanded = true;\n while (expanded) {\n expanded = false;\n for (const message of messages) {\n const pid = message.meta.pid;\n const parentPid = message.meta.parentPid;\n if (pid && parentPid && pids.has(parentPid) && !pids.has(pid)) {\n pids.add(pid);\n expanded = true;\n }\n }\n }\n return pids;\n};\n\nconst isPendingToolCallEvent = (event: Trace.FlatEvent, toolCallContext: ToolCallContext): boolean => {\n if (!Trace.isOfType(Trace.CompleteBlock, event)) {\n return false;\n }\n if (event.data.block._tag !== 'toolCall') {\n return false;\n }\n return !toolCallContext.resultByCallId.has(event.data.block.toolCallId);\n};\n\n/**\n * A span is completed when its last recorded event is a matching end boundary.\n */\nconst isCompletedSpan = (span: Span): boolean => {\n if (span.id === ROOT_SPAN_ID) {\n return false;\n }\n const lastEvent = span.events[span.events.length - 1];\n return lastEvent !== undefined && isSpanEndEvent(lastEvent);\n};\n\n/**\n * A span is \"collapsible\" when it would otherwise render as an empty fork-and-merge:\n * exactly two events that form a begin/end pair and no child sub-spans. In that case\n * we emit a single commit for the end event on the parent branch.\n *\n * When `collapseCompletedSpans` is enabled, any completed span collapses to that single\n * end commit — middle events, child sub-spans, and the begin fork are all omitted.\n *\n * A *pending* span (one whose end event has not yet been recorded) is never collapsed:\n * its trailing events should keep rendering as middle commits on the span's own branch\n * — never as a fake \"end\" commit on the parent branch.\n *\n * Both nested spans and top-level spans (whose parent is the synthetic root) are eligible\n * once they have completed: a span with no inner activity is collapsed regardless of where\n * it sits in the tree.\n */\nconst isCollapsibleSpan = (span: Span, parent: Span | null, collapseCompletedSpans: boolean): boolean => {\n if (span.id === ROOT_SPAN_ID) {\n return false;\n }\n if (parent === null) {\n return false;\n }\n if (span.events.length === 2 && span.children.length === 0) {\n const firstEvent = span.events[0];\n const lastEvent = span.events[span.events.length - 1];\n if (isSpanBeginEvent(firstEvent) && isSpanEndEvent(lastEvent)) {\n return true;\n }\n }\n if (collapseCompletedSpans && isCompletedSpan(span)) {\n return true;\n }\n return false;\n};\n\n/**\n * Converts a span tree into a flat list of commits + branches suitable for `Timeline` rendering.\n *\n * For every span the algorithm:\n * - emits the **first** event as a \"begin\" commit on the parent span's branch (fork);\n * - emits **middle** events as commits on the span's own branch;\n * - emits the **last** event as an \"end\" commit on the parent span's branch with two parents\n * (the begin commit and the last commit on the span's own branch — a merge).\n *\n * Collapsible spans (`isCollapsibleSpan`) emit only the end commit on the parent branch with\n * a single parent — a tidier rendering for sub-operations that have no inner detail.\n *\n * Events are processed in categorical span-tree order: each span's begin events, its child\n * subtrees (depth-first), then its remaining events. Active-process running rows are inserted\n * at the end of each matching span block — not appended after the entire tree.\n */\nconst spanTreeToCommits = (\n root: Span,\n activeProcesses: readonly Process.Info[],\n toolCallContext: ToolCallContext,\n collapseCompletedSpans: boolean,\n): { branches: string[]; commits: Commit[]; details: ExecutionGraphDetailsMap } => {\n const builder = new GraphBuilder();\n const details: ExecutionGraphDetailsMap = {};\n builder.addBranch(MAIN_BRANCH);\n\n // Build a child → parent lookup using the tree's own structure (already correctly parented\n // when the tree was constructed, including sequential spans of the same process).\n const parentBySpan = new Map<Span, Span | null>();\n parentBySpan.set(root, null);\n const indexParents = (span: Span): void => {\n for (const child of span.children) {\n parentBySpan.set(child, span);\n indexParents(child);\n }\n };\n indexParents(root);\n\n const findParentSpan = (span: Span): Span | null => parentBySpan.get(span) ?? null;\n\n const collapsedSpanIds = new Set<string>();\n walkSpanTree(root, (span) => {\n if (isCollapsibleSpan(span, findParentSpan(span), collapseCompletedSpans)) {\n collapsedSpanIds.add(span.id);\n }\n });\n\n const isUnderCollapsedAncestor = (span: Span): boolean => {\n let ancestor = findParentSpan(span);\n while (ancestor) {\n if (collapsedSpanIds.has(ancestor.id)) {\n return true;\n }\n ancestor = findParentSpan(ancestor);\n }\n return false;\n };\n\n // The branch name for a span is its pid — multiple sequential spans of the same process\n // (e.g. successive agent requests in one session) share a branch so they reuse a single lane.\n const branchOf = (span: Span | null): string => {\n if (!span || span.id === ROOT_SPAN_ID) {\n return MAIN_BRANCH;\n }\n return span.meta.pid ?? span.id;\n };\n\n // Track the id of the begin commit for each non-collapsible span so the end commit can merge into it.\n const beginCommitIdBySpan = new Map<string, string>();\n\n // Selector that returns \"the most recent commit in this span's structural context\".\n //\n // The walk is structural (pid/parentPid), not topological: at each ancestor, we prefer\n // 1) the last commit on that span's own branch, then\n // 2) that span's begin commit (the fork point on its parent branch),\n // 3) and only then recurse into the parent span.\n //\n // Crucially, we never silently slip onto a *sibling* span's commit on a shared ancestor\n // branch. E.g. if a sub-span of agent A fires before A has any middle commits, we anchor\n // to A.begin — not to whatever unrelated commit happens to be the latest on main.\n // This keeps fork edges visually attached to the correct span even when sibling top-level\n // spans (different pids) overlap in time on main.\n const lastInSpanContext = (span: Span | null): CommitSelector => {\n if (!span || span.id === ROOT_SPAN_ID) {\n return CommitSelector.branch(MAIN_BRANCH).pipe(CommitSelector.compose(CommitSelector.last()));\n }\n const ownBranch = branchOf(span);\n const beginId = beginCommitIdBySpan.get(span.id);\n return CommitSelector.firstOf(\n CommitSelector.branch(ownBranch).pipe(CommitSelector.compose(CommitSelector.last())),\n beginId ? CommitSelector.id(beginId) : CommitSelector.filter(() => false),\n lastInSpanContext(findParentSpan(span)),\n );\n };\n\n const lastCommitIdBySpan = new Map<string, string>();\n let globalIndex = 0;\n const insertedRunningPids = new Set<string>();\n const activeProcessByPid = new Map(activeProcesses.map((process) => [process.pid, process]));\n\n const emitRunningIndicator = (pid: Process.ID): void => {\n if (insertedRunningPids.has(pid)) {\n return;\n }\n\n const process = activeProcessByPid.get(pid);\n if (!process) {\n return;\n }\n\n if (\n Process.isHarnessHost(process) &&\n Option.isSome(Annotation.getDictionary(process.params.annotations, Process.TargetAnnotation)) &&\n (process.state === Process.State.RUNNING || process.state === Process.State.HYBERNATING)\n ) {\n builder.addCommit({\n id: `running:${process.pid}`,\n branch: process.pid,\n // Falls back to the tail of main: a completed request collapses onto main, leaving the\n // agent's own branch empty, and a parentless spinner draws as a second, disconnected root.\n parents: builder.computeParents(\n CommitSelector.firstOf(\n CommitSelector.branch(process.pid).pipe(CommitSelector.compose(CommitSelector.last())),\n CommitSelector.branch(MAIN_BRANCH).pipe(CommitSelector.compose(CommitSelector.last())),\n ),\n ),\n icon: ICONS.agentRequestRunning.icon,\n level: ICONS.agentRequestRunning.level,\n message: 'Generating...',\n timestamp: new Date(),\n tags: [SHIMMER_EFFECT_TAG],\n });\n insertedRunningPids.add(pid);\n } else if (process.state === Process.State.RUNNING && builder.hasBranch(process.pid)) {\n builder.addCommit({\n id: `running:${process.pid}`,\n branch: process.pid,\n parents: builder.computeParents(\n CommitSelector.branch(process.pid).pipe(CommitSelector.compose(CommitSelector.last())),\n ),\n icon: ICONS.processRunning.icon,\n level: ICONS.processRunning.level,\n message: 'Running...',\n timestamp: new Date(),\n tags: [SHIMMER_EFFECT_TAG],\n });\n insertedRunningPids.add(pid);\n }\n };\n\n const emitEventCommit = (span: Span, event: Trace.FlatEvent, eventIndex: number): void => {\n const presentation = presentEvent(event, toolCallContext);\n if (!presentation) {\n return;\n }\n\n // Classify based on event TYPE, not array index. A pending span's trailing\n // middle event (e.g. a user message awaiting an agent response) must not be\n // mistaken for the span's end event — otherwise it would render on the\n // parent branch instead of the span's own branch.\n const isBeginEvent = isSpanBeginEvent(event);\n const isEndEvent = isSpanEndEvent(event);\n const parentSpan = findParentSpan(span);\n const collapsible = isCollapsibleSpan(span, parentSpan, collapseCompletedSpans);\n\n // Descendants of a collapsed span emit no commits — inner activity is folded into the ancestor end row.\n if (isUnderCollapsedAncestor(span)) {\n return;\n }\n\n // Collapsed spans: skip every event except the end commit.\n if (collapsible && !isEndEvent) {\n return;\n }\n\n const parentBranch = branchOf(parentSpan);\n const ownBranch = branchOf(span);\n\n // A \"process boundary\" span is a concurrent child PROCESS (its own pid, differing from the\n // parent's) with real sub-flow content (a middle event) — e.g. a delegated sub-agent. Such a\n // span gets its own lane: it forks onto its own branch at begin and collapses back to main at\n // end (so neither its lane nor its parent's lane dangles). A bare operation (begin+end only)\n // collapses to a single commit and is NOT treated as a boundary — forking its transient begin\n // mid-stream would flash a throwaway lane.\n const ownPid = span.meta.pid;\n const parentPid = parentSpan?.meta.pid;\n const spanHasMiddle = span.events.some((spanEvent) => !isSpanBeginEvent(spanEvent) && !isSpanEndEvent(spanEvent));\n const isProcessBoundary = ownPid != null && parentPid != null && ownPid !== parentPid && spanHasMiddle;\n\n let branch: string;\n let parents: string[];\n\n if (span.id === ROOT_SPAN_ID) {\n // Root-level events (no pid) attach sequentially to main.\n branch = MAIN_BRANCH;\n parents = builder.computeParents(lastInSpanContext(null));\n } else if (collapsible) {\n // Only the end event reaches here for collapsible spans.\n // Anchor to the parent span's structural context so the fork attaches to the parent\n // — not to a sibling span's commit that happens to be the latest on the shared ancestor.\n branch = parentBranch;\n parents = builder.computeParents(lastInSpanContext(parentSpan));\n } else if (isBeginEvent) {\n // Begin commit, anchored to the parent's structural context. A nested sub-span stays on the\n // parent lane (only its middle events fork). A concurrent child process forks onto its own\n // branch from this first event so it gets its own lane immediately.\n branch = isProcessBoundary ? ownBranch : parentBranch;\n parents = builder.computeParents(lastInSpanContext(parentSpan));\n } else if (isEndEvent) {\n // End commit: continues the parent branch chronologically and merges in own-branch work.\n //\n // Parent #1 is the *immediate predecessor* on the parent branch (not the matching begin\n // commit). Pointing back to the begin commit creates a visual edge that skips over any\n // sibling span's commits emitted between begin and end — e.g. when two top-level Routine\n // spans overlap on main, R1.end would otherwise draw an arrow back to R1.begin that\n // crosses over R2.begin. Anchoring to the previous main commit keeps main linear.\n //\n // A concurrent child process collapses all the way back to MAIN (merging its own branch),\n // rather than to its parent's branch: the parent (e.g. a supervisor whose turn already merged\n // to main) would otherwise gain commits after its own merge and never re-collapse — leaving a\n // dangling lane after the child finishes.\n branch = isProcessBoundary ? MAIN_BRANCH : parentBranch;\n parents = builder.computeParents(\n CommitSelector.unionAll(\n CommitSelector.branch(branch).pipe(CommitSelector.compose(CommitSelector.last())),\n CommitSelector.branch(ownBranch).pipe(CommitSelector.compose(CommitSelector.last())),\n ),\n );\n } else {\n // Middle event: continue the span's own branch; fall back to span's own context so the\n // first middle event of a span forks from the span's begin commit, not from a sibling's\n // commit on an ancestor branch.\n branch = ownBranch;\n parents = builder.computeParents(lastInSpanContext(span));\n }\n\n const commitIndex = globalIndex++;\n const commitId = formatCommitId(span, commitIndex, presentation.idSuffix);\n // A pending tool call still in flight gets Timeline shimmer styling.\n const shimmer = isPendingToolCallEvent(event, toolCallContext);\n const commit: Commit = {\n id: commitId,\n branch,\n parents,\n timestamp: new Date(event.timestamp),\n icon: presentation.icon,\n level: presentation.level,\n message: presentation.message,\n ...(shimmer && { tags: [SHIMMER_EFFECT_TAG] }),\n };\n builder.addCommit(commit);\n details[commitId] = event;\n lastCommitIdBySpan.set(span.id, commitId);\n\n // Record begin commit so a later end event can merge into it.\n if (isBeginEvent && !collapsible && span.id !== ROOT_SPAN_ID) {\n beginCommitIdBySpan.set(span.id, commitId);\n }\n };\n\n const finishSpan = (span: Span): void => {\n const pid = span.meta.pid;\n if (pid) {\n // Trace.Meta.pid is plain string (avoids circular dep); construct brand here.\n emitRunningIndicator(Process.ID.make(pid));\n }\n\n if (span.id === ROOT_SPAN_ID || isCompletedSpan(span)) {\n return;\n }\n\n if (pid && insertedRunningPids.has(pid)) {\n return;\n }\n\n const lastCommitId = lastCommitIdBySpan.get(span.id);\n if (lastCommitId) {\n builder.addTag(lastCommitId, SHIMMER_EFFECT_TAG);\n }\n };\n\n const emitSpanCommits = (span: Span): void => {\n for (let eventIndex = 0; eventIndex < span.events.length; eventIndex += 1) {\n const event = span.events[eventIndex]!;\n if (isSpanBeginEvent(event)) {\n emitEventCommit(span, event, eventIndex);\n }\n }\n\n for (const child of span.children) {\n emitSpanCommits(child);\n }\n\n for (let eventIndex = 0; eventIndex < span.events.length; eventIndex += 1) {\n const event = span.events[eventIndex]!;\n if (!isSpanBeginEvent(event)) {\n emitEventCommit(span, event, eventIndex);\n }\n }\n\n finishSpan(span);\n };\n\n emitSpanCommits(root);\n\n for (const process of activeProcesses) {\n emitRunningIndicator(process.pid);\n }\n\n const { commits, branches } = builder.build();\n return { commits, branches, details };\n};\n\nconst formatCommitId = (span: Span, globalIndex: number, suffix?: string): string => {\n const base = `${span.id}:${globalIndex}`;\n return suffix ? `${base}:${suffix}` : base;\n};\n\nconst trimText = (text: string) => text.slice(0, 100).trim().split('\\n')[0];\n\ntype Falsy = false | null | undefined;\n\nexport interface CommitSelector extends Pipeable.Pipeable {\n select: (commits: Commit[]) => Commit[];\n}\n\nexport const CommitSelector = {\n make: (select: CommitSelector['select']): CommitSelector => ({\n select,\n pipe(...args: any) {\n return Pipeable.pipeArguments(this, args);\n },\n }),\n\n identity: (): CommitSelector => CommitSelector.make((commits) => commits),\n\n /**\n * Selects commits that match the given predicate.\n */\n filter: (predicate: (commit: Commit) => unknown): CommitSelector =>\n CommitSelector.make((commits) => commits.filter(predicate)),\n\n /**\n * Selects commits by id.\n */\n id: (id: string): CommitSelector => CommitSelector.filter((commit) => commit.id === id),\n /**\n * Selects commits by tag.\n */\n tag: (tag: string | Falsy): CommitSelector => CommitSelector.filter((commit) => tag && commit.tags?.includes(tag)),\n /**\n * Selects commits by if any of the given tags are present.\n */\n anyTags: (tags: (string | Falsy)[]): CommitSelector =>\n CommitSelector.filter((commit) => tags.some((tag) => tag && commit.tags?.includes(tag))),\n /**\n * Selects commits by branch.\n */\n branch: (branch: string | Falsy): CommitSelector =>\n CommitSelector.filter((commit) => branch && commit.branch === branch),\n\n /**\n * Chains two selectors together, applying the second selector to the result of the first.\n *\n * Example:\n *\n * ```\n * CommitSelector.tag('tag').pipe(CommitSelector.compose(CommitSelector.branch('main')));\n * ```\n */\n compose:\n (next: CommitSelector) =>\n (prev: CommitSelector): CommitSelector =>\n CommitSelector.make((commits) => next.select(prev.select(commits))),\n\n /**\n * If `prev` selector matches no commits, return `next` selector, otherwise return `prev` selector.\n * Same as `CommitSelector.firstOf(prev, next)`.\n *\n * Example:\n *\n * ```\n * CommitSelector.tag('tag').pipe(CommitSelector.orElse(CommitSelector.branch('main')));\n * ```\n */\n orElse:\n (next: CommitSelector) =>\n (prev: CommitSelector): CommitSelector =>\n CommitSelector.make((commits) => {\n const selected = prev.select(commits);\n if (selected.length > 0) {\n return selected;\n }\n return next.select(commits);\n }),\n\n /**\n * Selects commits that match either of the given selectors.\n */\n andAlso:\n (next: CommitSelector) =>\n (prev: CommitSelector): CommitSelector =>\n CommitSelector.unionAll(prev, next),\n\n /**\n * Selects the first n commits.\n */\n first: (n: number = 1): CommitSelector => CommitSelector.make((commits) => commits.slice(0, n)),\n /**\n * Selects the last n commits (reverses the order of the commits).\n */\n last: (n: number = 1): CommitSelector => CommitSelector.make((commits) => commits.toReversed().slice(0, n)),\n /**\n * Selects commits that do not match the given selector.\n */\n not: (selector: CommitSelector): CommitSelector =>\n CommitSelector.make((commits) => {\n const selected = selector.select(commits);\n return commits.filter((commit) => !selected.includes(commit));\n }),\n\n /**\n * Selects commits that match any of the given selectors.\n */\n unionAll: (...selectors: CommitSelector[]): CommitSelector =>\n CommitSelector.make((commits) => {\n return Array.dedupeWith(\n selectors.flatMap((selector) => selector.select(commits)),\n (a, b) => a.id === b.id,\n );\n }),\n\n /**\n * Selects commits that match all of the given selectors.\n */\n intersectAll: (...selectors: CommitSelector[]): CommitSelector =>\n CommitSelector.make((commits) => {\n const selected = selectors.map((selector) => selector.select(commits));\n if (selected.length === 0) {\n return [];\n }\n return selected[0].filter((commit) => selected.every((selected) => selected.some((c) => c.id === commit.id)));\n }),\n\n /**\n * Returns the result of the first selector that matches any commits.\n */\n firstOf: (...selectors: CommitSelector[]): CommitSelector =>\n CommitSelector.make((commits) => {\n for (const selector of selectors) {\n const selected = selector.select(commits);\n if (selected.length > 0) {\n return selected;\n }\n }\n return [];\n }),\n};\n\nclass GraphBuilder {\n #commits: Commit[] = [];\n #branches = new Set<string>();\n\n findCommits(selector: CommitSelector): Commit[] {\n return selector.select(this.#commits);\n }\n\n hasBranch(branch: string): boolean {\n return this.#branches.has(branch);\n }\n\n addCommit(commit: Commit) {\n this.addBranch(commit.branch);\n this.#commits.push(commit);\n }\n\n addTag(commitId: string, tag: string) {\n const index = this.#commits.findIndex((commit) => commit.id === commitId);\n if (index < 0) {\n return;\n }\n const commit = this.#commits[index]!;\n if (commit.tags?.includes(tag)) {\n return;\n }\n this.#commits[index] = { ...commit, tags: [...(commit.tags ?? []), tag] };\n }\n\n /**\n * Computes parents — picks first matching commit's id.\n */\n computeParents(selector: CommitSelector): string[] {\n return Array.dedupe(selector.select(this.#commits).map((commit) => commit.id));\n }\n\n addBranch(branch: string) {\n this.#branches.add(branch);\n }\n\n /**\n * Removes duplicate commits and dangling parents.\n */\n doctor() {\n this.#commits = pipe(\n this.#commits,\n Array.dedupeWith((a, b) => a.id === b.id),\n Array.map(\n Struct.evolve({\n parents: (parents) =>\n parents ? Array.filter(parents, (id) => this.#commits.some((commit) => commit.id === id)) : undefined,\n }),\n ),\n );\n }\n\n build() {\n this.doctor();\n return {\n commits: this.#commits,\n branches: [...this.#branches],\n };\n }\n}\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Trace from '@dxos/compute/Trace';\nimport { type ContentBlock } from '@dxos/types';\n\n/**\n * Approximate streamed token count from partial text (UTF-8 length / 4).\n */\nexport const estimateTokenCount = (text: string): number =>\n Math.max(1, Math.ceil(new TextEncoder().encode(text).length / 4));\n\nconst formatOperationInputStatus = (data: { key: string; name?: string; input: unknown }): string => {\n const name = data.name ?? data.key;\n const bytes = new TextEncoder().encode(JSON.stringify(data.input)).length;\n return `Calling ${name} (${bytes} bytes)...`;\n};\n\n/** Raw routine status updates (e.g. `Running 01KVB9WBRG…`) carry an opaque ULID, not a useful label. */\nconst ROUTINE_ULID_STATUS = /^Running [0-9A-HJKMNP-TV-Z]{26}$/i;\n\n/**\n * Formats a pending assistant block for the delegated-task status line.\n */\nexport const formatPendingBlockStatus = (block: ContentBlock.Any): string | undefined => {\n if (!block.pending) {\n return undefined;\n }\n\n if (block._tag === 'text') {\n return `Generating ${estimateTokenCount(block.text)} tokens....`;\n }\n\n if (block._tag === 'toolCall') {\n const bytes = new TextEncoder().encode(block.input).length;\n const name = block.operationName ?? block.name;\n return `Calling ${name} (${bytes} bytes)...`;\n }\n\n return undefined;\n};\n\n/**\n * Reads the latest pending partial block from an ephemeral trace message.\n */\nexport const pendingStatusFromEphemeralMessage = (message: Trace.Message): string | undefined => {\n for (const event of message.events) {\n if (Trace.isOfType(Trace.PartialBlock, event)) {\n const status = formatPendingBlockStatus(event.data.block);\n if (status) {\n return status;\n }\n continue;\n }\n\n if (Trace.isOfType(Trace.OperationInput, event)) {\n return formatOperationInputStatus(event.data);\n }\n\n if (Trace.isOfType(Trace.StatusUpdate, event)) {\n const message = event.data.message?.trim();\n // Suppress opaque routine ULID lines so descriptive partial-block / operation-input lines win.\n if (!message || ROUTINE_ULID_STATUS.test(message)) {\n continue;\n }\n return message;\n }\n }\n return undefined;\n};\n\nexport type EphemeralStatusUpdate = 'unchanged' | { readonly line: string };\n\n/**\n * Maps an ephemeral trace message to a task-status update.\n *\n * The status line is \"sticky\": a message without a pending line (e.g. a completed block during an\n * LLM-thinking gap) leaves the previous line in place rather than clearing it, so the row keeps\n * showing the latest meaningful activity until a new line arrives or the subscription ends.\n */\nexport const resolveEphemeralStatusUpdate = (message: Trace.Message): EphemeralStatusUpdate => {\n const line = pendingStatusFromEphemeralMessage(message);\n if (line) {\n return { line };\n }\n return 'unchanged';\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Duration from 'effect/Duration';\nimport { pipe } from 'effect/Function';\nimport * as Atom from 'effect/unstable/reactivity/Atom';\nimport { useMemo } from 'react';\n\nimport { FeedTraceSink } from '@dxos/compute-runtime';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Filter, Query } from '@dxos/echo';\nimport { type Space } from '@dxos/react-client/echo';\n\nconst atomEmpty = Atom.make(() => [] as const);\n\n/**\n * Atom of raw trace messages for a space — the input to `buildExecutionGraph`.\n */\nexport const getTraceMessagesAtom = (space: Space): Atom.Atom<readonly Trace.Message[]> =>\n pipe(\n space.db.query(FeedTraceSink.query).atom,\n Atom.map(\n (feeds) =>\n // Query across ALL trace feeds: writers race on feed creation (the edge's indexer-backed\n // lookup can miss a not-yet-indexed feed and create a duplicate), so a space may hold\n // several trace feeds — reading only one would silently drop the others' events.\n space.db.query(\n feeds.length > 0\n ? Query.type(Trace.Message).from([...feeds])\n : (Query.select(Filter.nothing()) as Query.Query<never>),\n ).atom,\n ),\n (atom) => Atom.make((get) => get(get(atom))),\n );\n\nexport type UseTraceMessagesOptions = {\n /** Caps the re-render rate; the feed emits per message, which is far faster than a reader can read. */\n debounce?: Duration.Duration;\n};\n\n/**\n * Subscribes to the space invocation trace feed.\n */\nexport const useTraceMessages = (\n space?: Space,\n { debounce }: UseTraceMessagesOptions = {},\n): readonly Trace.Message[] => {\n const atom = useMemo(() => {\n if (!space) {\n return atomEmpty;\n }\n const traces = getTraceMessagesAtom(space);\n return debounce ? traces.pipe(Atom.debounce(debounce)) : traces;\n }, [space, debounce]);\n return useAtomValue(atom);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Duration from 'effect/Duration';\nimport { pipe } from 'effect/Function';\nimport * as Atom from 'effect/unstable/reactivity/Atom';\nimport { useEffect, useMemo, useState } from 'react';\n\nimport * as Process from '@dxos/compute/Process';\nimport { type Space } from '@dxos/react-client/echo';\n\nimport { filterTraceMessages } from '../components/TracePanel/trace-filter.ts';\nimport { type ExecutionGraph, buildExecutionGraph } from '../execution-graph/index.ts';\n\nimport { getTraceMessagesAtom } from './useTraceMessages.ts';\n\n// Stable refs.\nconst atomEmpty = Atom.make(() => [] as const);\nconst NO_PIDS: readonly string[] = [];\n\n// How often the graph re-checks for spans that timed out with no closing event.\n// Coarse-grained on purpose: `spanTimeoutMs` operates on a 20-minute scale, so there is no\n// benefit to re-deriving the graph more often than this just to catch the timeout crossing.\nconst SPAN_TIMEOUT_CHECK_INTERVAL_MS = 60_000;\n\nexport type UseExecutionGraphOptions = {\n collapseCompletedSpans?: boolean;\n eventLimit?: number;\n /** Pids to narrow the graph to (with their descendants); empty shows everything. */\n selectedPids?: readonly string[];\n};\n\n/**\n * The commit graph of a space's trace, rebuilt as messages land and as the process tree changes.\n * `processesAtom` is the host's live process tree (a running agent draws a spinner commit); without\n * it the graph is the durable trace alone.\n */\nexport const useExecutionGraph = (\n space: Space,\n processesAtom: Atom.Atom<readonly Process.Info[]> | undefined,\n { collapseCompletedSpans, eventLimit, selectedPids = NO_PIDS }: UseExecutionGraphOptions = {},\n): ExecutionGraph => {\n // Ticks periodically so spans that are still open purely because no new trace event has\n // arrived (e.g. the runtime crashed before writing its `operationEnd`) eventually get\n // force-closed by `buildExecutionGraph`'s `spanTimeoutMs` check, instead of staying stuck\n // until unrelated trace activity happens to trigger a recompute.\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const id = setInterval(() => setNow(Date.now()), SPAN_TIMEOUT_CHECK_INTERVAL_MS);\n return () => clearInterval(id);\n }, []);\n\n const atom = useMemo(\n () =>\n getExecutionGraph(space, processesAtom ?? atomEmpty, { collapseCompletedSpans, eventLimit, selectedPids, now }),\n [space, processesAtom, collapseCompletedSpans, eventLimit, selectedPids, now],\n );\n\n return useAtomValue(atom);\n};\n\n/** Identity for the graph: only a process appearing, disappearing or changing state redraws it. */\nconst sameProcesses = (left: readonly Process.Info[], right: readonly Process.Info[]): boolean =>\n left.length === right.length &&\n left.every((process, index) => process.pid === right[index].pid && process.state === right[index].state);\n\nconst getExecutionGraph = (\n space: Space,\n processesAtom: Atom.Atom<readonly Process.Info[]>,\n {\n collapseCompletedSpans = true,\n eventLimit = 100,\n selectedPids = NO_PIDS,\n now,\n }: UseExecutionGraphOptions & { now: number },\n): Atom.Atom<ExecutionGraph> => {\n const traceMessages = getTraceMessagesAtom(space).pipe(\n Atom.map((messages) => filterTraceMessages(messages, selectedPids)),\n );\n\n const activeProcesses = pipe(\n processesAtom,\n Atom.debounce(Duration.millis(500)),\n Atom.map((processes) =>\n processes.filter(\n (process) =>\n (process.state === Process.State.RUNNING || process.state === Process.State.HYBERNATING) &&\n (selectedPids.length === 0 || selectedPids.includes(process.pid)),\n ),\n ),\n // The monitor rebuilds the process list on every poll, so without a structural comparison the\n // graph would be rebuilt on each tick even when nothing moved.\n Atom.withEquality(sameProcesses),\n );\n\n return Atom.make((get) =>\n buildExecutionGraph({\n traceMessages: get(traceMessages),\n activeProcesses: get(activeProcesses),\n collapseCompletedSpans,\n eventLimit,\n now,\n }),\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Option from 'effect/Option';\nimport * as Schema from 'effect/Schema';\n\nimport * as Process from '@dxos/compute/Process';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Annotation } from '@dxos/echo';\nimport { EID } from '@dxos/keys';\nimport { Task } from '@dxos/types';\n\nimport { type Span, buildSpanTree, flattenSpanTree } from '../execution-graph/index.ts';\n\nimport {\n type Lane,\n type LaneStatus,\n type Marker,\n type Session,\n type SessionTimeline,\n type TokenUsage,\n} from './types.ts';\n\nexport interface BuildSessionTimelineInput {\n traceMessages: readonly Trace.Message[];\n processes?: readonly Process.Info[];\n /** The sessions to draw; each contributes a lane and its checklist's task lanes. */\n sessions?: readonly Session[];\n tasks?: readonly Task.Task[];\n /** Reference time; extends the range past open lanes. */\n now?: number;\n}\n\nconst ACTIVE_STATES = new Set<Process.State>([Process.State.RUNNING, Process.State.HYBERNATING]);\n\n/** How long an open lane may be silent before the axis stops following `now`. */\nconst OPEN_LANE_STALE_MS = 10 * 60_000;\n\nconst TASK_STATUS: Partial<Record<Task.Status, LaneStatus>> = {\n todo: 'pending',\n backlog: 'pending',\n blocked: 'blocked',\n started: 'running',\n review: 'review',\n done: 'done',\n failed: 'failed',\n};\n\n/** Entity id of an ECHO URI, the join key between a process target, a trace meta and a chat. */\nconst entityKey = (uri: string): string => {\n const eid = EID.tryParse(uri);\n return (eid && EID.getEntityId(eid)) ?? uri;\n};\n\nconst eventFeedKey = (event: Trace.FlatEvent): string | undefined =>\n event.meta.conversation ? entityKey(event.meta.conversation.uri) : undefined;\n\nconst decode = <S extends Schema.ConstraintDecoder<unknown>>(schema: S, data: unknown): S['Type'] | undefined =>\n Option.getOrUndefined(Schema.decodeUnknownOption(schema)(data));\n\ntype MutableLane = { -readonly [K in keyof Lane]: Lane[K] };\n\nconst sessionLaneId = (key: string): string => `session:${key}`;\nconst taskLaneId = (taskId: string): string => `task:${taskId}`;\n\ninterface SessionSource {\n key: string;\n label: string;\n session?: Session;\n pids: Set<string>;\n}\n\n/**\n * The stretch of a session during which one task was the active one, bounded by the status events\n * the planning tool writes. Everything the session did inside it belongs to that task.\n */\ninterface TaskSegment {\n taskId: string;\n laneId: string;\n start: number;\n end?: number;\n}\n\n/**\n * Cuts a session's events into one segment per task worked, from the status events its task tools\n * write. Only tasks in `taskIds` — the session's own checklist — take part: an agent is free to move\n * a task belonging to nothing on this chart, and such an event must not close the segment that is\n * open or move the boundary.\n *\n * A `started` event opens a segment and closes the one still open — the agent keeps exactly one task\n * in progress. Any other status ends the agent's work on the task: `todo` puts it down as surely as\n * `done`, and whatever the agent does next is no longer that task's. A task can also finish without\n * a start: delegation marks every task it hands over\n * `started` before the agent's first turn, so the run's only event for that task is the one closing\n * it. Such a task gets the stretch since the last boundary, which is where its work happened — but\n * only on the transition out of `started` and only while no other task holds the stretch: a task\n * merely dismissed (`todo` → `blocked`) claims nothing, a second close (`review` → `done`) mints\n * nothing, and a close arriving after the next task has started leaves that task's segment alone\n * rather than overlapping it.\n */\nconst buildTaskSegments = (\n events: readonly Trace.FlatEvent[],\n sessionStart: number | undefined,\n taskIds: ReadonlySet<string>,\n): TaskSegment[] => {\n const segments: TaskSegment[] = [];\n let open: TaskSegment | undefined;\n let boundary = sessionStart;\n const close = (segment: TaskSegment, timestamp: number): void => {\n segment.end = timestamp;\n boundary = timestamp;\n if (open === segment) {\n open = undefined;\n }\n };\n\n for (const event of events) {\n if (event.type !== Trace.TaskStatusChanged.key) {\n continue;\n }\n const data = decode(Trace.TaskStatusChanged.schema, event.data);\n if (!data || !taskIds.has(data.taskId)) {\n continue;\n }\n if (data.status === 'started') {\n if (open && open.taskId !== data.taskId) {\n close(open, event.timestamp);\n }\n if (!open) {\n open = { taskId: data.taskId, laneId: taskLaneId(data.taskId), start: event.timestamp };\n segments.push(open);\n boundary = event.timestamp;\n }\n } else {\n const started = segments.findLast((candidate) => candidate.taskId === data.taskId && candidate.end === undefined);\n if (started) {\n close(started, event.timestamp);\n } else if (data.previousStatus === 'started' && open === undefined) {\n const segment = {\n taskId: data.taskId,\n laneId: taskLaneId(data.taskId),\n start: Math.min(boundary ?? event.timestamp, event.timestamp),\n };\n segments.push(segment);\n close(segment, event.timestamp);\n }\n }\n }\n return segments;\n};\n\n/**\n * The segment an event belongs to. Segments meet where one task starts over another, so a\n * status event is matched to its own task's segment, and any other event at a shared boundary\n * goes to the later segment — the newcomer's start is the first thing the agent did on it.\n */\nconst segmentFor = (segments: readonly TaskSegment[] | undefined, event: Trace.FlatEvent): TaskSegment | undefined => {\n if (!segments) {\n return undefined;\n }\n const contains = (segment: TaskSegment) =>\n event.timestamp >= segment.start && event.timestamp <= (segment.end ?? Number.MAX_SAFE_INTEGER);\n if (event.type === Trace.TaskStatusChanged.key) {\n const data = decode(Trace.TaskStatusChanged.schema, event.data);\n return data && segments.findLast((segment) => segment.taskId === data.taskId && contains(segment));\n }\n return segments.findLast(contains);\n};\n\ninterface SubAgentSpan {\n span: Span;\n pid: string;\n startEvent: Trace.FlatEvent;\n}\n\n/**\n * Builds the gantt-shaped view of one or more assistant sessions from their trace: session lanes\n * (supervisors and the sub-agents they delegate to), task lanes, and the markers on each.\n */\nexport const buildSessionTimeline = ({\n traceMessages,\n processes = [],\n sessions,\n tasks = [],\n now,\n}: BuildSessionTimelineInput): SessionTimeline => {\n const root = buildSpanTree(traceMessages);\n const spans = flattenSpanTree(root);\n const events = spans.flatMap((span) => span.events).sort((a, b) => a.timestamp - b.timestamp);\n const requestBegins = events.filter(\n (event): event is Trace.FlatEvent & { meta: { pid: string } } =>\n event.type === Trace.AgentRequestBegin.key && event.meta.pid !== undefined,\n );\n\n // The agent process targets the chat; its trace meta carries the chat's feed.\n const agentPidsByChat = new Map<string, string[]>();\n for (const process of processes) {\n if (!Process.isHarnessHost(process)) {\n continue;\n }\n const target = Option.getOrUndefined(\n Annotation.getDictionary(process.params.annotations, Process.TargetAnnotation),\n );\n if (target !== undefined) {\n const key = entityKey(target.toString());\n agentPidsByChat.set(key, [...(agentPidsByChat.get(key) ?? []), process.pid]);\n }\n }\n\n const sources: SessionSource[] = [];\n if (sessions) {\n for (const session of sessions) {\n if (session.taskIds.length === 0) {\n continue;\n }\n const feed = session.feedId;\n const pids = new Set<string>(agentPidsByChat.get(entityKey(session.uri)) ?? []);\n for (const event of requestBegins) {\n if (feed !== undefined && eventFeedKey(event) === feed) {\n pids.add(event.meta.pid);\n }\n }\n // A feed or object id is not a name: an unnamed chat reads as the session it is until the\n // naming turn lands.\n sources.push({ key: session.id, label: session.label?.trim() || 'Session', session, pids });\n }\n } else {\n // Without chats, the conversation feed groups a session's pids; a trace with no conversation\n // meta falls back to one session per agent pid.\n const byKey = new Map<string, SessionSource>();\n for (const event of requestBegins) {\n const pid = event.meta.pid;\n const key = eventFeedKey(event) ?? pid;\n const source = byKey.get(key) ?? {\n key,\n label: eventFeedKey(event) ?? event.meta.processName ?? pid,\n pids: new Set<string>(),\n };\n source.pids.add(pid);\n byKey.set(key, source);\n }\n sources.push(...byKey.values());\n }\n\n const processByPid = new Map<string, Process.Info>(processes.map((process) => [process.pid, process]));\n const taskById = new Map(tasks.map((task) => [task.id, task]));\n const laneByPid = new Map<string, string>();\n const lanes: MutableLane[] = [];\n const markers: Marker[] = [];\n const childSessions: { lane: MutableLane; sessionLaneId: string }[] = [];\n const replacedTaskLanes = new Map<string, string>();\n /** Per session lane: the task segments its markers are attributed to. */\n const segmentsBySession = new Map<string, TaskSegment[]>();\n\n for (const source of sources) {\n const laneId = sessionLaneId(source.key);\n const sessionEvents = events.filter((event) => event.meta.pid && source.pids.has(event.meta.pid));\n const begins = sessionEvents.filter((event) => event.type === Trace.AgentRequestBegin.key);\n const ends = sessionEvents.filter((event) => event.type === Trace.AgentRequestEnd.key);\n const requestOpen = begins.length > ends.length;\n const processActive = [...source.pids].some((pid) => {\n const process = processByPid.get(pid);\n return process !== undefined && ACTIVE_STATES.has(process.state);\n });\n const lastEnd = ends.at(-1);\n const lastEndStatus = lastEnd ? decode(Trace.AgentRequestEnd.schema, lastEnd.data)?.status : undefined;\n // An unmatched request begin is a run in flight only while its process is; with the process\n // recorded as ended, the run died before writing its end, so the lane closes at its last event\n // rather than staying open (and stretching the chart) indefinitely.\n const processKnown = [...source.pids].some((pid) => processByPid.has(pid));\n const died = requestOpen && processKnown && !processActive;\n const open = requestOpen && !died;\n const status: LaneStatus =\n processActive || open ? 'running' : died || lastEndStatus === 'error' ? 'failed' : 'done';\n\n lanes.push({\n id: laneId,\n kind: 'session',\n label: source.label,\n status,\n start: begins[0]?.timestamp,\n end: open ? undefined : died ? sessionEvents.at(-1)?.timestamp : lastEnd?.timestamp,\n sessionId: source.session?.id,\n pid: [...source.pids].at(-1),\n });\n for (const pid of source.pids) {\n laneByPid.set(pid, laneId);\n }\n\n // The spawn event is the only durable pid ↔ task pairing; a sub-agent's own trace carries\n // neither the task nor the conversation.\n const taskByPid = new Map<string, string>();\n for (const event of sessionEvents) {\n if (event.type === Trace.DelegationSpawned.key) {\n const data = decode(Trace.DelegationSpawned.schema, event.data);\n if (data) {\n taskByPid.set(data.pid, data.taskId);\n }\n }\n }\n\n // A child span is a sub-agent (not a tool call) when it was spawned as one or emits its own\n // content blocks.\n const subAgentSpans: SubAgentSpan[] = spans.flatMap((span) => {\n const startEvent = span.events[0];\n const pid = span.meta.pid;\n if (\n pid === undefined ||\n span.meta.parentPid === undefined ||\n !source.pids.has(span.meta.parentPid) ||\n startEvent?.type !== Trace.OperationStart.key\n ) {\n return [];\n }\n const isAgent = taskByPid.has(pid) || span.events.some((event) => event.type === Trace.CompleteBlock.key);\n return isAgent ? [{ span, pid, startEvent }] : [];\n });\n\n const chatTasks = (source.session?.taskIds ?? [])\n .map((id) => taskById.get(id))\n .filter((task): task is Task.Task => task !== undefined);\n // Only a dependency on the checklist gets a lane, so `blockedOn` never names a lane that is\n // not drawn.\n const chatTaskIds = new Set(chatTasks.map((task) => task.id));\n const taskLanes = new Map<string, MutableLane>();\n for (const task of chatTasks) {\n const taskLane: MutableLane = {\n id: taskLaneId(task.id),\n kind: 'task',\n label: task.title,\n status: taskLaneStatus(task, tasks),\n parentId: laneId,\n sessionId: source.session?.id,\n taskId: task.id,\n };\n const blockedOn = (task.dependsOn ?? [])\n .map((ref) => Task.refEntityId(ref))\n .filter((id): id is string => id !== undefined && chatTaskIds.has(id))\n .map(taskLaneId);\n if (blockedOn.length > 0) {\n taskLane.blockedOn = blockedOn;\n }\n taskLanes.set(task.id, taskLane);\n lanes.push(taskLane);\n }\n\n // Spawned pids without a trace yet still get a lane from their process.\n const subAgentPids = new Set<string>([...subAgentSpans.map(({ pid }) => pid), ...taskByPid.keys()]);\n\n // The status events bound each task's stretch of the session, giving its lane a span of its own\n // and a node where it started and finished. A status tool runs as a child process of the agent,\n // so its events carry their own pid and reach the session through `parentPid`; a spawned\n // sub-agent's do too, and those belong to its own lane rather than cutting this one.\n const ownEvents = events.filter(\n (event) =>\n (event.meta.pid !== undefined && source.pids.has(event.meta.pid)) ||\n (event.meta.parentPid !== undefined &&\n source.pids.has(event.meta.parentPid) &&\n !(event.meta.pid !== undefined && subAgentPids.has(event.meta.pid))),\n );\n const segments = buildTaskSegments(ownEvents, begins[0]?.timestamp, chatTaskIds);\n segmentsBySession.set(laneId, segments);\n for (const segment of segments) {\n const taskLane = taskLanes.get(segment.taskId);\n if (!taskLane) {\n continue;\n }\n taskLane.start = Math.min(taskLane.start ?? segment.start, segment.start);\n // An open segment leaves the lane open, even if an earlier one closed.\n taskLane.end = segment.end === undefined ? undefined : Math.max(taskLane.end ?? segment.end, segment.end);\n }\n\n for (const subPid of subAgentPids) {\n const match = subAgentSpans.find((candidate) => candidate.pid === subPid);\n const process = processByPid.get(subPid);\n if (!match && !process) {\n continue;\n }\n const taskId = taskByPid.get(subPid);\n const task = taskId === undefined ? undefined : taskById.get(taskId);\n const startName = match ? decode(Trace.OperationStart.schema, match.startEvent.data)?.name : undefined;\n const endEvent = match?.span.events.find((event) => event.type === Trace.OperationEnd.key);\n const start = match?.startEvent.timestamp ?? process?.startedAt;\n const end = endEvent?.timestamp ?? (process ? Option.getOrUndefined(process.completedAt) : undefined);\n const subLane: MutableLane = {\n id: sessionLaneId(subPid),\n kind: 'session',\n label: task?.title ?? startName ?? process?.params.name ?? subPid,\n status: subSessionStatus(endEvent, process),\n start,\n end,\n parentId: laneId,\n sessionId: source.session?.id,\n taskId,\n pid: subPid,\n };\n laneByPid.set(subPid, subLane.id);\n childSessions.push({ lane: subLane, sessionLaneId: laneId });\n // A delegated task IS its child session: the session lane takes the task lane's place and\n // its dependencies, so a task is either worked in-session (a task lane) or spawned (a session).\n const taskLane = taskId === undefined ? undefined : taskLanes.get(taskId);\n if (taskLane) {\n subLane.blockedOn = taskLane.blockedOn;\n lanes.splice(lanes.indexOf(taskLane), 1, subLane);\n replacedTaskLanes.set(taskLane.id, subLane.id);\n } else {\n lanes.push(subLane);\n }\n }\n }\n\n // A delegated task IS its child session, drawn with the child's own span; the parent's markers in\n // that stretch are the parent's work of handing it over, so the segment goes rather than moving.\n for (const [sessionId, segments] of segmentsBySession) {\n segmentsBySession.set(\n sessionId,\n segments.filter((segment) => !replacedTaskLanes.has(segment.laneId)),\n );\n }\n\n // Dependencies named the task lane; they follow it to the session that replaced it.\n for (const lane of lanes) {\n if (lane.blockedOn) {\n lane.blockedOn = lane.blockedOn.map((id) => replacedTaskLanes.get(id) ?? id);\n }\n }\n\n // Markers and token totals, attributed to the lane owning the event's pid or its parent pid.\n const tokens = new Map<string, { usage: TokenUsage; toolCalls: number }>();\n const spawnMarkerByPid = new Map<string, string>();\n for (const event of events) {\n const laneId =\n (event.meta.pid && laneByPid.get(event.meta.pid)) ??\n (event.meta.parentPid && laneByPid.get(event.meta.parentPid)) ??\n undefined;\n if (laneId === undefined) {\n continue;\n }\n // Everything the session did while a task was active is that task's, so the session bar keeps\n // only what brackets the whole run (its request markers) and the timeline reads per task.\n const markerLaneId =\n event.type === Trace.AgentRequestBegin.key || event.type === Trace.AgentRequestEnd.key\n ? laneId\n : (segmentFor(segmentsBySession.get(laneId), event)?.laneId ?? laneId);\n const marker = toMarker(event, `${markerLaneId}:${markers.length}`, markerLaneId);\n if (marker) {\n markers.push(marker);\n if (marker.kind === 'delegation') {\n const data = decode(Trace.DelegationSpawned.schema, event.data);\n if (data) {\n spawnMarkerByPid.set(data.pid, marker.id);\n }\n }\n }\n if (event.type === Trace.CompleteBlock.key) {\n const data = decode(Trace.CompleteBlock.schema, event.data);\n if (data?.block._tag === 'stats') {\n const entry = tokens.get(laneId) ?? { usage: { input: 0, output: 0, total: 0 }, toolCalls: 0 };\n // A provider that reports no total still reports the parts.\n const input = data.block.usage?.inputTokens ?? 0;\n const output = data.block.usage?.outputTokens ?? 0;\n const total = data.block.usage?.totalTokens ?? input + output;\n entry.usage = {\n input: entry.usage.input + input,\n output: entry.usage.output + output,\n total: entry.usage.total + total,\n };\n entry.toolCalls += data.block.toolCalls ?? 0;\n tokens.set(laneId, entry);\n }\n }\n }\n for (const lane of lanes) {\n const entry = tokens.get(lane.id);\n if (entry) {\n lane.tokens = entry.usage;\n lane.toolCalls = entry.toolCalls;\n }\n }\n\n // The connector starts at the spawn marker, else at the supervisor's last node before the child began.\n for (const { lane, sessionLaneId } of childSessions) {\n const markerId =\n (lane.pid && spawnMarkerByPid.get(lane.pid)) ??\n markers.filter((marker) => marker.laneId === sessionLaneId && marker.timestamp <= (lane.start ?? 0)).at(-1)?.id;\n if (markerId !== undefined) {\n lane.delegatedFrom = { laneId: sessionLaneId, markerId };\n }\n }\n\n // A session working exactly one task is that task: the two lanes would carry the same label,\n // so the task lane folds into the session's (which keeps its run span and totals, and takes the\n // task's id and status so it still reads as the work). Only a lone in-session task, with nothing\n // depending on it and no spawned child, folds — a checklist of several stays a tree.\n for (const session of lanes.filter((lane) => lane.kind === 'session' && lane.parentId === undefined)) {\n const children = lanes.filter((lane) => lane.parentId === session.id);\n const [task] = children;\n if (children.length !== 1 || task.kind !== 'task' || lanes.some((lane) => lane.blockedOn?.includes(task.id))) {\n continue;\n }\n lanes.splice(lanes.indexOf(task), 1);\n session.taskId = task.taskId;\n if (task.status === 'blocked' || task.status === 'review' || task.status === 'pending') {\n session.status = task.status;\n }\n markers.forEach((marker, index) => {\n if (marker.laneId === task.id) {\n markers[index] = { ...marker, laneId: session.id };\n }\n });\n }\n\n const times = [\n ...lanes.flatMap((lane) => [lane.start, lane.end]).filter((time): time is number => time !== undefined),\n ...markers.map((marker) => marker.timestamp),\n ];\n // The axis reaches `now` for a run still in flight; one whose last event is long past is idle or\n // dead whatever its status says, and stretching the axis to now would bunch its nodes into a sliver.\n const hasOpen = lanes.some((lane) => lane.start !== undefined && lane.end === undefined);\n const latest = times.length > 0 ? Math.max(...times) : undefined;\n if (hasOpen && now !== undefined && (latest === undefined || now - latest <= OPEN_LANE_STALE_MS)) {\n times.push(now);\n }\n const start = times.length > 0 ? Math.min(...times) : (now ?? 0);\n const end = times.length > 0 ? Math.max(...times) : start;\n\n return { lanes, markers, range: { start, end } };\n};\n\nconst taskLaneStatus = (task: Task.Task, tasks: readonly Task.Task[]): LaneStatus => {\n if (task.status === 'todo' && !Task.isTaskReady(tasks, task)) {\n return 'blocked';\n }\n return (task.status && TASK_STATUS[task.status]) ?? 'pending';\n};\n\nconst subSessionStatus = (endEvent: Trace.FlatEvent | undefined, process: Process.Info | undefined): LaneStatus => {\n if (endEvent) {\n return decode(Trace.OperationEnd.schema, endEvent.data)?.outcome === 'failure' ? 'failed' : 'done';\n }\n if (process && !ACTIVE_STATES.has(process.state)) {\n return process.state === Process.State.FAILED ? 'failed' : 'done';\n }\n return 'running';\n};\n\nconst toMarker = (event: Trace.FlatEvent, id: string, laneId: string): Marker | undefined => {\n const base = { id, laneId, timestamp: event.timestamp, pid: event.meta.pid };\n switch (event.type) {\n case Trace.AgentRequestBegin.key:\n return { ...base, kind: 'request', label: 'Request started' };\n case Trace.AgentRequestEnd.key: {\n const data = decode(Trace.AgentRequestEnd.schema, event.data);\n return {\n ...base,\n kind: 'request',\n label: `Request ${data?.status ?? 'ended'}`,\n level: data?.status === 'error' ? 'error' : data?.status === 'interrupted' ? 'warn' : undefined,\n detail: data?.error,\n };\n }\n case Trace.TaskStatusChanged.key: {\n const data = decode(Trace.TaskStatusChanged.schema, event.data);\n return {\n ...base,\n kind: 'task',\n label: data?.status === 'started' ? 'Task started' : `Task ${data?.status ?? 'updated'}`,\n level: data?.status === 'failed' ? 'error' : undefined,\n detail: data,\n };\n }\n case Trace.DelegationSpawned.key: {\n const data = decode(Trace.DelegationSpawned.schema, event.data);\n return { ...base, kind: 'delegation', label: 'Delegated', detail: data };\n }\n case Trace.OperationStart.key: {\n const data = decode(Trace.OperationStart.schema, event.data);\n return { ...base, kind: 'operation', label: data?.name ?? data?.key ?? 'Operation' };\n }\n case Trace.OperationEnd.key: {\n const data = decode(Trace.OperationEnd.schema, event.data);\n const failed = data?.outcome === 'failure';\n return {\n ...base,\n kind: 'operation',\n label: data?.name ?? data?.key ?? 'Operation',\n level: failed ? 'error' : undefined,\n detail: failed ? data?.error : undefined,\n };\n }\n case Trace.CompleteBlock.key: {\n const data = decode(Trace.CompleteBlock.schema, event.data);\n if (data?.block._tag === 'toolCall') {\n return { ...base, kind: 'tool', label: data.block.name };\n }\n if (data?.block._tag === 'text' && data.role === 'user') {\n return { ...base, kind: 'message', label: data.block.text.split('\\n')[0] ?? '' };\n }\n return undefined;\n }\n default:\n return undefined;\n }\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nexport const LaneKind = Schema.Literals(['session', 'task']);\nexport type LaneKind = Schema.Schema.Type<typeof LaneKind>;\n\nexport const LaneStatus = Schema.Literals(['pending', 'blocked', 'running', 'review', 'done', 'failed']);\nexport type LaneStatus = Schema.Schema.Type<typeof LaneStatus>;\n\nexport const TokenUsage = Schema.Struct({\n input: Schema.Number,\n output: Schema.Number,\n total: Schema.Number,\n});\nexport type TokenUsage = Schema.Schema.Type<typeof TokenUsage>;\n\n/**\n * A conversation the timeline draws as a session lane: the chat, reduced to what the join needs so\n * the builder does not depend on the chat's schema. `uri` is what the agent process targets and\n * `feedId` what its trace meta names; `taskIds` is the checklist.\n */\nexport const Session = Schema.Struct({\n id: Schema.String,\n label: Schema.optional(Schema.String),\n uri: Schema.String,\n feedId: Schema.optional(Schema.String),\n taskIds: Schema.Array(Schema.String),\n});\nexport type Session = Schema.Schema.Type<typeof Session>;\n\n/**\n * Node in the supervisor lane a child session was spawned from, so the connector can start at the\n * exact marker rather than at the lane's edge.\n */\nexport const DelegationSource = Schema.Struct({\n laneId: Schema.String,\n markerId: Schema.String,\n});\nexport type DelegationSource = Schema.Schema.Type<typeof DelegationSource>;\n\n/**\n * One row of the timeline: a session (supervisor or delegated sub-agent) rendered as a box spanning\n * `start`..`end`, or a task rendered as a thin line grouped under its session.\n */\nexport const Lane = Schema.Struct({\n id: Schema.String,\n kind: LaneKind,\n label: Schema.String,\n status: LaneStatus,\n /** Epoch ms. */\n start: Schema.optional(Schema.Number),\n end: Schema.optional(Schema.Number),\n parentId: Schema.optional(Schema.String),\n sessionId: Schema.optional(Schema.String),\n taskId: Schema.optional(Schema.String),\n pid: Schema.optional(Schema.String),\n /** Lane ids this lane waits on (task dependencies). */\n blockedOn: Schema.optional(Schema.Array(Schema.String)),\n delegatedFrom: Schema.optional(DelegationSource),\n tokens: Schema.optional(TokenUsage),\n toolCalls: Schema.optional(Schema.Number),\n});\nexport type Lane = Schema.Schema.Type<typeof Lane>;\n\nexport const MarkerKind = Schema.Literals(['request', 'operation', 'tool', 'message', 'error', 'delegation', 'task']);\nexport type MarkerKind = Schema.Schema.Type<typeof MarkerKind>;\n\nexport const MarkerLevel = Schema.Literals(['info', 'warn', 'error']);\nexport type MarkerLevel = Schema.Schema.Type<typeof MarkerLevel>;\n\n/**\n * A point event on a lane, rendered as a node inside the session box.\n */\nexport const Marker = Schema.Struct({\n id: Schema.String,\n laneId: Schema.String,\n kind: MarkerKind,\n timestamp: Schema.Number,\n label: Schema.String,\n level: Schema.optional(MarkerLevel),\n pid: Schema.optional(Schema.String),\n detail: Schema.optional(Schema.Unknown),\n});\nexport type Marker = Schema.Schema.Type<typeof Marker>;\n\nexport const TimeRange = Schema.Struct({\n start: Schema.Number,\n end: Schema.Number,\n});\nexport type TimeRange = Schema.Schema.Type<typeof TimeRange>;\n\nexport const SessionTimeline = Schema.Struct({\n lanes: Schema.Array(Lane),\n markers: Schema.Array(Marker),\n range: TimeRange,\n});\nexport type SessionTimeline = Schema.Schema.Type<typeof SessionTimeline>;\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Duration from 'effect/Duration';\nimport { useEffect, useMemo, useState } from 'react';\n\nimport type * as Process from '@dxos/compute/Process';\nimport { type Space } from '@dxos/react-client/echo';\nimport { type Task } from '@dxos/types';\n\nimport { type Session, type SessionTimeline, buildSessionTimeline } from '../session-timeline/index.ts';\n\nimport { useTraceMessages } from './useTraceMessages.ts';\n\n/** How often `now` advances while a session is open, so a running lane's range keeps growing. */\nconst TICK_MS = 5_000;\n\n// The trace feed emits continuously while anything runs, and every emission rebuilds the whole\n// timeline from the full message history — so the rebuild rate is capped rather than the feed's.\nconst TRACE_DEBOUNCE = Duration.millis(500);\n\nconst NO_PROCESSES: readonly Process.Info[] = [];\n\nexport type UseSessionTimelineOptions = {\n /** The sessions shown; each contributes a session lane and its checklist's task lanes. */\n sessions: readonly Session[];\n tasks?: readonly Task.Task[];\n /** The live process tree, from whichever monitor the host has; without it a session's liveness is read from the trace alone. */\n processes?: readonly Process.Info[];\n};\n\n/**\n * The live gantt-shaped view of the given sessions: rebuilt as trace events land on the space's\n * trace feed and as the process tree changes, and ticked so open lanes keep extending.\n */\nexport const useSessionTimeline = (\n space: Space | undefined,\n { sessions, tasks, processes = NO_PROCESSES }: UseSessionTimelineOptions,\n): SessionTimeline => {\n const traceMessages = useTraceMessages(space, { debounce: TRACE_DEBOUNCE });\n\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const interval = setInterval(() => setNow(Date.now()), TICK_MS);\n return () => clearInterval(interval);\n }, []);\n\n return useMemo(\n () => buildSessionTimeline({ traceMessages, processes, sessions, tasks, now }),\n [traceMessages, processes, sessions, tasks, now],\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/components/Gantt/gantt-rows.ts","../../src/components/Gantt/gantt-scale.ts","../../src/components/Gantt/useEnter.ts","../../src/components/Gantt/useRangeTween.ts","../../src/components/Gantt/Gantt.tsx","../../src/components/ProcessTree/ProcessTree.tsx","../../src/components/Timeline/timeline-layout.ts","../../src/components/Timeline/timeline-options.ts","../../src/components/Timeline/Timeline.tsx","../../src/components/Timeline/timeline-printer.ts","../../src/components/TracePanel/SpanTreeView.tsx","../../src/components/TracePanel/trace-filter.ts","../../src/components/TracePanel/useTraceMenu.ts","../../src/components/TracePanel/TracePanel.tsx","../../src/execution-graph/span-tree.ts","../../src/execution-graph/execution-graph.ts","../../src/execution-graph/pending-block-status.ts","../../src/hooks/useTraceMessages.ts","../../src/hooks/useExecutionGraph.ts","../../src/session-timeline/gantt-mapping.ts","../../src/session-timeline/session-timeline.ts","../../src/session-timeline/types.ts","../../src/hooks/useSessionTimeline.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// Kept out of `Gantt.tsx`: react-refresh only fast-refreshes a module whose exports are all\n// components, so a layout function exported beside them forces a full reload on every edit.\n\nimport { type GanttGroup, type GanttLane } from './Gantt.tsx';\n\nexport type Row = {\n lane: GanttLane;\n depth: number;\n index: number;\n groupId: string | undefined;\n};\n\n/** A group's rows, contiguous — which is what lets one rectangle enclose them. */\nexport type Band = {\n group: GanttGroup;\n first: number;\n last: number;\n};\n\n/**\n * Rows in reading order: the ungrouped lanes, then each group's band, a nested group's band directly\n * after its parent's. Within a band the lanes come in the order given, each nested under its\n * `parentId`.\n *\n * A band is contiguous by construction, which is the whole reason the order is settled here rather\n * than left to the caller: one rectangle can only enclose a run of adjacent rows.\n */\nexport const orderRows = (\n groups: readonly GanttGroup[],\n lanes: readonly GanttLane[],\n): { rows: Row[]; bands: Band[] } => {\n const rows: Row[] = [];\n const bands: Band[] = [];\n\n /** A group's lanes, nested under one another by `parentId`; a parent in another group is ignored. */\n const pushLanes = (members: readonly GanttLane[], parentId: string | undefined, depth: number): void => {\n for (const lane of members.filter((member) => member.parentId === parentId)) {\n rows.push({ lane, depth, index: rows.length, groupId: lane.groupId });\n pushLanes(members, lane.id, depth + 1);\n }\n };\n\n const visitGroup = (group: GanttGroup, depth: number): void => {\n const first = rows.length;\n pushLanes(\n lanes.filter((lane) => lane.groupId === group.id),\n undefined,\n depth,\n );\n if (rows.length > first) {\n bands.push({ group, first, last: rows.length - 1 });\n }\n for (const child of groups.filter((candidate) => candidate.parentId === group.id)) {\n visitGroup(child, depth + 1);\n }\n };\n\n pushLanes(\n lanes.filter((lane) => lane.groupId === undefined),\n undefined,\n 0,\n );\n for (const group of groups.filter((group) => group.parentId === undefined)) {\n visitGroup(group, 0);\n }\n return { rows, bands };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n/**\n * What the horizontal axis measures.\n * - `time` — real duration, fitted to the width available: an idle gap is as wide as it was long.\n * - `unit` — one fixed step per event: a burst and a lull read alike, and the drawing grows to the\n * right instead of compressing, so an event already placed never moves again. That is what makes a\n * live chart watchable — on a fitted axis every arrival shifts the whole history left.\n */\nexport type GanttAxis = 'time' | 'unit';\n\n/** A labelled gridline, positioned in the same pixels as `GanttScale.at`. */\nexport type GanttTick = { at: number; label: string };\n\n/** The mapping every part of the drawing shares: an instant to a horizontal offset in pixels. */\nexport type GanttScale = {\n at: (time: number) => number;\n /** The drawing's width: the time axis takes what it is given, the unit axis states its own. */\n width: number;\n /** The labelled gridlines, as many as fit — the label's own width decides, so the scale owns this. */\n ticks: GanttTick[];\n};\n\n/** Room a tick label needs; elapsed labels are short, so this also caps how many fit. */\nconst TIME_LABEL_WIDTH = 56;\nconst MAX_TIME_TICKS = 10;\n\n/** Round tick intervals in milliseconds, so elapsed labels read `0s, 10s, 20s` rather than `13.4s`. */\nconst TICK_STEPS = [\n 100, 200, 500, 1_000, 2_000, 5_000, 10_000, 15_000, 30_000, 60_000, 120_000, 300_000, 600_000, 900_000, 1_800_000,\n 3_600_000, 7_200_000, 21_600_000, 43_200_000, 86_400_000,\n];\n\nconst pad2 = (value: number): string => String(value).padStart(2, '0');\n\n/**\n * Elapsed time since the start of the axis. The span picks the form for every tick alike, so a\n * run's labels read as one unit: `0.2s` below a second's step, `45s` below a minute, `1:05` below an\n * hour, `1:02:05` beyond.\n */\nexport const formatElapsed = (elapsed: number, { span, step }: { span: number; step: number }): string => {\n const seconds = Math.round(elapsed / 1_000);\n if (span >= 3_600_000) {\n return `${Math.floor(seconds / 3_600)}:${pad2(Math.floor(seconds / 60) % 60)}:${pad2(seconds % 60)}`;\n }\n if (span >= 60_000) {\n return `${Math.floor(seconds / 60)}:${pad2(seconds % 60)}`;\n }\n if (step < 1_000) {\n return `${(elapsed / 1_000).toFixed(1)}s`;\n }\n return `${seconds}s`;\n};\n\n/** An event's ordinal is two or three glyphs, so its labels pack tighter than a clock's. */\nconst EVENT_LABEL_WIDTH = 40;\n\nexport type TimeScaleOptions = {\n range: { start: number; end: number };\n /** The width the range is fitted into. */\n width: number;\n /** Clearance at each end, so a bar's cap and the first tick's label stay inside the drawing. */\n pad: number;\n};\n\n/** Duration against width, labelled with the time elapsed since the start of the range. */\nexport const timeScale = ({ range, width, pad }: TimeScaleOptions): GanttScale => {\n const span = Math.max(range.end - range.start, 1);\n const inner = Math.max(width - 2 * pad, 1);\n const at = (time: number): number => pad + ((time - range.start) / span) * inner;\n const maxTicks = Math.max(2, Math.min(MAX_TIME_TICKS, Math.floor(inner / TIME_LABEL_WIDTH)));\n const step =\n TICK_STEPS.find((candidate) => span / candidate <= maxTicks - 1) ??\n Math.ceil(span / (maxTicks - 1) / TICK_STEPS[TICK_STEPS.length - 1]) * TICK_STEPS[TICK_STEPS.length - 1];\n const ticks: GanttTick[] = [];\n for (let elapsed = 0; elapsed <= span; elapsed += step) {\n ticks.push({ at: at(range.start + elapsed), label: formatElapsed(elapsed, { span, step }) });\n }\n return { at, width, ticks };\n};\n\nexport type UnitScaleOptions = {\n /** Every event's instant; order and duplicates do not matter. */\n times: readonly number[];\n /** Pixels per event — the axis's one unit. */\n step: number;\n /** Clearance at each end, which also keeps the newest node off the edge. */\n pad: number;\n};\n\n/**\n * One step per event, in the order they happened. Ordinals are global rather than per lane: a\n * delegation drops from a parent's node to its child's first node, and only a shared ordering keeps\n * those two at the same offset.\n */\nexport const unitScale = ({ times, step, pad }: UnitScaleOptions): GanttScale => {\n const events = [...new Set(times)].sort((left, right) => left - right);\n const last = Math.max(events.length - 1, 0);\n\n /** Index of the last event at or before `time`, or -1 when `time` precedes every event. */\n const floorIndex = (time: number): number => {\n let low = 0;\n let high = events.length - 1;\n let found = -1;\n while (low <= high) {\n const mid = (low + high) >> 1;\n if (events[mid] <= time) {\n found = mid;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n return found;\n };\n\n // An instant between two events sits proportionally between their units: a lane's start or end is\n // rarely an event of its own, and snapping it to the nearest would pull a bar's edge off its node.\n const unit = (time: number): number => {\n if (events.length === 0) {\n return 0;\n }\n const index = floorIndex(time);\n if (index < 0) {\n return 0;\n }\n if (index >= last) {\n return last;\n }\n const from = events[index];\n return index + (time - from) / (events[index + 1] - from);\n };\n\n const stride = Math.max(1, Math.ceil(last / Math.max(Math.floor((last * step) / EVENT_LABEL_WIDTH), 1)));\n const ticks: GanttTick[] = [];\n for (let index = 0; events.length > 0 && index <= last; index += stride) {\n ticks.push({ at: pad + index * step, label: `#${index + 1}` });\n }\n\n return { at: (time) => pad + unit(time) * step, width: 2 * pad + last * step, ticks };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useEffect, useState } from 'react';\n\n/**\n * Which of `ids` arrived since the last frame.\n *\n * A caller draws an entering element at the place it came from — the event before it, the node that\n * spawned its lane — and the next frame draws it where it belongs, leaving a CSS transition to carry\n * it the rest of the way. That is all the bookkeeping an enter animation needs: everything else in\n * the drawing animates from its own previous value, which the browser already has.\n *\n * Nothing present on mount ever counts as entering — a chart that animates its whole history open on\n * first paint is noise, since the reader was not there to see it arrive.\n */\nexport const useEnter = (ids: readonly string[]): ((id: string) => boolean) => {\n const [settled, setSettled] = useState<ReadonlySet<string>>(() => new Set(ids));\n const entering = ids.some((id) => !settled.has(id));\n\n useEffect(() => {\n if (!entering) {\n return;\n }\n // The transition needs one painted frame at the origin to run from. This effect is already past\n // that paint, so the frame after it is where the resting value belongs.\n const frame = requestAnimationFrame(() => setSettled(new Set(ids)));\n return () => cancelAnimationFrame(frame);\n });\n\n return (id) => !settled.has(id);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useEffect, useRef, useState } from 'react';\n\nexport type TimeRange = { start: number; end: number };\n\n/** How long the axis takes to settle on new bounds. */\nconst TWEEN_DURATION = 400;\n\nconst easeOutCubic = (progress: number): number => 1 - (1 - progress) ** 3;\n\n/** Motion is skipped where nothing would see it, or where the reader asked for less of it. */\nconst shouldSnap = (): boolean =>\n typeof document === 'undefined' ||\n document.hidden ||\n (typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches);\n\n/**\n * The range to draw with: `target`, reached over a short ease rather than in one step, so a\n * time axis whose bounds move (a new event, `now` advancing) slides every span, node and tick to\n * its new place together instead of jumping. A new target mid-flight eases on from wherever the\n * drawing is, so a stream of updates reads as one continuous motion.\n */\nexport const useRangeTween = (target: TimeRange, enabled: boolean): TimeRange => {\n const [shown, setShown] = useState(target);\n const shownRef = useRef(target);\n\n useEffect(() => {\n const from = shownRef.current;\n const settle = (range: TimeRange) => {\n shownRef.current = range;\n setShown(range);\n };\n if (!enabled || shouldSnap() || (from.start === target.start && from.end === target.end)) {\n settle(target);\n return;\n }\n\n let frame: number | undefined;\n const startedAt = performance.now();\n const step = (time: number) => {\n const progress = Math.min((time - startedAt) / TWEEN_DURATION, 1);\n const eased = easeOutCubic(progress);\n settle({\n start: from.start + (target.start - from.start) * eased,\n end: from.end + (target.end - from.end) * eased,\n });\n frame = progress < 1 ? requestAnimationFrame(step) : undefined;\n };\n frame = requestAnimationFrame(step);\n return () => {\n if (frame !== undefined) {\n cancelAnimationFrame(frame);\n }\n };\n }, [enabled, target.start, target.end]);\n\n return enabled ? shown : target;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { format } from 'date-fns';\nimport React, {\n Fragment,\n type KeyboardEvent,\n type PropsWithChildren,\n type ReactNode,\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { createContext, useComposedRefs } from '@dxos/react-hooks';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as HoverCard from '@dxos/react-ui/HoverCard';\nimport * as ScrollArea from '@dxos/react-ui/ScrollArea';\nimport * as Util from '@dxos/react-ui/Util';\nimport { type Hue, mx } from '@dxos/ui-theme';\n\nimport { translationKey } from '../../translations.ts';\nimport { type Band, type Row, orderRows } from './gantt-rows.ts';\nimport { type GanttAxis, type GanttScale, formatElapsed, timeScale, unitScale } from './gantt-scale.ts';\nimport { useEnter } from './useEnter.ts';\nimport { useRangeTween } from './useRangeTween.ts';\n\n/**\n * The chart's vocabulary is groups, lanes, segments and markers — deliberately not the vocabulary of\n * whatever is being charted. A host maps its own nouns onto these (a process onto a group, a task\n * onto a lane, a status change onto a marker) and the chart stays ignorant of what they mean.\n */\nexport type GanttLaneStatus = 'pending' | 'blocked' | 'running' | 'review' | 'done' | 'failed';\n\n/**\n * A band of related lanes, enclosed by one rectangle. Pure structure: the lanes inside carry the\n * labels, so a group needs no name of its own.\n */\nexport type GanttGroup = {\n id: string;\n /** Indents under another group; a nested group's band is drawn after its parent's. */\n parentId?: string;\n};\n\n/** One stretch during which a lane was worked. `end` is absent while the stretch is still open. */\nexport type GanttSegment = {\n start: number;\n end?: number;\n};\n\n/** A fact the host wants beside a lane: the legend shows it in place of, or over, the lane's title, and never interprets it. */\nexport type GanttMeta = {\n label: string;\n title?: string;\n};\n\n/**\n * One row. Its three references are deliberately distinct: `groupId` is which band it sits in,\n * `parentId` is what it nests under, and `openedFrom` is what caused it. Collapsing any two of them\n * into one edge is what left the previous model unable to hold a task hierarchy and a process tree\n * at the same time.\n */\nexport type GanttLane = {\n id: string;\n label: string;\n status: GanttLaneStatus;\n /** The band this lane sits in. */\n groupId?: string;\n /** Indents under another lane of the same group — nesting, nothing more. */\n parentId?: string;\n /** Every stretch this lane was worked. A lane with none exists but has no extent, so no bar. */\n segments?: readonly GanttSegment[];\n /** The node this lane opened out of, on another lane. */\n openedFrom?: { laneId: string; markerId: string };\n /**\n * The node this lane's result came back into, on another lane — the mirror of `openedFrom`, and a\n * separate fact: a lane can open out of another and end without ever reporting back.\n */\n closedInto?: { laneId: string; markerId: string };\n /** Colours the legend dot, the bar, its nodes and its thread in place of the status colour. */\n hue?: Hue;\n /** Lanes this one waits on. */\n blockedOn?: readonly string[];\n meta?: readonly GanttMeta[];\n};\n\nexport type GanttMarker = {\n id: string;\n laneId: string;\n /** The host's own word for what happened; shown in the hover card, never interpreted. */\n kind?: string;\n timestamp: number;\n label: string;\n level?: 'info' | 'warn' | 'error';\n /**\n * A wait begun at this node and since ended — a question put to the reader and answered. Drawn as a\n * dashed line along the lane to the node that ended it; a wait still open draws nothing, so the lane\n * ends at the question until the answer lands.\n */\n wait?: { until: string };\n /** Awaiting a response — an unanswered question. The node pings until the response arrives. */\n pending?: boolean;\n};\n\nconst PAD_X = 16;\nconst ROW_HEIGHT = 24;\nconst HEADER_HEIGHT = 20;\n\n/** Pixels per event on the `unit` axis — wide enough that two adjacent nodes read as two. */\nconst UNIT_STEP = 32;\n/** How long a newly arrived element takes to travel from where it came from to where it belongs. */\nconst ENTER_TRANSITION = 'duration-500 ease-out';\n\n/** Within this of the live edge the chart keeps following it; past it the reader is reading history. */\nconst FOLLOW_SLACK = 4;\n/**\n * How long the chart takes to drift to the live edge. Longer than the enter transition on purpose:\n * the arriving event settles into place first, and the window follows it rather than racing it.\n */\nconst FOLLOW_DURATION = 600;\n\nconst NODE_RADIUS = 6;\nconst BAR_HEIGHT = 15;\n/** The thread through a lane's nodes: a hairline, so the nodes remain what the row reads as. */\nconst THREAD_HEIGHT = 1;\n/**\n * A bar reaches half its height past its first and last instant, so a node sitting on either one is\n * as far from the bar's end as it is from its top and bottom.\n */\nconst BAR_OVERHANG = BAR_HEIGHT / 2;\n\n/** Gap between adjacent band rectangles, halved on each. */\nconst GROUP_INSET = 2;\n/** The rectangle's clearance around its bars, the same on every side, so its corners stay concentric with theirs. */\nconst GROUP_PAD = ROW_HEIGHT / 2 - BAR_HEIGHT / 2 - GROUP_INSET;\nconst GROUP_RADIUS = BAR_HEIGHT / 2 + GROUP_PAD;\n\n/** Radius of the connector's bend from the drop into the lane it opens. */\nconst BEND_RADIUS = BAR_HEIGHT / 2;\n\n/**\n * Bar, node, thread and label colours per status: nodes and the thread through them are the bar's\n * hue in a lighter shade, and `edge` — the live end of a lane still running — is the stronger shade\n * the legend's own status dot uses, so the two read as the same statement about the lane.\n */\n/**\n * A hued lane's colour: the theme's tag surface token, read as a variable because the hue is data, so\n * the lane matches a `Tag` of the same hue.\n */\nconst hueColor = (hue: Hue): string => `var(--color-${hue}-surface)`;\n\n/** The hue's strong shade, for a node that needs attention (a question, an error) within its lane. */\nconst hueStrongColor = (hue: Hue): string => `var(--color-${hue}-text)`;\n\nconst STATUS_COLOR: Record<\n GanttLaneStatus,\n { fill: string; node: string; edge: string; thread: string; text: string }\n> = {\n pending: {\n fill: 'fill-neutral-500/40',\n node: 'fill-neutral-300',\n edge: 'fill-neutral-400',\n thread: 'stroke-neutral-300',\n text: 'text-neutral-400',\n },\n blocked: {\n fill: 'fill-orange-500/40',\n node: 'fill-orange-300',\n edge: 'fill-orange-500',\n thread: 'stroke-orange-300',\n text: 'text-orange-500',\n },\n running: {\n fill: 'fill-sky-500/40',\n node: 'fill-sky-300',\n edge: 'fill-sky-500',\n thread: 'stroke-sky-300',\n text: 'text-sky-500',\n },\n review: {\n fill: 'fill-cyan-500/40',\n node: 'fill-cyan-300',\n edge: 'fill-cyan-500',\n thread: 'stroke-cyan-300',\n text: 'text-cyan-500',\n },\n done: {\n fill: 'fill-green-500/40',\n node: 'fill-green-300',\n edge: 'fill-green-500',\n thread: 'stroke-green-300',\n text: 'text-green-500',\n },\n failed: {\n fill: 'fill-red-500/40',\n node: 'fill-red-300',\n edge: 'fill-red-500',\n thread: 'stroke-red-300',\n text: 'text-red-500',\n },\n};\n\n/** A node that asks for attention: a question put to the reader, or something that went wrong. */\nconst isAlert = (marker: GanttMarker): boolean => marker.level === 'warn' || marker.level === 'error';\n\nconst CONNECTOR_CLASSNAME = 'stroke-fuchsia-500';\n\n/** What the legend's column shows per lane: its title, or the facts the host attached to it. */\nexport type GanttLegendMode = 'title' | 'stats';\n\nexport type GanttData = {\n /** The bands. A chart with none draws its lanes plain, with no rectangles. */\n groups?: readonly GanttGroup[];\n lanes: readonly GanttLane[];\n markers?: readonly GanttMarker[];\n range?: { start: number; end: number };\n now?: number;\n showNow?: boolean;\n /**\n * What the horizontal axis measures: `unit` steps once per event and scrolls to follow the newest;\n * `time` fits the whole range to the width and eases to new bounds. `unit` by default.\n */\n axis?: GanttAxis;\n /** Pixels per event on the `unit` axis. */\n unitStep?: number;\n /**\n * Slide a newly arrived event out of the one before it — out of the node that opened its lane, for\n * a lane's first — and grow its bar to meet it, on the `unit` axis. Only events that arrive while the\n * chart is on screen animate, so a chart that is merely mounted is still.\n */\n animate?: boolean;\n onLaneSelect?: (lane: GanttLane) => void;\n onMarkerSelect?: (marker: GanttMarker) => void;\n /** Called by `Gantt.AxisToggle`; without it the toggle does not render. */\n onAxisChange?: (axis: GanttAxis) => void;\n /** What the legend's column shows; held by the root when absent, `title` to begin with. */\n legend?: GanttLegendMode;\n /** Called by `Gantt.LegendToggle`. */\n onLegendChange?: (legend: GanttLegendMode) => void;\n};\n\n/** What every part reads: the ordered rows and the shared axis, resolved once by the root. */\ntype GanttContextValue = {\n rows: Row[];\n bands: Band[];\n rowById: Map<string, Row>;\n markers: readonly GanttMarker[];\n markerById: Map<string, GanttMarker>;\n range: { start: number; end: number };\n legend: GanttLegendMode;\n setLegend: (legend: GanttLegendMode) => void;\n /** The one scrolling element: lanes scroll vertically under the axis, the drawing horizontally beside the legend. */\n viewport: HTMLDivElement | null;\n /** Reports the sticky legend's width, which the horizontal bar keeps clear of since the legend does not scroll. */\n setLegendWidth: (width: number) => void;\n} & Pick<\n GanttData,\n 'onLaneSelect' | 'onMarkerSelect' | 'onAxisChange' | 'now' | 'showNow' | 'axis' | 'unitStep' | 'animate'\n>;\n\nconst [GanttProvider, useGanttContext] = createContext<GanttContextValue>('Gantt');\n\n//\n// Root\n//\n\ntype GanttRootProps = Util.ThemedClassName<GanttData & { children?: ReactNode }>;\n\n/**\n * Gantt view of lanes on a shared axis. The root resolves the rows and the axis and fills its host;\n * the parts lay out side by side in the order given, sharing one row grid: `Legend` names the lanes\n * and `Chart` draws them. A host that already lists the lanes renders the chart alone.\n *\n * The root owns the scrolling, on both axes at once: the legend's rows and the chart's move together\n * vertically, the legend stays put while the drawing scrolls horizontally, and the horizontal bar is\n * at the foot of the host rather than under the last lane.\n */\nconst GanttRoot = Util.composable<HTMLDivElement, GanttRootProps>(\n (\n {\n groups = [],\n lanes,\n markers = [],\n range: rangeProp,\n now,\n showNow,\n axis = 'unit',\n unitStep,\n animate,\n onLaneSelect,\n onMarkerSelect,\n onAxisChange,\n legend: legendProp,\n onLegendChange,\n children,\n ...props\n },\n forwardedRef,\n ) => {\n const [legendState, setLegendState] = useState<GanttLegendMode>('title');\n const legend = legendProp ?? legendState;\n const setLegend = useCallback(\n (next: GanttLegendMode) => {\n setLegendState(next);\n onLegendChange?.(next);\n },\n [onLegendChange],\n );\n const [viewport, setViewport] = useState<HTMLDivElement | null>(null);\n const [legendWidth, setLegendWidth] = useState(0);\n const { rows, bands } = useMemo(() => orderRows(groups, lanes), [groups, lanes]);\n const rowById = useMemo(() => new Map(rows.map((row) => [row.lane.id, row])), [rows]);\n const markerById = useMemo(() => new Map(markers.map((marker) => [marker.id, marker])), [markers]);\n const range = useMemo(() => {\n if (rangeProp) {\n return rangeProp;\n }\n const times = [\n ...lanes.flatMap((lane) => (lane.segments ?? []).flatMap((segment) => [segment.start, segment.end])),\n ...markers.map((marker) => marker.timestamp),\n ]\n .filter((time): time is number => time !== undefined)\n .concat(now === undefined ? [] : [now]);\n const start = times.length > 0 ? Math.min(...times) : 0;\n return { start, end: times.length > 0 ? Math.max(...times) : start };\n }, [rangeProp, lanes, markers, now]);\n\n return (\n <GanttProvider\n rows={rows}\n bands={bands}\n rowById={rowById}\n markers={markers}\n markerById={markerById}\n range={range}\n now={now}\n showNow={showNow}\n axis={axis}\n unitStep={unitStep}\n animate={animate}\n onLaneSelect={onLaneSelect}\n onMarkerSelect={onMarkerSelect}\n onAxisChange={onAxisChange}\n legend={legend}\n setLegend={setLegend}\n viewport={viewport}\n setLegendWidth={setLegendWidth}\n >\n <ScrollArea.Root\n {...Util.composableProps(props, { classNames: 'dx-expand text-xs font-mono' })}\n orientation='all'\n trackStart={legendWidth}\n ref={forwardedRef}\n >\n {/* `items-start`: the parts are drawn in pixel rows, so a stretching host must not spread them. */}\n <ScrollArea.Viewport classNames='flex items-start' ref={setViewport}>\n {children}\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </GanttProvider>\n );\n },\n);\n\nGanttRoot.displayName = 'Gantt.Root';\n\n//\n// Legend\n//\n\ntype GanttLegendProps = Util.ThemedClassName<PropsWithChildren>;\n\n/**\n * The lane names, one per row, indented by depth; each row is the lane's keyboard path. Children go\n * in the header row above the names, beside the chart's axis labels (e.g. `Gantt.AxisToggle`).\n *\n * The column shows each lane's title or its stats (`legend` on the root), and whichever it is not\n * showing is in a hover card over the row, so neither costs a column of its own.\n */\nconst GanttLegend = Util.composable<HTMLDivElement, GanttLegendProps>(({ children, ...props }, forwardedRef) => {\n const { rows, legend, onLaneSelect, setLegendWidth } = useGanttContext('Gantt.Legend');\n const legendRef = useRef<HTMLDivElement>(null);\n const ref = useComposedRefs(forwardedRef, legendRef);\n useEffect(() => {\n const element = legendRef.current;\n if (!element) {\n return;\n }\n const observer = new ResizeObserver(() => setLegendWidth(element.offsetWidth));\n observer.observe(element);\n return () => {\n observer.disconnect();\n setLegendWidth(0);\n };\n }, [setLegendWidth]);\n\n return (\n <div\n {...Util.composableProps(props, {\n // Sticky and opaque: the drawing scrolls horizontally beneath it. Sized against the scroll\n // frame (`cqw`) rather than its parent, whose width is the drawing's.\n classNames:\n 'sticky left-0 z-[1] shrink-0 w-[min(15rem,20cqw)] min-w-40 flex flex-col font-sans bg-(--surface-bg)',\n })}\n ref={ref}\n >\n <div className='flex items-center' style={{ height: HEADER_HEIGHT }}>\n {children}\n </div>\n {rows.map(({ lane, depth }) => (\n <div\n key={lane.id}\n className={mx(\n 'flex items-center gap-2 min-w-0',\n onLaneSelect && 'cursor-pointer hover:bg-hover-surface-subtle',\n )}\n style={{ height: ROW_HEIGHT, paddingInlineStart: `${0.5 + depth}rem` }}\n data-testid='gantt.legend.row'\n // Button semantics only when there is something to select: the label row is the lane's\n // keyboard path, and an inert focus stop would be noise.\n {...(onLaneSelect && {\n role: 'button',\n tabIndex: 0,\n onClick: () => onLaneSelect(lane),\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n onLaneSelect(lane);\n }\n },\n })}\n >\n <span\n className={mx('shrink-0 w-2 h-2 rounded-full bg-current', !lane.hue && STATUS_COLOR[lane.status].text)}\n style={lane.hue ? { color: hueColor(lane.hue) } : undefined}\n />\n <GanttLaneLabel lane={lane} legend={legend} />\n </div>\n ))}\n </div>\n );\n});\n\nGanttLegend.displayName = 'Gantt.Legend';\n\n/** A legend row's text, and a hover card holding what the column is not showing. */\nconst GanttLaneLabel = ({ lane, legend }: { lane: GanttLane; legend: GanttLegendMode }) => {\n const meta = lane.meta ?? [];\n const title = (\n <span className='truncate text-fg' data-testid='gantt.legend.title'>\n {lane.label}\n </span>\n );\n // Grows across the row so a lane with no stats still has something to hover for its title.\n const stats = (\n <span\n className='grow flex gap-2 truncate text-fg-muted whitespace-nowrap tabular-nums'\n data-testid='gantt.legend.stats'\n >\n {meta.map(({ label }, index) => (\n <span key={index}>{label}</span>\n ))}\n </span>\n );\n if (legend === 'title' && meta.length === 0) {\n return title;\n }\n\n return (\n <HoverCard.Root>\n <HoverCard.Trigger asChild>{legend === 'title' ? title : stats}</HoverCard.Trigger>\n <HoverCard.Content classNames='p-2 max-w-72 text-xs' data-testid='gantt.legend.card'>\n {legend === 'title' ? (\n meta.map(({ label, title }, index) => (\n <div key={index} className='tabular-nums'>\n {label}\n {title && <span className='text-fg-muted'>{` · ${title}`}</span>}\n </div>\n ))\n ) : (\n <div className='font-medium'>{lane.label}</div>\n )}\n </HoverCard.Content>\n </HoverCard.Root>\n );\n};\n\n//\n// AxisToggle\n//\n\ntype GanttAxisToggleProps = {};\n\n/**\n * Switches the chart between its axes: `time`, the run fitted to the width, and `unit`, one step per\n * event. Renders nothing unless the root was given `onAxisChange`, since the axis is the host's state.\n */\nconst GanttAxisToggle = (_: GanttAxisToggleProps) => {\n const { t } = Hooks.useTranslation(translationKey);\n const { axis = 'unit', onAxisChange } = useGanttContext('Gantt.AxisToggle');\n if (!onAxisChange) {\n return null;\n }\n\n // The icon names the axis in use; the label names the one a click switches to.\n return (\n <Button.Root\n variant='ghost'\n size='sm'\n iconSize='xs'\n iconOnly\n icon={axis === 'time' ? 'ph--clock--regular' : 'ph--dots-three-outline--regular'}\n label={t(axis === 'time' ? 'gantt-axis-unit.label' : 'gantt-axis-time.label')}\n onClick={() => onAxisChange(axis === 'time' ? 'unit' : 'time')}\n data-testid='gantt.axisToggle'\n />\n );\n};\n\nGanttAxisToggle.displayName = 'Gantt.AxisToggle';\n\n//\n// LegendToggle\n//\n\ntype GanttLegendToggleProps = {};\n\n/** Switches the legend's column between the lanes' titles and their stats. */\nconst GanttLegendToggle = (_: GanttLegendToggleProps) => {\n const { t } = Hooks.useTranslation(translationKey);\n const { legend, setLegend } = useGanttContext('Gantt.LegendToggle');\n\n // As the axis toggle: the icon names what is shown, the label what a click shows instead.\n return (\n <Button.Root\n variant='ghost'\n size='sm'\n iconSize='xs'\n iconOnly\n icon={legend === 'title' ? 'ph--text-aa--regular' : 'ph--chart-bar--regular'}\n label={t(legend === 'title' ? 'gantt-legend-stats.label' : 'gantt-legend-title.label')}\n onClick={() => setLegend(legend === 'title' ? 'stats' : 'title')}\n data-testid='gantt.legendToggle'\n />\n );\n};\n\nGanttLegendToggle.displayName = 'Gantt.LegendToggle';\n\n//\n// Chart\n//\n\ntype GanttChartProps = Util.ThemedClassName<{}>;\n\n/** One drawn stretch of a lane: where its bar runs, and the nodes threaded through it. */\ntype Stretch = {\n /** The instants the segment spans, in pixels. */\n from: number;\n to: number;\n /** The drawn positions of the first and last node inside it; absent when it holds fewer than two. */\n threadFrom?: number;\n threadTo?: number;\n};\n\n/**\n * The drawing: a lane is a rounded bar per segment with its markers threaded through as nodes, a\n * group's rectangle encloses its band, and connectors draw dependencies and the node a lane opened\n * out of.\n *\n * On the `unit` axis the drawing is as wide as the events need and follows the newest of them in the\n * root's scroll frame, while the legend beside it stays where it is.\n *\n * The drawing is one keyboard stop: clicking a node focuses it, the arrows walk the nodes (left and\n * right along a lane, up and down to the nearest node of the next lane), Space opens the current\n * node's card and Enter selects it — the same keys a legend row answers to.\n */\nconst GanttChart = forwardRef<SVGSVGElement, GanttChartProps>(({ classNames }, forwardedRef) => {\n const {\n rows,\n bands,\n rowById,\n markers,\n markerById,\n range,\n now,\n showNow,\n axis = 'unit',\n unitStep = UNIT_STEP,\n animate,\n onLaneSelect,\n onMarkerSelect,\n viewport,\n } = useGanttContext('Gantt.Chart');\n const { t } = Hooks.useTranslation(translationKey);\n const svgRef = useRef<SVGSVGElement | null>(null);\n const ref = useComposedRefs(forwardedRef, svgRef);\n const nodeIdPrefix = useId();\n /** The node the keyboard is on, and the node whose card is open (by hover or by Space). */\n const [currentId, setCurrentId] = useState<string>();\n const [openId, setOpenId] = useState<string>();\n const followRef = useRef(true);\n const glideRef = useRef(false);\n const frameRef = useRef<number | undefined>(undefined);\n const drawnRef = useRef<number | undefined>(undefined);\n const [width, setWidth] = useState(600);\n useEffect(() => {\n const element = viewport;\n if (!element) {\n return;\n }\n // The time axis is fitted to what the viewport shows beside the legend, not to the drawing, which may be wider.\n const measure = (): void => {\n const svg = svgRef.current;\n const offset = svg\n ? svg.getBoundingClientRect().left - element.getBoundingClientRect().left + element.scrollLeft\n : 0;\n setWidth(Math.max(element.clientWidth - offset, 0));\n };\n const observer = new ResizeObserver(measure);\n observer.observe(element);\n // Listened for rather than taken as a prop: `ScrollArea.Viewport` accepts only what it slots.\n const onScroll = (): void => {\n const atEdge = element.scrollWidth - element.clientWidth - element.scrollLeft <= FOLLOW_SLACK;\n // A glide of our own emits scroll events all the way there, every one of them short of the\n // edge. Reading those as the reader scrolling away would unpin the chart on the very frame it\n // set out to follow; only its arrival is worth acting on.\n if (glideRef.current) {\n glideRef.current = !atEdge;\n return;\n }\n followRef.current = atEdge;\n };\n element.addEventListener('scroll', onScroll, { passive: true });\n return () => {\n observer.disconnect();\n element.removeEventListener('scroll', onScroll);\n };\n }, [viewport]);\n\n /** Each lane's markers in the order they happened: the threads, the bars and the enter origins read it. */\n const laneMarkers = useMemo(() => {\n const byLane = new Map<string, GanttMarker[]>();\n for (const marker of markers) {\n const list = byLane.get(marker.laneId);\n if (list) {\n list.push(marker);\n } else {\n byLane.set(marker.laneId, [marker]);\n }\n }\n for (const list of byLane.values()) {\n list.sort((left, right) => left.timestamp - right.timestamp);\n }\n return byLane;\n }, [markers]);\n\n // The time axis is fitted to the viewport, so moving bounds rescale everything already drawn;\n // easing the range makes that a slide rather than a jump. The unit axis never rescales.\n // The time axis moves only when something happens: its bounds end at the newest drawn instant (a\n // node or a segment edge) rather than at the host's range, which may follow the wall clock and would\n // rescale an idle chart forever. Open lanes run to that same edge, so none is clipped.\n const lastEvent = useMemo(() => {\n const times = [\n ...markers.map((marker) => marker.timestamp),\n ...rows.flatMap(({ lane }) => (lane.segments ?? []).flatMap(({ start, end }) => [start, end ?? start])),\n ];\n return times.length > 0 ? Math.max(...times) : undefined;\n }, [markers, rows]);\n const targetRange = useMemo(\n () => (lastEvent === undefined ? range : { start: range.start, end: Math.max(lastEvent, range.start) }),\n [range.start, range.end, lastEvent],\n );\n const shownRange = useRangeTween(targetRange, axis === 'time');\n // CSS geometry transitions would chase every frame of that ease and trail behind it, so they run\n // on the unit axis only; the stroke dash drawing a connector on is not geometry and always may.\n const slide = animate === true && axis === 'unit';\n const scale: GanttScale = useMemo(\n () =>\n axis === 'unit'\n ? unitScale({ times: markers.map((marker) => marker.timestamp), step: unitStep, pad: PAD_X })\n : timeScale({ range: shownRange, width, pad: PAD_X }),\n [axis, markers, unitStep, shownRange, width],\n );\n const isEntering = useEnter(markers.map((marker) => marker.id));\n\n // On the time axis the right edge is \"now\" — the newest event, where open lanes end. While the range\n // eases toward new bounds, anything newer than the drawn range is held at that edge rather than drawn\n // past it: the new event and the open ends stay pinned while everything older compresses leftward.\n const edge = axis === 'time' ? scale.at(shownRange.end) : undefined;\n const x = (time: number): number => (edge === undefined ? scale.at(time) : Math.min(scale.at(time), edge));\n const rowY = (index: number): number => HEADER_HEIGHT + index * ROW_HEIGHT + ROW_HEIGHT / 2;\n const openSource = (lane: GanttLane): GanttMarker | undefined =>\n lane.openedFrom && markerById.get(lane.openedFrom.markerId);\n\n // Where each node is drawn: its own place, or — for the one frame in which it arrives — the place it\n // came from, which is what the transitions below then travel out of. A lane's first node comes from\n // the node the lane opened out of, so a lane reads as branching from whatever caused it.\n const markerX = new Map<string, number>();\n // The newest node of a lane that is still running: the end the next event will land on, and the\n // one thing in the drawing that is not yet history.\n const activeEdges = new Set<string>();\n for (const [laneId, list] of laneMarkers) {\n const row = rowById.get(laneId);\n if (!row) {\n continue;\n }\n const newest = list[list.length - 1];\n if (row.lane.status === 'running' && newest) {\n activeEdges.add(newest.id);\n }\n list.forEach((marker, index) => {\n const previous = index > 0 ? list[index - 1] : undefined;\n const source = previous ? undefined : openSource(row.lane);\n const origin = previous ? x(previous.timestamp) : source && x(source.timestamp);\n const resting = x(marker.timestamp);\n markerX.set(marker.id, slide && origin !== undefined && isEntering(marker.id) ? origin : resting);\n });\n }\n\n /**\n * A lane's drawn stretches, one per segment. An open segment reaches its last node, taking the\n * node's drawn position rather than its instant so the bar grows with an arriving event instead of\n * jumping ahead of it — and on to the chart's newest event when that is later.\n */\n const stretchesOf = (lane: GanttLane): Stretch[] => {\n const list = laneMarkers.get(lane.id) ?? [];\n const segments = lane.segments ?? [];\n return segments.map((segment, index) => {\n const upper = segment.end ?? segments[index + 1]?.start ?? Number.MAX_SAFE_INTEGER;\n const inside = list.filter((marker) => marker.timestamp >= segment.start && marker.timestamp <= upper);\n const first = inside[0];\n const last = inside[inside.length - 1];\n const from = x(segment.start);\n // An open stretch runs to its newest node, and on to the newest event anywhere on the chart when\n // that is later: a lane still being worked between its own events (a parent task while its\n // sub-tasks run) is not a point.\n const lastX = last ? (markerX.get(last.id) ?? x(last.timestamp)) : undefined;\n const edgeX = lastEvent !== undefined ? x(lastEvent) : undefined;\n const to =\n segment.end !== undefined\n ? x(segment.end)\n : lastX !== undefined && edgeX !== undefined\n ? Math.max(lastX, edgeX)\n : (lastX ?? edgeX ?? from);\n const threaded = inside.length > 1 && first && last;\n return {\n from,\n to: Math.max(to, from),\n threadFrom: threaded ? markerX.get(first.id) : undefined,\n threadTo: threaded ? markerX.get(last.id) : undefined,\n };\n });\n };\n\n // A lane whose first node has just arrived is opening: its bar extends from its own beginning\n // rather than appearing at full length, and the connector that caused it draws out to meet it.\n const isOpening = (lane: GanttLane): boolean => {\n const first = laneMarkers.get(lane.id)?.[0];\n return slide && first !== undefined && isEntering(first.id);\n };\n\n const height = HEADER_HEIGHT + rows.length * ROW_HEIGHT;\n const grow = slide && mx('transition-[width]', ENTER_TRANSITION);\n\n const nodeIds = useMemo(\n () => new Map(markers.map((marker, index) => [marker.id, `${nodeIdPrefix}-node-${index}`])),\n [markers, nodeIdPrefix],\n );\n const current = currentId === undefined ? undefined : markerById.get(currentId);\n\n /** The node an arrow key moves to from `from`; `from` itself where there is nowhere further to go. */\n const neighbour = (from: GanttMarker, key: string): GanttMarker => {\n if (key === 'ArrowLeft' || key === 'ArrowRight') {\n const list = laneMarkers.get(from.laneId) ?? [];\n const index = list.findIndex((marker) => marker.id === from.id);\n return list[index + (key === 'ArrowLeft' ? -1 : 1)] ?? from;\n }\n const row = rowById.get(from.laneId);\n if (!row) {\n return from;\n }\n // The nearest node in drawn position rather than in time: on the unit axis the two disagree, and\n // the reader is following what they see.\n const fromX = markerX.get(from.id) ?? x(from.timestamp);\n const distance = (marker: GanttMarker): number => Math.abs((markerX.get(marker.id) ?? x(marker.timestamp)) - fromX);\n const direction = key === 'ArrowUp' ? -1 : 1;\n // Lanes with no nodes are passed over: there is nothing on them to land on.\n for (let index = row.index + direction; index >= 0 && index < rows.length; index += direction) {\n const list = laneMarkers.get(rows[index].lane.id) ?? [];\n if (list.length > 0) {\n return list.reduce((best, marker) => (distance(marker) < distance(best) ? marker : best));\n }\n }\n return from;\n };\n\n /** Scrolls the frame just enough to show `marker` clear of the sticky legend and the frame's edges. */\n const reveal = (marker: GanttMarker): void => {\n const svg = svgRef.current;\n const row = rowById.get(marker.laneId);\n const cx = markerX.get(marker.id);\n if (!viewport || !svg || !row || cx === undefined) {\n return;\n }\n const frame = viewport.getBoundingClientRect();\n const drawing = svg.getBoundingClientRect();\n const legendWidth = drawing.left - frame.left + viewport.scrollLeft;\n const nodeX = drawing.left - frame.left + cx;\n const nodeY = drawing.top - frame.top + rowY(row.index);\n const margin = ROW_HEIGHT;\n const left =\n nodeX - margin < legendWidth\n ? nodeX - margin - legendWidth\n : nodeX + margin > viewport.clientWidth\n ? nodeX + margin - viewport.clientWidth\n : 0;\n const top =\n nodeY - margin < 0\n ? nodeY - margin\n : nodeY + margin > viewport.clientHeight\n ? nodeY + margin - viewport.clientHeight\n : 0;\n if (left !== 0 || top !== 0) {\n viewport.scrollBy({ left, top });\n }\n };\n\n const moveTo = (marker: GanttMarker): void => {\n setCurrentId(marker.id);\n // An open card travels with the current node.\n setOpenId((open) => (open === undefined ? undefined : marker.id));\n reveal(marker);\n };\n\n const handleKeyDown = (event: KeyboardEvent<SVGSVGElement>): void => {\n switch (event.key) {\n case 'ArrowLeft':\n case 'ArrowRight':\n case 'ArrowUp':\n case 'ArrowDown': {\n event.preventDefault();\n // With no node yet, the first lane's newest: the unit axis opens on the present.\n const next = current\n ? neighbour(current, event.key)\n : rows.map(({ lane }) => laneMarkers.get(lane.id)?.at(-1)).find((marker) => marker !== undefined);\n if (next) {\n moveTo(next);\n }\n break;\n }\n case ' ': {\n event.preventDefault();\n if (current) {\n setOpenId((open) => (open === current.id ? undefined : current.id));\n }\n break;\n }\n case 'Escape': {\n if (openId !== undefined) {\n event.preventDefault();\n setOpenId(undefined);\n }\n break;\n }\n case 'Enter': {\n if (current) {\n event.preventDefault();\n onMarkerSelect?.(current);\n }\n break;\n }\n }\n };\n\n // The unit axis grows to the right, so the newest event has to be followed — but only while the\n // reader is at its edge; having scrolled back, they are reading, not watching. A layout effect, so\n // the first paint already shows the newest events rather than jumping to them from the start.\n useLayoutEffect(() => {\n const element = viewport;\n // Recorded only once there is a frame to scroll, so the first paint with one still opens on the present.\n if (!element) {\n return;\n }\n const previous = drawnRef.current;\n drawnRef.current = scale.width;\n\n // Opened on the present: what is happening now is what the chart is looked at for. A drawing that\n // fitted until now counts as opening too — its events arrived after mount, and there was no place\n // in it for the reader to keep.\n const grown = previous !== undefined && scale.width > previous;\n if (previous === undefined || (grown && previous <= width)) {\n element.scrollLeft = element.scrollWidth;\n return;\n }\n\n if (!grown || !followRef.current) {\n return;\n }\n\n // Glided rather than jumped: the drawing is unchanged to the left of the new event, and a jump\n // asks the reader to re-find their place in it every time one arrives. A reader who asked for\n // less motion gets none.\n if (window.matchMedia?.('(prefers-reduced-motion: reduce)').matches) {\n element.scrollLeft = element.scrollWidth;\n return;\n }\n\n // Animated here rather than by `scrollTo({ behavior: 'smooth' })`, whose curve is the browser's\n // own and fixed: it arrives in a fraction of the time the event that caused it takes to settle,\n // so the window lurches ahead of the drawing it is following.\n const from = element.scrollLeft;\n const to = element.scrollWidth - element.clientWidth;\n if (to <= from) {\n return;\n }\n const started = performance.now();\n glideRef.current = true;\n const step = (now: number): void => {\n const progress = Math.min((now - started) / FOLLOW_DURATION, 1);\n // Eased out, the shape everything else in the drawing travels on, so the two agree.\n element.scrollLeft = from + (to - from) * (1 - (1 - progress) ** 3);\n if (progress < 1) {\n frameRef.current = requestAnimationFrame(step);\n } else {\n glideRef.current = false;\n }\n };\n frameRef.current = requestAnimationFrame(step);\n // A glide still running when the next event arrives is abandoned where it got to; the glide that\n // replaces it starts from there, so the drift retargets rather than restarting.\n return () => {\n if (frameRef.current !== undefined) {\n cancelAnimationFrame(frameRef.current);\n }\n glideRef.current = false;\n };\n }, [scale.width, viewport]);\n\n return (\n <svg\n // Pixel coordinates against the drawing's own width, with no viewBox: a viewBox would\n // letterbox the drawing to the column's aspect ratio and shrink every node with it. Grows into\n // the row the legend leaves when the events need less.\n className={mx('grow shrink-0 dx-focus-ring', classNames)}\n style={{ width: scale.width, height }}\n tabIndex={0}\n role='group'\n aria-label={t('gantt-chart.label')}\n aria-activedescendant={current ? nodeIds.get(current.id) : undefined}\n onKeyDown={handleKeyDown}\n data-testid='gantt.chart'\n ref={ref}\n >\n {scale.ticks.map(({ at, label }, index) => (\n <g key={index}>\n <line x1={at} x2={at} y1={HEADER_HEIGHT} y2={height} className='stroke-separator' />\n <text\n x={at}\n y={HEADER_HEIGHT - 6}\n // Anchored inward at the drawing's own edges, so no label is drawn outside it.\n textAnchor={at <= PAD_X ? 'start' : at >= scale.width - PAD_X ? 'end' : 'middle'}\n className='fill-current text-fg-subtle'\n >\n {label}\n </text>\n </g>\n ))}\n\n {/* Under the lanes and connectors: a dependency on a still-running lane anchors at `now`\n and would otherwise be hidden by this line. */}\n {now !== undefined && showNow && (\n <line\n x1={x(now)}\n x2={x(now)}\n y1={0}\n y2={height}\n strokeDasharray='3 3'\n className={STATUS_COLOR.running.thread}\n />\n )}\n\n {/* A group's rectangle encloses its band — the lanes it holds, and only those: a nested\n group is a band of its own, drawn further down. */}\n {bands.flatMap(({ group, first, last }) => {\n const stretches = rows.slice(first, last + 1).flatMap((row) => stretchesOf(row.lane));\n if (stretches.length === 0) {\n return [];\n }\n const left = Math.min(...stretches.map((stretch) => stretch.from)) - BAR_OVERHANG - GROUP_PAD;\n const right = Math.max(...stretches.map((stretch) => stretch.to)) + BAR_OVERHANG + GROUP_PAD;\n return [\n <rect\n key={`band:${group.id}`}\n x={left}\n y={rowY(first) - ROW_HEIGHT / 2 + GROUP_INSET}\n width={Math.max(right - left, ROW_HEIGHT)}\n height={(last - first + 1) * ROW_HEIGHT - 2 * GROUP_INSET}\n rx={GROUP_RADIUS}\n className={mx('fill-input-surface', grow)}\n />,\n ];\n })}\n\n {/* Connectors next, so the drop to a lane passes beneath any bar it crosses. */}\n {rows.flatMap(({ lane, index }) =>\n (lane.blockedOn ?? []).flatMap((depId) => {\n const dep = rowById.get(depId);\n if (!dep) {\n return [];\n }\n // Anchored on the end of the dependency's last stretch, so the line meets a node rather\n // than a bar edge.\n const stretches = stretchesOf(dep.lane);\n const anchor = stretches[stretches.length - 1];\n if (!anchor) {\n return [];\n }\n const anchorX = anchor.to;\n return [\n <line\n key={`${lane.id}:${depId}`}\n x1={anchorX}\n x2={anchorX}\n y1={rowY(dep.index)}\n y2={rowY(index)}\n strokeDasharray='2 2'\n className={STATUS_COLOR.blocked.thread}\n />,\n // A waiter with no bar has nothing on its row for the line to reach, so it ends on a\n // hollow node: the point the waiter is held at until the dependency resolves.\n ...((lane.segments ?? []).length === 0\n ? [\n <circle\n key={`${lane.id}:${depId}:hold`}\n cx={anchorX}\n cy={rowY(index)}\n r={NODE_RADIUS}\n className={mx('fill-base-surface', STATUS_COLOR.blocked.thread)}\n />,\n ]\n : []),\n ];\n }),\n )}\n\n {/* Down from the node a lane opened out of, a quarter bend, then right to where it begins. */}\n {rows.flatMap(({ lane, index }) => {\n const source = openSource(lane);\n const sourceRow = lane.openedFrom && rowById.get(lane.openedFrom.laneId);\n const stretches = stretchesOf(lane);\n if (!source || !sourceRow || stretches.length === 0) {\n return [];\n }\n const sourceX = x(source.timestamp);\n const y = rowY(index);\n const targetX = stretches[0].from;\n // Down, a quarter bend, then right to where the lane begins — but only while there is\n // somewhere forward to go. A lane that begins at or before the node that opened it has no\n // run to make, and bending anyway would hook the connector sideways into the middle of its\n // own bar; the drop lands on the row instead. The bar stays where the data puts it either\n // way: a connector doubling back over itself reads as a line to somewhere else entirely.\n const path =\n targetX > sourceX + BEND_RADIUS\n ? `M ${sourceX} ${rowY(sourceRow.index)} V ${y - BEND_RADIUS} Q ${sourceX} ${y} ${sourceX + BEND_RADIUS} ${y} H ${targetX}`\n : `M ${sourceX} ${rowY(sourceRow.index)} V ${y}`;\n return [\n <path\n key={`opened:${lane.id}`}\n d={path}\n fill='none'\n // Drawn on by its dash rather than by its shape: `d` is beyond what a transition can\n // reach, while `stroke-dashoffset` is a property every renderer animates. `pathLength`\n // normalises the path to 1 so one dash covers it whatever its actual length — which is\n // also why these are inert, and the connector solid, when it is not opening.\n pathLength={1}\n strokeDasharray={1}\n strokeDashoffset={isOpening(lane) ? 1 : 0}\n className={mx(animate && mx('transition-[stroke-dashoffset]', ENTER_TRANSITION), CONNECTOR_CLASSNAME)}\n />,\n ];\n })}\n\n {/* Back out of the lane's last stretch and up into the node its result answered. Dashed, and\n the spawn is not: one is the moment work was handed over, the other the moment an answer\n arrived, and a reader following a cascade needs to tell the two directions apart. */}\n {rows.flatMap(({ lane, index }) => {\n const target = lane.closedInto && markerById.get(lane.closedInto.markerId);\n const targetRow = lane.closedInto && rowById.get(lane.closedInto.laneId);\n const stretches = stretchesOf(lane);\n const last = stretches[stretches.length - 1];\n if (!target || !targetRow || !last) {\n return [];\n }\n const targetX = x(target.timestamp);\n const y = rowY(index);\n const targetY = rowY(targetRow.index);\n // Which way the bend turns depends on whether the answer went up the chart or down it;\n // a lane is normally below the one it reports to, but nothing in the model requires it.\n const rise = Math.sign(targetY - y) * BEND_RADIUS;\n // Forward only, for the same reason the spawn connector is: a run doubling back reads as\n // a line to somewhere else. With nowhere to run, the rise happens at the answer's own node.\n const path =\n targetX > last.to + BEND_RADIUS\n ? `M ${last.to} ${y} H ${targetX - BEND_RADIUS} Q ${targetX} ${y} ${targetX} ${y + rise} V ${targetY}`\n : `M ${targetX} ${y} V ${targetY}`;\n return [\n <path key={`closed:${lane.id}`} d={path} fill='none' strokeDasharray='3 2' className={CONNECTOR_CLASSNAME} />,\n ];\n })}\n\n {/* One bar per segment: the gaps between them are the stretches the lane was not worked. */}\n {rows.flatMap(({ lane, index }) =>\n stretchesOf(lane).map((stretch, segment) => {\n const start = stretch.from - BAR_OVERHANG;\n const bar = {\n x: start,\n y: rowY(index) - BAR_HEIGHT / 2,\n // An opening lane is a dot at its own beginning for one frame, so it extends from where\n // the connector lands instead of being there at full length before the connector is.\n width: isOpening(lane) ? BAR_HEIGHT : Math.max(stretch.to + BAR_OVERHANG - start, BAR_HEIGHT),\n height: BAR_HEIGHT,\n rx: BAR_HEIGHT / 2,\n };\n // An opaque backing under the translucent tint: the connectors pass beneath the bars, and\n // without it they would show through.\n return (\n <g key={`${lane.id}:${segment}`} className='cursor-pointer' onClick={() => onLaneSelect?.(lane)}>\n <rect {...bar} className={mx('fill-base-surface', grow)} />\n {lane.hue ? (\n <rect {...bar} className={mx(grow)} style={{ fill: hueColor(lane.hue), fillOpacity: 0.4 }} />\n ) : (\n <rect {...bar} className={mx(STATUS_COLOR[lane.status].fill, grow)} />\n )}\n </g>\n );\n }),\n )}\n\n {/* The thread through a segment's nodes, so a stretch reads as a sequence rather than dots. */}\n {rows.flatMap(({ lane, index }) =>\n stretchesOf(lane).flatMap((stretch, segment) =>\n stretch.threadFrom === undefined || stretch.threadTo === undefined\n ? []\n : [\n // A hairline rect rather than a line: a line's `x1`/`x2` are attributes and nothing\n // else, while `x` and `width` are geometry properties a transition can reach, so the\n // thread grows with the node it is reaching for instead of arriving ahead of it.\n <rect\n key={`thread:${lane.id}:${segment}`}\n x={stretch.threadFrom}\n y={rowY(index) - THREAD_HEIGHT / 2}\n width={Math.max(stretch.threadTo - stretch.threadFrom, 0)}\n height={THREAD_HEIGHT}\n className={mx(\n slide && mx('transition-[x,width]', ENTER_TRANSITION),\n !lane.hue && STATUS_COLOR[lane.status].node,\n )}\n style={lane.hue ? { fill: hueColor(lane.hue) } : undefined}\n />,\n ],\n ),\n )}\n\n {/* An answered wait, dashed from the node that began it to the one that ended it, so the stretch\n a task spent held up reads as part of its lane rather than a gap in it. */}\n {markers.flatMap((marker) => {\n const row = marker.wait && rowById.get(marker.laneId);\n const from = markerX.get(marker.id);\n const to = marker.wait && markerX.get(marker.wait.until);\n if (!row || from === undefined || to === undefined || to <= from) {\n return [];\n }\n return [\n <line\n key={`wait:${marker.id}`}\n x1={from}\n x2={to}\n y1={rowY(row.index)}\n y2={rowY(row.index)}\n strokeWidth={2}\n strokeDasharray='4 3'\n className={row.lane.hue ? undefined : STATUS_COLOR[row.lane.status].thread}\n style={row.lane.hue ? { stroke: hueStrongColor(row.lane.hue) } : undefined}\n />,\n ];\n })}\n\n {/* Nodes last, over the bars and every line, so a line reads as ending at a node's centre. */}\n {markers.map((marker) => {\n const row = rowById.get(marker.laneId);\n const cx = markerX.get(marker.id);\n return row && cx !== undefined ? (\n <Fragment key={marker.id}>\n {/* Pings out from behind the node until answered, so the node itself stays readable. */}\n {marker.pending && (\n <circle\n cx={cx}\n cy={rowY(row.index)}\n r={NODE_RADIUS}\n className='animate-ping transform-fill origin-center pointer-events-none fill-error-500'\n />\n )}\n <HoverCard.Root\n open={openId === marker.id}\n onOpenChange={({ open }) =>\n setOpenId((previous) => (open ? marker.id : previous === marker.id ? undefined : previous))\n }\n >\n <HoverCard.Trigger asChild>\n <circle\n id={nodeIds.get(marker.id)}\n role='img'\n aria-label={marker.label}\n data-marker-id={marker.id}\n data-lane-id={marker.laneId}\n cx={cx}\n cy={rowY(row.index)}\n r={NODE_RADIUS}\n className={mx(\n 'cursor-pointer hover:stroke-[3px] hover:stroke-fg',\n // A question or an error is ringed in red; an error pulses while its lane stays\n // failed (an unanswered question pings instead — the ring drawn behind it).\n isAlert(marker) ? 'stroke-red-500 stroke-2' : 'stroke-base-surface',\n marker.level === 'error' && row.lane.status === 'failed' && 'animate-pulse',\n // `cx` as a transition: where a browser exposes SVG geometry as CSS the node\n // slides out of the one before it, and where it does not it simply appears.\n slide ? mx('transition-[stroke-width,cx]', ENTER_TRANSITION) : 'transition-[stroke-width]',\n // The live end pulses in the lane's stronger shade: scanning a wall of finished\n // lanes, the ones still moving should be findable without reading the legend.\n // A question or an error is a solid node in the lane's own hue: the same thread,\n // so it reads as that task's, but the stronger shade so it is found at a glance.\n activeEdges.has(marker.id)\n ? mx('animate-pulse', !row.lane.hue && STATUS_COLOR[row.lane.status].edge)\n : !row.lane.hue &&\n (isAlert(marker) ? STATUS_COLOR[row.lane.status].edge : STATUS_COLOR[row.lane.status].node),\n // The keyboard's place, ringed as a hovered node is.\n marker.id === currentId && 'stroke-[3px] stroke-fg',\n )}\n style={\n row.lane.hue\n ? { fill: isAlert(marker) ? hueStrongColor(row.lane.hue) : hueColor(row.lane.hue) }\n : undefined\n }\n onClick={() => {\n setCurrentId(marker.id);\n svgRef.current?.focus({ preventScroll: true });\n onMarkerSelect?.(marker);\n }}\n />\n </HoverCard.Trigger>\n <HoverCard.Content classNames='p-2 max-w-72 text-xs' data-testid='gantt.markerCard'>\n <div className='font-medium truncate'>{marker.label}</div>\n <div className='text-fg-muted truncate'>{row.lane.label}</div>\n <div className='text-fg-muted tabular-nums'>\n {marker.kind && `${marker.kind} · `}\n {format(marker.timestamp, 'HH:mm:ss')}\n {/* Elapsed on the axis's own terms, so it reads against the tick labels. */}\n {` · +${formatElapsed(marker.timestamp - range.start, { span: marker.timestamp - range.start, step: 1_000 })}`}\n {marker.level && marker.level !== 'info' && (\n <span className={mx('ms-2', marker.level === 'error' ? 'text-error-text' : 'text-warning-text')}>\n {marker.level}\n </span>\n )}\n </div>\n </HoverCard.Content>\n </HoverCard.Root>\n </Fragment>\n ) : null;\n })}\n </svg>\n );\n});\n\nGanttChart.displayName = 'Gantt.Chart';\n\nexport const Gantt = {\n Root: GanttRoot,\n Legend: GanttLegend,\n AxisToggle: GanttAxisToggle,\n LegendToggle: GanttLegendToggle,\n Chart: GanttChart,\n};\n\nexport type { GanttAxisToggleProps, GanttChartProps, GanttLegendProps, GanttLegendToggleProps, GanttRootProps };\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { RegistryContext } from '@effect/atom-react/RegistryContext';\nimport * as Match from 'effect/Match';\nimport * as Option from 'effect/Option';\nimport React, { useCallback, useContext, useMemo, useRef } from 'react';\n\nimport * as Process from '@dxos/compute/Process';\nimport { Tree, type TreeNode, type TreeSelectEvent, createStaticTreeModel } from '@dxos/react-ui-list';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport * as Tooltip from '@dxos/react-ui/Tooltip';\nimport * as Util from '@dxos/react-ui/Util';\nimport { Unit } from '@dxos/util';\n\nconst DEFAULT_DEPTH = 1;\n/** Nested subprocess rows (level > 1) only surface still-active processes. */\nconst NESTED_ACTIVE_STATES = new Set<Process.State>([\n Process.State.RUNNING,\n Process.State.HYBERNATING,\n Process.State.TERMINATING,\n]);\n\nexport type ProcessTreeProps = {\n // TODO(burdon): Atom.\n processes: readonly Process.Process[];\n /**\n * Maximum nesting depth from the root (1 = top-level processes only).\n *\n * @default 1\n */\n depth?: number;\n /**\n * Overrides the row label for a process (e.g. the name of the chat it is serving), falling back to\n * the process name when it returns `undefined`.\n *\n * Must be referentially stable — `ProcessTree` is memoized on its props.\n */\n resolveLabel?: (process: Process.Process) => string | undefined;\n /** Pids drawn as selected; the tree is controlled, so a click reports through `onSelectedChange`. */\n selected?: readonly string[];\n /** The selection after a click: the clicked pid alone, or toggled among the others on a meta-click. */\n onSelectedChange?: (selected: string[]) => void;\n onProcessTerminate?: (process: Process.Process) => void;\n};\n\n/** Node of the pruned process forest handed to the tree model. */\ntype ProcessNode = {\n id: string;\n /** Absent on the synthetic root, which anchors the top-level processes and is never rendered. */\n process?: Process.Process;\n children: ProcessNode[];\n};\n\n/** Synthetic root; the tree renders its children, never the root itself. */\nconst ROOT_ID = 'processes';\n\nconst NO_SELECTION: readonly string[] = [];\n\n/**\n * The agent's running processes as a tree, one row per process with its status glyph and metrics\n * in trailing columns. The forest is rebuilt on every metrics tick, so open state lives outside the\n * model and is re-seeded — a collapse must survive the next tick. Renders through `Tree`.\n */\nexport const ProcessTree = React.memo(\n Util.composable<HTMLDivElement, ProcessTreeProps>(\n (\n {\n processes,\n depth = DEFAULT_DEPTH,\n resolveLabel,\n selected = NO_SELECTION,\n onSelectedChange,\n onProcessTerminate,\n ...props\n },\n forwardedRef,\n ) => {\n // Open state lives outside the model: `processes` carries live metrics, so the forest (and with\n // it the model) is rebuilt on every tick, and a collapse held only inside the model would be\n // undone by the next one.\n const openRef = useRef(new Map<string, boolean>());\n const registry = useContext(RegistryContext);\n const root = useMemo(() => buildProcessForest(processes, depth), [processes, depth]);\n\n const model = useMemo(\n () =>\n createStaticTreeModel<ProcessNode>(root, {\n getChildren: (node) => node.children,\n getProps: (node) => ({\n label: (node.process && resolveLabel?.(node.process)) ?? node.process?.params.name ?? node.id,\n }),\n // Expanded by default, matching the flattened view this replaced.\n isOpen: (_node, path) => openRef.current.get(path.join('/')) ?? true,\n isCurrent: (node) => node.process !== undefined && selected.includes(node.process.pid),\n }),\n [root, resolveLabel, selected],\n );\n\n // The ref survives model rebuilds; the atom is what the controlled tree actually reads, so a\n // toggle has to land in both.\n const handleOpenChange = useCallback(\n ({ path, open }: { path: string[]; open: boolean }) => {\n openRef.current.set(path.join('/'), open);\n const atom = model.stateAtom(path);\n registry.set(atom, { ...registry.get(atom), open });\n },\n [model, registry],\n );\n\n const handleSelect = useCallback(\n ({ item, current, meta }: TreeSelectEvent<ProcessNode>) => {\n if (!item.process) {\n return;\n }\n const pid = item.process.pid.toString();\n onSelectedChange?.(\n !meta ? [pid] : current ? [...selected, pid] : selected.filter((candidate) => candidate !== pid),\n );\n },\n [selected, onSelectedChange],\n );\n\n const renderRow = useCallback(\n (node: TreeNode<ProcessNode>) => <ProcessRow node={node} onProcessTerminate={onProcessTerminate} />,\n [onProcessTerminate],\n );\n\n return (\n <div {...Util.composableProps(props, { classNames: 'flex flex-col min-h-0' })} ref={forwardedRef}>\n <Tree.Root\n id={ROOT_ID}\n model={model}\n virtual='fixed'\n size='sm'\n selectionMode='multiple'\n columns={COLUMNS}\n onOpenChange={handleOpenChange}\n onSelect={handleSelect}\n >\n <Tree.Content>{renderRow}</Tree.Content>\n </Tree.Root>\n </div>\n );\n },\n ),\n);\n\n/** Disclosure, status glyph, label, then the elapsed time and the terminate control. */\nconst COLUMNS = 'var(--dx-half-block-size) var(--dx-block-size) minmax(0, 1fr) min-content min-content';\n\ntype ProcessRowProps = {\n node: TreeNode<ProcessNode>;\n onProcessTerminate?: (process: Process.Process) => void;\n};\n\n/** One process: its status glyph (animated, coloured and tooltipped per state), elapsed time and terminate control. */\nconst ProcessRow = ({ node, onProcessTerminate }: ProcessRowProps) => {\n const process = node.item?.process;\n return (\n <Tree.Item node={node}>\n <Tree.ItemIndicator />\n <Tree.ItemIcon>{process && <StatusIcon process={process} />}</Tree.ItemIcon>\n <Tree.ItemText />\n <span className='text-end ps-1 text-xs text-fg-muted tabular-nums whitespace-nowrap'>\n {process &&\n [Process.State.FAILED, Process.State.SUCCEEDED].includes(process.state) &&\n Unit.Duration(process.metrics.wallTime).toString()}\n </span>\n <span>\n {process && onProcessTerminate && process.state !== Process.State.TERMINATED && (\n <Button.Root\n icon='ph--x--regular'\n iconOnly\n size='sm'\n variant='ghost'\n label='Actions'\n onClick={(event) => {\n event.stopPropagation();\n onProcessTerminate(process);\n }}\n />\n )}\n </span>\n </Tree.Item>\n );\n};\n\nconst StatusIcon = ({ process }: { process: Process.Process }) => (\n <Tooltip.Trigger content={process.state.toString()}>\n <Icon.Icon\n size='md'\n spin={process.state === Process.State.RUNNING}\n valence={\n process.state === Process.State.FAILED\n ? 'error'\n : process.state === Process.State.SUCCEEDED\n ? 'success'\n : undefined\n }\n icon={Match.value(process.state).pipe(\n Match.when(Process.State.RUNNING, () => 'ph--spinner-gap--regular'),\n Match.when(Process.State.SUCCEEDED, () => 'ph--check-circle--regular'),\n Match.when(Process.State.FAILED, () => 'ph--warning--regular'),\n Match.when(Process.State.HYBERNATING, () => 'ph--spinner--regular'),\n Match.when(Process.State.IDLE, () => 'ph--moon-stars--regular'),\n Match.when(Process.State.TERMINATING, () => 'ph--x-circle--regular'),\n Match.when(Process.State.TERMINATED, () => 'ph--x-circle--regular'),\n Match.orElse(() => 'ph--spinner-gap--regular'),\n )}\n />\n </Tooltip.Trigger>\n);\n\nconst sortProcesses = (processes: readonly Process.Process[]): Process.Process[] => {\n return [\n ...processes.filter((process) => [Process.State.RUNNING, Process.State.HYBERNATING].includes(process.state)),\n ...processes.filter((process) => [Process.State.IDLE].includes(process.state)).slice(0, 3),\n ...processes.filter((process) =>\n [Process.State.SUCCEEDED, Process.State.FAILED, Process.State.TERMINATED].includes(process.state),\n ),\n ].sort((left, right) => {\n const leftCompletedAt = Option.getOrElse(left.completedAt, () => Infinity);\n const rightCompletedAt = Option.getOrElse(right.completedAt, () => Infinity);\n return rightCompletedAt - leftCompletedAt;\n });\n};\n\nconst sortNestedActive = (processes: readonly Process.Process[]): Process.Process[] =>\n processes\n .filter((process) => NESTED_ACTIVE_STATES.has(process.state))\n .sort((left, right) => {\n const priority = (state: Process.State) =>\n state === Process.State.RUNNING ? 0 : state === Process.State.HYBERNATING ? 1 : 2;\n return priority(left.state) - priority(right.state);\n });\n\n/**\n * Builds the process forest, pruned to `maxDepth` from each root. Nested levels surface only still-\n * active processes, so a deep tree stays readable while completed work collapses out of view.\n */\nconst buildProcessForest = (processes: readonly Process.Process[], maxDepth: number): ProcessNode => {\n const pidSet = new Set(processes.map((process) => String(process.pid)));\n const childrenByParent = new Map<string, Process.Process[]>();\n const roots: Process.Process[] = [];\n\n for (const process of processes) {\n const parent = process.parentPid;\n if (parent === null || !pidSet.has(String(parent))) {\n roots.push(process);\n continue;\n }\n const key = String(parent);\n const siblings = childrenByParent.get(key) ?? [];\n siblings.push(process);\n childrenByParent.set(key, siblings);\n }\n\n const visit = (process: Process.Process, level: number): ProcessNode => {\n const children = level >= maxDepth ? [] : sortNestedActive(childrenByParent.get(String(process.pid)) ?? []);\n return {\n id: String(process.pid),\n process,\n children: children.map((child) => visit(child, level + 1)),\n };\n };\n\n return {\n id: ROOT_ID,\n children: sortProcesses(roots).map((process) => visit(process, 1)),\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Commit } from './Timeline.tsx';\n\n/** The row range a branch's line covers, in commit indices. */\nexport type TimelineSpan = {\n start: number;\n end: number;\n};\n\nexport type TimelineRow = {\n commit: Commit;\n /** Index into the commit list the layout was built from; `spans` share these coordinates. */\n index: number;\n};\n\nexport type TimelineLayout = {\n /** One row per commit on a whitelisted branch, in commit order. */\n rows: TimelineRow[];\n /** Lane per branch; a branch outside the whitelist gets none, and so gets no rows. */\n branchLane: Map<string, number>;\n /** Lanes the row graphic has to be wide enough for. */\n laneCount: number;\n /** The span each branch's line covers. */\n spans: Map<string, TimelineSpan>;\n /** Row index per commit index — the keyboard navigates in commit indices but scrolls rows. */\n rowByCommitIndex: Map<number, number>;\n /** Commit index per commit id — a click names a commit, everything else speaks in indices. */\n commitIndexById: Map<string, number>;\n};\n\n/**\n * Lays a commit graph out into rows: which lane each branch draws in, how far each branch's line\n * runs, and which commits get a row at all.\n *\n * Pure and linear in the number of commits: every lookup a commit makes about a parent, and every\n * lane release, is served from an index built in one pass. Commits are assumed to be in topological\n * order — a parent always precedes its children.\n */\nexport const layoutTimeline = (commits: readonly Commit[], branches: readonly string[]): TimelineLayout => {\n const visibleBranches = new Set(branches);\n const firstBranch = branches[0];\n\n const commitIndexById = new Map<string, number>();\n commits.forEach((commit, index) => {\n if (!commitIndexById.has(commit.id)) {\n commitIndexById.set(commit.id, index);\n }\n });\n\n const positionOf = (commitId: string): { index: number; branch: string } | undefined => {\n const index = commitIndexById.get(commitId);\n return index === undefined ? undefined : { index, branch: commits[index].branch };\n };\n\n // The row at which each branch is merged by another branch, and so may hand its lane back.\n const mergeRow = new Map<string, number>();\n commits.forEach((commit, row) => {\n for (const parentId of commit.parents ?? []) {\n const parent = positionOf(parentId);\n if (parent && parent.branch !== commit.branch && visibleBranches.has(parent.branch)) {\n mergeRow.set(parent.branch, row);\n }\n }\n });\n\n // Inverted so a row releases lanes with one lookup instead of a scan of every merge.\n const releasedAtRow = new Map<number, string[]>();\n for (const [branch, endRow] of mergeRow) {\n if (branch === firstBranch) {\n continue;\n }\n const released = releasedAtRow.get(endRow);\n if (released) {\n released.push(branch);\n } else {\n releasedAtRow.set(endRow, [branch]);\n }\n }\n\n // Assign branches to lanes, reusing a lane once its branch has been merged. Unmerged branches\n // keep their lane active — they may still be in progress.\n const branchLane = new Map<string, number>();\n if (firstBranch !== undefined) {\n branchLane.set(firstBranch, 0);\n }\n\n const activeLanes = new Set<number>([0]);\n let maxLane = 0;\n\n commits.forEach((commit, row) => {\n if (visibleBranches.has(commit.branch) && !branchLane.has(commit.branch)) {\n let lane = 1;\n while (activeLanes.has(lane)) {\n lane++;\n }\n branchLane.set(commit.branch, lane);\n activeLanes.add(lane);\n maxLane = Math.max(maxLane, lane);\n }\n\n for (const branch of releasedAtRow.get(row) ?? []) {\n const lane = branchLane.get(branch);\n if (lane !== undefined) {\n activeLanes.delete(lane);\n }\n }\n });\n\n // How far each branch's line runs: from its first commit (or the fork it came off) to its last\n // commit (or the merge that absorbed it).\n const spans = new Map<string, TimelineSpan>();\n commits.forEach((commit, index) => {\n let span = spans.get(commit.branch);\n if (span) {\n span.end = index;\n } else {\n span = { start: index, end: index };\n spans.set(commit.branch, span);\n }\n\n const parents = commit.parents ?? [];\n for (const parentId of parents) {\n const parent = positionOf(parentId);\n if (!parent || parent.branch === commit.branch) {\n continue;\n }\n\n span.start = Math.min(span.start, parent.index);\n\n // A merge extends the branch being merged in, down to this row.\n if (parents.length > 1) {\n const parentSpan = spans.get(parent.branch);\n if (parentSpan) {\n parentSpan.end = Math.max(parentSpan.end, index);\n }\n }\n }\n });\n\n const rows: TimelineRow[] = [];\n const rowByCommitIndex = new Map<number, number>();\n commits.forEach((commit, index) => {\n if (branchLane.has(commit.branch)) {\n rowByCommitIndex.set(index, rows.length);\n rows.push({ commit, index });\n }\n });\n\n return { rows, branchLane, laneCount: maxLane + 1, spans, rowByCommitIndex, commitIndexById };\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\n// Kept out of `Timeline.tsx`: react-refresh only fast-refreshes a module whose exports are all\n// components, so constants exported beside them force a full page reload on every edit.\n\nexport type TimelineOptions = {\n lineHeight: number;\n columnWidth: number;\n nodeRadius: number;\n lineStyle: string;\n};\n\nexport const defaultOptions: TimelineOptions = {\n lineHeight: 24,\n columnWidth: 14,\n nodeRadius: 5,\n lineStyle: 'stroke-1',\n};\n\nexport const compactOptions: TimelineOptions = {\n lineHeight: 20,\n columnWidth: 12,\n nodeRadius: 4,\n lineStyle: 'stroke-1',\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { format } from 'date-fns';\nimport React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { addEventListener } from '@dxos/async';\nimport { LogLevel } from '@dxos/log';\nimport { Shimmer } from '@dxos/react-ui-components';\nimport { type WindowController, useListModel, useWindow, windowRowProps } from '@dxos/react-ui-virtual';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\nimport { trim } from '@dxos/util';\n\nimport { translationKey } from '../../translations.ts';\nimport { type TimelineLayout, type TimelineRow, type TimelineSpan, layoutTimeline } from './timeline-layout.ts';\nimport { type TimelineOptions, compactOptions, defaultOptions } from './timeline-options.ts';\n\n/**\n * Mercurial-style Commit.\n */\nexport type Commit = {\n id: string;\n timestamp?: Date; // TODO(burdon): Unix time?\n parents?: string[];\n branch: string;\n icon?: string;\n level?: LogLevel;\n message: string;\n tags?: string[];\n /** DXN link for navigation to referenced objects. */\n link?: string;\n};\n\nconst SHIMMER_EFFECT_TAG = 'effect:shimmer';\n\n/** Wall-clock to the second: a trace line is read against its neighbours, and milliseconds only widen the column. */\nconst TIMESTAMP_FORMAT = 'HH:mm:ss';\n\nconst hasShimmerEffect = (commit: Commit): boolean => commit.tags?.includes(SHIMMER_EFFECT_TAG) ?? false;\n\nconst empty = Object.freeze([]);\n\nexport type TimelineProps = Util.ThemedClassName<{\n /** Optional whitelist. */\n branches?: string[];\n /**\n * Controlled value for the highlighted branch.\n * When provided, takes precedence over the branch derived from the currently selected commit.\n */\n branch?: string | null;\n commits?: Commit[];\n showTimestamp?: boolean;\n showIcon?: boolean;\n compact?: boolean;\n options?: TimelineOptions;\n debug?: boolean;\n /**\n * The element the rows are windowed against, which the host owns: a `ScrollArea.Viewport` or a\n * `ScrollContainer.Viewport`, as `MessageList` binds to. Rows mount once it exists.\n */\n scroller: HTMLElement | null;\n onChange?: (props: { current?: number; commit?: Commit }) => void;\n /**\n * Callback when a commit with a link is clicked.\n * If provided, commits with links will be navigable.\n */\n onSelect?: (commit: Commit | undefined) => void;\n}>;\n\n/**\n * GitGraph-style timeline.\n *\n * Rows are windowed by `useWindow`, so rendering costs the viewport rather than the history. The\n * layout is still computed over the whole history, so a windowed row draws every lane crossing it.\n */\nexport const Timeline = memo(\n Util.composable<HTMLDivElement, TimelineProps>(\n (\n {\n branches: branchesProp,\n branch,\n commits = empty,\n showTimestamp = false,\n showIcon = true,\n compact = false,\n options = compact ? compactOptions : defaultOptions,\n debug = false,\n scroller,\n onChange,\n onSelect,\n ...props\n },\n forwardedRef,\n ) => {\n const { t } = Hooks.useTranslation(translationKey);\n const containerRef = Hooks.useForwardedRef(forwardedRef);\n\n // Auto-discover branches if not provided.\n const branches = useMemo(() => {\n if (branchesProp) {\n return branchesProp;\n }\n\n return commits.reduce((branches, commit) => {\n if (!branches.includes(commit.branch)) {\n branches.push(commit.branch);\n }\n\n return branches;\n }, [] as string[]);\n }, [branchesProp, commits]);\n\n const layout = useMemo(() => layoutTimeline(commits, branches), [commits, branches]);\n\n // Navigation.\n const [current, setCurrent] = useState<number | undefined>(undefined);\n const currentRef = Hooks.useDynamicRef<number | undefined>(current);\n const selectedRef = Hooks.useDynamicRef<number | undefined>(undefined);\n const currentCommit = useMemo(() => (current !== undefined ? commits[current] : undefined), [current, commits]);\n\n // Controlled `branch` takes precedence over the branch derived from the selected commit.\n const highlightedBranch = branch ?? currentCommit?.branch;\n\n const currentRow = current === undefined ? undefined : layout.rowByCommitIndex.get(current);\n\n useEffect(() => {\n onChange?.({ current, commit: current === undefined ? undefined : commits[current] });\n }, [onChange, current]);\n\n // When the controlled `branch` changes, jump to the first commit on that branch — but\n // never override an explicit commit selection that already sits on that branch. Otherwise a\n // click that selects a commit (and drives `branch` via the parent) would be snapped\n // back to the branch's first commit.\n useEffect(() => {\n if (!branch) {\n return;\n }\n if (currentRef.current !== undefined && commits[currentRef.current]?.branch === branch) {\n return;\n }\n\n const index = commits.findIndex((commit) => commit.branch === branch);\n if (index >= 0) {\n setCurrent(index);\n }\n }, [branch]);\n\n useEffect(() => {\n if (!containerRef.current) {\n return;\n }\n\n return addEventListener(containerRef.current, 'keydown', (event) => {\n switch (event.key) {\n case 'ArrowUp': {\n event.preventDefault(); // Prevent implicit scrolling.\n if (event.metaKey || currentRef.current === undefined) {\n setCurrent(0);\n } else {\n setCurrent((selected) => {\n if (event.shiftKey && selected !== undefined) {\n const branch = commits[selected].branch;\n for (let i = selected - 1; i >= 0; i--) {\n if (commits[i].branch === branch) {\n return i;\n }\n }\n\n return selected;\n } else {\n return selected === undefined ? commits.length - 1 : Math.max(0, selected - 1);\n }\n });\n }\n break;\n }\n case 'ArrowDown': {\n event.preventDefault(); // Prevent implicit scrolling.\n if (event.metaKey || currentRef.current === undefined) {\n setCurrent(commits.length - 1);\n } else {\n setCurrent((selected) => {\n if (event.shiftKey && selected !== undefined) {\n const branch = commits[selected].branch;\n for (let i = selected + 1; i <= commits.length - 1; i++) {\n if (commits[i].branch === branch) {\n return i;\n }\n }\n return selected;\n } else {\n return selected === undefined ? 0 : Math.min(commits.length - 1, selected + 1);\n }\n });\n }\n break;\n }\n case 'Enter': {\n event.preventDefault();\n if (currentRef.current !== undefined) {\n selectedRef.current = currentRef.current === selectedRef.current ? undefined : currentRef.current;\n onSelect?.(selectedRef.current !== undefined ? commits[selectedRef.current] : undefined);\n }\n break;\n }\n }\n });\n }, [commits, containerRef.current]);\n\n // Clicking the current commit clears the selection, as Enter does.\n const handleRowClick = useCallback(\n (index: number) => {\n if (selectedRef.current === index) {\n selectedRef.current = undefined;\n setCurrent(undefined);\n onSelect?.(undefined);\n return;\n }\n setCurrent(index);\n selectedRef.current = index;\n onSelect?.(commits[index]);\n },\n [commits, onSelect],\n );\n\n // Positioned rows cannot share one subgrid, so every row carries the template the subgrid\n // used to provide. The columns still line up: a layout pass gives every row the same lane\n // width, and the icon and timestamp columns are fixed.\n const gridTemplateColumns = useMemo(\n () => ['min-content', showIcon && '1.25rem', '1fr', showTimestamp && 'max-content'].filter(Boolean).join(' '),\n [showIcon, showTimestamp],\n );\n\n return (\n <div\n {...Util.composableProps(props, { classNames: 'relative outline-none' })}\n role='list'\n tabIndex={0}\n ref={containerRef}\n >\n {layout.rows.length < 1 ? (\n <p className='text-fg-muted p-trim-md'>{t('no-commits.message')}</p>\n ) : (\n scroller && (\n <TimelineWindow\n scroller={scroller}\n layout={layout}\n options={options}\n currentRow={currentRow}\n showIcon={showIcon}\n showTimestamp={showTimestamp}\n debug={debug}\n highlightedBranch={highlightedBranch}\n linkable={!!onSelect}\n gridTemplateColumns={gridTemplateColumns}\n onRowClick={handleRowClick}\n />\n )\n )}\n </div>\n );\n },\n ),\n);\n\nTimeline.displayName = 'Timeline';\n\n//\n// TimelineWindow\n//\n\ntype TimelineRowContext = {\n layout: TimelineLayout;\n options: TimelineOptions;\n showIcon: boolean;\n showTimestamp: boolean;\n debug: boolean;\n highlightedBranch: string | undefined;\n /** Whether a commit's link is navigable, i.e. the host passed `onSelect`. */\n linkable: boolean;\n gridTemplateColumns: string;\n onRowClick: (commitIndex: number) => void;\n};\n\ntype TimelineWindowProps = TimelineRowContext & {\n scroller: HTMLElement;\n currentRow: number | undefined;\n};\n\nconst getRowId = (row: TimelineRow) => row.commit.id;\n\n/**\n * The mounted rows: a sizer that gives the scrollbar the whole history's extent, and a window\n * holding the rows in view, translated to where they belong. Rendered only once the host's\n * scroller exists, because the placement binds to the element on mount.\n */\nconst TimelineWindow = ({ scroller, layout, options, currentRow, ...context }: TimelineWindowProps) => {\n const scrollerRef = useRef<HTMLElement | null>(scroller);\n scrollerRef.current = scroller;\n\n const model = useListModel(layout.rows, getRowId);\n // Exact: every row is `lineHeight` tall, so offsets are a prefix sum and nothing is ever corrected.\n const extents = useMemo(() => ({ of: () => options.lineHeight, exact: true }), [options.lineHeight]);\n const controllerRef = useRef<WindowController>(null);\n const {\n layout: { visible },\n windowRef,\n offset,\n sizerExtent,\n first,\n last,\n } = useWindow({ scrollerRef, model, extents, controllerRef });\n\n // Nearest edge, as the `scrollIntoView({ block: 'nearest' })` this replaces did: a row already in\n // view is left alone, so an arrow press moves the view only when the current row would leave it.\n const visibleRef = useRef(visible);\n visibleRef.current = visible;\n useEffect(() => {\n if (currentRow === undefined) {\n return;\n }\n\n const { first, last } = visibleRef.current;\n if (currentRow < first) {\n controllerRef.current?.scrollToIndex(currentRow, 'start');\n } else if (currentRow > last) {\n controllerRef.current?.scrollToIndex(currentRow, 'end');\n }\n }, [currentRow]);\n\n const rows = [];\n for (let index = first; index <= last; index++) {\n // From the layout rather than the model: the model folds a new layout in one effect later, and\n // a row read from it in between would be drawn against spans it was not laid out with.\n const row = layout.rows[index];\n if (!row) {\n continue;\n }\n\n rows.push(\n <TimelineRowView\n key={row.commit.id}\n index={index}\n row={row}\n current={index === currentRow}\n layout={layout}\n options={options}\n {...context}\n />,\n );\n }\n\n return (\n <>\n <div style={{ height: sizerExtent }} />\n <div\n ref={windowRef}\n className='absolute top-0 left-0 flex flex-col w-full'\n style={{ transform: `translateY(${offset}px)` }}\n >\n {rows}\n </div>\n </>\n );\n};\n\n//\n// TimelineRow\n//\n\ntype TimelineRowViewProps = TimelineRowContext & {\n /** Row index in the window, which the placement measures rows by. */\n index: number;\n row: TimelineRow;\n current: boolean;\n};\n\nconst TimelineRowView = memo(\n ({\n index,\n row,\n current,\n layout,\n options,\n showIcon,\n showTimestamp,\n debug,\n highlightedBranch,\n linkable,\n gridTemplateColumns,\n onRowClick,\n }: TimelineRowViewProps) => {\n const { commit } = row;\n const handleClick = useCallback(() => onRowClick(row.index), [onRowClick, row.index]);\n\n const hasLink = !!commit.link && linkable;\n const message = debug ? JSON.stringify({ id: commit.id, parents: commit.parents }) : commit.message;\n\n return (\n <div\n role='listitem'\n data-object-id={commit.id}\n {...windowRowProps(index, commit.id)}\n data-commit-index={row.index}\n aria-current={current ? 'true' : undefined}\n className='group/row grid gap-1 px-[2px] overflow-hidden items-center pe-2 dx-hover dx-current'\n style={{ gridTemplateColumns, height: `${options.lineHeight}px` }}\n onClick={handleClick}\n >\n <div className='px-2'>\n <LineVector\n layout={layout}\n index={row.index}\n commit={commit}\n highlightedBranch={highlightedBranch}\n options={options}\n />\n </div>\n {showIcon && <CommitIcon commit={commit} />}\n <div\n className={mx(\n 'text-sm truncate cursor-pointer text-fg-muted font-thin group-aria-current/row:text-current-fg hover:text-current-fg',\n hasLink && 'underline decoration-dotted underline-offset-2',\n )}\n >\n {hasShimmerEffect(commit) ? <Shimmer>{message}</Shimmer> : message}\n </div>\n {showTimestamp && (\n <div className='text-xs tabular-nums items-center text-fg-muted font-thin'>\n {commit.timestamp && format(commit.timestamp, TIMESTAMP_FORMAT)}\n </div>\n )}\n </div>\n );\n },\n);\n\nTimelineRowView.displayName = 'TimelineRowView';\n\nconst CommitIcon = memo(({ commit }: { commit: Commit }) => {\n if (!commit.icon) {\n return <div />;\n }\n\n return (\n <Icon.Icon\n icon={commit.icon}\n size='md'\n spin={commit.icon === 'ph--spinner-gap--regular'}\n classNames={commit.level !== undefined ? levelColors[commit.level] : undefined}\n />\n );\n});\n\ntype Color = {\n stroke: string;\n fill: string;\n};\n\nconst colors: Color[] = [\n { stroke: 'stroke-orange-500', fill: 'group-aria-[current=true]:fill-orange-500' },\n { stroke: 'stroke-sky-500', fill: 'group-aria-[current=true]:fill-sky-500' },\n { stroke: 'stroke-green-500', fill: 'group-aria-[current=true]:fill-green-500' },\n { stroke: 'stroke-fuchsia-500', fill: 'group-aria-[current=true]:fill-fuchsia-500' },\n { stroke: 'stroke-cyan-500', fill: 'group-aria-[current=true]:fill-cyan-500' },\n { stroke: 'stroke-emerald-500', fill: 'group-aria-[current=true]:fill-emerald-500' },\n { stroke: 'stroke-violet-500', fill: 'group-aria-[current=true]:fill-violet-500' },\n { stroke: 'stroke-teal-500', fill: 'group-aria-[current=true]:fill-teal-500' },\n];\n\nconst levelColors: Record<LogLevel, string> = {\n [LogLevel.TRACE]: 'text-gray-500',\n [LogLevel.DEBUG]: 'text-gray-500',\n [LogLevel.VERBOSE]: 'text-gray-500',\n [LogLevel.INFO]: 'text-green-500',\n [LogLevel.WARN]: 'text-orange-500',\n [LogLevel.ERROR]: 'text-red-500',\n};\n\ntype LineVectorProps = {\n layout: TimelineLayout;\n index: number;\n commit: Commit;\n highlightedBranch: string | undefined;\n options: TimelineOptions;\n};\n\n/**\n * SVG for node and connector paths.\n */\nconst LineVector = memo(({ layout, index, commit, highlightedBranch, options }: LineVectorProps) => {\n const { branchLane, laneCount, spans } = layout;\n const halfHeight = options.lineHeight / 2;\n const cx = (column: number) => column * options.columnWidth + options.columnWidth / 2;\n const getBranchIndex = (branch: string): number => branchLane.get(branch) ?? -1;\n\n // Create connector path.\n const createPath = (index: number, commit: Commit, branch: string, span: TimelineSpan): string | undefined => {\n const parents = commit.parents ?? [];\n const commitIndex = getBranchIndex(commit.branch);\n const branchIndex = getBranchIndex(branch);\n\n // Vertical connectors.\n if (span.start < index && index < span.end) {\n return `M ${cx(branchIndex)} 0 l 0 ${options.lineHeight}`;\n } else if (commit.branch === branch && parents.length > 0) {\n return `M ${cx(branchIndex)} 0 l 0 ${halfHeight}`;\n } else if (commit.branch === branch && index < span.end) {\n return `M ${cx(branchIndex)} ${halfHeight} l 0 ${options.lineHeight}`;\n }\n\n // Branch.\n // TODO(burdon): Assumes can only branch to the right.\n if (commit.branch !== branch && index === span.start) {\n return trim`\n M ${cx(commitIndex)} ${halfHeight}\n L ${cx(branchIndex) - halfHeight} ${halfHeight}\n a ${halfHeight} ${halfHeight} 0 0 1 ${halfHeight} ${halfHeight}\n `;\n }\n\n // Merge.\n if (commit.branch !== branch && index === span.end) {\n return trim`\n M ${cx(commitIndex)} ${halfHeight}\n L ${cx(branchIndex) - halfHeight} ${halfHeight}\n a ${halfHeight} ${halfHeight} -90 0 0 ${halfHeight} ${-halfHeight}\n `;\n }\n };\n\n const col = getBranchIndex(commit.branch);\n const color = colors[col % colors.length];\n const opacity = (branch: string | undefined) => [\n 'duration-500 transition-opacity',\n highlightedBranch === undefined || branch === highlightedBranch ? 'opacity-100' : 'opacity-40',\n ];\n\n return (\n <svg width={laneCount * options.columnWidth} height={options.lineHeight}>\n {/* Connectors */}\n {[...spans.entries()].map(([branch, span]) => {\n const lane = getBranchIndex(branch);\n if (lane < 0) {\n return null;\n }\n\n const color = colors[lane % colors.length];\n const path = createPath(index, commit, branch, span);\n if (!path) {\n return null;\n }\n\n return (\n <path\n key={branch}\n d={path}\n fill='none'\n className={mx(options.lineStyle, color.stroke, color.fill, opacity(branch))}\n />\n );\n })}\n\n <circle\n cx={cx(col)}\n cy={halfHeight}\n r={options.nodeRadius}\n className={mx('fill-base-surface stroke-base-surface')}\n />\n <circle\n cx={cx(col)}\n cy={halfHeight}\n r={options.nodeRadius}\n className={mx('fill-base-surface', options.lineStyle, color?.stroke, color?.fill, opacity(commit.branch))}\n />\n </svg>\n );\n});\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Commit } from './Timeline.tsx';\n\nconst NODE = '●';\nconst MERGE_NODE = '◆';\nconst RAIL = '│';\nconst HORIZ = '─';\nconst COL_WIDTH = 3;\n\n/**\n * Renders commits as a monospace ASCII graph with rounded box-drawing arcs and vertical rails.\n * Commits must be ordered chronologically (oldest first, newest last). Parents must refer to older commits.\n */\nexport const renderTimelineAscii = (commits: Commit[], branches: string[]): string => {\n if (commits.length === 0) {\n return '';\n }\n\n const laneById = assignLanes(commits, branches);\n const lanes = commits.map((commit) => laneById.get(commit.id)!);\n const maxLane = Math.max(...lanes);\n\n if (maxLane === 0) {\n return commits.map((commit) => `${NODE} ${formatLabel(commit)}`).join('\\n');\n }\n\n const active = computeActiveColumns(commits, lanes, laneById);\n\n const graphParts = commits.map((commit, row) => renderRow(commit, lanes[row]!, maxLane, active[row]!, laneById));\n\n const maxGraphWidth = Math.max(...graphParts.map((part) => part.length));\n return commits.map((commit, row) => `${graphParts[row]!.padEnd(maxGraphWidth)} ${formatLabel(commit)}`).join('\\n');\n};\n\nconst renderRow = (\n commit: Commit,\n commitLane: number,\n maxLane: number,\n activeRow: boolean[],\n laneById: Map<string, number>,\n): string => {\n const totalChars = (maxLane + 1) * COL_WIDTH;\n const chars: string[] = Array(totalChars).fill(' ');\n\n const merge = isMergeCommit(commit);\n const fork = !merge && isForkCommit(commit, laneById, commitLane);\n\n let connectLane = -1;\n if (fork) {\n const parentLane = laneById.get(commit.parents![0]!);\n if (parentLane !== undefined) {\n connectLane = parentLane;\n }\n } else if (merge) {\n for (const parentId of commit.parents ?? []) {\n const parentLane = laneById.get(parentId);\n if (parentLane !== undefined && parentLane !== commitLane) {\n connectLane = parentLane;\n break;\n }\n }\n }\n\n for (let col = 0; col <= maxLane; col++) {\n if (col === commitLane) {\n continue;\n }\n if (activeRow[col]) {\n chars[col * COL_WIDTH] = RAIL;\n }\n }\n\n chars[commitLane * COL_WIDTH] = merge ? MERGE_NODE : NODE;\n if (connectLane >= 0) {\n const connectPos = connectLane * COL_WIDTH;\n if (fork) {\n chars[connectPos] = connectLane < commitLane ? '├' : '┤';\n } else {\n chars[connectPos] = connectLane > commitLane ? '╯' : '╰';\n }\n\n const minCol = Math.min(commitLane, connectLane);\n const maxCol = Math.max(commitLane, connectLane);\n for (let pos = minCol * COL_WIDTH + 1; pos < maxCol * COL_WIDTH; pos++) {\n if (pos % COL_WIDTH === 0) {\n const col = pos / COL_WIDTH;\n if (activeRow[col]) {\n chars[pos] = '┼';\n } else {\n chars[pos] = HORIZ;\n }\n } else {\n chars[pos] = HORIZ;\n }\n }\n }\n\n return chars.join('').trimEnd();\n};\n\nconst formatLabel = (commit: Commit): string => {\n const icon = commit.icon\n ?.replace(/^ph--/, '')\n .replace(/--regular$/, '')\n .replace(/--bold$/, '')\n .replace(/--fill$/, '');\n return icon ? `[${icon}] ${commit.message}` : commit.message;\n};\n\n/**\n * Assigns each commit to a lane (column), reusing lanes once a branch has been merged.\n * A branch is considered \"merged\" when a commit on another branch references it as a parent.\n * Unmerged branches keep their lane active (they may still be in progress).\n * Lane 0 is reserved for the first branch (typically 'main').\n */\nconst assignLanes = (commits: Commit[], branches: string[]): Map<string, number> => {\n // Build commit-id to branch lookup.\n const commitBranch = new Map<string, string>();\n for (const commit of commits) {\n commitBranch.set(commit.id, commit.branch);\n }\n\n // Find the row at which each branch is merged (closed) by another branch.\n const mergeRow = new Map<string, number>();\n for (let row = 0; row < commits.length; row++) {\n const commit = commits[row]!;\n for (const parentId of commit.parents ?? []) {\n const parentBranch = commitBranch.get(parentId);\n if (parentBranch && parentBranch !== commit.branch) {\n mergeRow.set(parentBranch, Math.max(mergeRow.get(parentBranch) ?? row, row));\n }\n }\n }\n\n const branchLane = new Map<string, number>();\n if (branches.length > 0) {\n branchLane.set(branches[0]!, 0);\n }\n\n const activeLanes = new Set<number>([0]);\n const laneById = new Map<string, number>();\n\n for (let row = 0; row < commits.length; row++) {\n const commit = commits[row]!;\n\n if (!branchLane.has(commit.branch)) {\n let lane = 1;\n while (activeLanes.has(lane)) {\n lane++;\n }\n branchLane.set(commit.branch, lane);\n activeLanes.add(lane);\n }\n\n laneById.set(commit.id, branchLane.get(commit.branch)!);\n\n // Release lanes for branches that have been merged at this row.\n for (const [branch, endRow] of mergeRow) {\n if (endRow === row && branch !== branches[0] && branchLane.has(branch)) {\n activeLanes.delete(branchLane.get(branch)!);\n }\n }\n }\n\n return laneById;\n};\n\nconst isMergeCommit = (commit: Commit): boolean => (commit.parents?.length ?? 0) > 1;\n\nconst isForkCommit = (commit: Commit, laneById: Map<string, number>, lane: number): boolean => {\n const parents = commit.parents;\n if (!parents || parents.length !== 1) {\n return false;\n }\n const parentLane = laneById.get(parents[0]!);\n return parentLane !== undefined && parentLane !== lane;\n};\n\n/**\n * Column `col` is active on `row` when `row` falls inside the vertical span\n * of that column (the range of rows that include commits on that lane plus\n * merge rows referencing parents on that lane) AND the row's own commit\n * is not on that column.\n */\nconst computeActiveColumns = (commits: Commit[], lanes: number[], laneById: Map<string, number>): boolean[][] => {\n const rows = commits.length;\n const cols = Math.max(...lanes, 0) + 1;\n const rowIndicesByCol: number[][] = Array.from({ length: cols }, () => []);\n\n for (let row = 0; row < rows; row++) {\n rowIndicesByCol[lanes[row]!]!.push(row);\n }\n\n for (let row = 0; row < rows; row++) {\n for (const parentId of commits[row]?.parents ?? []) {\n const parentLane = laneById.get(parentId);\n if (parentLane === undefined) {\n continue;\n }\n rowIndicesByCol[parentLane]!.push(row);\n }\n }\n\n const active: boolean[][] = Array.from({ length: rows }, () => Array(cols).fill(false));\n for (let col = 0; col < cols; col++) {\n const indices = rowIndicesByCol[col]!;\n if (indices.length === 0) {\n continue;\n }\n const minR = Math.min(...indices);\n const maxR = Math.max(...indices);\n for (let row = minR; row <= maxR; row++) {\n if (lanes[row] !== col) {\n active[row]![col] = true;\n }\n }\n }\n\n return active;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useMemo } from 'react';\n\nimport { TextEditor } from '@dxos/react-ui-editor';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { createBasicExtensions, createThemeExtensions, folding, json } from '@dxos/ui-editor';\nimport { safeStringify } from '@dxos/util';\n\nexport type SpanTreeViewProps = Util.ThemedClassName<{\n spanTree: unknown;\n}>;\n\n/**\n * The trace's span tree as read-only JSON.\n *\n * CodeMirror puts only the lines in view into the DOM and parses the rest in time-sliced chunks, so\n * showing a tree stops costing what the tree is worth — a highlighter renders every one of its lines\n * in one synchronous pass. `TextEditor` rather than `Editor.View`: this pane has no toolbar, so the\n * compound component's context would only be wiring nothing reads.\n */\nexport const SpanTreeView = ({ classNames, spanTree }: SpanTreeViewProps) => {\n const themeMode = Hooks.useThemeMode();\n const value = useMemo(() => safeStringify(spanTree, undefined, 2), [spanTree]);\n const extensions = useMemo(\n () => [\n createBasicExtensions({ readOnly: true, lineWrapping: false, search: true }),\n createThemeExtensions({ themeMode, syntaxHighlighting: true }),\n json(),\n folding(),\n ],\n [themeMode],\n );\n\n return <TextEditor classNames={['text-xs', classNames]} value={value} extensions={extensions} />;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as Process from '@dxos/compute/Process';\nimport type * as Trace from '@dxos/compute/Trace';\n\n/**\n * What a running process is working on behalf of, as a single bucket.\n *\n * Bucketed from the inherited {@link Process.Environment}, so filtering keeps whole subtrees together.\n */\n// TODO(burdon): Factor out.\nexport const ProcessEnvironment = {\n /** Not scoped to a space: layout, navigation, identity, settings, space lifecycle. */\n App: 'app',\n /** Scoped to a space, but not to a conversation within it. */\n Space: 'space',\n /** Serving a conversation: an agent's turn and every tool call it spawns. */\n Conversation: 'conversation',\n} as const;\n\nexport type ProcessEnvironment = (typeof ProcessEnvironment)[keyof typeof ProcessEnvironment];\n\n/** Every environment, in menu order — widening scope, so the filter reads the same on every trace. */\nexport const ALL_PROCESS_ENVIRONMENTS: readonly ProcessEnvironment[] = [\n ProcessEnvironment.App,\n ProcessEnvironment.Space,\n ProcessEnvironment.Conversation,\n];\n\n/** App-level processes start hidden: that bucket fires on every click, whatever the user is watching. */\nexport const DEFAULT_PROCESS_ENVIRONMENTS: readonly ProcessEnvironment[] = [\n ProcessEnvironment.Space,\n ProcessEnvironment.Conversation,\n];\n\nconst ENVIRONMENT_ICONS: Record<ProcessEnvironment, string> = {\n [ProcessEnvironment.App]: 'ph--app-window--regular',\n [ProcessEnvironment.Space]: 'ph--planet--regular',\n [ProcessEnvironment.Conversation]: 'ph--chat-teardrop-text--regular',\n};\n\nexport const environmentIcon = (environment: ProcessEnvironment): string => ENVIRONMENT_ICONS[environment];\n\n/** `conversation` outranks `space`, since a conversation always runs inside one. */\nexport const processEnvironment = (process: Process.Process): ProcessEnvironment => {\n if (process.environment.conversation !== undefined) {\n return ProcessEnvironment.Conversation;\n }\n if (process.environment.space !== undefined) {\n return ProcessEnvironment.Space;\n }\n return ProcessEnvironment.App;\n};\n\nexport const filterProcesses = (\n processes: readonly Process.Process[],\n selected: readonly ProcessEnvironment[],\n): readonly Process.Process[] => {\n // Identity when nothing is excluded, so `ProcessTree`'s `React.memo` still holds.\n if (selected.length === ALL_PROCESS_ENVIRONMENTS.length) {\n return processes;\n }\n const selection = new Set(selected);\n return processes.filter((process) => selection.has(processEnvironment(process)));\n};\n\n/** Toggles an environment, preserving the canonical order. */\nexport const toggleProcessEnvironment = (\n selected: readonly ProcessEnvironment[],\n environment: ProcessEnvironment,\n): ProcessEnvironment[] =>\n ALL_PROCESS_ENVIRONMENTS.filter((candidate) =>\n candidate === environment ? !selected.includes(environment) : selected.includes(candidate),\n );\n\n/**\n * Narrows a persisted selection to the known environments, in canonical order.\n *\n * Settings outlive the vocabulary that wrote them; an unrecognized value would filter the panel to nothing.\n */\nexport const parseProcessEnvironments = (selected: readonly string[] | undefined): readonly ProcessEnvironment[] =>\n selected === undefined\n ? DEFAULT_PROCESS_ENVIRONMENTS\n : ALL_PROCESS_ENVIRONMENTS.filter((environment) => selected.includes(environment));\n\n/**\n * Narrows trace messages to the selected processes and their descendants: a tool call or sub-agent\n * runs as a child of the process it serves, so its events are that process's work. An empty\n * selection is no filter.\n */\n/**\n * Narrows the process tree to the selected processes and their descendants, the process-side twin of\n * {@link filterTraceMessages}: a running child of a picked process is that process's live work.\n */\nexport const filterProcessesBySelection = (\n processes: readonly Process.Process[],\n selected: readonly string[],\n): readonly Process.Process[] => {\n if (selected.length === 0) {\n return processes;\n }\n const parentByPid = new Map<string, string | null>(processes.map((process) => [process.pid, process.parentPid]));\n const selection = new Set(selected);\n const isSelected = (pid: string, depth = 0): boolean => {\n if (selection.has(pid)) {\n return true;\n }\n const parent = parentByPid.get(pid);\n // Bounded so a cyclic parent chain (a corrupt tree) terminates.\n return parent !== null && parent !== undefined && depth < processes.length && isSelected(parent, depth + 1);\n };\n return processes.filter((process) => isSelected(process.pid));\n};\n\nexport const filterTraceMessages = (\n messages: readonly Trace.Message[],\n selected: readonly string[],\n): readonly Trace.Message[] => {\n if (selected.length === 0) {\n return messages;\n }\n const parentByPid = new Map<string, string | undefined>();\n for (const message of messages) {\n if (message.meta.pid !== undefined) {\n parentByPid.set(message.meta.pid, message.meta.parentPid);\n }\n }\n const selection = new Set(selected);\n const matches = new Map<string, boolean>();\n const isSelected = (pid: string): boolean => {\n const known = matches.get(pid);\n if (known !== undefined) {\n return known;\n }\n // Pinned before the walk so a cyclic parent chain (a corrupt trace) terminates.\n matches.set(pid, false);\n const parent = parentByPid.get(pid);\n const result = selection.has(pid) || (parent !== undefined && isSelected(parent));\n matches.set(pid, result);\n return result;\n };\n return messages.filter((message) => message.meta.pid !== undefined && isSelected(message.meta.pid));\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useCallback } from 'react';\n\nimport { MenuBuilder, useMenuBuilder } from '@dxos/react-ui-menu';\n\nimport { translationKey } from '../../translations.ts';\nimport {\n ALL_PROCESS_ENVIRONMENTS,\n type ProcessEnvironment,\n environmentIcon,\n toggleProcessEnvironment,\n} from './trace-filter.ts';\n\nexport type UseTraceMenuOptions = {\n /** Process environments currently shown. */\n selected: readonly ProcessEnvironment[];\n onSelectedChange: (environments: ProcessEnvironment[]) => void;\n /** How many processes are picked; the clear action shows only while there are some. */\n selectionCount?: number;\n onClearSelection?: () => void;\n};\n\n/**\n * Environment filter menu for the trace panel's toolbar.\n * The group collapses to a funnel trigger, so the panel's own rows keep the width.\n */\nexport const useTraceMenu = ({\n selected,\n onSelectedChange,\n selectionCount = 0,\n onClearSelection,\n}: UseTraceMenuOptions) => {\n const handleToggle = useCallback(\n (environment: ProcessEnvironment) => onSelectedChange(toggleProcessEnvironment(selected, environment)),\n [selected, onSelectedChange],\n );\n\n return useMenuBuilder(\n () =>\n MenuBuilder.make()\n .action(\n 'clearSelection',\n {\n label: ['trace-clear-selection.label', { ns: translationKey }],\n icon: 'ph--selection-slash--regular',\n iconOnly: true,\n hidden: selectionCount === 0,\n testId: 'tracePanel.clearSelection',\n },\n () => onClearSelection?.(),\n )\n .group(\n 'processEnvironments',\n {\n label: ['trace-filter.menu', { ns: translationKey }],\n icon: 'ph--funnel--regular',\n iconOnly: true,\n variant: 'dropdownMenu',\n selectCardinality: 'multiple',\n value: [...selected],\n testId: 'tracePanel.filter',\n },\n (group) => {\n for (const environment of ALL_PROCESS_ENVIRONMENTS) {\n group.action(\n environment,\n {\n label: [`trace-environment-${environment}.label`, { ns: translationKey }],\n icon: environmentIcon(environment),\n checked: selected.includes(environment),\n },\n () => handleToggle(environment),\n );\n }\n group.separator('line');\n group.action(\n 'all',\n { label: ['trace-filter-all.label', { ns: translationKey }], icon: 'ph--list-checks--regular' },\n () => onSelectedChange([...ALL_PROCESS_ENVIRONMENTS]),\n );\n group.action(\n 'none',\n { label: ['trace-filter-none.label', { ns: translationKey }], icon: 'ph--prohibit--regular' },\n () => onSelectedChange([]),\n );\n },\n )\n .build(),\n [handleToggle, selected, onSelectedChange, selectionCount, onClearSelection],\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useCallback, useDeferredValue, useMemo, useState } from 'react';\n\nimport type * as Process from '@dxos/compute/Process';\nimport { ActionToolbar } from '@dxos/react-ui-menu';\nimport { JsonHighlighter } from '@dxos/react-ui-syntax-highlighter';\nimport * as Accordion from '@dxos/react-ui/Accordion';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Panel from '@dxos/react-ui/Panel';\nimport * as ScrollContainer from '@dxos/react-ui/ScrollContainer';\nimport * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type ExecutionGraph } from '../../execution-graph/index.ts';\nimport { translationKey } from '../../translations.ts';\nimport { ProcessTree, type ProcessTreeProps } from '../ProcessTree/index.ts';\nimport { type Commit, Timeline } from '../Timeline/index.ts';\nimport { SpanTreeView } from './SpanTreeView.tsx';\nimport { type ProcessEnvironment, filterProcesses } from './trace-filter.ts';\nimport { useTraceMenu } from './useTraceMenu.ts';\n\nexport type TracePanelProps = Util.ThemedClassName<\n Pick<ProcessTreeProps, 'resolveLabel' | 'selected' | 'onSelectedChange' | 'onProcessTerminate'> & {\n /** The live process tree; narrowed here by `environments`. */\n processes: readonly Process.Process[];\n /** The trace as a commit graph, built by `useExecutionGraph` (already narrowed to `selected`). */\n graph: ExecutionGraph;\n /** Process environments shown; the toolbar's funnel edits it. */\n environments: readonly ProcessEnvironment[];\n onEnvironmentsChange: (environments: ProcessEnvironment[]) => void;\n /** Shows the span tree as JSON in place of the timeline. */\n debug?: boolean;\n /** A commit whose message links an object was picked; the host decides what opening it means. */\n onOpenLink?: (uri: string) => void;\n }\n>;\n\n/**\n * A space's runtime: its processes as a tree, its trace as a commit graph, and the picked commit's\n * event. Presentation only — the host resolves the process monitor, the trace feed, settings and\n * navigation and hands them in as props.\n */\nexport const TracePanel = Util.composable<HTMLDivElement, TracePanelProps>(\n (\n {\n classNames,\n processes,\n graph,\n environments,\n onEnvironmentsChange,\n debug = false,\n resolveLabel,\n selected = NO_SELECTION,\n onSelectedChange,\n onProcessTerminate,\n onOpenLink,\n ...props\n },\n forwardedRef,\n ) => {\n const { t } = Hooks.useTranslation(translationKey);\n const handleClearSelection = useCallback(() => onSelectedChange?.([]), [onSelectedChange]);\n const menu = useTraceMenu({\n selected: environments,\n onSelectedChange: onEnvironmentsChange,\n selectionCount: selected.length,\n onClearSelection: handleClearSelection,\n });\n\n // `useDeferredValue` batches update bursts, works together with `React.memo`.\n // See the comment in `ProcessTreeContainer` for more details.\n const { branches, commits, spanTree, details } = useDeferredValue(graph);\n\n // A commit the graph no longer holds (the process selection moved) is no longer picked.\n const [pickedCommit, setSelectedCommit] = useState<Commit | undefined>();\n const selectedCommit = useMemo(\n () => (pickedCommit && commits.some((commit) => commit.id === pickedCommit.id) ? pickedCommit : undefined),\n [pickedCommit, commits],\n );\n // Remembered across selections, so collapsing a section once keeps it collapsed.\n const [openSections, setOpenSections] = useState<string[]>(SECTIONS.map((section) => section.id));\n // The timeline windows its rows against this scroller.\n const [traceViewport, setTraceViewport] = useState<HTMLDivElement | null>(null);\n const handleCommitSelect = useCallback(\n (commit: Commit | undefined) => {\n setSelectedCommit(commit);\n if (commit?.link) {\n onOpenLink?.(commit.link);\n }\n },\n [onOpenLink],\n );\n\n // The most recently picked process is the highlighted branch, while it is still picked.\n const currentBranch = useMemo(() => {\n const last = selected.at(-1);\n return last !== undefined && branches.includes(last) ? last : null;\n }, [selected, branches]);\n\n return (\n <Panel.Root {...Util.composableProps(props, { classNames: ['h-full', classNames] })} ref={forwardedRef}>\n <Panel.Header>\n <ActionToolbar {...menu} alwaysActive classNames='justify-end' />\n </Panel.Header>\n\n <Panel.Body>\n <Accordion.Root\n value={openSections}\n onValueChange={setOpenSections}\n classNames='h-full min-h-0'\n border={false}\n >\n {SECTIONS.map((section) => {\n switch (section.id) {\n case 'processes':\n return (\n <Accordion.Item key={section.id} value={section.id}>\n <Accordion.ItemTrigger>\n <span className='text-sm text-fg-muted'>{t('trace-processes.label')}</span>\n </Accordion.ItemTrigger>\n <Accordion.ItemContent classNames='p-0'>\n <ProcessTreeContainer\n classNames='max-h-[8lh]'\n processes={processes}\n environments={environments}\n resolveLabel={resolveLabel}\n selected={selected}\n onSelectedChange={onSelectedChange}\n onProcessTerminate={onProcessTerminate}\n />\n </Accordion.ItemContent>\n </Accordion.Item>\n );\n case 'trace':\n return (\n // The trace takes the slack: item and body are flex columns so the scroll\n // container inside gets a definite height to scroll within. The body's slide\n // animation is off here — it ramps to a measured height, and this body's height\n // comes from the flex slack, not its content.\n <Accordion.Item\n key={section.id}\n value={section.id}\n disabled\n classNames={mx(\n 'dx-grow flex flex-col',\n '[&>[data-part=item-content]]:dx-grow [&>[data-part=item-content]]:flex [&>[data-part=item-content]]:flex-col [&>[data-part=item-content]]:animate-none',\n )}\n >\n <Accordion.ItemTrigger>\n <span className='text-sm text-fg-muted'>{t('trace.label')}</span>\n </Accordion.ItemTrigger>\n <Accordion.ItemContent classNames='dx-grow grid grid-rows-[minmax(0,1fr)]'>\n {/* Opens at the tail and follows new entries while pinned; scrolling up unpins. */}\n <ScrollContainer.Root pin>\n <ScrollContainer.Content width='thin'>\n <ScrollContainer.Fade classNames='h-8' />\n <ScrollContainer.Viewport ref={setTraceViewport}>\n {debug ? (\n <SpanTreeView spanTree={spanTree} />\n ) : (\n <Timeline\n branches={branches}\n branch={currentBranch}\n commits={commits}\n showTimestamp\n scroller={traceViewport}\n onSelect={handleCommitSelect}\n />\n )}\n </ScrollContainer.Viewport>\n <ScrollContainer.ScrollDownButton />\n </ScrollContainer.Content>\n </ScrollContainer.Root>\n </Accordion.ItemContent>\n </Accordion.Item>\n );\n case 'details': {\n const commit = debug ? undefined : selectedCommit;\n return (\n // With nothing selected the section stays as a plain, closed row.\n <Accordion.Item key={section.id} value={section.id} disabled={!commit}>\n <Accordion.ItemTrigger>\n <span className='flex items-center truncate text-sm text-fg-muted'>\n {t('trace-details.label')}\n </span>\n </Accordion.ItemTrigger>\n {commit && (\n <Accordion.ItemContent classNames='p-0'>\n <JsonHighlighter\n data={details[commit.id] ?? commit}\n classNames='max-h-[20lh] text-xs p-1.5'\n />\n </Accordion.ItemContent>\n )}\n </Accordion.Item>\n );\n }\n }\n })}\n </Accordion.Root>\n </Panel.Body>\n </Panel.Root>\n );\n },\n);\n\nTracePanel.displayName = 'TracePanel';\n\ntype TraceSection = { id: 'processes' | 'trace' | 'details' };\n\nconst SECTIONS: TraceSection[] = [{ id: 'processes' }, { id: 'trace' }, { id: 'details' }];\n\nconst NO_SELECTION: readonly string[] = [];\n\ntype ProcessTreeContainerProps = Util.ThemedClassName<\n Pick<ProcessTreeProps, 'resolveLabel' | 'selected' | 'onSelectedChange' | 'onProcessTerminate'> & {\n processes: readonly Process.Process[];\n environments: readonly ProcessEnvironment[];\n }\n>;\n\n// Isolate `ProcessTree` updates from the rest of the panel.\nconst ProcessTreeContainer = ({\n classNames,\n processes,\n environments,\n resolveLabel,\n selected,\n onSelectedChange,\n onProcessTerminate,\n}: ProcessTreeContainerProps) => {\n // `processes` updates in bursts (about 14 updates per navigation).\n // `useDeferredValue` will debounce update propagation, returning stale value for short periods.\n // NOTE: `ProcessTree` MUST use `React.memo`, otherwise this will not work.\n const processesDeferred = useDeferredValue(processes);\n const visibleProcesses = useMemo(\n () => filterProcesses(processesDeferred, environments),\n [processesDeferred, environments],\n );\n\n return (\n <ProcessTree\n classNames={classNames}\n depth={3}\n processes={visibleProcesses}\n resolveLabel={resolveLabel}\n selected={selected}\n onSelectedChange={onSelectedChange}\n onProcessTerminate={onProcessTerminate}\n />\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Option from 'effect/Option';\nimport * as Schema from 'effect/Schema';\n\nimport * as Trace from '@dxos/compute/Trace';\nimport { EID } from '@dxos/keys';\n\n/**\n * Default duration a span may sit open with no new events before it's considered abandoned\n * (the runtime crashed, lost connectivity, or otherwise never wrote the closing event).\n */\nexport const DEFAULT_SPAN_TIMEOUT_MS = 20 * 60 * 1_000;\n\n/**\n * Synthetic id assigned to the root span.\n * The root is a virtual container for top-level spans (those without a parent in the captured trace).\n */\nexport const ROOT_SPAN_ID = '<main>';\n\n/**\n * Computed metadata for a span.\n * Derived from the meta of the begin event that opened the span.\n */\nexport interface SpanMeta {\n readonly pid?: string;\n readonly parentPid?: string;\n readonly processName?: string;\n readonly conversationId?: string;\n readonly triggerId?: string;\n readonly toolCallId?: string;\n readonly runtimeName?: string;\n}\n\n/**\n * A span in the trace hierarchy.\n *\n * Each span represents a single bounded unit of work — an operation invocation or an\n * agent request. Spans are opened by `OperationStart` / `Trace.AgentRequestBegin` events and\n * closed by their matching `OperationEnd` / `Trace.AgentRequestEnd` events. A single process\n * (pid) may produce multiple sequential spans (for example, an agent session that serves\n * three prompts produces three sibling spans sharing the agent's pid).\n *\n * `events` contains the bounded events for this span only — child spans' events are not\n * duplicated here. `children` contains sub-spans that opened while this span was active.\n */\nexport interface Span {\n readonly id: string;\n readonly meta: SpanMeta;\n readonly events: Trace.FlatEvent[];\n readonly children: Span[];\n}\n\nexport const BEGIN_EVENT_TYPES = new Set<string>([Trace.OperationStart.key, Trace.AgentRequestBegin.key]);\nexport const END_EVENT_TYPES = new Set<string>([Trace.OperationEnd.key, Trace.AgentRequestEnd.key]);\n\nexport const isSpanBeginEvent = (event: Trace.FlatEvent): boolean => BEGIN_EVENT_TYPES.has(event.type);\nexport const isSpanEndEvent = (event: Trace.FlatEvent): boolean => END_EVENT_TYPES.has(event.type);\n\nconst computeMeta = (rawMeta: Trace.Meta): SpanMeta => ({\n pid: rawMeta.pid,\n parentPid: rawMeta.parentPid,\n processName: rawMeta.processName,\n conversationId: rawMeta.conversation ? EID.getEntityId(EID.parse(rawMeta.conversation.uri)) : undefined,\n triggerId: rawMeta.trigger ? EID.getEntityId(EID.parse(rawMeta.trigger.uri)) : undefined,\n toolCallId: rawMeta.toolCallId,\n runtimeName: rawMeta.runtimeName,\n});\n\ninterface MutableSpan {\n id: string;\n meta: SpanMeta;\n events: Trace.FlatEvent[];\n children: MutableSpan[];\n firstTimestamp: number;\n}\n\nconst makeMutableSpan = (id: string, meta: SpanMeta): MutableSpan => ({\n id,\n meta,\n events: [],\n children: [],\n firstTimestamp: Number.POSITIVE_INFINITY,\n});\n\nconst freezeSpan = (span: MutableSpan): Span => ({\n id: span.id,\n meta: span.meta,\n events: span.events,\n children: span.children.map(freezeSpan),\n});\n\nexport interface BuildSpanTreeOptions {\n /**\n * If provided, caps how many *non-boundary* events (status updates, partial blocks, etc.)\n * are retained — only the most recent `eventLimit` of them survive. Span boundary events\n * (`OperationStart` / `OperationEnd` / `Trace.AgentRequestBegin` / `Trace.AgentRequestEnd`) are *always*\n * retained regardless of the limit, because dropping them would orphan their child spans\n * and collapse them onto the root branch.\n */\n eventLimit?: number;\n\n /**\n * Duration a span may sit open with no new events before it's force-closed with a synthetic\n * end event. Only takes effect when `now` is also provided. Defaults to\n * `DEFAULT_SPAN_TIMEOUT_MS`.\n */\n spanTimeoutMs?: number;\n\n /**\n * Reference time used to detect abandoned spans. Force-closing is skipped entirely when this\n * is omitted, so callers that don't pass it (tests, deterministic snapshots) keep the prior\n * behavior of leaving unterminated spans open regardless of their fixture timestamps.\n */\n now?: number;\n}\n\n/**\n * Builds a hierarchical span tree from a list of trace messages.\n *\n * Algorithm:\n * 1. Flatten messages into events and sort them chronologically.\n * 2. For each event:\n * - Begin events (`OperationStart`, `Trace.AgentRequestBegin`) open a new span whose parent\n * is the currently-open span of the event's `meta.parentPid`, or the root if there is\n * none. The begin event itself becomes the first event of the new span.\n * - End events (`OperationEnd`, `Trace.AgentRequestEnd`) close the currently-open span for\n * the event's `meta.pid` and become its last event.\n * - Other events attach to the currently-open span for their `meta.pid`, or to the\n * root span if no span is currently open for that pid (or the event has no pid).\n * 3. Sort each span's children by their earliest event timestamp.\n */\nexport const buildSpanTree = (messages: readonly Trace.Message[], options: BuildSpanTreeOptions = {}): Span => {\n const allEvents = messages.flatMap((message) => Trace.flatten(message));\n allEvents.sort((a, b) => a.timestamp - b.timestamp);\n\n // The limit caps verbose middle events (status/partial-block) only. Span boundary events\n // are always retained so the parent/child structure of older spans isn't dropped — losing a\n // begin event detaches every descendant and collapses them onto the root branch.\n const events = applyEventLimit(allEvents, options.eventLimit);\n\n const root = makeMutableSpan(ROOT_SPAN_ID, {});\n\n // Currently-open span for each pid.\n // A process may host multiple sequential spans (e.g. successive agent requests), so we\n // track the active one and start a new span on the next begin event.\n const openSpans = new Map<string, MutableSpan>();\n\n // Most-recent span for each pid, open OR already closed. Used as the parent fallback for a\n // child process whose parent span has already ended — e.g. a delegated sub-agent runs\n // concurrently and its begin event arrives after the supervisor's turn (its parent) closed.\n // Without this the child would nest at the root and render on its own top-level lane, reusing\n // a sibling's released lane instead of forking off its parent.\n const lastSpanByPid = new Map<string, MutableSpan>();\n\n // Every span ever opened, including ones later superseded by a same-pid begin event before\n // getting an end event (§15 \"interleaved same-pid begin/end pairs\"). `openSpans` only tracks\n // the *current* span per pid, so a superseded span — which will never receive an end event —\n // would otherwise be unreachable by the timeout sweep below.\n const allSpans: MutableSpan[] = [];\n\n let spanCounter = 0;\n const allocSpanId = (pid: string): string => {\n const id = `${pid}#${spanCounter}`;\n spanCounter += 1;\n return id;\n };\n\n const noteTimestamp = (span: MutableSpan, timestamp: number): void => {\n if (timestamp < span.firstTimestamp) {\n span.firstTimestamp = timestamp;\n }\n };\n\n for (const event of events) {\n const pid = event.meta.pid;\n\n if (!pid) {\n // Events without a pid attach to the root.\n root.events.push(event);\n noteTimestamp(root, event.timestamp);\n continue;\n }\n\n if (BEGIN_EVENT_TYPES.has(event.type)) {\n const parentPid = event.meta.parentPid;\n // Prefer the parent's currently-open span; fall back to its most-recent (closed) span so a\n // child process whose parent has already ended still nests under it (delegated sub-agents).\n const parent = (parentPid && (openSpans.get(parentPid) ?? lastSpanByPid.get(parentPid))) || root;\n const span = makeMutableSpan(allocSpanId(pid), computeMeta(event.meta));\n span.events.push(event);\n noteTimestamp(span, event.timestamp);\n parent.children.push(span);\n allSpans.push(span);\n // The new span supersedes any previously-open span for this pid.\n openSpans.set(pid, span);\n lastSpanByPid.set(pid, span);\n continue;\n }\n\n if (END_EVENT_TYPES.has(event.type)) {\n const span = openSpans.get(pid);\n if (span) {\n span.events.push(event);\n noteTimestamp(span, event.timestamp);\n openSpans.delete(pid);\n } else {\n // End event without a matching begin — attach to root so the event isn't lost.\n root.events.push(event);\n noteTimestamp(root, event.timestamp);\n }\n continue;\n }\n\n // Non-boundary event: attach to the currently-open span for this pid if any.\n const open = openSpans.get(pid);\n if (open) {\n open.events.push(event);\n noteTimestamp(open, event.timestamp);\n } else {\n root.events.push(event);\n noteTimestamp(root, event.timestamp);\n }\n }\n\n // Force-close spans the runtime never reported the end of (crash, dropped connection, etc.) —\n // otherwise they stay open forever and the UI renders them as stuck mid-flight. Walks every\n // span ever opened (not just `openSpans`) so a span superseded by a later same-pid begin event\n // — which never receives its own end event — is force-closed too. Skipped when `now` isn't\n // supplied so callers that don't care about wall-clock staleness are unaffected.\n if (options.now !== undefined) {\n const now = options.now;\n const spanTimeoutMs = options.spanTimeoutMs ?? DEFAULT_SPAN_TIMEOUT_MS;\n for (const span of allSpans) {\n const lastEvent = span.events[span.events.length - 1]!;\n if (isSpanEndEvent(lastEvent)) {\n continue;\n }\n const timeoutAt = lastEvent.timestamp + spanTimeoutMs;\n if (now < timeoutAt) {\n continue;\n }\n const endEvent = makeTimeoutEndEvent(span, timeoutAt);\n span.events.push(endEvent);\n noteTimestamp(span, endEvent.timestamp);\n }\n }\n\n // Sort children chronologically for deterministic output.\n const sortChildren = (span: MutableSpan): void => {\n span.children.sort((a, b) => a.firstTimestamp - b.firstTimestamp);\n for (const child of span.children) {\n sortChildren(child);\n }\n };\n sortChildren(root);\n\n return freezeSpan(root);\n};\n\n/**\n * Message stamped on synthetic end events produced when a span times out.\n */\nconst SPAN_TIMEOUT_MESSAGE = 'No end event was recorded for this span; it was closed after a timeout.';\n\n/**\n * Synthesizes the end event that closes an abandoned span, matching the event type its begin\n * event opened it with (`OperationStart` → `OperationEnd`, `Trace.AgentRequestBegin` → `Trace.AgentRequestEnd`).\n */\nconst makeTimeoutEndEvent = (span: MutableSpan, timestamp: number): Trace.FlatEvent => {\n const beginEvent = span.events[0]!;\n if (beginEvent.type === Trace.AgentRequestBegin.key) {\n return {\n type: Trace.AgentRequestEnd.key,\n timestamp,\n meta: beginEvent.meta,\n isEphemeral: false,\n data: { status: 'interrupted', error: SPAN_TIMEOUT_MESSAGE },\n };\n }\n\n // `beginEvent.data` is unvalidated wire data; decode defensively rather than trusting its shape.\n const fallback: Schema.Schema.Type<typeof Trace.OperationStart.schema> = { key: 'unknown' };\n const beginData = Option.getOrElse(\n Schema.decodeUnknownOption(Trace.OperationStart.schema)(beginEvent.data),\n () => fallback,\n );\n return {\n type: Trace.OperationEnd.key,\n timestamp,\n meta: beginEvent.meta,\n isEphemeral: false,\n data: {\n key: beginData.key,\n name: beginData.name,\n icon: beginData.icon,\n outcome: 'failure',\n error: SPAN_TIMEOUT_MESSAGE,\n },\n };\n};\n\n/**\n * Caps the number of non-boundary events while retaining every span boundary event.\n *\n * Boundary events define the span tree's structure: dropping a begin event detaches every\n * descendant span (its `parentPid` lookup fails, so children fall back to the root), and\n * dropping an end event leaves a span open and corrupts the open-span map for sibling spans\n * that share a pid. Status/partial-block events are the noisy bulk and the only ones the\n * limit needs to control.\n *\n * The returned array stays in chronological order.\n */\nconst applyEventLimit = (events: readonly Trace.FlatEvent[], eventLimit: number | undefined): Trace.FlatEvent[] => {\n if (eventLimit === undefined) {\n return [...events];\n }\n\n let nonBoundaryCount = 0;\n for (const event of events) {\n if (!isBoundary(event)) {\n nonBoundaryCount += 1;\n }\n }\n if (nonBoundaryCount <= eventLimit) {\n return [...events];\n }\n\n const dropCount = nonBoundaryCount - eventLimit;\n let dropped = 0;\n const result: Trace.FlatEvent[] = [];\n for (const event of events) {\n if (!isBoundary(event) && dropped < dropCount) {\n dropped += 1;\n continue;\n }\n result.push(event);\n }\n return result;\n};\n\nconst isBoundary = (event: Trace.FlatEvent): boolean =>\n BEGIN_EVENT_TYPES.has(event.type) || END_EVENT_TYPES.has(event.type);\n\n/**\n * A single event positioned within the span tree for commit emission.\n */\nexport interface SpanEventCursor {\n readonly span: Span;\n readonly event: Trace.FlatEvent;\n readonly eventIndex: number;\n}\n\n/**\n * Flattens span-tree events in categorical (depth-first) order: each span's begin events, its\n * child subtrees in sibling order, then its remaining events (middle and end).\n */\nexport const collectSpanTreeEventsCategorically = (root: Span): SpanEventCursor[] => {\n const stream: SpanEventCursor[] = [];\n\n const visitSpan = (span: Span): void => {\n for (let eventIndex = 0; eventIndex < span.events.length; eventIndex += 1) {\n const event = span.events[eventIndex]!;\n if (isSpanBeginEvent(event)) {\n stream.push({ span, event, eventIndex });\n }\n }\n\n for (const child of span.children) {\n visitSpan(child);\n }\n\n for (let eventIndex = 0; eventIndex < span.events.length; eventIndex += 1) {\n const event = span.events[eventIndex]!;\n if (!isSpanBeginEvent(event)) {\n stream.push({ span, event, eventIndex });\n }\n }\n };\n\n visitSpan(root);\n return stream;\n};\n\n/**\n * Walks the span tree in depth-first pre-order, invoking `visit` for each span (root included).\n */\nexport const walkSpanTree = (root: Span, visit: (span: Span, depth: number) => void, depth = 0): void => {\n visit(root, depth);\n for (const child of root.children) {\n walkSpanTree(child, visit, depth + 1);\n }\n};\n\n/**\n * Returns all spans in the tree in depth-first pre-order, root first.\n */\nexport const flattenSpanTree = (root: Span): Span[] => {\n const result: Span[] = [];\n walkSpanTree(root, (span) => result.push(span));\n return result;\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Array from 'effect/Array';\nimport { pipe } from 'effect/Function';\nimport * as Option from 'effect/Option';\nimport * as Pipeable from 'effect/Pipeable';\nimport * as Schema from 'effect/Schema';\nimport * as Struct from 'effect/Struct';\n\nimport * as Process from '@dxos/compute/Process';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Annotation } from '@dxos/echo';\nimport { EID } from '@dxos/keys';\nimport { LogLevel, log } from '@dxos/log';\nimport { type ContentBlock } from '@dxos/types';\n\nimport { type Commit } from '../components/Timeline/index.ts';\nimport { ROOT_SPAN_ID, type Span, buildSpanTree, isSpanBeginEvent, isSpanEndEvent, walkSpanTree } from './span-tree.ts';\n\n/**\n * Branch name for top-level operation invocations.\n */\nconst MAIN_BRANCH = 'main';\n\n/** Timeline tag that applies a shimmer message effect. */\nconst SHIMMER_EFFECT_TAG = 'effect:shimmer';\n\nconst ICONS = {\n agentRequestBegin: {\n icon: 'ph--atom--regular',\n level: LogLevel.VERBOSE,\n },\n agentRequestEndSuccess: {\n icon: 'ph--atom--regular',\n level: LogLevel.INFO,\n },\n agentRequestEndError: {\n icon: 'ph--atom--regular',\n level: LogLevel.ERROR,\n },\n agentRequestEndInterrupted: {\n icon: 'ph--atom--regular',\n level: LogLevel.WARN,\n },\n userMessage: {\n icon: 'ph--user--regular',\n level: LogLevel.VERBOSE,\n },\n statusMessage: {\n icon: 'ph--info--regular',\n level: LogLevel.VERBOSE,\n },\n operationStart: {\n icon: 'ph--function--regular',\n level: LogLevel.VERBOSE,\n },\n operationEndSuccess: {\n icon: 'ph--function--regular',\n level: LogLevel.INFO,\n },\n operationEndError: {\n icon: 'ph--function--regular',\n level: LogLevel.ERROR,\n },\n operationEndIncomplete: {\n icon: 'ph--arrows-clockwise--regular',\n level: LogLevel.WARN,\n },\n toolCall: {\n icon: 'ph--wrench--regular',\n level: LogLevel.VERBOSE,\n },\n toolResultSuccess: {\n icon: 'ph--wrench--regular',\n level: LogLevel.INFO,\n },\n toolResultError: {\n icon: 'ph--wrench--regular',\n level: LogLevel.ERROR,\n },\n agentRequestRunning: {\n icon: 'ph--spinner-gap--regular',\n level: LogLevel.VERBOSE,\n },\n processRunning: {\n icon: 'ph--spinner-gap--regular',\n level: LogLevel.VERBOSE,\n },\n} as const;\n\nexport interface BuildExecutionGraphParams {\n traceMessages: readonly Trace.Message[];\n activeProcesses?: readonly Process.Process[];\n collapseCompletedSpans?: boolean;\n eventLimit?: number;\n /**\n * Duration a span may sit open with no new events before it's force-closed with a synthetic\n * end event. Only takes effect when `now` is also provided. Defaults to\n * `DEFAULT_SPAN_TIMEOUT_MS`.\n */\n spanTimeoutMs?: number;\n /**\n * Reference time used to detect abandoned spans. Force-closing is skipped entirely when this\n * is omitted.\n */\n now?: number;\n}\n\n/**\n * Builds a Timeline-compatible execution graph from trace messages and active processes.\n *\n * The conversion runs in two stages:\n * 1. `buildSpanTree` converts the flat list of trace messages into a hierarchical\n * tree of spans grouped by process id (pid). See `./span-tree.ts`.\n * 2. `spanTreeToCommits` walks the tree and emits one commit per event, using the\n * tree structure to decide which branch each commit belongs to and how to wire parents.\n *\n * Pure function — no signals or atoms.\n */\nexport type ExecutionGraph = {\n branches: string[];\n commits: Commit[];\n spanTree: Span;\n /** Commit id -> trace event. */\n details: ExecutionGraphDetailsMap;\n};\n\nexport type ExecutionGraphDetailsMap = Record<string, Trace.FlatEvent | undefined>;\n\nexport const buildExecutionGraph = ({\n traceMessages,\n activeProcesses = [],\n collapseCompletedSpans = false,\n eventLimit = 500,\n spanTimeoutMs,\n now,\n}: BuildExecutionGraphParams): ExecutionGraph => {\n const spanTree = buildSpanTree(traceMessages, { eventLimit, spanTimeoutMs, now });\n const toolCallContext = buildToolCallContext(traceMessages);\n const built = spanTreeToCommits(spanTree, activeProcesses, toolCallContext, collapseCompletedSpans);\n log('trace execution graph', {\n traceMessages: traceMessages.length,\n commits: built.commits.length,\n branches: built.branches.length,\n activeProcesses: activeProcesses.length,\n });\n return { ...built, spanTree };\n};\n\n/**\n * Lookup tables that pair `toolCall` blocks with their matching `toolResult` blocks so the\n * renderer can collapse the two events into a single commit (mirroring how begin/end events of\n * an empty operation span collapse). Indexed by the shared `toolCallId`.\n */\ninterface ToolCallContext {\n callById: Map<string, ContentBlock.ToolCall>;\n resultByCallId: Map<string, ContentBlock.ToolResult>;\n}\n\nconst buildToolCallContext = (messages: readonly Trace.Message[]): ToolCallContext => {\n const callById = new Map<string, ContentBlock.ToolCall>();\n const resultByCallId = new Map<string, ContentBlock.ToolResult>();\n for (const message of messages) {\n for (const event of message.events) {\n if (event.type !== Trace.CompleteBlock.key) {\n continue;\n }\n const data = event.data as { block?: ContentBlock.Any } | undefined;\n const block = data?.block;\n if (!block) {\n continue;\n }\n if (block._tag === 'toolCall') {\n callById.set(block.toolCallId, block);\n } else if (block._tag === 'toolResult') {\n resultByCallId.set(block.toolCallId, block);\n }\n }\n }\n return { callById, resultByCallId };\n};\n\n/**\n * Visual representation of a single trace event — icon, log level, message string.\n * `undefined` indicates that the event should not produce a commit.\n */\ninterface EventPresentation {\n icon: string;\n level: LogLevel;\n message: string;\n idSuffix?: string;\n}\n\ntype AgentRequestEndData = Schema.Schema.Type<typeof Trace.AgentRequestEnd.schema>;\n\n/**\n * Parses `Trace.AgentRequestEnd` payload, accepting legacy traces that omitted `status`.\n */\nconst parseAgentRequestEnd = (data: unknown): AgentRequestEndData | undefined => {\n if (Schema.is(Trace.AgentRequestEnd.schema)(data)) {\n return data;\n }\n // Traces emitted before `status` was added wrote an empty object.\n if (data != null && typeof data === 'object' && Object.keys(data).length === 0) {\n return { status: 'success' };\n }\n log('invalid trace event', { type: Trace.AgentRequestEnd.key });\n return undefined;\n};\n\nconst presentAgentRequestEnd = (data: AgentRequestEndData): EventPresentation => {\n switch (data.status) {\n case 'error':\n return {\n icon: ICONS.agentRequestEndError.icon,\n level: ICONS.agentRequestEndError.level,\n message: data.error ? trimText(`Agent request failed: ${data.error}`) : 'Agent request failed',\n };\n case 'interrupted':\n return {\n icon: ICONS.agentRequestEndInterrupted.icon,\n level: ICONS.agentRequestEndInterrupted.level,\n message: 'Agent request interrupted',\n };\n default:\n return {\n icon: ICONS.agentRequestEndSuccess.icon,\n level: ICONS.agentRequestEndSuccess.level,\n message: 'Agent completed request',\n };\n }\n};\n\nconst presentEvent = (event: Trace.FlatEvent, toolCallContext: ToolCallContext): EventPresentation | undefined => {\n if (Trace.isOfType(Trace.AgentRequestBegin, event)) {\n if (!Schema.is(Trace.AgentRequestBegin.schema)(event.data)) {\n log('invalid trace event', { type: event.type });\n return undefined;\n }\n return {\n icon: ICONS.agentRequestBegin.icon,\n level: ICONS.agentRequestBegin.level,\n message: 'Agent processing request...',\n };\n }\n if (Trace.isOfType(Trace.AgentRequestEnd, event)) {\n const endData = parseAgentRequestEnd(event.data);\n if (!endData) {\n return undefined;\n }\n return presentAgentRequestEnd(endData);\n }\n if (Trace.isOfType(Trace.CompleteBlock, event)) {\n if (!Schema.is(Trace.CompleteBlock.schema)(event.data)) {\n log('invalid trace event', { type: event.type });\n return undefined;\n }\n switch (event.data.block._tag) {\n case 'text':\n return event.data.role === 'user'\n ? {\n icon: ICONS.userMessage.icon,\n level: ICONS.userMessage.level,\n message: trimText(event.data.block.text),\n }\n : undefined;\n case 'status':\n return {\n icon: ICONS.statusMessage.icon,\n level: ICONS.statusMessage.level,\n message: trimText(event.data.block.statusText),\n };\n case 'toolCall': {\n // Operation-backed tool calls already have a dedicated routine span (Trace.OperationStart /\n // Trace.OperationEnd) that produces its own commits — skip the duplicate toolCall commit\n // to avoid double-rendering.\n if (event.data.block.operationKey) {\n return undefined;\n }\n // Collapse the toolCall/toolResult pair: when the matching toolResult has arrived, the\n // result event is the visible commit and carries the success/error state. The toolCall\n // itself only renders while still pending (i.e. no result yet) — same intent as an\n // operation span that collapses to a single end commit once both boundaries are present.\n if (toolCallContext.resultByCallId.has(event.data.block.toolCallId)) {\n return undefined;\n }\n return {\n icon: ICONS.toolCall.icon,\n level: ICONS.toolCall.level,\n message: event.data.block.name,\n idSuffix: `toolCall:${event.data.block.toolCallId}`,\n };\n }\n case 'toolResult': {\n // Suppress results for operation-backed calls — those are covered by the routine span.\n const call = toolCallContext.callById.get(event.data.block.toolCallId);\n if (call?.operationKey) {\n return undefined;\n }\n const success = event.data.block.error === undefined;\n const name = call?.name ?? event.data.block.name;\n return {\n icon: success ? ICONS.toolResultSuccess.icon : ICONS.toolResultError.icon,\n level: success ? ICONS.toolResultSuccess.level : ICONS.toolResultError.level,\n message: `${name}${!success ? ' - Error' : ''}`,\n idSuffix: `toolResult:${event.data.block.toolCallId}`,\n };\n }\n default:\n return undefined;\n }\n }\n if (Trace.isOfType(Trace.OperationStart, event)) {\n if (!Schema.is(Trace.OperationStart.schema)(event.data)) {\n log('invalid trace event', { type: event.type });\n return undefined;\n }\n return {\n icon: event.data.icon ?? ICONS.operationStart.icon,\n level: ICONS.operationStart.level,\n message: event.data.name ?? event.data.key,\n idSuffix: `${event.data.key}:start`,\n };\n }\n if (Trace.isOfType(Trace.OperationEnd, event)) {\n if (!Schema.is(Trace.OperationEnd.schema)(event.data)) {\n log('invalid trace event', { type: event.type });\n return undefined;\n }\n // A `RunAgainError` (Operation.runAgain) is a scheduler yield, not a hard error: the trace records\n // it as a failure tagged with the run-again error code, but it will be re-invoked. Detect it here\n // and present it as a distinct warn-level state rather than folding it into failure. Fall back to\n // the legacy message for events persisted before `errorCode` existed.\n const incomplete =\n event.data.outcome === 'failure' &&\n (event.data.errorCode === Process.RUN_AGAIN_ERROR_CODE ||\n (event.data.errorCode === undefined && event.data.error === Process.RUN_AGAIN_MESSAGE));\n const presentation =\n event.data.outcome === 'success'\n ? { icon: ICONS.operationEndSuccess.icon, level: ICONS.operationEndSuccess.level, suffix: '' }\n : incomplete\n ? {\n icon: ICONS.operationEndIncomplete.icon,\n level: ICONS.operationEndIncomplete.level,\n suffix: ' - Incomplete',\n }\n : { icon: ICONS.operationEndError.icon, level: ICONS.operationEndError.level, suffix: ' - Error' };\n return {\n icon: event.data.icon ?? presentation.icon,\n level: presentation.level,\n message: `${event.data.name ?? event.data.key}${presentation.suffix}`,\n idSuffix: `${event.data.key}:end`,\n };\n }\n return undefined;\n};\n\nexport type CollectProcessActivityOptions = {\n /**\n * When set, messages with a `conversationId` that disagrees are excluded.\n * Messages without `conversationId` still match when their pid is in the subtree.\n */\n conversationId?: string;\n eventLimit?: number;\n};\n\n/**\n * Collects human-readable activity lines for a process subtree (root pid and descendants).\n * Used to surface live sub-agent status in the task list.\n */\nexport const collectProcessActivityLines = (\n messages: readonly Trace.Message[],\n rootPid: string,\n options: CollectProcessActivityOptions = {},\n): string[] => {\n const { conversationId, eventLimit = 50 } = options;\n const descendantPids = collectDescendantPids(messages, rootPid);\n const filtered = messages.filter((message) => {\n const pid = message.meta.pid;\n if (!pid || !descendantPids.has(pid)) {\n return false;\n }\n const metaConvId = message.meta.conversation\n ? EID.getEntityId(EID.parse(message.meta.conversation.uri))\n : undefined;\n if (conversationId && metaConvId !== undefined && metaConvId !== conversationId) {\n return false;\n }\n return true;\n });\n\n const events = filtered\n .flatMap((message) => Trace.flatten(message))\n .sort((left, right) => left.timestamp - right.timestamp)\n .slice(-eventLimit);\n\n const toolCallContext = buildToolCallContext(filtered);\n const lines: string[] = [];\n for (const event of events) {\n const presentation = presentEvent(event, toolCallContext);\n if (presentation) {\n lines.push(presentation.message);\n }\n }\n return lines;\n};\n\n/**\n * Derives a single in-flight status line from durable trace when ephemeral subscription\n * is unavailable (e.g. between partial blocks or while a child operation is running).\n */\nexport const deriveInFlightActivityLine = (\n messages: readonly Trace.Message[],\n rootPid: string,\n options: CollectProcessActivityOptions = {},\n): string | undefined => {\n const { conversationId, eventLimit = 50 } = options;\n const descendantPids = collectDescendantPids(messages, rootPid);\n const filtered = messages.filter((message) => {\n const pid = message.meta.pid;\n if (!pid || !descendantPids.has(pid)) {\n return false;\n }\n const metaConvId = message.meta.conversation\n ? EID.getEntityId(EID.parse(message.meta.conversation.uri))\n : undefined;\n if (conversationId && metaConvId !== undefined && metaConvId !== conversationId) {\n return false;\n }\n return true;\n });\n\n const events = filtered\n .flatMap((message) => Trace.flatten(message))\n .sort((left, right) => left.timestamp - right.timestamp)\n .slice(-eventLimit);\n\n const openOperations = new Map<string, { name: string; timestamp: number }>();\n let agentRequestOpen = false;\n let lastLine: string | undefined;\n\n for (const event of events) {\n const pid = event.meta.pid ?? rootPid;\n if (Trace.isOfType(Trace.OperationStart, event)) {\n const key = `${pid}:${event.data.key}`;\n const name = event.data.name ?? event.data.key;\n openOperations.set(key, { name, timestamp: event.timestamp });\n lastLine = `${name}...`;\n continue;\n }\n if (Trace.isOfType(Trace.OperationEnd, event)) {\n openOperations.delete(`${pid}:${event.data.key}`);\n continue;\n }\n if (Trace.isOfType(Trace.AgentRequestBegin, event)) {\n agentRequestOpen = true;\n lastLine = 'Generating...';\n continue;\n }\n if (Trace.isOfType(Trace.AgentRequestEnd, event)) {\n agentRequestOpen = false;\n }\n }\n\n if (agentRequestOpen) {\n return 'Generating...';\n }\n\n const latestOperation = [...openOperations.values()].sort((left, right) => right.timestamp - left.timestamp)[0];\n if (latestOperation) {\n return `${latestOperation.name}...`;\n }\n\n return lastLine;\n};\n\nconst collectDescendantPids = (messages: readonly Trace.Message[], rootPid: string): Set<string> => {\n // Indexed first so the walk costs one pass over the messages rather than one per tree level.\n const childPidsByParent = new Map<string, Set<string>>();\n for (const message of messages) {\n const { pid, parentPid } = message.meta;\n if (!pid || !parentPid) {\n continue;\n }\n let children = childPidsByParent.get(parentPid);\n if (!children) {\n children = new Set();\n childPidsByParent.set(parentPid, children);\n }\n children.add(pid);\n }\n\n const pids = new Set([rootPid]);\n const pending = [rootPid];\n while (pending.length > 0) {\n for (const childPid of childPidsByParent.get(pending.pop()!) ?? []) {\n if (!pids.has(childPid)) {\n pids.add(childPid);\n pending.push(childPid);\n }\n }\n }\n return pids;\n};\n\nconst isPendingToolCallEvent = (event: Trace.FlatEvent, toolCallContext: ToolCallContext): boolean => {\n if (!Trace.isOfType(Trace.CompleteBlock, event)) {\n return false;\n }\n if (event.data.block._tag !== 'toolCall') {\n return false;\n }\n return !toolCallContext.resultByCallId.has(event.data.block.toolCallId);\n};\n\n/**\n * A span is completed when its last recorded event is a matching end boundary.\n */\nconst isCompletedSpan = (span: Span): boolean => {\n if (span.id === ROOT_SPAN_ID) {\n return false;\n }\n const lastEvent = span.events[span.events.length - 1];\n return lastEvent !== undefined && isSpanEndEvent(lastEvent);\n};\n\n/**\n * A span is \"collapsible\" when it would otherwise render as an empty fork-and-merge:\n * exactly two events that form a begin/end pair and no child sub-spans. In that case\n * we emit a single commit for the end event on the parent branch.\n *\n * When `collapseCompletedSpans` is enabled, any completed span collapses to that single\n * end commit — middle events, child sub-spans, and the begin fork are all omitted.\n *\n * A *pending* span (one whose end event has not yet been recorded) is never collapsed:\n * its trailing events should keep rendering as middle commits on the span's own branch\n * — never as a fake \"end\" commit on the parent branch.\n *\n * Both nested spans and top-level spans (whose parent is the synthetic root) are eligible\n * once they have completed: a span with no inner activity is collapsed regardless of where\n * it sits in the tree.\n */\nconst isCollapsibleSpan = (span: Span, parent: Span | null, collapseCompletedSpans: boolean): boolean => {\n if (span.id === ROOT_SPAN_ID) {\n return false;\n }\n if (parent === null) {\n return false;\n }\n if (span.events.length === 2 && span.children.length === 0) {\n const firstEvent = span.events[0];\n const lastEvent = span.events[span.events.length - 1];\n if (isSpanBeginEvent(firstEvent) && isSpanEndEvent(lastEvent)) {\n return true;\n }\n }\n if (collapseCompletedSpans && isCompletedSpan(span)) {\n return true;\n }\n return false;\n};\n\n/**\n * Converts a span tree into a flat list of commits + branches suitable for `Timeline` rendering.\n *\n * For every span the algorithm:\n * - emits the **first** event as a \"begin\" commit on the parent span's branch (fork);\n * - emits **middle** events as commits on the span's own branch;\n * - emits the **last** event as an \"end\" commit on the parent span's branch with two parents\n * (the begin commit and the last commit on the span's own branch — a merge).\n *\n * Collapsible spans (`isCollapsibleSpan`) emit only the end commit on the parent branch with\n * a single parent — a tidier rendering for sub-operations that have no inner detail.\n *\n * Events are processed in categorical span-tree order: each span's begin events, its child\n * subtrees (depth-first), then its remaining events. Active-process running rows are inserted\n * at the end of each matching span block — not appended after the entire tree.\n */\n/** Branch tips as a commit's parent list; a branch with no commit yet contributes nothing. */\nconst parentIds = (...tips: (Commit | undefined)[]): string[] =>\n Array.dedupe(tips.filter((tip) => tip !== undefined).map((tip) => tip.id));\n\nconst spanTreeToCommits = (\n root: Span,\n activeProcesses: readonly Process.Process[],\n toolCallContext: ToolCallContext,\n collapseCompletedSpans: boolean,\n): { branches: string[]; commits: Commit[]; details: ExecutionGraphDetailsMap } => {\n const builder = new GraphBuilder();\n const details: ExecutionGraphDetailsMap = {};\n builder.addBranch(MAIN_BRANCH);\n\n // Build a child → parent lookup using the tree's own structure (already correctly parented\n // when the tree was constructed, including sequential spans of the same process).\n const parentBySpan = new Map<Span, Span | null>();\n parentBySpan.set(root, null);\n const indexParents = (span: Span): void => {\n for (const child of span.children) {\n parentBySpan.set(child, span);\n indexParents(child);\n }\n };\n indexParents(root);\n\n const findParentSpan = (span: Span): Span | null => parentBySpan.get(span) ?? null;\n\n const collapsedSpanIds = new Set<string>();\n walkSpanTree(root, (span) => {\n if (isCollapsibleSpan(span, findParentSpan(span), collapseCompletedSpans)) {\n collapsedSpanIds.add(span.id);\n }\n });\n\n const isUnderCollapsedAncestor = (span: Span): boolean => {\n let ancestor = findParentSpan(span);\n while (ancestor) {\n if (collapsedSpanIds.has(ancestor.id)) {\n return true;\n }\n ancestor = findParentSpan(ancestor);\n }\n return false;\n };\n\n // The branch name for a span is its pid — multiple sequential spans of the same process\n // (e.g. successive agent requests in one session) share a branch so they reuse a single lane.\n const branchOf = (span: Span | null): string => {\n if (!span || span.id === ROOT_SPAN_ID) {\n return MAIN_BRANCH;\n }\n return span.meta.pid ?? span.id;\n };\n\n // Track the id of the begin commit for each non-collapsible span so the end commit can merge into it.\n const beginCommitIdBySpan = new Map<string, string>();\n\n // The parents for \"the most recent commit in this span's structural context\".\n //\n // The walk is structural (pid/parentPid), not topological: at each ancestor, we prefer\n // 1) the last commit on that span's own branch, then\n // 2) that span's begin commit (the fork point on its parent branch),\n // 3) and only then recurse into the parent span.\n //\n // Crucially, we never silently slip onto a *sibling* span's commit on a shared ancestor\n // branch. E.g. if a sub-span of agent A fires before A has any middle commits, we anchor\n // to A.begin — not to whatever unrelated commit happens to be the latest on main.\n // This keeps fork edges visually attached to the correct span even when sibling top-level\n // spans (different pids) overlap in time on main.\n const lastInSpanContext = (span: Span | null): string[] => {\n if (!span || span.id === ROOT_SPAN_ID) {\n return parentIds(builder.tipOf(MAIN_BRANCH));\n }\n const ownTip = builder.tipOf(branchOf(span));\n if (ownTip) {\n return parentIds(ownTip);\n }\n const beginId = beginCommitIdBySpan.get(span.id);\n if (beginId && builder.hasCommit(beginId)) {\n return [beginId];\n }\n return lastInSpanContext(findParentSpan(span));\n };\n\n const lastCommitIdBySpan = new Map<string, string>();\n let globalIndex = 0;\n const insertedRunningPids = new Set<string>();\n const activeProcessByPid = new Map(activeProcesses.map((process) => [process.pid, process]));\n\n const emitRunningIndicator = (pid: Process.ID): void => {\n if (insertedRunningPids.has(pid)) {\n return;\n }\n\n const process = activeProcessByPid.get(pid);\n if (!process) {\n return;\n }\n\n if (\n Process.isHarnessHost(process) &&\n Option.isSome(Annotation.getDictionary(process.params.annotations, Process.TargetAnnotation)) &&\n (process.state === Process.State.RUNNING || process.state === Process.State.HYBERNATING)\n ) {\n builder.addCommit({\n id: `running:${process.pid}`,\n branch: process.pid,\n // Falls back to the tail of main: a completed request collapses onto main, leaving the\n // agent's own branch empty, and a parentless spinner draws as a second, disconnected root.\n parents: parentIds(builder.firstTipOf(process.pid, MAIN_BRANCH)),\n icon: ICONS.agentRequestRunning.icon,\n level: ICONS.agentRequestRunning.level,\n message: 'Generating...',\n timestamp: new Date(),\n tags: [SHIMMER_EFFECT_TAG],\n });\n insertedRunningPids.add(pid);\n } else if (process.state === Process.State.RUNNING && builder.hasBranch(process.pid)) {\n builder.addCommit({\n id: `running:${process.pid}`,\n branch: process.pid,\n parents: parentIds(builder.tipOf(process.pid)),\n icon: ICONS.processRunning.icon,\n level: ICONS.processRunning.level,\n message: 'Running...',\n timestamp: new Date(),\n tags: [SHIMMER_EFFECT_TAG],\n });\n insertedRunningPids.add(pid);\n }\n };\n\n const emitEventCommit = (span: Span, event: Trace.FlatEvent, eventIndex: number): void => {\n const presentation = presentEvent(event, toolCallContext);\n if (!presentation) {\n return;\n }\n\n // Classify based on event TYPE, not array index. A pending span's trailing\n // middle event (e.g. a user message awaiting an agent response) must not be\n // mistaken for the span's end event — otherwise it would render on the\n // parent branch instead of the span's own branch.\n const isBeginEvent = isSpanBeginEvent(event);\n const isEndEvent = isSpanEndEvent(event);\n const parentSpan = findParentSpan(span);\n const collapsible = isCollapsibleSpan(span, parentSpan, collapseCompletedSpans);\n\n // Descendants of a collapsed span emit no commits — inner activity is folded into the ancestor end row.\n if (isUnderCollapsedAncestor(span)) {\n return;\n }\n\n // Collapsed spans: skip every event except the end commit.\n if (collapsible && !isEndEvent) {\n return;\n }\n\n const parentBranch = branchOf(parentSpan);\n const ownBranch = branchOf(span);\n\n // A \"process boundary\" span is a concurrent child PROCESS (its own pid, differing from the\n // parent's) with real sub-flow content (a middle event) — e.g. a delegated sub-agent. Such a\n // span gets its own lane: it forks onto its own branch at begin and collapses back to main at\n // end (so neither its lane nor its parent's lane dangles). A bare operation (begin+end only)\n // collapses to a single commit and is NOT treated as a boundary — forking its transient begin\n // mid-stream would flash a throwaway lane.\n const ownPid = span.meta.pid;\n const parentPid = parentSpan?.meta.pid;\n const spanHasMiddle = span.events.some((spanEvent) => !isSpanBeginEvent(spanEvent) && !isSpanEndEvent(spanEvent));\n const isProcessBoundary = ownPid != null && parentPid != null && ownPid !== parentPid && spanHasMiddle;\n\n let branch: string;\n let parents: string[];\n\n if (span.id === ROOT_SPAN_ID) {\n // Root-level events (no pid) attach sequentially to main.\n branch = MAIN_BRANCH;\n parents = lastInSpanContext(null);\n } else if (collapsible) {\n // Only the end event reaches here for collapsible spans.\n // Anchor to the parent span's structural context so the fork attaches to the parent\n // — not to a sibling span's commit that happens to be the latest on the shared ancestor.\n branch = parentBranch;\n parents = lastInSpanContext(parentSpan);\n } else if (isBeginEvent) {\n // Begin commit, anchored to the parent's structural context. A nested sub-span stays on the\n // parent lane (only its middle events fork). A concurrent child process forks onto its own\n // branch from this first event so it gets its own lane immediately.\n branch = isProcessBoundary ? ownBranch : parentBranch;\n parents = lastInSpanContext(parentSpan);\n } else if (isEndEvent) {\n // End commit: continues the parent branch chronologically and merges in own-branch work.\n //\n // Parent #1 is the *immediate predecessor* on the parent branch (not the matching begin\n // commit). Pointing back to the begin commit creates a visual edge that skips over any\n // sibling span's commits emitted between begin and end — e.g. when two top-level Routine\n // spans overlap on main, R1.end would otherwise draw an arrow back to R1.begin that\n // crosses over R2.begin. Anchoring to the previous main commit keeps main linear.\n //\n // A concurrent child process collapses all the way back to MAIN (merging its own branch),\n // rather than to its parent's branch: the parent (e.g. a supervisor whose turn already merged\n // to main) would otherwise gain commits after its own merge and never re-collapse — leaving a\n // dangling lane after the child finishes.\n branch = isProcessBoundary ? MAIN_BRANCH : parentBranch;\n parents = parentIds(builder.tipOf(branch), builder.tipOf(ownBranch));\n } else {\n // Middle event: continue the span's own branch; fall back to span's own context so the\n // first middle event of a span forks from the span's begin commit, not from a sibling's\n // commit on an ancestor branch.\n branch = ownBranch;\n parents = lastInSpanContext(span);\n }\n\n const commitIndex = globalIndex++;\n const commitId = formatCommitId(span, commitIndex, presentation.idSuffix);\n // A pending tool call still in flight gets Timeline shimmer styling.\n const shimmer = isPendingToolCallEvent(event, toolCallContext);\n const commit: Commit = {\n id: commitId,\n branch,\n parents,\n timestamp: new Date(event.timestamp),\n icon: presentation.icon,\n level: presentation.level,\n message: presentation.message,\n ...(shimmer && { tags: [SHIMMER_EFFECT_TAG] }),\n };\n builder.addCommit(commit);\n details[commitId] = event;\n lastCommitIdBySpan.set(span.id, commitId);\n\n // Record begin commit so a later end event can merge into it.\n if (isBeginEvent && !collapsible && span.id !== ROOT_SPAN_ID) {\n beginCommitIdBySpan.set(span.id, commitId);\n }\n };\n\n const finishSpan = (span: Span): void => {\n const pid = span.meta.pid;\n if (pid) {\n // Trace.Meta.pid is plain string (avoids circular dep); construct brand here.\n emitRunningIndicator(Process.ID.make(pid));\n }\n\n if (span.id === ROOT_SPAN_ID || isCompletedSpan(span)) {\n return;\n }\n\n if (pid && insertedRunningPids.has(pid)) {\n return;\n }\n\n const lastCommitId = lastCommitIdBySpan.get(span.id);\n if (lastCommitId) {\n builder.addTag(lastCommitId, SHIMMER_EFFECT_TAG);\n }\n };\n\n const emitSpanCommits = (span: Span): void => {\n for (let eventIndex = 0; eventIndex < span.events.length; eventIndex += 1) {\n const event = span.events[eventIndex]!;\n if (isSpanBeginEvent(event)) {\n emitEventCommit(span, event, eventIndex);\n }\n }\n\n for (const child of span.children) {\n emitSpanCommits(child);\n }\n\n for (let eventIndex = 0; eventIndex < span.events.length; eventIndex += 1) {\n const event = span.events[eventIndex]!;\n if (!isSpanBeginEvent(event)) {\n emitEventCommit(span, event, eventIndex);\n }\n }\n\n finishSpan(span);\n };\n\n emitSpanCommits(root);\n\n for (const process of activeProcesses) {\n emitRunningIndicator(process.pid);\n }\n\n const { commits, branches } = builder.build();\n return { commits, branches, details };\n};\n\nconst formatCommitId = (span: Span, globalIndex: number, suffix?: string): string => {\n const base = `${span.id}:${globalIndex}`;\n return suffix ? `${base}:${suffix}` : base;\n};\n\nconst trimText = (text: string) => text.slice(0, 100).trim().split('\\n')[0];\n\ntype Falsy = false | null | undefined;\n\nexport interface CommitSelector extends Pipeable.Pipeable {\n select: (commits: Commit[]) => Commit[];\n}\n\nexport const CommitSelector = {\n make: (select: CommitSelector['select']): CommitSelector => ({\n select,\n pipe(...args: any) {\n return Pipeable.pipeArguments(this, args);\n },\n }),\n\n identity: (): CommitSelector => CommitSelector.make((commits) => commits),\n\n /**\n * Selects commits that match the given predicate.\n */\n filter: (predicate: (commit: Commit) => unknown): CommitSelector =>\n CommitSelector.make((commits) => commits.filter(predicate)),\n\n /**\n * Selects commits by id.\n */\n id: (id: string): CommitSelector => CommitSelector.filter((commit) => commit.id === id),\n /**\n * Selects commits by tag.\n */\n tag: (tag: string | Falsy): CommitSelector => CommitSelector.filter((commit) => tag && commit.tags?.includes(tag)),\n /**\n * Selects commits by if any of the given tags are present.\n */\n anyTags: (tags: (string | Falsy)[]): CommitSelector =>\n CommitSelector.filter((commit) => tags.some((tag) => tag && commit.tags?.includes(tag))),\n /**\n * Selects commits by branch.\n */\n branch: (branch: string | Falsy): CommitSelector =>\n CommitSelector.filter((commit) => branch && commit.branch === branch),\n\n /**\n * Chains two selectors together, applying the second selector to the result of the first.\n *\n * Example:\n *\n * ```\n * CommitSelector.tag('tag').pipe(CommitSelector.compose(CommitSelector.branch('main')));\n * ```\n */\n compose:\n (next: CommitSelector) =>\n (prev: CommitSelector): CommitSelector =>\n CommitSelector.make((commits) => next.select(prev.select(commits))),\n\n /**\n * If `prev` selector matches no commits, return `next` selector, otherwise return `prev` selector.\n * Same as `CommitSelector.firstOf(prev, next)`.\n *\n * Example:\n *\n * ```\n * CommitSelector.tag('tag').pipe(CommitSelector.orElse(CommitSelector.branch('main')));\n * ```\n */\n orElse:\n (next: CommitSelector) =>\n (prev: CommitSelector): CommitSelector =>\n CommitSelector.make((commits) => {\n const selected = prev.select(commits);\n if (selected.length > 0) {\n return selected;\n }\n return next.select(commits);\n }),\n\n /**\n * Selects commits that match either of the given selectors.\n */\n andAlso:\n (next: CommitSelector) =>\n (prev: CommitSelector): CommitSelector =>\n CommitSelector.unionAll(prev, next),\n\n /**\n * Selects the first n commits.\n */\n first: (n: number = 1): CommitSelector => CommitSelector.make((commits) => commits.slice(0, n)),\n /**\n * Selects the last n commits (reverses the order of the commits).\n */\n last: (n: number = 1): CommitSelector => CommitSelector.make((commits) => commits.toReversed().slice(0, n)),\n /**\n * Selects commits that do not match the given selector.\n */\n not: (selector: CommitSelector): CommitSelector =>\n CommitSelector.make((commits) => {\n const selected = selector.select(commits);\n return commits.filter((commit) => !selected.includes(commit));\n }),\n\n /**\n * Selects commits that match any of the given selectors.\n */\n unionAll: (...selectors: CommitSelector[]): CommitSelector =>\n CommitSelector.make((commits) => {\n return Array.dedupeWith(\n selectors.flatMap((selector) => selector.select(commits)),\n (a, b) => a.id === b.id,\n );\n }),\n\n /**\n * Selects commits that match all of the given selectors.\n */\n intersectAll: (...selectors: CommitSelector[]): CommitSelector =>\n CommitSelector.make((commits) => {\n const selected = selectors.map((selector) => selector.select(commits));\n if (selected.length === 0) {\n return [];\n }\n return selected[0].filter((commit) => selected.every((selected) => selected.some((c) => c.id === commit.id)));\n }),\n\n /**\n * Returns the result of the first selector that matches any commits.\n */\n firstOf: (...selectors: CommitSelector[]): CommitSelector =>\n CommitSelector.make((commits) => {\n for (const selector of selectors) {\n const selected = selector.select(commits);\n if (selected.length > 0) {\n return selected;\n }\n }\n return [];\n }),\n};\n\n/**\n * Accumulates the commit list. Every lookup the graph makes while building — the tip of a branch,\n * a commit by id — is served from an index, because each is asked once per commit and a scan would\n * make the whole build quadratic in the history.\n */\nclass GraphBuilder {\n #commits: Commit[] = [];\n #branches = new Set<string>();\n #indexById = new Map<string, number>();\n #tipIndexByBranch = new Map<string, number>();\n\n hasBranch(branch: string): boolean {\n return this.#branches.has(branch);\n }\n\n hasCommit(commitId: string): boolean {\n return this.#indexById.has(commitId);\n }\n\n /** The most recent commit on a branch, or undefined while the branch has none. */\n tipOf(branch: string | Falsy): Commit | undefined {\n if (!branch) {\n return undefined;\n }\n const index = this.#tipIndexByBranch.get(branch);\n return index === undefined ? undefined : this.#commits[index];\n }\n\n /** The most recent commit on the first of `branches` that has one. */\n firstTipOf(...branches: (string | Falsy)[]): Commit | undefined {\n for (const branch of branches) {\n const tip = this.tipOf(branch);\n if (tip) {\n return tip;\n }\n }\n return undefined;\n }\n\n addCommit(commit: Commit) {\n this.addBranch(commit.branch);\n const index = this.#commits.push(commit) - 1;\n // Duplicate ids survive until `doctor` drops them, and it keeps the first — so does this index.\n if (!this.#indexById.has(commit.id)) {\n this.#indexById.set(commit.id, index);\n }\n this.#tipIndexByBranch.set(commit.branch, index);\n }\n\n addTag(commitId: string, tag: string) {\n const index = this.#indexById.get(commitId);\n if (index === undefined) {\n return;\n }\n const commit = this.#commits[index]!;\n if (commit.tags?.includes(tag)) {\n return;\n }\n this.#commits[index] = { ...commit, tags: [...(commit.tags ?? []), tag] };\n }\n\n addBranch(branch: string) {\n this.#branches.add(branch);\n }\n\n /**\n * Removes duplicate commits and dangling parents.\n */\n doctor() {\n const seen = new Set<string>();\n this.#commits = pipe(\n this.#commits,\n Array.filter((commit) => {\n if (seen.has(commit.id)) {\n return false;\n }\n seen.add(commit.id);\n return true;\n }),\n Array.map(\n Struct.evolve({\n parents: (parents) => (parents ? Array.filter(parents, (id) => seen.has(id)) : undefined),\n }),\n ),\n );\n this.#reindex();\n }\n\n build() {\n this.doctor();\n return {\n commits: this.#commits,\n branches: [...this.#branches],\n };\n }\n\n #reindex() {\n this.#indexById.clear();\n this.#tipIndexByBranch.clear();\n this.#commits.forEach((commit, index) => {\n if (!this.#indexById.has(commit.id)) {\n this.#indexById.set(commit.id, index);\n }\n this.#tipIndexByBranch.set(commit.branch, index);\n });\n }\n}\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Trace from '@dxos/compute/Trace';\nimport { type ContentBlock } from '@dxos/types';\n\n/**\n * Approximate streamed token count from partial text (UTF-8 length / 4).\n */\nexport const estimateTokenCount = (text: string): number =>\n Math.max(1, Math.ceil(new TextEncoder().encode(text).length / 4));\n\nconst formatOperationInputStatus = (data: { key: string; name?: string; input: unknown }): string => {\n const name = data.name ?? data.key;\n const bytes = new TextEncoder().encode(JSON.stringify(data.input)).length;\n return `Calling ${name} (${bytes} bytes)...`;\n};\n\n/** Raw routine status updates (e.g. `Running 01KVB9WBRG…`) carry an opaque ULID, not a useful label. */\nconst ROUTINE_ULID_STATUS = /^Running [0-9A-HJKMNP-TV-Z]{26}$/i;\n\n/**\n * Formats a pending assistant block for the delegated-task status line.\n */\nexport const formatPendingBlockStatus = (block: ContentBlock.Any): string | undefined => {\n if (!block.pending) {\n return undefined;\n }\n\n if (block._tag === 'text') {\n return `Generating ${estimateTokenCount(block.text)} tokens....`;\n }\n\n if (block._tag === 'toolCall') {\n const bytes = new TextEncoder().encode(block.input).length;\n const name = block.displayName ?? block.operationName ?? block.name;\n return `Calling ${name} (${bytes} bytes)...`;\n }\n\n return undefined;\n};\n\n/**\n * Reads the latest pending partial block from an ephemeral trace message.\n */\nexport const pendingStatusFromEphemeralMessage = (message: Trace.Message): string | undefined => {\n for (const event of message.events) {\n if (Trace.isOfType(Trace.PartialBlock, event)) {\n const status = formatPendingBlockStatus(event.data.block);\n if (status) {\n return status;\n }\n continue;\n }\n\n if (Trace.isOfType(Trace.OperationInput, event)) {\n return formatOperationInputStatus(event.data);\n }\n\n if (Trace.isOfType(Trace.StatusUpdate, event)) {\n const message = event.data.message?.trim();\n // Suppress opaque routine ULID lines so descriptive partial-block / operation-input lines win.\n if (!message || ROUTINE_ULID_STATUS.test(message)) {\n continue;\n }\n return message;\n }\n }\n return undefined;\n};\n\nexport type EphemeralStatusUpdate = 'unchanged' | { readonly line: string };\n\n/**\n * Maps an ephemeral trace message to a task-status update.\n *\n * The status line is \"sticky\": a message without a pending line (e.g. a completed block during an\n * LLM-thinking gap) leaves the previous line in place rather than clearing it, so the row keeps\n * showing the latest meaningful activity until a new line arrives or the subscription ends.\n */\nexport const resolveEphemeralStatusUpdate = (message: Trace.Message): EphemeralStatusUpdate => {\n const line = pendingStatusFromEphemeralMessage(message);\n if (line) {\n return { line };\n }\n return 'unchanged';\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Duration from 'effect/Duration';\nimport { pipe } from 'effect/Function';\nimport * as Atom from 'effect/reactivity/Atom';\nimport { useMemo } from 'react';\n\nimport { FeedTraceSink } from '@dxos/compute-runtime';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Filter, Query } from '@dxos/echo';\nimport { type Space } from '@dxos/react-client/echo';\n\nconst atomEmpty = Atom.make(() => [] as const);\n\n/**\n * Atom of raw trace messages for a space — the input to `buildExecutionGraph`.\n */\nexport const getTraceMessagesAtom = (space: Space): Atom.Atom<readonly Trace.Message[]> =>\n pipe(\n space.db.query(FeedTraceSink.query).atom,\n Atom.map(\n (feeds) =>\n // Query across ALL trace feeds: writers race on feed creation (the edge's indexer-backed\n // lookup can miss a not-yet-indexed feed and create a duplicate), so a space may hold\n // several trace feeds — reading only one would silently drop the others' events.\n space.db.query(\n feeds.length > 0\n ? Query.type(Trace.Message).from([...feeds])\n : (Query.select(Filter.nothing()) as Query.Query<never>),\n ).atom,\n ),\n (atom) => Atom.make((get) => get(get(atom))),\n );\n\nexport type UseTraceMessagesOptions = {\n /** Caps the re-render rate; the feed emits per message, which is far faster than a reader can read. */\n debounce?: Duration.Duration;\n};\n\n/**\n * Subscribes to the space invocation trace feed.\n */\nexport const useTraceMessages = (\n space?: Space,\n { debounce }: UseTraceMessagesOptions = {},\n): readonly Trace.Message[] => {\n const atom = useMemo(() => {\n if (!space) {\n return atomEmpty;\n }\n const traces = getTraceMessagesAtom(space);\n return debounce ? traces.pipe(Atom.debounce(debounce)) : traces;\n }, [space, debounce]);\n return useAtomValue(atom);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Duration from 'effect/Duration';\nimport { pipe } from 'effect/Function';\nimport * as Atom from 'effect/reactivity/Atom';\nimport { useEffect, useMemo, useState } from 'react';\n\nimport * as Process from '@dxos/compute/Process';\nimport { type Space } from '@dxos/react-client/echo';\n\nimport { filterProcessesBySelection, filterTraceMessages } from '../components/TracePanel/trace-filter.ts';\nimport { type ExecutionGraph, buildExecutionGraph } from '../execution-graph/index.ts';\nimport { getTraceMessagesAtom } from './useTraceMessages.ts';\n\n// Stable refs.\nconst atomEmpty = Atom.make(() => [] as const);\nconst NO_PIDS: readonly string[] = [];\n\n// How often the graph re-checks for spans that timed out with no closing event.\n// Coarse-grained on purpose: `spanTimeoutMs` operates on a 20-minute scale, so there is no\n// benefit to re-deriving the graph more often than this just to catch the timeout crossing.\nconst SPAN_TIMEOUT_CHECK_INTERVAL_MS = 60_000;\n\n// The trace feed emits per message while anything runs, and the process monitor re-polls on its own\n// clock; every emission rebuilds the graph from the whole history, so the rebuild rate is capped\n// rather than either input's, as `useSessionTimeline` already does.\nconst REBUILD_DEBOUNCE = Duration.millis(500);\n\nexport type UseExecutionGraphOptions = {\n collapseCompletedSpans?: boolean;\n eventLimit?: number;\n /** Pids to narrow the graph to (with their descendants); empty shows everything. */\n selectedPids?: readonly string[];\n};\n\n/**\n * The commit graph of a space's trace, rebuilt as messages land and as the process tree changes.\n * `processesAtom` is the host's live process tree (a running agent draws a spinner commit); without\n * it the graph is the durable trace alone.\n */\nexport const useExecutionGraph = (\n space: Space,\n processesAtom: Atom.Atom<readonly Process.Process[]> | undefined,\n { collapseCompletedSpans, eventLimit, selectedPids = NO_PIDS }: UseExecutionGraphOptions = {},\n): ExecutionGraph => {\n // Ticks periodically so spans that are still open purely because no new trace event has\n // arrived (e.g. the runtime crashed before writing its `operationEnd`) eventually get\n // force-closed by `buildExecutionGraph`'s `spanTimeoutMs` check, instead of staying stuck\n // until unrelated trace activity happens to trigger a recompute.\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const id = setInterval(() => setNow(Date.now()), SPAN_TIMEOUT_CHECK_INTERVAL_MS);\n return () => clearInterval(id);\n }, []);\n\n const atom = useMemo(\n () =>\n getExecutionGraph(space, processesAtom ?? atomEmpty, { collapseCompletedSpans, eventLimit, selectedPids, now }),\n [space, processesAtom, collapseCompletedSpans, eventLimit, selectedPids, now],\n );\n\n return useAtomValue(atom);\n};\n\n/** Identity for the graph: only a process appearing, disappearing or changing state redraws it. */\nconst sameProcesses = (left: readonly Process.Process[], right: readonly Process.Process[]): boolean =>\n left.length === right.length &&\n left.every((process, index) => process.pid === right[index].pid && process.state === right[index].state);\n\nconst getExecutionGraph = (\n space: Space,\n processesAtom: Atom.Atom<readonly Process.Process[]>,\n {\n collapseCompletedSpans = true,\n eventLimit = 100,\n selectedPids = NO_PIDS,\n now,\n }: UseExecutionGraphOptions & { now: number },\n): Atom.Atom<ExecutionGraph> => {\n const traceMessages = getTraceMessagesAtom(space).pipe(\n Atom.debounce(REBUILD_DEBOUNCE),\n Atom.map((messages) => filterTraceMessages(messages, selectedPids)),\n );\n\n const activeProcesses = pipe(\n processesAtom,\n Atom.debounce(REBUILD_DEBOUNCE),\n Atom.map((processes) =>\n filterProcessesBySelection(processes, selectedPids).filter(\n (process) => process.state === Process.State.RUNNING || process.state === Process.State.HYBERNATING,\n ),\n ),\n // The monitor rebuilds the process list on every poll, so without a structural comparison the\n // graph would be rebuilt on each tick even when nothing moved.\n Atom.withEquality(sameProcesses),\n );\n\n return Atom.make((get) =>\n buildExecutionGraph({\n traceMessages: get(traceMessages),\n activeProcesses: get(activeProcesses),\n collapseCompletedSpans,\n eventLimit,\n now,\n }),\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { Task } from '@dxos/types';\nimport { Unit } from '@dxos/util';\n\nimport {\n type GanttData,\n type GanttGroup,\n type GanttLane,\n type GanttMarker,\n type GanttMeta,\n type GanttSegment,\n} from '../components/Gantt/index.ts';\nimport { type Lane, type SessionTimeline, type TokenUsage } from './types.ts';\n\n/**\n * The one place the domain's nouns meet the chart's.\n *\n * The chart knows only groups, lanes, segments and markers; this file knows that a **process** is a\n * group — the band around the lanes of the tasks it works, with no row of its own — a **task** is a\n * lane inside it, a **subtask** nests under its parent task, and a **delegation** opens a lane out of\n * the node that spawned it. Keeping the translation here is what lets either vocabulary change without\n * dragging the other with it.\n */\nconst formatTokens = (tokens: TokenUsage): string =>\n tokens.total >= 1_000 ? Unit.Thousand(tokens.total).toString() : String(tokens.total);\n\n/** Tokens and tool calls, formatted here because the chart renders `meta` without reading it. */\nconst laneMeta = (lane: Lane): GanttMeta[] => [\n ...(lane.tokens\n ? [{ label: formatTokens(lane.tokens), title: `${lane.tokens.input} in / ${lane.tokens.output} out` }]\n : []),\n ...(lane.toolCalls !== undefined ? [{ label: `${lane.toolCalls} tools` }] : []),\n];\n\n/**\n * A lane's stretch as segments: one run, split around each gap where its task was put down, so a\n * question and its answer are separate runs with the wait between them left open.\n */\nconst segmentsOf = (lane: Lane): GanttLane['segments'] => {\n if (lane.start === undefined) {\n return undefined;\n }\n const segments: GanttSegment[] = [];\n let start = lane.start;\n for (const gap of [...(lane.gaps ?? [])].sort((left, right) => left.start - right.start)) {\n // Clipped to the lane: a folded session lane keeps its own span while taking its task's gaps.\n const gapStart = Math.max(gap.start, start);\n const gapEnd = lane.end === undefined ? gap.end : Math.min(gap.end, lane.end);\n if (gapEnd <= gapStart) {\n continue;\n }\n if (gapStart > start) {\n segments.push({ start, end: gapStart });\n }\n start = gapEnd;\n }\n if (lane.end === undefined) {\n segments.push({ start });\n } else if (lane.end > start) {\n segments.push({ start, end: lane.end });\n }\n return segments;\n};\n\nconst isHistoryEntry = Schema.is(Task.HistoryEntry);\n\n/**\n * Maps a session timeline onto the chart's model.\n *\n * Every process becomes a band holding the lanes of the tasks it works; the process itself draws no\n * row, so its own nodes (requests, tool calls no task claims) are dropped. A process standing for one\n * task — a delegated sub-agent, or a session the builder folded its lone task into — is that task's\n * lane, so it keeps its span, its nodes and the node it opened out of. A process spawned by another\n * nests its band under its parent's — so causality is drawn by `openedFrom` while membership is\n * `groupId` and nesting is `parentId`, three facts the timeline's single `parentId` used to carry.\n */\nexport const sessionTimelineToGantt = (timeline: SessionTimeline): Pick<GanttData, 'groups' | 'lanes' | 'markers'> => {\n const byId = new Map(timeline.lanes.map((lane) => [lane.id, lane]));\n const groups: GanttGroup[] = [];\n const lanes: GanttLane[] = [];\n\n /** The band a lane belongs to: its own, for a process; its process's, for a task. */\n const bandOf = (lane: Lane): string | undefined => {\n if (lane.kind === 'session') {\n return lane.id;\n }\n const parent = lane.parentId === undefined ? undefined : byId.get(lane.parentId);\n return parent ? bandOf(parent) : undefined;\n };\n\n for (const lane of timeline.lanes) {\n const meta = laneMeta(lane);\n const facts = {\n label: lane.label,\n status: lane.status,\n ...(segmentsOf(lane) ? { segments: segmentsOf(lane) } : {}),\n ...(lane.delegatedFrom ? { openedFrom: lane.delegatedFrom } : {}),\n ...(lane.returnedTo ? { closedInto: lane.returnedTo } : {}),\n ...(lane.hue ? { hue: lane.hue } : {}),\n ...(lane.blockedOn ? { blockedOn: lane.blockedOn } : {}),\n ...(meta.length > 0 ? { meta } : {}),\n };\n const parent = lane.parentId === undefined ? undefined : byId.get(lane.parentId);\n\n if (lane.kind === 'session') {\n groups.push({\n id: lane.id,\n // A process spawned by another sits inside its parent's band; a task's parent resolves to the\n // process working it, which is the band this one nests under.\n ...(parent ? { parentId: bandOf(parent) } : {}),\n });\n if (lane.taskId === undefined) {\n continue;\n }\n }\n\n lanes.push({\n id: lane.id,\n groupId: bandOf(lane),\n // A task nests under its parent task; one hanging off its process sits at the top of the band.\n ...(lane.kind === 'task' && parent?.kind === 'task' ? { parentId: parent.id } : {}),\n ...facts,\n });\n }\n\n const drawn = new Set(lanes.map((lane) => lane.id));\n // A question waits for its answer: each answer node names the question it closes, by the question's\n // id in the task's history, so the pair is joined on the same lane.\n const answerByQuestion = new Map<string, string>();\n for (const marker of timeline.markers) {\n if (isHistoryEntry(marker.detail) && Task.isAnswerEntry(marker.detail)) {\n answerByQuestion.set(`${marker.laneId}:${marker.detail.questionId}`, marker.id);\n }\n }\n const markers: GanttMarker[] = timeline.markers\n .flatMap((marker) => (drawn.has(marker.laneId) ? [marker] : []))\n .map((marker) => {\n const question = isHistoryEntry(marker.detail) && Task.isQuestionEntry(marker.detail) ? marker.detail : undefined;\n const until = question && answerByQuestion.get(`${marker.laneId}:${question.id}`);\n return {\n id: marker.id,\n laneId: marker.laneId,\n kind: marker.kind,\n timestamp: marker.timestamp,\n label: marker.label,\n ...(marker.level ? { level: marker.level } : {}),\n ...(until ? { wait: { until } } : {}),\n ...(question && !until ? { pending: true } : {}),\n };\n });\n\n return { groups, lanes, markers };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Option from 'effect/Option';\nimport * as Schema from 'effect/Schema';\n\nimport * as Process from '@dxos/compute/Process';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Annotation, Obj } from '@dxos/echo';\nimport { EID } from '@dxos/keys';\nimport { Task } from '@dxos/types';\nimport { getHashHue } from '@dxos/ui-theme';\n\nimport { type Span, buildSpanTree, flattenSpanTree } from '../execution-graph/index.ts';\nimport {\n type DelegationSource,\n type Lane,\n type LaneStatus,\n type Marker,\n type Session,\n type SessionTimeline,\n type TokenUsage,\n} from './types.ts';\n\nexport interface BuildSessionTimelineInput {\n traceMessages: readonly Trace.Message[];\n processes?: readonly Process.Process[];\n /** The sessions to draw; each contributes a lane and its checklist's task lanes. */\n sessions?: readonly Session[];\n tasks?: readonly Task.Task[];\n /** Per task id, the status moves its edit history records, oldest first (see {@link readTaskStatusChanges}). */\n taskStatusChanges?: ReadonlyMap<string, readonly TaskStatusChange[]>;\n /** Reference time; extends the range past open lanes. */\n now?: number;\n}\n\n/** One move of a task's status, as its edit history records it. */\nexport type TaskStatusChange = {\n /** Epoch ms. */\n timestamp: number;\n status: Task.Status;\n /** Absent when the task held no status before. */\n previousStatus?: Task.Status;\n};\n\nconst isStatus = Schema.is(Task.Status);\n\n/**\n * The status moves in a task's edit history, oldest first; none for a task not stored in a database,\n * which keeps no history.\n */\nexport const readTaskStatusChanges = (task: Task.Task): TaskStatusChange[] =>\n Obj.getDatabase(task) === undefined\n ? []\n : Obj.getChanges(task, { property: 'status' }).flatMap(({ time, before, after }) =>\n isStatus(after)\n ? [{ timestamp: time, status: after, ...(isStatus(before) ? { previousStatus: before } : {}) }]\n : [],\n );\n\n/** Statuses of a task not yet picked up. */\nconst PENDING_STATUSES = new Set<Task.Status>(['todo', 'backlog']);\n\n/**\n * The edit history's status moves, each timed by the trace event recording the same move when there is\n * one. History times are whole seconds, rounded down, so on their own they start a lane up to a second\n * before the node that marks its start; everything derived from them — spans, nodes — reads these.\n */\nconst refineStatusChanges = (\n changes: ReadonlyMap<string, readonly TaskStatusChange[]>,\n events: readonly Trace.FlatEvent[],\n): ReadonlyMap<string, readonly TaskStatusChange[]> => {\n const traced = new Map<string, { timestamp: number; status: string }[]>();\n for (const event of events) {\n if (event.type === Trace.TaskStatusChanged.key) {\n const data = decode(Trace.TaskStatusChanged.schema, event.data);\n if (data) {\n traced.set(data.taskId, [\n ...(traced.get(data.taskId) ?? []),\n { timestamp: event.timestamp, status: data.status },\n ]);\n }\n }\n }\n return new Map(\n [...changes].map(([taskId, list]) => {\n const candidates = [...(traced.get(taskId) ?? [])];\n return [\n taskId,\n list.map((change) => {\n const index = candidates.findIndex(\n ({ timestamp, status }) =>\n status === change.status && Math.abs(timestamp - change.timestamp) <= HISTORY_MATCH_MS,\n );\n if (index < 0) {\n return change;\n }\n const [match] = candidates.splice(index, 1);\n return { ...change, timestamp: match.timestamp };\n }),\n ];\n }),\n );\n};\n\n/** Statuses that end a stretch of work on a task. */\nconst CLOSED_STATUSES = new Set<Task.Status>(['done', 'review', 'failed', 'cancelled']);\n\nconst isStatusChange = (detail: unknown): detail is TaskStatusChange =>\n typeof detail === 'object' && detail !== null && 'status' in detail && isStatus(detail.status);\n\nconst ACTIVE_STATES = new Set<Process.State>([Process.State.RUNNING, Process.State.HYBERNATING]);\n\n/** How long an open lane may be silent before the axis stops following `now`. */\nconst OPEN_LANE_STALE_MS = 10 * 60_000;\n\n/** How far apart a task's recorded status move and the trace event recording the same move may land. */\nconst HISTORY_MATCH_MS = 5_000;\n\nconst TASK_STATUS: Partial<Record<Task.Status, LaneStatus>> = {\n todo: 'pending',\n backlog: 'pending',\n blocked: 'blocked',\n started: 'running',\n review: 'review',\n done: 'done',\n failed: 'failed',\n};\n\n/** Entity id of an ECHO URI, the join key between a process target, a trace meta and a chat. */\nconst entityKey = (uri: string): string => {\n const eid = EID.tryParse(uri);\n return (eid && EID.getEntityId(eid)) ?? uri;\n};\n\nconst eventFeedKey = (event: Trace.FlatEvent): string | undefined =>\n event.meta.conversation ? entityKey(event.meta.conversation.uri) : undefined;\n\nconst decode = <S extends Schema.ConstraintDecoder<unknown>>(schema: S, data: unknown): S['Type'] | undefined =>\n Option.getOrUndefined(Schema.decodeUnknownOption(schema)(data));\n\ntype MutableLane = { -readonly [K in keyof Lane]: Lane[K] };\n\nconst sessionLaneId = (key: string): string => `session:${key}`;\nconst taskLaneId = (taskId: string): string => `task:${taskId}`;\n\ninterface SessionSource {\n key: string;\n label: string;\n session?: Session;\n pids: Set<string>;\n}\n\n/**\n * The stretch of a session during which one task was the active one, bounded by the status events\n * the planning tool writes. Everything the session did inside it belongs to that task.\n */\ninterface TaskSegment {\n taskId: string;\n laneId: string;\n start: number;\n end?: number;\n}\n\n/**\n * Cuts a session's events into segments of task work, from the status events its task tools write.\n * Only tasks in `taskIds` — the session's own checklist — take part: an agent is free to move a task\n * belonging to nothing on this chart, and such an event must not open or close anything here.\n *\n * An agent may hold several tasks in progress at once, and may put one down and pick it up again as\n * it discovers what depends on what: a `started` event opens a segment for its task and leaves every\n * other open segment alone, and any other status closes that task's open segment. A task can also\n * finish without a start: delegation marks every task it hands over `started` before the agent's\n * first turn, so the run's only event for that task is the one closing it. Such a task gets the\n * stretch since the last boundary, which is where its work happened — but only on the transition out\n * of `started` and only while no other task holds the stretch: a task merely dismissed\n * (`todo` → `blocked`) claims nothing, a second close (`review` → `done`) mints nothing, and a close\n * arriving while other work is open leaves that work alone rather than overlapping it.\n */\nconst buildTaskSegments = (\n events: readonly Trace.FlatEvent[],\n sessionStart: number | undefined,\n taskIds: ReadonlySet<string>,\n): TaskSegment[] => {\n const segments: TaskSegment[] = [];\n const open = new Map<string, TaskSegment>();\n let boundary = sessionStart;\n\n for (const event of events) {\n if (event.type !== Trace.TaskStatusChanged.key) {\n continue;\n }\n const data = decode(Trace.TaskStatusChanged.schema, event.data);\n if (!data || !taskIds.has(data.taskId)) {\n continue;\n }\n const current = open.get(data.taskId);\n if (data.status === 'started') {\n if (!current) {\n const segment = { taskId: data.taskId, laneId: taskLaneId(data.taskId), start: event.timestamp };\n segments.push(segment);\n open.set(data.taskId, segment);\n }\n boundary = event.timestamp;\n } else if (current) {\n current.end = event.timestamp;\n open.delete(data.taskId);\n boundary = event.timestamp;\n } else if (data.previousStatus === 'started' && open.size === 0) {\n segments.push({\n taskId: data.taskId,\n laneId: taskLaneId(data.taskId),\n start: Math.min(boundary ?? event.timestamp, event.timestamp),\n end: event.timestamp,\n });\n boundary = event.timestamp;\n }\n }\n return segments;\n};\n\n/**\n * The segment an event belongs to. A status event goes to its own task's segment. Any other event\n * goes to the one segment in progress when it happened; where segments merely meet, the one ending\n * there yields to the one beginning — the newcomer's start is the first thing the agent did on it.\n * With several tasks genuinely in progress at once the event belongs to none of them in particular,\n * so it stays with the session rather than being credited to whichever started last.\n */\nconst segmentFor = (segments: readonly TaskSegment[] | undefined, event: Trace.FlatEvent): TaskSegment | undefined => {\n if (!segments) {\n return undefined;\n }\n const contains = (segment: TaskSegment) =>\n event.timestamp >= segment.start && event.timestamp <= (segment.end ?? Number.MAX_SAFE_INTEGER);\n if (event.type === Trace.TaskStatusChanged.key) {\n const data = decode(Trace.TaskStatusChanged.schema, event.data);\n return data && segments.findLast((segment) => segment.taskId === data.taskId && contains(segment));\n }\n const candidates = segments.filter(contains);\n const inside = candidates.filter((segment) => segment.end === undefined || event.timestamp < segment.end);\n if (inside.length > 1) {\n return undefined;\n }\n return inside[0] ?? candidates.at(-1);\n};\n\n/**\n * The stretch a task's edit history says it was worked: from its first move to `started` to the last\n * move out of it. `end` is absent while the history leaves it `started`; `last` is its last move.\n * Absent when the task was never started.\n */\nconst historySpan = (\n changes: readonly TaskStatusChange[],\n): { start: number; end?: number; last: number } | undefined => {\n let start: number | undefined;\n let end: number | undefined;\n let open = false;\n for (const change of changes) {\n if (change.status === 'started') {\n start ??= change.timestamp;\n open = true;\n } else if (open) {\n end = change.timestamp;\n open = false;\n }\n }\n const last = changes.at(-1)?.timestamp;\n return start === undefined || last === undefined ? undefined : { start, end: open ? undefined : end, last };\n};\n\n/**\n * The stretches a task was put down between two runs of work: from a move out of `started` that did\n * not finish it (a question blocking it, say) to the next move back. One still open is no gap — the\n * lane simply ends there — and nothing before the first start is one either.\n */\nconst workGaps = (changes: readonly TaskStatusChange[]): { start: number; end: number }[] => {\n const gaps: { start: number; end: number }[] = [];\n let started = false;\n let pausedAt: number | undefined;\n for (const change of changes) {\n if (change.status === 'started') {\n if (pausedAt !== undefined && change.timestamp > pausedAt) {\n gaps.push({ start: pausedAt, end: change.timestamp });\n }\n started = true;\n pausedAt = undefined;\n } else if (started && pausedAt === undefined && !CLOSED_STATUSES.has(change.status)) {\n pausedAt = change.timestamp;\n }\n }\n return gaps;\n};\n\n/** A question or answer in the task's log; other entries are edits the edit history already holds. */\nconst exchangeMarker = (entry: Task.HistoryEntry, id: string, laneId: string): Marker | undefined => {\n const timestamp = Date.parse(entry.date);\n if (Number.isNaN(timestamp)) {\n return undefined;\n }\n const base = { id, laneId, kind: 'task' as const, timestamp, detail: entry };\n switch (entry.event) {\n case 'question':\n return { ...base, label: entry.text, level: 'warn' };\n case 'answer':\n return { ...base, label: `Answered: ${entry.answer}` };\n default:\n return undefined;\n }\n};\n\ninterface SubAgentSpan {\n span: Span;\n pid: string;\n startEvent: Trace.FlatEvent;\n}\n\n/**\n * Builds the gantt-shaped view of one or more assistant sessions from their trace: session lanes\n * (supervisors and the sub-agents they delegate to), task lanes, and the markers on each.\n */\nexport const buildSessionTimeline = ({\n traceMessages,\n processes = [],\n sessions,\n tasks = [],\n taskStatusChanges: recordedChanges,\n now,\n}: BuildSessionTimelineInput): SessionTimeline => {\n const root = buildSpanTree(traceMessages);\n const spans = flattenSpanTree(root);\n const events = spans.flatMap((span) => span.events).sort((a, b) => a.timestamp - b.timestamp);\n const taskStatusChanges = recordedChanges && refineStatusChanges(recordedChanges, events);\n const requestBegins = events.filter(\n (event): event is Trace.FlatEvent & { meta: { pid: string } } =>\n event.type === Trace.AgentRequestBegin.key && event.meta.pid !== undefined,\n );\n\n // The agent process targets the chat; its trace meta carries the chat's feed.\n const agentPidsByChat = new Map<string, string[]>();\n for (const process of processes) {\n if (!Process.isHarnessHost(process)) {\n continue;\n }\n const target = Option.getOrUndefined(\n Annotation.getDictionary(process.params.annotations, Process.TargetAnnotation),\n );\n if (target !== undefined) {\n const key = entityKey(target.toString());\n agentPidsByChat.set(key, [...(agentPidsByChat.get(key) ?? []), process.pid]);\n }\n }\n\n const sources: SessionSource[] = [];\n if (sessions) {\n for (const session of sessions) {\n if (session.taskIds.length === 0) {\n continue;\n }\n const feed = session.feedId;\n const pids = new Set<string>(agentPidsByChat.get(entityKey(session.uri)) ?? []);\n for (const event of requestBegins) {\n if (feed !== undefined && eventFeedKey(event) === feed) {\n pids.add(event.meta.pid);\n }\n }\n // A feed or object id is not a name: an unnamed chat reads as the session it is until the\n // naming turn lands.\n sources.push({ key: session.id, label: session.label?.trim() || 'Session', session, pids });\n }\n } else {\n // Without chats, the conversation feed groups a session's pids; a trace with no conversation\n // meta falls back to one session per agent pid.\n const byKey = new Map<string, SessionSource>();\n for (const event of requestBegins) {\n const pid = event.meta.pid;\n const key = eventFeedKey(event) ?? pid;\n const source = byKey.get(key) ?? {\n key,\n label: eventFeedKey(event) ?? event.meta.processName ?? pid,\n pids: new Set<string>(),\n };\n source.pids.add(pid);\n byKey.set(key, source);\n }\n sources.push(...byKey.values());\n }\n\n const processByPid = new Map<string, Process.Process>(processes.map((process) => [process.pid, process]));\n const taskById = new Map(tasks.map((task) => [task.id, task]));\n const laneByPid = new Map<string, string>();\n const lanes: MutableLane[] = [];\n const markers: Marker[] = [];\n const childSessions: { lane: MutableLane; sessionLaneId: string }[] = [];\n const replacedTaskLanes = new Map<string, string>();\n /** Per session lane: the task segments its markers are attributed to. */\n const segmentsBySession = new Map<string, TaskSegment[]>();\n\n for (const source of sources) {\n const laneId = sessionLaneId(source.key);\n const sessionEvents = events.filter((event) => event.meta.pid && source.pids.has(event.meta.pid));\n const begins = sessionEvents.filter((event) => event.type === Trace.AgentRequestBegin.key);\n const ends = sessionEvents.filter((event) => event.type === Trace.AgentRequestEnd.key);\n const requestOpen = begins.length > ends.length;\n const processActive = [...source.pids].some((pid) => {\n const process = processByPid.get(pid);\n return process !== undefined && ACTIVE_STATES.has(process.state);\n });\n const lastEnd = ends.at(-1);\n const lastEndStatus = lastEnd ? decode(Trace.AgentRequestEnd.schema, lastEnd.data)?.status : undefined;\n // An unmatched request begin is a run in flight only while its process is; with the process\n // recorded as ended, the run died before writing its end, so the lane closes at its last event\n // rather than staying open (and stretching the chart) indefinitely.\n const processKnown = [...source.pids].some((pid) => processByPid.has(pid));\n const died = requestOpen && processKnown && !processActive;\n const open = requestOpen && !died;\n const status: LaneStatus =\n processActive || open ? 'running' : died || lastEndStatus === 'error' ? 'failed' : 'done';\n\n lanes.push({\n id: laneId,\n kind: 'session',\n label: source.label,\n status,\n start: begins[0]?.timestamp,\n end: open ? undefined : died ? sessionEvents.at(-1)?.timestamp : lastEnd?.timestamp,\n sessionId: source.session?.id,\n pid: [...source.pids].at(-1),\n });\n for (const pid of source.pids) {\n laneByPid.set(pid, laneId);\n }\n\n // The spawn event is the only durable pid ↔ task pairing; a sub-agent's own trace carries\n // neither the task nor the conversation.\n const taskByPid = new Map<string, string>();\n for (const event of sessionEvents) {\n if (event.type === Trace.DelegationSpawned.key) {\n const data = decode(Trace.DelegationSpawned.schema, event.data);\n if (data) {\n taskByPid.set(data.pid, data.taskId);\n }\n }\n }\n\n // A child span is a sub-agent (not a tool call) when it was spawned as one or emits its own\n // content blocks.\n const subAgentSpans: SubAgentSpan[] = spans.flatMap((span) => {\n const startEvent = span.events[0];\n const pid = span.meta.pid;\n if (\n pid === undefined ||\n span.meta.parentPid === undefined ||\n !source.pids.has(span.meta.parentPid) ||\n startEvent?.type !== Trace.OperationStart.key\n ) {\n return [];\n }\n const isAgent = taskByPid.has(pid) || span.events.some((event) => event.type === Trace.CompleteBlock.key);\n return isAgent ? [{ span, pid, startEvent }] : [];\n });\n\n const chatTasks = (source.session?.taskIds ?? [])\n .map((id) => taskById.get(id))\n .filter((task): task is Task.Task => task !== undefined);\n // Only a dependency on the checklist gets a lane, so `blockedOn` never names a lane that is\n // not drawn.\n const chatTaskIds = new Set(chatTasks.map((task) => task.id));\n const taskLanes = new Map<string, MutableLane>();\n for (const task of chatTasks) {\n // A sub-task of a task on the same checklist nests under it, so the chart keeps the hierarchy\n // the ledger shows; any other task hangs off the session.\n const parentTask = Task.getParentTask(task);\n const taskLane: MutableLane = {\n id: taskLaneId(task.id),\n kind: 'task',\n label: task.title,\n status: taskLaneStatus(task, tasks),\n parentId: parentTask && chatTaskIds.has(parentTask.id) ? taskLaneId(parentTask.id) : laneId,\n sessionId: source.session?.id,\n taskId: task.id,\n };\n const blockedOn = (task.dependsOn ?? [])\n .map((ref) => Task.refEntityId(ref))\n .filter((id): id is string => id !== undefined && chatTaskIds.has(id))\n .map(taskLaneId);\n if (blockedOn.length > 0) {\n taskLane.blockedOn = blockedOn;\n }\n taskLanes.set(task.id, taskLane);\n lanes.push(taskLane);\n }\n\n // Spawned pids without a trace yet still get a lane from their process.\n const subAgentPids = new Set<string>([...subAgentSpans.map(({ pid }) => pid), ...taskByPid.keys()]);\n\n // The status events bound each task's stretch of the session, giving its lane a span of its own\n // and a node where it started and finished. A status tool runs as a child process of the agent,\n // so its events carry their own pid and reach the session through `parentPid`; a spawned\n // sub-agent's do too, and those belong to its own lane rather than cutting this one.\n const ownEvents = events.filter(\n (event) =>\n (event.meta.pid !== undefined && source.pids.has(event.meta.pid)) ||\n (event.meta.parentPid !== undefined &&\n source.pids.has(event.meta.parentPid) &&\n !(event.meta.pid !== undefined && subAgentPids.has(event.meta.pid))),\n );\n const segments = buildTaskSegments(ownEvents, begins[0]?.timestamp, chatTaskIds);\n segmentsBySession.set(laneId, segments);\n for (const segment of segments) {\n const taskLane = taskLanes.get(segment.taskId);\n if (!taskLane) {\n continue;\n }\n taskLane.start = Math.min(taskLane.start ?? segment.start, segment.start);\n // An open segment leaves the lane open, even if an earlier one closed.\n taskLane.end = segment.end === undefined ? undefined : Math.max(taskLane.end ?? segment.end, segment.end);\n }\n\n // The task's edit history bounds its lane too, so a task worked where the trace does not reach\n // (another device, a pruned feed, a person's edit) still gets a span. The lane stays open only while\n // the task itself is `started`, whatever the history last says.\n for (const task of chatTasks) {\n const taskLane = taskLanes.get(task.id);\n const span = historySpan(taskStatusChanges?.get(task.id) ?? []);\n if (!taskLane || !span) {\n continue;\n }\n const tracedEnd = taskLane.start === undefined ? undefined : taskLane.end;\n taskLane.start = Math.min(taskLane.start ?? span.start, span.start);\n if (span.end === undefined && task.status === 'started') {\n taskLane.end = undefined;\n } else {\n const end = span.end ?? tracedEnd ?? span.last;\n taskLane.end = tracedEnd === undefined ? end : Math.max(tracedEnd, end);\n }\n }\n\n for (const subPid of subAgentPids) {\n const match = subAgentSpans.find((candidate) => candidate.pid === subPid);\n const process = processByPid.get(subPid);\n if (!match && !process) {\n continue;\n }\n const taskId = taskByPid.get(subPid);\n const task = taskId === undefined ? undefined : taskById.get(taskId);\n const startName = match ? decode(Trace.OperationStart.schema, match.startEvent.data)?.name : undefined;\n const endEvent = match?.span.events.find((event) => event.type === Trace.OperationEnd.key);\n const start = match?.startEvent.timestamp ?? process?.startedAt;\n const end = endEvent?.timestamp ?? (process ? Option.getOrUndefined(process.completedAt) : undefined);\n const subLane: MutableLane = {\n id: sessionLaneId(subPid),\n kind: 'session',\n label: task?.title ?? startName ?? process?.params.name ?? subPid,\n status: subSessionStatus(endEvent, process),\n start,\n end,\n parentId: laneId,\n sessionId: source.session?.id,\n taskId,\n pid: subPid,\n };\n laneByPid.set(subPid, subLane.id);\n childSessions.push({ lane: subLane, sessionLaneId: laneId });\n // A delegated task IS its child session: the session lane takes the task lane's place and\n // its dependencies, so a task is either worked in-session (a task lane) or spawned (a session).\n const taskLane = taskId === undefined ? undefined : taskLanes.get(taskId);\n if (taskLane) {\n subLane.blockedOn = taskLane.blockedOn;\n lanes.splice(lanes.indexOf(taskLane), 1, subLane);\n replacedTaskLanes.set(taskLane.id, subLane.id);\n } else {\n lanes.push(subLane);\n }\n }\n }\n\n // A task no drawn session works (an external harness's, a person's) is drawn from its edit history\n // alone, as a lane of its own, so the chart still shows it; one never started has no span to draw.\n const lanedTaskIds = new Set(lanes.flatMap((lane) => (lane.taskId === undefined ? [] : [lane.taskId])));\n const unownedLanes = new Map<string, MutableLane>();\n for (const task of tasks) {\n const span = lanedTaskIds.has(task.id) ? undefined : historySpan(taskStatusChanges?.get(task.id) ?? []);\n if (!span) {\n continue;\n }\n unownedLanes.set(task.id, {\n id: taskLaneId(task.id),\n kind: 'task',\n label: task.title,\n status: taskLaneStatus(task, tasks),\n start: span.start,\n end: span.end === undefined && task.status === 'started' ? undefined : (span.end ?? span.last),\n taskId: task.id,\n });\n }\n for (const [taskId, lane] of unownedLanes) {\n const blockedOn = (taskById.get(taskId)?.dependsOn ?? [])\n .map((ref) => Task.refEntityId(ref))\n .filter((id): id is string => id !== undefined && unownedLanes.has(id))\n .map(taskLaneId);\n if (blockedOn.length > 0) {\n lane.blockedOn = blockedOn;\n }\n lanes.push(lane);\n }\n\n // A delegated task IS its child session, drawn with the child's own span; the parent's markers in\n // that stretch are the parent's work of handing it over, so the segment goes rather than moving.\n for (const [sessionId, segments] of segmentsBySession) {\n segmentsBySession.set(\n sessionId,\n segments.filter((segment) => !replacedTaskLanes.has(segment.laneId)),\n );\n }\n\n // Each status move in a task's edit history is a node on its lane, and so is each question and answer\n // in its log. A move the trace also recorded is drawn once, from the history, taking the trace event's\n // pid. Only a trace event on a drawn lane is matched, so none is hidden that had a node.\n const tracedChanges = new Map<string, Trace.FlatEvent[]>();\n for (const event of events) {\n const drawn =\n (event.meta.pid !== undefined && laneByPid.has(event.meta.pid)) ||\n (event.meta.parentPid !== undefined && laneByPid.has(event.meta.parentPid));\n if (drawn && event.type === Trace.TaskStatusChanged.key) {\n const data = decode(Trace.TaskStatusChanged.schema, event.data);\n if (data) {\n tracedChanges.set(data.taskId, [...(tracedChanges.get(data.taskId) ?? []), event]);\n }\n }\n }\n const mergedEvents = new Set<Trace.FlatEvent>();\n // A delegated task's lane is its child session, which carries the task id, so it gets the nodes too.\n for (const lane of lanes) {\n const task = lane.taskId === undefined ? undefined : taskById.get(lane.taskId);\n if (!task) {\n continue;\n }\n const traced = tracedChanges.get(task.id) ?? [];\n const changes = taskStatusChanges?.get(task.id) ?? [];\n // Waiting to be picked up is the lane's absence, not an event on it: a node for it would sit\n // alone before the bar, reading as work that happened and then a pause.\n const firstStart = changes.findIndex((change) => change.status === 'started');\n for (const [index, change] of changes.entries()) {\n if (PENDING_STATUSES.has(change.status) && (firstStart < 0 || index < firstStart)) {\n continue;\n }\n const match = traced.find(\n (event) =>\n !mergedEvents.has(event) &&\n decode(Trace.TaskStatusChanged.schema, event.data)?.status === change.status &&\n Math.abs(event.timestamp - change.timestamp) <= HISTORY_MATCH_MS,\n );\n if (match) {\n mergedEvents.add(match);\n }\n markers.push({\n id: `${lane.id}:${markers.length}`,\n laneId: lane.id,\n kind: 'task',\n // The trace's instant when it recorded the same move: edit-history times are whole seconds, so\n // on their own they land before the work they mark.\n timestamp: match?.timestamp ?? change.timestamp,\n label: `Task ${change.status}`,\n level: change.status === 'failed' ? 'error' : undefined,\n pid: match?.meta.pid,\n detail: change,\n });\n }\n for (const entry of task.history ?? []) {\n const marker = exchangeMarker(entry, `${lane.id}:${markers.length}`, lane.id);\n if (marker) {\n markers.push(marker);\n }\n }\n }\n\n // Dependencies named the task lane; they follow it to the session that replaced it.\n for (const lane of lanes) {\n if (lane.blockedOn) {\n lane.blockedOn = lane.blockedOn.map((id) => replacedTaskLanes.get(id) ?? id);\n }\n }\n\n // Markers and token totals, attributed to the lane owning the event's pid or its parent pid.\n const tokens = new Map<string, { usage: TokenUsage; toolCalls: number }>();\n // The marker's own lane travels with its id: `markerLaneId` routes an event to whichever task\n // segment was open at the time, so a delegation node does not always land on the session's lane —\n // and a connector drawn to a row that does not hold the node points at nothing.\n const spawnMarkerByPid = new Map<string, DelegationSource>();\n const returnMarkerByPid = new Map<string, DelegationSource>();\n for (const event of events) {\n const laneId =\n (event.meta.pid && laneByPid.get(event.meta.pid)) ??\n (event.meta.parentPid && laneByPid.get(event.meta.parentPid)) ??\n undefined;\n if (laneId === undefined) {\n continue;\n }\n // Everything the session did while a task was active is that task's, so the session bar keeps\n // only what brackets the whole run (its request markers) and the timeline reads per task.\n const markerLaneId =\n event.type === Trace.AgentRequestBegin.key || event.type === Trace.AgentRequestEnd.key\n ? laneId\n : (segmentFor(segmentsBySession.get(laneId), event)?.laneId ?? laneId);\n const marker = mergedEvents.has(event)\n ? undefined\n : toMarker(event, `${markerLaneId}:${markers.length}`, markerLaneId);\n if (marker) {\n markers.push(marker);\n if (event.type === Trace.DelegationSpawned.key) {\n const data = decode(Trace.DelegationSpawned.schema, event.data);\n if (data) {\n spawnMarkerByPid.set(data.pid, { laneId: marker.laneId, markerId: marker.id });\n }\n }\n if (event.type === Trace.DelegationCompleted.key) {\n const data = decode(Trace.DelegationCompleted.schema, event.data);\n if (data) {\n returnMarkerByPid.set(data.pid, { laneId: marker.laneId, markerId: marker.id });\n }\n }\n }\n if (event.type === Trace.CompleteBlock.key) {\n const data = decode(Trace.CompleteBlock.schema, event.data);\n if (data?.block._tag === 'stats') {\n const entry = tokens.get(laneId) ?? { usage: { input: 0, output: 0, total: 0 }, toolCalls: 0 };\n // A provider that reports no total still reports the parts.\n const input = data.block.usage?.inputTokens ?? 0;\n const output = data.block.usage?.outputTokens ?? 0;\n const total = data.block.usage?.totalTokens ?? input + output;\n entry.usage = {\n input: entry.usage.input + input,\n output: entry.usage.output + output,\n total: entry.usage.total + total,\n };\n entry.toolCalls += data.block.toolCalls ?? 0;\n tokens.set(laneId, entry);\n }\n }\n }\n for (const lane of lanes) {\n const entry = tokens.get(lane.id);\n if (entry) {\n lane.tokens = entry.usage;\n lane.toolCalls = entry.toolCalls;\n }\n }\n\n // The connector starts at the spawn marker, else at the supervisor's last node before the child began.\n for (const { lane, sessionLaneId } of childSessions) {\n const fallbackId = markers\n .filter((marker) => marker.laneId === sessionLaneId && marker.timestamp <= (lane.start ?? 0))\n .at(-1)?.id;\n const spawn =\n (lane.pid === undefined ? undefined : spawnMarkerByPid.get(lane.pid)) ??\n (fallbackId === undefined ? undefined : { laneId: sessionLaneId, markerId: fallbackId });\n if (spawn) {\n lane.delegatedFrom = spawn;\n }\n // The return connector has no such fallback: only the completion event says the child reported\n // back, and guessing from the supervisor's next node would invent a causal edge that may not\n // exist — a child can end without ever answering.\n const returned = lane.pid === undefined ? undefined : returnMarkerByPid.get(lane.pid);\n if (returned) {\n lane.returnedTo = returned;\n }\n }\n\n // A session working exactly one task is that task: the two lanes would carry the same label,\n // so the task lane folds into the session's (which keeps its run span and totals, and takes the\n // task's id and status so it still reads as the work). Only a lone in-session task, with nothing\n // depending on it, no sub-tasks and no spawned child, folds — a checklist of several stays a tree.\n for (const session of lanes.filter((lane) => lane.kind === 'session' && lane.parentId === undefined)) {\n const children = lanes.filter((lane) => lane.parentId === session.id);\n const [task] = children;\n if (\n children.length !== 1 ||\n task.kind !== 'task' ||\n lanes.some((lane) => lane.parentId === task.id || lane.blockedOn?.includes(task.id))\n ) {\n continue;\n }\n lanes.splice(lanes.indexOf(task), 1);\n session.taskId = task.taskId;\n // The task was started (delegated) before the session's first request, so the folded lane begins\n // with the task; otherwise its first node would sit alone ahead of the bar.\n if (task.start !== undefined) {\n session.start = session.start === undefined ? task.start : Math.min(session.start, task.start);\n }\n if (task.status === 'blocked' || task.status === 'review' || task.status === 'pending') {\n session.status = task.status;\n }\n markers.forEach((marker, index) => {\n if (marker.laneId === task.id) {\n markers[index] = { ...marker, laneId: session.id };\n }\n });\n }\n\n // A parent task's lane carries each of its sub-tasks' starts and finishes as nodes of its own, so it reads as the\n // span of the work it contains rather than one unbroken bar, and its first node is where that work began. Read from\n // the task tree rather than the lanes' `parentId`, which joins a sub-task to its parent only when both sit on one\n // checklist, and carried to every ancestor, since a grandchild's work is inside its grandparent too.\n const laneById = new Map(lanes.map((lane) => [lane.id, lane]));\n const laneByTaskId = new Map(lanes.flatMap((lane) => (lane.taskId === undefined ? [] : [[lane.taskId, lane]])));\n const ancestorLanesOf = (lane: Lane): Lane[] => {\n const task = lane.taskId === undefined ? undefined : taskById.get(lane.taskId);\n const ancestors: Lane[] = [];\n const seen = new Set<string>(task ? [task.id] : []);\n for (\n let parent = task && Task.getParentTask(task);\n parent && !seen.has(parent.id);\n parent = Task.getParentTask(parent)\n ) {\n seen.add(parent.id);\n const parentLane = laneByTaskId.get(parent.id);\n if (parentLane?.kind === 'task') {\n ancestors.push(parentLane);\n }\n }\n return ancestors;\n };\n for (const marker of [...markers]) {\n const lane = laneById.get(marker.laneId);\n if (lane?.kind !== 'task' || !isStatusChange(marker.detail)) {\n continue;\n }\n const { status } = marker.detail;\n if (status !== 'started' && !CLOSED_STATUSES.has(status)) {\n continue;\n }\n for (const ancestor of ancestorLanesOf(lane)) {\n markers.push({\n ...marker,\n id: `${ancestor.id}:sub:${marker.id}`,\n laneId: ancestor.id,\n label: `${lane.label}: ${status}`,\n });\n }\n }\n\n // A parent task encloses its sub-tasks, so its bar begins no later than the earliest of theirs. Read\n // from the task tree rather than the lanes' `parentId`, which joins a sub-task to its parent only when\n // both sit on one checklist: a parent drawn from its edit history alone, or a sub-task worked by\n // another session, would otherwise begin at its own `started` move, after work it contains.\n for (const lane of lanes) {\n const task = lane.taskId === undefined ? undefined : taskById.get(lane.taskId);\n if (!task || lane.start === undefined) {\n continue;\n }\n const seen = new Set<string>([task.id]);\n for (let parent = Task.getParentTask(task); parent && !seen.has(parent.id); parent = Task.getParentTask(parent)) {\n seen.add(parent.id);\n const parentLane = laneByTaskId.get(parent.id);\n if (parentLane?.start !== undefined && lane.start < parentLane.start) {\n parentLane.start = lane.start;\n }\n }\n }\n\n // Hashed from the mnemonic, as the task's mnemonic chip is, so a lane and its chip share a hue.\n for (const lane of lanes) {\n const task = lane.taskId === undefined ? undefined : taskById.get(lane.taskId);\n if (task) {\n lane.hue = getHashHue(Obj.getMnemonic(task));\n // After the fold, so a session standing for its one task breaks where the task was put down too.\n const gaps = workGaps(taskStatusChanges?.get(task.id) ?? []);\n if (gaps.length > 0) {\n lane.gaps = gaps;\n }\n }\n }\n\n const times = [\n ...lanes.flatMap((lane) => [lane.start, lane.end]).filter((time): time is number => time !== undefined),\n ...markers.map((marker) => marker.timestamp),\n ];\n // The axis reaches `now` for a run still in flight; one whose last event is long past is idle or\n // dead whatever its status says, and stretching the axis to now would bunch its nodes into a sliver.\n const hasOpen = lanes.some((lane) => lane.start !== undefined && lane.end === undefined);\n const latest = times.length > 0 ? Math.max(...times) : undefined;\n if (hasOpen && now !== undefined && (latest === undefined || now - latest <= OPEN_LANE_STALE_MS)) {\n times.push(now);\n }\n const start = times.length > 0 ? Math.min(...times) : (now ?? 0);\n const end = times.length > 0 ? Math.max(...times) : start;\n\n return { lanes, markers, range: { start, end } };\n};\n\nconst taskLaneStatus = (task: Task.Task, tasks: readonly Task.Task[]): LaneStatus => {\n if (task.status === 'todo' && !Task.isTaskReady(tasks, task)) {\n return 'blocked';\n }\n return (task.status && TASK_STATUS[task.status]) ?? 'pending';\n};\n\nconst subSessionStatus = (endEvent: Trace.FlatEvent | undefined, process: Process.Process | undefined): LaneStatus => {\n if (endEvent) {\n return decode(Trace.OperationEnd.schema, endEvent.data)?.outcome === 'failure' ? 'failed' : 'done';\n }\n if (process && !ACTIVE_STATES.has(process.state)) {\n return process.state === Process.State.FAILED ? 'failed' : 'done';\n }\n return 'running';\n};\n\nconst toMarker = (event: Trace.FlatEvent, id: string, laneId: string): Marker | undefined => {\n const base = { id, laneId, timestamp: event.timestamp, pid: event.meta.pid };\n switch (event.type) {\n case Trace.AgentRequestBegin.key:\n return { ...base, kind: 'request', label: 'Request started' };\n case Trace.AgentRequestEnd.key: {\n const data = decode(Trace.AgentRequestEnd.schema, event.data);\n return {\n ...base,\n kind: 'request',\n label: `Request ${data?.status ?? 'ended'}`,\n level: data?.status === 'error' ? 'error' : data?.status === 'interrupted' ? 'warn' : undefined,\n detail: data?.error,\n };\n }\n case Trace.TaskStatusChanged.key: {\n const data = decode(Trace.TaskStatusChanged.schema, event.data);\n return {\n ...base,\n kind: 'task',\n label: data?.status === 'started' ? 'Task started' : `Task ${data?.status ?? 'updated'}`,\n level: data?.status === 'failed' ? 'error' : undefined,\n detail: data,\n };\n }\n case Trace.DelegationSpawned.key: {\n const data = decode(Trace.DelegationSpawned.schema, event.data);\n return { ...base, kind: 'delegation', label: 'Delegated', detail: data };\n }\n case Trace.DelegationCompleted.key: {\n const data = decode(Trace.DelegationCompleted.schema, event.data);\n return {\n ...base,\n kind: 'delegation',\n label: data?.status === 'failure' ? 'Sub-agent failed' : `Returned${data?.result ? `: ${data.result}` : ''}`,\n level: data?.status === 'failure' ? 'error' : undefined,\n detail: data,\n };\n }\n case Trace.OperationStart.key: {\n const data = decode(Trace.OperationStart.schema, event.data);\n return { ...base, kind: 'operation', label: data?.name ?? data?.key ?? 'Operation' };\n }\n case Trace.OperationEnd.key: {\n const data = decode(Trace.OperationEnd.schema, event.data);\n const failed = data?.outcome === 'failure';\n return {\n ...base,\n kind: 'operation',\n label: data?.name ?? data?.key ?? 'Operation',\n level: failed ? 'error' : undefined,\n detail: failed ? data?.error : undefined,\n };\n }\n case Trace.CompleteBlock.key: {\n const data = decode(Trace.CompleteBlock.schema, event.data);\n if (data?.block._tag === 'toolCall') {\n return { ...base, kind: 'tool', label: data.block.name };\n }\n if (data?.block._tag === 'text' && data.role === 'user') {\n return { ...base, kind: 'message', label: data.block.text.split('\\n')[0] ?? '' };\n }\n return undefined;\n }\n default:\n return undefined;\n }\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { palette } from '@dxos/ui-theme';\n\nexport const LaneKind = Schema.Literals(['session', 'task']);\nexport type LaneKind = Schema.Schema.Type<typeof LaneKind>;\n\nexport const LaneHue = Schema.Literals([palette.neutral.hue, ...palette.hues.map((style) => style.hue)]);\nexport type LaneHue = Schema.Schema.Type<typeof LaneHue>;\n\nexport const LaneStatus = Schema.Literals(['pending', 'blocked', 'running', 'review', 'done', 'failed']);\nexport type LaneStatus = Schema.Schema.Type<typeof LaneStatus>;\n\nexport const TokenUsage = Schema.Struct({\n input: Schema.Number,\n output: Schema.Number,\n total: Schema.Number,\n});\nexport type TokenUsage = Schema.Schema.Type<typeof TokenUsage>;\n\n/**\n * A conversation the timeline draws as a session lane: the chat, reduced to what the join needs so\n * the builder does not depend on the chat's schema. `uri` is what the agent process targets and\n * `feedId` what its trace meta names; `taskIds` is the checklist.\n */\nexport const Session = Schema.Struct({\n id: Schema.String,\n label: Schema.optional(Schema.String),\n uri: Schema.String,\n feedId: Schema.optional(Schema.String),\n taskIds: Schema.Array(Schema.String),\n});\nexport type Session = Schema.Schema.Type<typeof Session>;\n\n/**\n * Node in the supervisor lane a child session was spawned from, so the connector can start at the\n * exact marker rather than at the lane's edge.\n */\nexport const DelegationSource = Schema.Struct({\n laneId: Schema.String,\n markerId: Schema.String,\n});\nexport type DelegationSource = Schema.Schema.Type<typeof DelegationSource>;\n\n/**\n * One row of the timeline: a session (supervisor or delegated sub-agent) rendered as a box spanning\n * `start`..`end`, or a task rendered as a thin line grouped under its session.\n */\nexport const Lane = Schema.Struct({\n id: Schema.String,\n kind: LaneKind,\n label: Schema.String,\n status: LaneStatus,\n /** Epoch ms. */\n start: Schema.optional(Schema.Number),\n end: Schema.optional(Schema.Number),\n /**\n * Stretches inside `start`..`end` when the lane's task was put down — blocked on a question, say —\n * and later picked up again; the lane is drawn as separate runs around them.\n */\n gaps: Schema.optional(Schema.Array(Schema.Struct({ start: Schema.Number, end: Schema.Number }))),\n parentId: Schema.optional(Schema.String),\n sessionId: Schema.optional(Schema.String),\n taskId: Schema.optional(Schema.String),\n /** The task's hue, hashed from its mnemonic, so the lane matches the task's mnemonic chip. */\n hue: Schema.optional(LaneHue),\n pid: Schema.optional(Schema.String),\n /** Lane ids this lane waits on (task dependencies). */\n blockedOn: Schema.optional(Schema.Array(Schema.String)),\n delegatedFrom: Schema.optional(DelegationSource),\n /** Node in the supervisor lane this lane's result was folded back into. */\n returnedTo: Schema.optional(DelegationSource),\n tokens: Schema.optional(TokenUsage),\n toolCalls: Schema.optional(Schema.Number),\n});\nexport type Lane = Schema.Schema.Type<typeof Lane>;\n\nexport const MarkerKind = Schema.Literals(['request', 'operation', 'tool', 'message', 'error', 'delegation', 'task']);\nexport type MarkerKind = Schema.Schema.Type<typeof MarkerKind>;\n\nexport const MarkerLevel = Schema.Literals(['info', 'warn', 'error']);\nexport type MarkerLevel = Schema.Schema.Type<typeof MarkerLevel>;\n\n/**\n * A point event on a lane, rendered as a node inside the session box.\n */\nexport const Marker = Schema.Struct({\n id: Schema.String,\n laneId: Schema.String,\n kind: MarkerKind,\n timestamp: Schema.Number,\n label: Schema.String,\n level: Schema.optional(MarkerLevel),\n pid: Schema.optional(Schema.String),\n detail: Schema.optional(Schema.Unknown),\n});\nexport type Marker = Schema.Schema.Type<typeof Marker>;\n\nexport const TimeRange = Schema.Struct({\n start: Schema.Number,\n end: Schema.Number,\n});\nexport type TimeRange = Schema.Schema.Type<typeof TimeRange>;\n\nexport const SessionTimeline = Schema.Struct({\n lanes: Schema.Array(Lane),\n markers: Schema.Array(Marker),\n range: TimeRange,\n});\nexport type SessionTimeline = Schema.Schema.Type<typeof SessionTimeline>;\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Duration from 'effect/Duration';\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport type * as Process from '@dxos/compute/Process';\nimport { Obj } from '@dxos/echo';\nimport { type Space } from '@dxos/react-client/echo';\nimport { type Task } from '@dxos/types';\n\nimport {\n type Session,\n type SessionTimeline,\n type TaskStatusChange,\n buildSessionTimeline,\n readTaskStatusChanges,\n} from '../session-timeline/index.ts';\nimport { useTraceMessages } from './useTraceMessages.ts';\n\n/** How often `now` advances while a session is open, so a running lane's range keeps growing. */\nconst TICK_MS = 5_000;\n\n// The trace feed emits continuously while anything runs, and every emission rebuilds the whole\n// timeline from the full message history — so the rebuild rate is capped rather than the feed's.\nconst TRACE_DEBOUNCE = Duration.millis(500);\n\nconst NO_PROCESSES: readonly Process.Process[] = [];\n\ntype StatusChangeCache = Map<string, { heads: string; changes: TaskStatusChange[] }>;\n\n/**\n * A task's status moves, re-read only when its document has moved on: reading them diffs every change\n * in the document, and the timeline rebuilds on every trace emission and tick.\n */\nconst cachedStatusChanges = (cache: StatusChangeCache, task: Task.Task): TaskStatusChange[] => {\n const heads = (Obj.version(task).automergeHeads ?? []).join(',');\n const cached = cache.get(task.id);\n if (cached?.heads === heads) {\n return cached.changes;\n }\n const changes = readTaskStatusChanges(task);\n cache.set(task.id, { heads, changes });\n return changes;\n};\n\nexport type UseSessionTimelineOptions = {\n /** The sessions shown; each contributes a session lane and its checklist's task lanes. */\n sessions: readonly Session[];\n tasks?: readonly Task.Task[];\n /** The live process tree, from whichever monitor the host has; without it a session's liveness is read from the trace alone. */\n processes?: readonly Process.Process[];\n};\n\n/**\n * The live gantt-shaped view of the given sessions: rebuilt as trace events land on the space's\n * trace feed and as the process tree changes, and ticked so open lanes keep extending.\n */\nexport const useSessionTimeline = (\n space: Space | undefined,\n { sessions, tasks, processes = NO_PROCESSES }: UseSessionTimelineOptions,\n): SessionTimeline => {\n const traceMessages = useTraceMessages(space, { debounce: TRACE_DEBOUNCE });\n\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const interval = setInterval(() => setNow(Date.now()), TICK_MS);\n return () => clearInterval(interval);\n }, []);\n\n const statusChangeCache = useRef<StatusChangeCache>(new Map());\n return useMemo(() => {\n const taskStatusChanges = new Map(\n (tasks ?? []).map((task) => [task.id, cachedStatusChanges(statusChangeCache.current, task)]),\n );\n return buildSessionTimeline({ traceMessages, processes, sessions, tasks, taskStatusChanges, now });\n }, [traceMessages, processes, sessions, tasks, now]);\n};\n"],"mappings":"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"}