@dxos/react-ui-trace 0.11.1

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 (148) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +3 -0
  3. package/dist/lib/index.mjs +2868 -0
  4. package/dist/lib/index.mjs.map +1 -0
  5. package/dist/lib/testing.mjs +338 -0
  6. package/dist/lib/testing.mjs.map +1 -0
  7. package/dist/lib/translations.mjs +19 -0
  8. package/dist/lib/translations.mjs.map +1 -0
  9. package/dist/types/src/components/Gantt/Gantt.d.ts +68 -0
  10. package/dist/types/src/components/Gantt/Gantt.d.ts.map +1 -0
  11. package/dist/types/src/components/Gantt/Gantt.stories.d.ts +30 -0
  12. package/dist/types/src/components/Gantt/Gantt.stories.d.ts.map +1 -0
  13. package/dist/types/src/components/Gantt/index.d.ts +2 -0
  14. package/dist/types/src/components/Gantt/index.d.ts.map +1 -0
  15. package/dist/types/src/components/ProcessTree/ProcessTree.d.ts +32 -0
  16. package/dist/types/src/components/ProcessTree/ProcessTree.d.ts.map +1 -0
  17. package/dist/types/src/components/ProcessTree/ProcessTree.stories.d.ts +8 -0
  18. package/dist/types/src/components/ProcessTree/ProcessTree.stories.d.ts.map +1 -0
  19. package/dist/types/src/components/ProcessTree/index.d.ts +2 -0
  20. package/dist/types/src/components/ProcessTree/index.d.ts.map +1 -0
  21. package/dist/types/src/components/Timeline/Timeline.d.ts +50 -0
  22. package/dist/types/src/components/Timeline/Timeline.d.ts.map +1 -0
  23. package/dist/types/src/components/Timeline/Timeline.stories.d.ts +24 -0
  24. package/dist/types/src/components/Timeline/Timeline.stories.d.ts.map +1 -0
  25. package/dist/types/src/components/Timeline/index.d.ts +4 -0
  26. package/dist/types/src/components/Timeline/index.d.ts.map +1 -0
  27. package/dist/types/src/components/Timeline/timeline-options.d.ts +9 -0
  28. package/dist/types/src/components/Timeline/timeline-options.d.ts.map +1 -0
  29. package/dist/types/src/components/Timeline/timeline-printer.d.ts +7 -0
  30. package/dist/types/src/components/Timeline/timeline-printer.d.ts.map +1 -0
  31. package/dist/types/src/components/Timeline/timeline-printer.test.d.ts +2 -0
  32. package/dist/types/src/components/Timeline/timeline-printer.test.d.ts.map +1 -0
  33. package/dist/types/src/components/TracePanel/TracePanel.d.ts +28 -0
  34. package/dist/types/src/components/TracePanel/TracePanel.d.ts.map +1 -0
  35. package/dist/types/src/components/TracePanel/dxn-extractor.d.ts +19 -0
  36. package/dist/types/src/components/TracePanel/dxn-extractor.d.ts.map +1 -0
  37. package/dist/types/src/components/TracePanel/dxn-extractor.test.d.ts +2 -0
  38. package/dist/types/src/components/TracePanel/dxn-extractor.test.d.ts.map +1 -0
  39. package/dist/types/src/components/TracePanel/index.d.ts +4 -0
  40. package/dist/types/src/components/TracePanel/index.d.ts.map +1 -0
  41. package/dist/types/src/components/TracePanel/trace-filter.d.ts +39 -0
  42. package/dist/types/src/components/TracePanel/trace-filter.d.ts.map +1 -0
  43. package/dist/types/src/components/TracePanel/trace-filter.test.d.ts +2 -0
  44. package/dist/types/src/components/TracePanel/trace-filter.test.d.ts.map +1 -0
  45. package/dist/types/src/components/TracePanel/useTraceMenu.d.ts +15 -0
  46. package/dist/types/src/components/TracePanel/useTraceMenu.d.ts.map +1 -0
  47. package/dist/types/src/components/index.d.ts +5 -0
  48. package/dist/types/src/components/index.d.ts.map +1 -0
  49. package/dist/types/src/execution-graph/execution-graph.d.ts +139 -0
  50. package/dist/types/src/execution-graph/execution-graph.d.ts.map +1 -0
  51. package/dist/types/src/execution-graph/execution-graph.test.d.ts +2 -0
  52. package/dist/types/src/execution-graph/execution-graph.test.d.ts.map +1 -0
  53. package/dist/types/src/execution-graph/index.d.ts +4 -0
  54. package/dist/types/src/execution-graph/index.d.ts.map +1 -0
  55. package/dist/types/src/execution-graph/pending-block-status.d.ts +26 -0
  56. package/dist/types/src/execution-graph/pending-block-status.d.ts.map +1 -0
  57. package/dist/types/src/execution-graph/pending-block-status.test.d.ts +2 -0
  58. package/dist/types/src/execution-graph/pending-block-status.test.d.ts.map +1 -0
  59. package/dist/types/src/execution-graph/remote-snapshot.test.d.ts +2 -0
  60. package/dist/types/src/execution-graph/remote-snapshot.test.d.ts.map +1 -0
  61. package/dist/types/src/execution-graph/span-tree.d.ts +106 -0
  62. package/dist/types/src/execution-graph/span-tree.d.ts.map +1 -0
  63. package/dist/types/src/execution-graph/span-tree.test.d.ts +2 -0
  64. package/dist/types/src/execution-graph/span-tree.test.d.ts.map +1 -0
  65. package/dist/types/src/execution-graph/sub-agent-delegation.test.d.ts +2 -0
  66. package/dist/types/src/execution-graph/sub-agent-delegation.test.d.ts.map +1 -0
  67. package/dist/types/src/execution-graph/testing/collect-trace-events.d.ts +40 -0
  68. package/dist/types/src/execution-graph/testing/collect-trace-events.d.ts.map +1 -0
  69. package/dist/types/src/execution-graph/testing/index.d.ts +2 -0
  70. package/dist/types/src/execution-graph/testing/index.d.ts.map +1 -0
  71. package/dist/types/src/hooks/index.d.ts +4 -0
  72. package/dist/types/src/hooks/index.d.ts.map +1 -0
  73. package/dist/types/src/hooks/useExecutionGraph.d.ts +17 -0
  74. package/dist/types/src/hooks/useExecutionGraph.d.ts.map +1 -0
  75. package/dist/types/src/hooks/useSessionTimeline.d.ts +17 -0
  76. package/dist/types/src/hooks/useSessionTimeline.d.ts.map +1 -0
  77. package/dist/types/src/hooks/useTraceMessages.d.ts +17 -0
  78. package/dist/types/src/hooks/useTraceMessages.d.ts.map +1 -0
  79. package/dist/types/src/index.d.ts +5 -0
  80. package/dist/types/src/index.d.ts.map +1 -0
  81. package/dist/types/src/session-timeline/index.d.ts +3 -0
  82. package/dist/types/src/session-timeline/index.d.ts.map +1 -0
  83. package/dist/types/src/session-timeline/session-timeline.d.ts +19 -0
  84. package/dist/types/src/session-timeline/session-timeline.d.ts.map +1 -0
  85. package/dist/types/src/session-timeline/session-timeline.test.d.ts +2 -0
  86. package/dist/types/src/session-timeline/session-timeline.test.d.ts.map +1 -0
  87. package/dist/types/src/session-timeline/types.d.ts +129 -0
  88. package/dist/types/src/session-timeline/types.d.ts.map +1 -0
  89. package/dist/types/src/testing/index.d.ts +5 -0
  90. package/dist/types/src/testing/index.d.ts.map +1 -0
  91. package/dist/types/src/testing/simulated-agent.d.ts +63 -0
  92. package/dist/types/src/testing/simulated-agent.d.ts.map +1 -0
  93. package/dist/types/src/testing/snapshot-playback.d.ts +12 -0
  94. package/dist/types/src/testing/snapshot-playback.d.ts.map +1 -0
  95. package/dist/types/src/testing/test-trace.d.ts +5 -0
  96. package/dist/types/src/testing/test-trace.d.ts.map +1 -0
  97. package/dist/types/src/translations.d.ts +19 -0
  98. package/dist/types/src/translations.d.ts.map +1 -0
  99. package/dist/types/tsconfig.tsbuildinfo +1 -0
  100. package/package.json +77 -0
  101. package/src/components/Gantt/Gantt.stories.tsx +241 -0
  102. package/src/components/Gantt/Gantt.tsx +589 -0
  103. package/src/components/Gantt/index.ts +5 -0
  104. package/src/components/ProcessTree/ProcessTree.stories.tsx +95 -0
  105. package/src/components/ProcessTree/ProcessTree.tsx +265 -0
  106. package/src/components/ProcessTree/index.ts +5 -0
  107. package/src/components/Timeline/Timeline.stories.tsx +326 -0
  108. package/src/components/Timeline/Timeline.tsx +534 -0
  109. package/src/components/Timeline/git.drawio.svg +821 -0
  110. package/src/components/Timeline/index.ts +7 -0
  111. package/src/components/Timeline/timeline-options.ts +27 -0
  112. package/src/components/Timeline/timeline-printer.test.ts +76 -0
  113. package/src/components/Timeline/timeline-printer.ts +223 -0
  114. package/src/components/TracePanel/TracePanel.tsx +248 -0
  115. package/src/components/TracePanel/dxn-extractor.test.ts +153 -0
  116. package/src/components/TracePanel/dxn-extractor.ts +166 -0
  117. package/src/components/TracePanel/index.ts +7 -0
  118. package/src/components/TracePanel/trace-filter.test.ts +137 -0
  119. package/src/components/TracePanel/trace-filter.ts +120 -0
  120. package/src/components/TracePanel/useTraceMenu.ts +95 -0
  121. package/src/components/index.ts +8 -0
  122. package/src/execution-graph/SPEC.md +749 -0
  123. package/src/execution-graph/execution-graph.test.ts +1205 -0
  124. package/src/execution-graph/execution-graph.ts +1076 -0
  125. package/src/execution-graph/index.ts +35 -0
  126. package/src/execution-graph/pending-block-status.test.ts +118 -0
  127. package/src/execution-graph/pending-block-status.ts +88 -0
  128. package/src/execution-graph/remote-snapshot.test.ts +116 -0
  129. package/src/execution-graph/span-tree.test.ts +370 -0
  130. package/src/execution-graph/span-tree.ts +404 -0
  131. package/src/execution-graph/sub-agent-delegation.test.ts +65 -0
  132. package/src/execution-graph/testing/collect-trace-events.ts +76 -0
  133. package/src/execution-graph/testing/index.ts +5 -0
  134. package/src/execution-graph/testing/sub-agent-delegation.json +1285 -0
  135. package/src/hooks/index.ts +7 -0
  136. package/src/hooks/useExecutionGraph.ts +107 -0
  137. package/src/hooks/useSessionTimeline.ts +53 -0
  138. package/src/hooks/useTraceMessages.ts +58 -0
  139. package/src/index.ts +8 -0
  140. package/src/session-timeline/index.ts +6 -0
  141. package/src/session-timeline/session-timeline.test.ts +662 -0
  142. package/src/session-timeline/session-timeline.ts +605 -0
  143. package/src/session-timeline/types.ts +100 -0
  144. package/src/testing/index.ts +8 -0
  145. package/src/testing/simulated-agent.ts +293 -0
  146. package/src/testing/snapshot-playback.ts +45 -0
  147. package/src/testing/test-trace.ts +22 -0
  148. package/src/translations.ts +29 -0
@@ -0,0 +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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"}