@tangle-network/ui 11.45.0 → 11.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 11.47.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 99cf964: A windowed transcript keeps the chat's rhythm and edge. `AgentTimeline` now renders through two new exports, `AgentTimelineColumn` (the centred reading column) and `AgentTimelineStep` (one row with the gap its neighbour pair calls for, from `agentTimelineStepKind`), so a consumer that virtualizes a long transcript renders its rows inside one column instead of one `AgentTimeline` per row.
8
+
9
+ `RunRowShell` (and so `InlineToolItem` and `InlineThinkingItem`) marks a failure on the row's own glyph, tinted to the danger ink beside the tool's name, instead of a red dot at the row's far edge. `data-run-row-status="error"` moves to the glyph slot. The collapsed error line, the hover duration, an opened reasoning body, a user message's timestamp row and the "Show more steps" toggle read at `text-sm` (14px) instead of 10–12px.
10
+
11
+ ## 11.46.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 7924be7: SegmentedControl (row): the selected segment is a raised thumb on one quiet well instead of a tint inside an inset ring, the track uses the hairline border token, and the control is 36px tall so it sits inside a 44px toolbar with air above and below.
16
+
17
+ ### Patch Changes
18
+
19
+ - 9bd1487: RunRowShell shows its description (the file, command or query) at every width, truncated, instead of hiding it below 640px, where a transcript read as a column of bare verbs ("Read", "Read", "Shell").
20
+
3
21
  ## 11.45.0
4
22
 
5
23
  ### Minor Changes
@@ -84,6 +84,35 @@ export interface AgentTimelineProps {
84
84
  */
85
85
  viewerId?: string;
86
86
  }
87
+ /**
88
+ * Vertical rhythm. Rows are grouped by what they are, and the gap between two
89
+ * neighbours follows from the pair: a turn boundary (user message) separates
90
+ * most, a tool sequence — and prose beside it — sits tightest, cards and
91
+ * consecutive paragraphs fall between.
92
+ */
93
+ export type AgentTimelineStepKind = "user" | "prose" | "tool" | "card";
94
+ /** What a row is, for the gap above the next one. */
95
+ export declare function agentTimelineStepKind(item: AgentTimelineItem): AgentTimelineStepKind;
96
+ /** The transcript column every timeline sits in: centred, at the reading width. */
97
+ export declare function AgentTimelineColumn({ className, children }: {
98
+ className?: string;
99
+ children?: ReactNode;
100
+ }): import("react").JSX.Element;
101
+ export interface AgentTimelineStepProps {
102
+ item: AgentTimelineItem;
103
+ /** The kind of the row above, which sets the gap; omit for the first row. */
104
+ previous?: AgentTimelineStepKind;
105
+ /** Draw the message's author line (the first prose of a turn). */
106
+ headed?: boolean;
107
+ renderToolActions?: (part: ToolPart) => ReactNode;
108
+ viewerId?: string;
109
+ }
110
+ /**
111
+ * One row of the timeline with the gap its neighbour pair calls for. A
112
+ * consumer that windows a long transcript renders these inside one
113
+ * `AgentTimelineColumn`, so the rows keep the column's rhythm and edge.
114
+ */
115
+ export declare function AgentTimelineStep({ item, previous, headed, renderToolActions, viewerId }: AgentTimelineStepProps): import("react").JSX.Element;
87
116
  /**
88
117
  * AgentTimeline — unified mixed-content transcript for agent-backed sandbox
89
118
  * sessions. Renders messages, tool rows, status cards, and artifact handoffs
@@ -42,7 +42,8 @@ const TONE_STYLES = {
42
42
  icon: AlertTriangle
43
43
  }
44
44
  };
45
- function stepKind(item) {
45
+ /** What a row is, for the gap above the next one. */
46
+ function agentTimelineStepKind(item) {
46
47
  if (item.kind === "message") return item.role === "user" ? "user" : "prose";
47
48
  if (item.kind === "status" || item.kind === "artifact") return "card";
48
49
  return "tool";
@@ -151,6 +152,71 @@ function ArtifactCard({ item }) {
151
152
  children: content
152
153
  });
153
154
  }
155
+ /** The transcript column every timeline sits in: centred, at the reading width. */
156
+ function AgentTimelineColumn({ className, children }) {
157
+ return /* @__PURE__ */ jsx("div", {
158
+ className: cn("mx-auto flex w-full max-w-5xl flex-col px-4 py-4", className),
159
+ children
160
+ });
161
+ }
162
+ /**
163
+ * One row of the timeline with the gap its neighbour pair calls for. A
164
+ * consumer that windows a long transcript renders these inside one
165
+ * `AgentTimelineColumn`, so the rows keep the column's rhythm and edge.
166
+ */
167
+ function AgentTimelineStep({ item, previous, headed, renderToolActions, viewerId }) {
168
+ const kind = agentTimelineStepKind(item);
169
+ return /* @__PURE__ */ jsx("div", {
170
+ "data-timeline-step": kind,
171
+ className: cn(spacingBefore(previous, kind), kind === "tool" && ROW_BLEED),
172
+ children: /* @__PURE__ */ jsx(TimelineItem, {
173
+ item,
174
+ headed,
175
+ renderToolActions,
176
+ viewerId
177
+ })
178
+ });
179
+ }
180
+ function TimelineItem({ item, headed, renderToolActions, viewerId }) {
181
+ if (item.kind === "message") return item.role === "user" ? /* @__PURE__ */ jsx(UserMessage, {
182
+ content: item.content,
183
+ timestamp: item.timestamp,
184
+ author: item.author,
185
+ viewerId
186
+ }) : /* @__PURE__ */ jsx(AssistantMessage, {
187
+ item,
188
+ author: headed ? item.author : void 0
189
+ });
190
+ if (item.kind === "tool") return /* @__PURE__ */ jsx(ToolCallStep, {
191
+ type: item.call.type,
192
+ label: item.call.label,
193
+ status: item.call.status,
194
+ detail: item.call.detail,
195
+ output: item.call.output,
196
+ duration: item.call.duration,
197
+ part: item.part,
198
+ actions: item.part ? renderToolActions?.(item.part) : void 0
199
+ });
200
+ if (item.kind === "tool_group") return /* @__PURE__ */ jsx(ToolCallGroup, {
201
+ title: item.title,
202
+ children: item.calls.map((call, callIndex) => {
203
+ const part = item.parts?.[callIndex];
204
+ return /* @__PURE__ */ jsx(ToolCallStep, {
205
+ type: call.type,
206
+ label: call.label,
207
+ status: call.status,
208
+ detail: call.detail,
209
+ output: call.output,
210
+ duration: call.duration,
211
+ part,
212
+ actions: part ? renderToolActions?.(part) : void 0
213
+ }, call.id);
214
+ })
215
+ });
216
+ if (item.kind === "status") return /* @__PURE__ */ jsx(StatusCard, { item });
217
+ if (item.kind === "artifact") return /* @__PURE__ */ jsx(ArtifactCard, { item });
218
+ return item.content;
219
+ }
154
220
  /**
155
221
  * AgentTimeline — unified mixed-content transcript for agent-backed sandbox
156
222
  * sessions. Renders messages, tool rows, status cards, and artifact handoffs
@@ -197,62 +263,20 @@ function AgentTimeline({ items, isThinking, emptyState, className, renderToolAct
197
263
  if (item.author && item.author.id !== speakingAgent) headedAgentMessages.add(item.id);
198
264
  speakingAgent = item.author?.id;
199
265
  }
200
- const renderItem = (item) => {
201
- if (item.kind === "message") return item.role === "user" ? /* @__PURE__ */ jsx(UserMessage, {
202
- content: item.content,
203
- timestamp: item.timestamp,
204
- author: item.author,
205
- viewerId
206
- }) : /* @__PURE__ */ jsx(AssistantMessage, {
266
+ return /* @__PURE__ */ jsxs(AgentTimelineColumn, {
267
+ className,
268
+ children: [renderList.map((item, index) => /* @__PURE__ */ jsx(AgentTimelineStep, {
207
269
  item,
208
- author: headedAgentMessages.has(item.id) ? item.author : void 0
209
- });
210
- if (item.kind === "tool") return /* @__PURE__ */ jsx(ToolCallStep, {
211
- type: item.call.type,
212
- label: item.call.label,
213
- status: item.call.status,
214
- detail: item.call.detail,
215
- output: item.call.output,
216
- duration: item.call.duration,
217
- part: item.part,
218
- actions: item.part ? renderToolActions?.(item.part) : void 0
219
- });
220
- if (item.kind === "tool_group") return /* @__PURE__ */ jsx(ToolCallGroup, {
221
- title: item.title,
222
- children: item.calls.map((call, callIndex) => {
223
- const part = item.parts?.[callIndex];
224
- return /* @__PURE__ */ jsx(ToolCallStep, {
225
- type: call.type,
226
- label: call.label,
227
- status: call.status,
228
- detail: call.detail,
229
- output: call.output,
230
- duration: call.duration,
231
- part,
232
- actions: part ? renderToolActions?.(part) : void 0
233
- }, call.id);
234
- })
235
- });
236
- if (item.kind === "status") return /* @__PURE__ */ jsx(StatusCard, { item });
237
- if (item.kind === "artifact") return /* @__PURE__ */ jsx(ArtifactCard, { item });
238
- return item.content;
239
- };
240
- return /* @__PURE__ */ jsxs("div", {
241
- className: cn("mx-auto flex w-full max-w-5xl flex-col px-4 py-4", className),
242
- children: [renderList.map((item, index) => {
243
- const kind = stepKind(item);
244
- const prev = index > 0 ? stepKind(renderList[index - 1]) : void 0;
245
- return /* @__PURE__ */ jsx("div", {
246
- "data-timeline-step": kind,
247
- className: cn(spacingBefore(prev, kind), kind === "tool" && ROW_BLEED),
248
- children: renderItem(item)
249
- }, item.id);
250
- }), collapsible ? /* @__PURE__ */ jsx("button", {
270
+ previous: index > 0 ? agentTimelineStepKind(renderList[index - 1]) : void 0,
271
+ headed: headedAgentMessages.has(item.id),
272
+ renderToolActions,
273
+ viewerId
274
+ }, item.id)), collapsible ? /* @__PURE__ */ jsx("button", {
251
275
  type: "button",
252
276
  onClick: () => setExpanded((value) => !value),
253
- className: "mt-2 self-start text-xs font-medium text-muted-foreground transition-colors hover:text-foreground",
277
+ className: "mt-2 self-start text-sm font-medium text-muted-foreground transition-colors hover:text-foreground",
254
278
  children: collapsed ? `Show ${hiddenCount} more step${hiddenCount === 1 ? "" : "s"}` : "Show less"
255
279
  }) : null]
256
280
  });
257
281
  }
258
- export { AgentTimeline };
282
+ export { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, agentTimelineStepKind };
@@ -12,7 +12,7 @@ function formatTime(date) {
12
12
  }
13
13
  function MessageActions({ children, align = "end" }) {
14
14
  return /* @__PURE__ */ jsx("div", {
15
- className: `flex flex-wrap items-center ${align === "end" ? "justify-end" : "justify-start"} gap-1.5 text-xs text-muted-foreground`,
15
+ className: `flex flex-wrap items-center ${align === "end" ? "justify-end" : "justify-start"} gap-1.5 text-sm text-muted-foreground`,
16
16
  children
17
17
  });
18
18
  }
package/dist/chat.d.ts CHANGED
@@ -5,6 +5,6 @@ import { UserMessage, UserMessageProps } from "./chat/user-message.js";
5
5
  import { ChatMessage, ChatMessageProps, MessageRole } from "./chat/chat-message.js";
6
6
  import { MessageAuthor, MessageAuthorProps, isViewerMessage } from "./chat/message-author.js";
7
7
  import { ThinkingIndicator, ThinkingIndicatorProps } from "./chat/thinking-indicator.js";
8
- import { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem } from "./chat/agent-timeline.js";
8
+ import { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineColumn, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineStep, AgentTimelineStepKind, AgentTimelineStepProps, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, agentTimelineStepKind } from "./chat/agent-timeline.js";
9
9
  import { TRANSCRIPT_TEXT } from "./chat/transcript-text.js";
10
- export { AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, type ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, TRANSCRIPT_TEXT, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps, isViewerMessage };
10
+ export { AgentTimeline, type AgentTimelineArtifactItem, AgentTimelineColumn, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, AgentTimelineStep, type AgentTimelineStepKind, type AgentTimelineStepProps, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, type ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, TRANSCRIPT_TEXT, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps, agentTimelineStepKind, isViewerMessage };
package/dist/chat.js CHANGED
@@ -3,7 +3,7 @@ import { MessageAuthor, isViewerMessage } from "./chat/message-author.js";
3
3
  import { UserMessage } from "./chat/user-message.js";
4
4
  import { MessageList } from "./chat/message-list.js";
5
5
  import { ThinkingIndicator } from "./chat/thinking-indicator.js";
6
- import { AgentTimeline } from "./chat/agent-timeline.js";
6
+ import { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, agentTimelineStepKind } from "./chat/agent-timeline.js";
7
7
  import { ChatContainer } from "./chat/chat-container.js";
8
8
  import { ChatMessage } from "./chat/chat-message.js";
9
- export { AgentTimeline, ChatContainer, ChatMessage, MessageAuthor, MessageList, TRANSCRIPT_TEXT, ThinkingIndicator, UserMessage, isViewerMessage };
9
+ export { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, ChatContainer, ChatMessage, MessageAuthor, MessageList, TRANSCRIPT_TEXT, ThinkingIndicator, UserMessage, agentTimelineStepKind, isViewerMessage };
package/dist/index.d.ts CHANGED
@@ -19,7 +19,7 @@ import { MessageAuthor, MessageAuthorProps, isViewerMessage } from "./chat/messa
19
19
  import { ThinkingIndicator, ThinkingIndicatorProps } from "./chat/thinking-indicator.js";
20
20
  import { ToolCallStatus, ToolCallType } from "./run/tool-call-step.js";
21
21
  import { FeedSegment, ToolCallData, ToolCallFeed, ToolCallFeedProps, parseToolEvent } from "./run/tool-call-feed.js";
22
- import { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem } from "./chat/agent-timeline.js";
22
+ import { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineColumn, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineStep, AgentTimelineStepKind, AgentTimelineStepProps, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, agentTimelineStepKind } from "./chat/agent-timeline.js";
23
23
  import { TRANSCRIPT_TEXT } from "./chat/transcript-text.js";
24
24
  import "./chat.js";
25
25
  import { codeBlockGrammar } from "./lib/code-presentation.js";
@@ -143,4 +143,4 @@ import { QuestionPreview, QuestionPreviewProps } from "./tool-previews/question-
143
143
  import { DiffPreview, DiffPreviewProps } from "./tool-previews/diff-preview.js";
144
144
  import { RedactedDocSegment, RedactedDocument, RedactedDocumentData, RedactedDocumentProps, RevealResult } from "./redaction/redacted-document.js";
145
145
  import "./redaction.js";
146
- export { ActiveProjectActivity, ActiveSessionActivityOptions, ActiveSessionConnectionOptions, ActiveSessionConnectionState, ActiveSessionReconnectState, ActiveSessionRecord, ActiveSessionStatus, ActiveSessionTransportMode, ActiveSessionsState, AgentBranding, AgentStreamEvent, AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, ApiSchema, type ApiSchemaProps, AppendUserMessageOptions, ApplySdkEventOptions, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ArtifactPane, type ArtifactPaneProps, AuthHeader, type AuthHeaderProps, AuthUser, AutomationStreamEvent, Avatar, AvatarFallback, AvatarImage, type AvatarProps, Badge, type BadgeProps, BeginAssistantMessageOptions, BotStreamEvent, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, type ChartReferenceLine, ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, type CommandPreviewProps, CompleteAssistantMessageOptions, ComplianceBadge, type ComplianceBadgeProps, type ComplianceProduct, type ComplianceStatus, ConnectionState, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, CustomToolRenderer, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, type DiffPreviewProps, DisplayVariant, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, Field, type FieldProps, FileArtifactPane, type FileArtifactPaneProps, FileCard, type FileCardProps, type FileDetails, type FileFormat, FileList, type FileListItem, type FileListProps, type FileNode, FilePreview, type FilePreviewKind, type FilePreviewProps, type FileTabData, FileTabs, type FileTabsProps, FileTree, type FileTreeProps, type FileTreeVisibilityOptions, type FileUploader, FilterField, type FilterFieldProps, FinalTextPart, GitHubLoginButton, type GitHubLoginButtonProps, GlobResultsPreview, type GlobResultsPreviewProps, GrepResultsPreview, type GrepResultsPreviewProps, GroupedMessage, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, Input, type InputProps, Label, LiveDuration, LoginLayout, type LoginLayoutProps, Logo, type LogoProps, Markdown, type MarkdownLinkChip, type MarkdownLinkChipResolver, type MarkdownProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, MessageRun, MessageUser, Metric, MetricChart, type MetricChartProps, type MetricProps, MetricStrip, type MetricStripProps, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, type OpenUIAction, type OpenUIActionsNode, OpenUIArtifactRenderer, type OpenUIArtifactRendererProps, type OpenUIBadgeNode, type OpenUICardNode, type OpenUICodeNode, type OpenUIComponentNode, type OpenUIGridNode, type OpenUIHeadingNode, type OpenUIKeyValueNode, type OpenUIMarkdownNode, type OpenUIPrimitive, type OpenUISchemaIssue, type OpenUISchemaValidation, type OpenUISeparatorNode, type OpenUIStackNode, type OpenUIStatNode, type OpenUITableNode, type OpenUITextNode, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, PdfViewer, type PdfViewerConfig, type PdfViewerProps, type PeriodDelta, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, type QuestionPreviewProps, RadioGroup, RadioGroupItem, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, ReasoningPart, type RedactedDocSegment, RedactedDocument, type RedactedDocumentData, type RedactedDocumentProps, RegisterActiveSessionOptions, type RevealResult, RichFileTree, type RichFileTreeGitEntry, type RichFileTreeGitStatus, type RichFileTreeProps, type RichFileTreeThemeVars, Run, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunRowStatusDot, RunStats, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeriesExtent, type SeriesPoint, type SeriesPointInput, type SeriesScale, SeriesSparkline, type SeriesSparklineProps, SessionMessage, SessionPart, SessionProjectKey, type SessionUser, SettingsList, type SettingsListAction, type SettingsListColumns, SettingsListItem, type SettingsListItemProps, type SettingsListMenuItem, type SettingsListProps, SettingsRow, type SettingsRowLayout, type SettingsRowProps, SettingsSection, type SettingsSectionProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, TaskStreamEvent, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TerminalStreamEvent, TextPart, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, ThinkingIndicator, type ThinkingIndicatorProps, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, ToolCategory, ToolDisplayMetadata, ToolPart, ToolState, ToolStatus, ToolTime, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, UserMenu, type UserMenuProps, UserMessage, type UserMessageProps, WebSearchPreview, type WebSearchPreviewProps, Wizard, type WizardProps, WizardStep, type WizardStepProps, WriteFilePreview, type WriteFilePreviewProps, activeSessionsAtom, addMessage, addParts, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
146
+ export { ActiveProjectActivity, ActiveSessionActivityOptions, ActiveSessionConnectionOptions, ActiveSessionConnectionState, ActiveSessionReconnectState, ActiveSessionRecord, ActiveSessionStatus, ActiveSessionTransportMode, ActiveSessionsState, AgentBranding, AgentStreamEvent, AgentTimeline, type AgentTimelineArtifactItem, AgentTimelineColumn, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, AgentTimelineStep, type AgentTimelineStepKind, type AgentTimelineStepProps, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, ApiSchema, type ApiSchemaProps, AppendUserMessageOptions, ApplySdkEventOptions, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ArtifactPane, type ArtifactPaneProps, AuthHeader, type AuthHeaderProps, AuthUser, AutomationStreamEvent, Avatar, AvatarFallback, AvatarImage, type AvatarProps, Badge, type BadgeProps, BeginAssistantMessageOptions, BotStreamEvent, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, type ChartReferenceLine, ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, type CommandPreviewProps, CompleteAssistantMessageOptions, ComplianceBadge, type ComplianceBadgeProps, type ComplianceProduct, type ComplianceStatus, ConnectionState, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, CustomToolRenderer, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, type DiffPreviewProps, DisplayVariant, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, Field, type FieldProps, FileArtifactPane, type FileArtifactPaneProps, FileCard, type FileCardProps, type FileDetails, type FileFormat, FileList, type FileListItem, type FileListProps, type FileNode, FilePreview, type FilePreviewKind, type FilePreviewProps, type FileTabData, FileTabs, type FileTabsProps, FileTree, type FileTreeProps, type FileTreeVisibilityOptions, type FileUploader, FilterField, type FilterFieldProps, FinalTextPart, GitHubLoginButton, type GitHubLoginButtonProps, GlobResultsPreview, type GlobResultsPreviewProps, GrepResultsPreview, type GrepResultsPreviewProps, GroupedMessage, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, Input, type InputProps, Label, LiveDuration, LoginLayout, type LoginLayoutProps, Logo, type LogoProps, Markdown, type MarkdownLinkChip, type MarkdownLinkChipResolver, type MarkdownProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, MessageRun, MessageUser, Metric, MetricChart, type MetricChartProps, type MetricProps, MetricStrip, type MetricStripProps, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, type OpenUIAction, type OpenUIActionsNode, OpenUIArtifactRenderer, type OpenUIArtifactRendererProps, type OpenUIBadgeNode, type OpenUICardNode, type OpenUICodeNode, type OpenUIComponentNode, type OpenUIGridNode, type OpenUIHeadingNode, type OpenUIKeyValueNode, type OpenUIMarkdownNode, type OpenUIPrimitive, type OpenUISchemaIssue, type OpenUISchemaValidation, type OpenUISeparatorNode, type OpenUIStackNode, type OpenUIStatNode, type OpenUITableNode, type OpenUITextNode, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, PdfViewer, type PdfViewerConfig, type PdfViewerProps, type PeriodDelta, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, type QuestionPreviewProps, RadioGroup, RadioGroupItem, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, ReasoningPart, type RedactedDocSegment, RedactedDocument, type RedactedDocumentData, type RedactedDocumentProps, RegisterActiveSessionOptions, type RevealResult, RichFileTree, type RichFileTreeGitEntry, type RichFileTreeGitStatus, type RichFileTreeProps, type RichFileTreeThemeVars, Run, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunRowStatusDot, RunStats, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeriesExtent, type SeriesPoint, type SeriesPointInput, type SeriesScale, SeriesSparkline, type SeriesSparklineProps, SessionMessage, SessionPart, SessionProjectKey, type SessionUser, SettingsList, type SettingsListAction, type SettingsListColumns, SettingsListItem, type SettingsListItemProps, type SettingsListMenuItem, type SettingsListProps, SettingsRow, type SettingsRowLayout, type SettingsRowProps, SettingsSection, type SettingsSectionProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, TaskStreamEvent, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TerminalStreamEvent, TextPart, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, ThinkingIndicator, type ThinkingIndicatorProps, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, ToolCategory, ToolDisplayMetadata, ToolPart, ToolState, ToolStatus, ToolTime, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, UserMenu, type UserMenuProps, UserMessage, type UserMessageProps, WebSearchPreview, type WebSearchPreviewProps, Wizard, type WizardProps, WizardStep, type WizardStepProps, WriteFilePreview, type WriteFilePreviewProps, activeSessionsAtom, addMessage, addParts, agentTimelineStepKind, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
package/dist/index.js CHANGED
@@ -95,7 +95,7 @@ import { MessageAuthor, isViewerMessage } from "./chat/message-author.js";
95
95
  import { UserMessage } from "./chat/user-message.js";
96
96
  import { MessageList } from "./chat/message-list.js";
97
97
  import { ThinkingIndicator } from "./chat/thinking-indicator.js";
98
- import { AgentTimeline } from "./chat/agent-timeline.js";
98
+ import { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, agentTimelineStepKind } from "./chat/agent-timeline.js";
99
99
  import { ChatContainer } from "./chat/chat-container.js";
100
100
  import { ChatMessage } from "./chat/chat-message.js";
101
101
  import { LiveDuration } from "./run/run-item-primitives.js";
@@ -127,4 +127,4 @@ import { addMessage, addParts, clearChat, isStreamingAtom, messagesAtom, partMap
127
127
  import { copyText } from "./utils/copy-text.js";
128
128
  import { timeAgo } from "./utils/time-ago.js";
129
129
  import { RedactedDocument } from "./redaction/redacted-document.js";
130
- export { AgentTimeline, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ApiSchema, ApprovalCard, ApprovalDiffSummary, ArtifactPane, AuthHeader, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatContainer, ChatMessage, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, ComplianceBadge, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ExpandedToolDetail, Field, FileArtifactPane, FileCard, FileList, FilePreview, FileTabs, FileTree, FilterField, GitHubLoginButton, GlobResultsPreview, GrepResultsPreview, Heading, HelpText, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, InlineCode, InlineThinkingItem, InlineToolItem, Input, Label, LiveDuration, LoginLayout, Logo, Markdown, MessageAuthor, MessageList, Metric, MetricChart, MetricStrip, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, OpenUIArtifactRenderer, PageHeader, PageShell, Pagination, PdfViewer, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, RadioGroup, RadioGroupItem, RealtimeSessionRegistry, RedactedDocument, RichFileTree, RunGroup, RunPhaseList, RunRowShell, RunRowStatusDot, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SeriesSparkline, SettingsList, SettingsListItem, SettingsRow, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, StatusPill, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TaskList, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, ThinkingIndicator, TimeSelect, ToastContainer, ToastProvider, ToolCallFeed, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, UserMenu, UserMessage, WebSearchPreview, Wizard, WizardStep, WriteFilePreview, activeSessionsAtom, addMessage, addParts, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
130
+ export { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ApiSchema, ApprovalCard, ApprovalDiffSummary, ArtifactPane, AuthHeader, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatContainer, ChatMessage, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, ComplianceBadge, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ExpandedToolDetail, Field, FileArtifactPane, FileCard, FileList, FilePreview, FileTabs, FileTree, FilterField, GitHubLoginButton, GlobResultsPreview, GrepResultsPreview, Heading, HelpText, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, InlineCode, InlineThinkingItem, InlineToolItem, Input, Label, LiveDuration, LoginLayout, Logo, Markdown, MessageAuthor, MessageList, Metric, MetricChart, MetricStrip, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, OpenUIArtifactRenderer, PageHeader, PageShell, Pagination, PdfViewer, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, RadioGroup, RadioGroupItem, RealtimeSessionRegistry, RedactedDocument, RichFileTree, RunGroup, RunPhaseList, RunRowShell, RunRowStatusDot, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SeriesSparkline, SettingsList, SettingsListItem, SettingsRow, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, StatusPill, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TaskList, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, ThinkingIndicator, TimeSelect, ToastContainer, ToastProvider, ToolCallFeed, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, UserMenu, UserMessage, WebSearchPreview, Wizard, WizardStep, WriteFilePreview, activeSessionsAtom, addMessage, addParts, agentTimelineStepKind, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, formatBytes, formatCalendarDate, formatDuration, formatUptime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
@@ -11,10 +11,13 @@ import * as React from "react";
11
11
  * console warning fires when both are omitted.
12
12
  *
13
13
  * Design rules baked into the default variant:
14
- * - The row track is a field well (`--well`, `--field-border`), so the
15
- * control reads as one inset group on whatever plane it sits on.
16
- * - Only the SELECTED segment shows a surface colour + accent text: the
17
- * shared selected state (`ixSelected`: tint plus an inset ring). A tab
14
+ * - The row track is one quiet well (`--well`, the hairline `border`), so
15
+ * the control reads as one inset group on whatever plane it sits on, and
16
+ * it is compact (36px) so it sits inside a 44px toolbar with air above
17
+ * and below instead of touching its edges.
18
+ * - Only the SELECTED segment shows a surface: a raised thumb (the card
19
+ * colour with a hairline and a soft shadow) with accent text. No ring is
20
+ * drawn around the track's segments, so the group never stacks rings. A tab
18
21
  * shows it as an underline instead (`ixTabUnderline`).
19
22
  * - Unselected segments have NO background — they're plain-text labels
20
23
  * that darken on hover. This keeps the selected segment as the
@@ -7,6 +7,8 @@ import * as React from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { ChevronLeft, ChevronRight } from "lucide-react";
9
9
  // src/primitives/segmented-control.tsx
10
+ /** The row variant's selected segment: a raised thumb on the well, not a tint inside a ring. */
11
+ const rowThumb = "aria-checked:bg-card aria-checked:border-border aria-checked:shadow-[0_1px_2px_rgb(0_0_0/0.08)] hover:aria-checked:bg-card";
10
12
  /** Size of the edge chevron, in px. The selected option is kept this far
11
13
  * (plus the strip's own padding) from an edge so the chevron never covers it. */
12
14
  const SCROLL_CUE_SIZE = 32;
@@ -123,7 +125,7 @@ function SegmentedControl({ value, onValueChange, options, variant = "row", clas
123
125
  ref: stripRef,
124
126
  onKeyDown: handleKeyDown,
125
127
  onScroll: measureOverflow,
126
- className: cn("relative flex gap-1", variant === "row" && "flex-wrap items-center rounded-lg border border-[var(--field-border)] bg-[var(--well)] p-1", variant === "tabs" && "flex-nowrap items-end border-b border-border pb-0 overflow-x-auto", className),
128
+ className: cn("relative flex gap-1", variant === "row" && "flex-wrap items-center rounded-lg border border-border bg-[var(--well)] p-0.5", variant === "tabs" && "flex-nowrap items-end border-b border-border pb-0 overflow-x-auto", className),
127
129
  children: [
128
130
  overflow.start && /* @__PURE__ */ jsx(ScrollCue, {
129
131
  side: "start",
@@ -146,10 +148,10 @@ function SegmentedControl({ value, onValueChange, options, variant = "row", clas
146
148
  if (!active) onValueChange(option.value);
147
149
  },
148
150
  className: cn("relative inline-flex items-center gap-2 whitespace-nowrap text-sm font-medium transition-[color,background-color,border-color,box-shadow]", variant === "row" && [
149
- "rounded-md border border-transparent px-3 py-1.5",
151
+ "rounded-md border border-transparent px-3 py-1",
150
152
  "focus-visible:outline-1 focus-visible:outline-[var(--focus-border)] focus-visible:ring-4 focus-visible:ring-[var(--focus-halo)] focus-visible:outline-offset-0",
151
153
  "hover:bg-[var(--ix-hover-bg)] active:bg-[var(--ix-sel-bg)]",
152
- "aria-pressed:bg-[var(--ix-sel-bg)] aria-pressed:text-[var(--accent-text)] aria-pressed:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] aria-checked:bg-[var(--ix-sel-bg)] aria-checked:text-[var(--accent-text)] aria-checked:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] aria-[current=page]:bg-[var(--ix-sel-bg)] aria-[current=page]:text-[var(--accent-text)] aria-[current=page]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] data-[state=on]:bg-[var(--ix-sel-bg)] data-[state=on]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)] data-[state=active]:bg-[var(--ix-sel-bg)] data-[state=active]:text-[var(--accent-text)] data-[state=active]:shadow-[inset_0_0_0_1px_var(--ix-sel-ring)]"
154
+ rowThumb
153
155
  ], variant === "tabs" && [
154
156
  "shrink-0 rounded-none border-b-2 border-transparent -mb-px px-4 py-2",
155
157
  "pointer-coarse:min-h-11 pointer-coarse:min-w-11",
@@ -51,7 +51,7 @@ const InlineThinkingItem = memo(({ part, defaultOpen = false, autoCollapse = tru
51
51
  children: /* @__PURE__ */ jsx(Markdown, { children: part.text })
52
52
  })
53
53
  }) : /* @__PURE__ */ jsx("div", {
54
- className: "px-3 py-2.5 text-xs text-muted-foreground",
54
+ className: "px-3 py-2.5 text-sm text-muted-foreground",
55
55
  children: "No reasoning text provided."
56
56
  })
57
57
  });
@@ -1,9 +1,10 @@
1
1
  import { ReactNode } from "react";
2
2
  export type RunRowStatus = "running" | "success" | "error" | "idle";
3
3
  /**
4
- * Trailing status indicator shared by every run row. Only `error` draws a
5
- * mark (a red dot). Success is silence, and a running row carries its state in
6
- * the title — a `TextShimmer` sweep — so neither renders anything here.
4
+ * A red dot for a failed row, for rows composed outside the shell. The shell
5
+ * itself marks a failure on the row's own glyph, beside its name, never at the
6
+ * far edge. Success is silence, and a running row carries its state in the
7
+ * title — a `TextShimmer` sweep.
7
8
  */
8
9
  export declare function RunRowStatusDot({ status }: {
9
10
  status: RunRowStatus;
@@ -6,9 +6,10 @@ import { ChevronRight } from "lucide-react";
6
6
  import * as Collapsible from "@radix-ui/react-collapsible";
7
7
  // src/run/run-row-shell.tsx
8
8
  /**
9
- * Trailing status indicator shared by every run row. Only `error` draws a
10
- * mark (a red dot). Success is silence, and a running row carries its state in
11
- * the title — a `TextShimmer` sweep — so neither renders anything here.
9
+ * A red dot for a failed row, for rows composed outside the shell. The shell
10
+ * itself marks a failure on the row's own glyph, beside its name, never at the
11
+ * far edge. Success is silence, and a running row carries its state in the
12
+ * title — a `TextShimmer` sweep.
12
13
  */
13
14
  function RunRowStatusDot({ status }) {
14
15
  if (status !== "error") return null;
@@ -61,7 +62,8 @@ function RunRowShell({ icon, title, description, descriptionMono = false, status
61
62
  children: [
62
63
  /* @__PURE__ */ jsxs("span", {
63
64
  "aria-hidden": true,
64
- className: "flex h-[1.375rem] w-[1.375rem] shrink-0 items-center justify-center text-muted-foreground",
65
+ "data-run-row-status": status === "error" ? "error" : void 0,
66
+ className: cn("flex h-[1.375rem] w-[1.375rem] shrink-0 items-center justify-center", status === "error" ? "text-[var(--surface-danger-text)]" : "text-muted-foreground"),
65
67
  children: [/* @__PURE__ */ jsx("span", {
66
68
  "data-run-row-glyph": "",
67
69
  className: cn("flex items-center justify-center", expandable && "group-hover:hidden", open && "hidden"),
@@ -76,22 +78,19 @@ function RunRowShell({ icon, title, description, descriptionMono = false, status
76
78
  children: title
77
79
  }),
78
80
  description ? /* @__PURE__ */ jsx("span", {
79
- className: cn("hidden min-w-0 flex-1 truncate text-sm text-muted-foreground transition-colors group-hover:text-foreground sm:inline", descriptionMono && "font-mono"),
81
+ className: cn("min-w-0 flex-1 truncate text-sm text-muted-foreground transition-colors group-hover:text-foreground", descriptionMono && "font-mono"),
80
82
  children: description
81
83
  }) : null,
82
- /* @__PURE__ */ jsxs("span", {
83
- className: "ml-auto flex shrink-0 items-center gap-1.5",
84
- children: [!isRunning && durationMs != null ? /* @__PURE__ */ jsx("span", {
85
- "data-run-row-duration": "",
86
- className: "font-mono text-[10px] tabular-nums text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
87
- children: formatDuration(durationMs)
88
- }) : null, /* @__PURE__ */ jsx(RunRowStatusDot, { status })]
89
- })
84
+ !isRunning && durationMs != null ? /* @__PURE__ */ jsx("span", {
85
+ "data-run-row-duration": "",
86
+ className: "ml-auto shrink-0 font-mono text-sm tabular-nums text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
87
+ children: formatDuration(durationMs)
88
+ }) : null
90
89
  ]
91
90
  })
92
91
  }),
93
92
  collapsedError && !open ? /* @__PURE__ */ jsx("div", {
94
- className: cn("pb-1.5 pr-2 text-xs leading-snug text-[var(--surface-danger-text)]", ERROR_INDENT),
93
+ className: cn("pb-1.5 pr-2 text-sm leading-snug text-[var(--surface-danger-text)]", ERROR_INDENT),
95
94
  children: collapsedError
96
95
  }) : null,
97
96
  expandable ? /* @__PURE__ */ jsx(Collapsible.Content, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/ui",
3
- "version": "11.45.0",
3
+ "version": "11.47.0",
4
4
  "description": "Generic React UI components for Tangle products — primitives, chat, run, files, editor, markdown.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -154,9 +154,11 @@ const TONE_STYLES: Record<AgentTimelineTone, { card: string; text: string; suppo
154
154
  * most, a tool sequence — and prose beside it — sits tightest, cards and
155
155
  * consecutive paragraphs fall between.
156
156
  */
157
- type StepKind = "user" | "prose" | "tool" | "card";
157
+ export type AgentTimelineStepKind = "user" | "prose" | "tool" | "card";
158
+ type StepKind = AgentTimelineStepKind;
158
159
 
159
- function stepKind(item: AgentTimelineItem): StepKind {
160
+ /** What a row is, for the gap above the next one. */
161
+ export function agentTimelineStepKind(item: AgentTimelineItem): AgentTimelineStepKind {
160
162
  if (item.kind === "message") return item.role === "user" ? "user" : "prose";
161
163
  if (item.kind === "status" || item.kind === "artifact") return "card";
162
164
  return "tool";
@@ -282,6 +284,87 @@ function ArtifactCard({ item }: { item: AgentTimelineArtifactItem }) {
282
284
  );
283
285
  }
284
286
 
287
+ /** The transcript column every timeline sits in: centred, at the reading width. */
288
+ export function AgentTimelineColumn({ className, children }: { className?: string; children?: ReactNode }) {
289
+ return <div className={cn("mx-auto flex w-full max-w-5xl flex-col px-4 py-4", className)}>{children}</div>;
290
+ }
291
+
292
+ export interface AgentTimelineStepProps {
293
+ item: AgentTimelineItem;
294
+ /** The kind of the row above, which sets the gap; omit for the first row. */
295
+ previous?: AgentTimelineStepKind;
296
+ /** Draw the message's author line (the first prose of a turn). */
297
+ headed?: boolean;
298
+ renderToolActions?: (part: ToolPart) => ReactNode;
299
+ viewerId?: string;
300
+ }
301
+
302
+ /**
303
+ * One row of the timeline with the gap its neighbour pair calls for. A
304
+ * consumer that windows a long transcript renders these inside one
305
+ * `AgentTimelineColumn`, so the rows keep the column's rhythm and edge.
306
+ */
307
+ export function AgentTimelineStep({ item, previous, headed, renderToolActions, viewerId }: AgentTimelineStepProps) {
308
+ const kind = agentTimelineStepKind(item);
309
+ return (
310
+ <div data-timeline-step={kind} className={cn(spacingBefore(previous, kind), kind === "tool" && ROW_BLEED)}>
311
+ <TimelineItem item={item} headed={headed} renderToolActions={renderToolActions} viewerId={viewerId} />
312
+ </div>
313
+ );
314
+ }
315
+
316
+ function TimelineItem({ item, headed, renderToolActions, viewerId }: Omit<AgentTimelineStepProps, "previous">): ReactNode {
317
+ if (item.kind === "message") {
318
+ return item.role === "user" ? (
319
+ <UserMessage content={item.content} timestamp={item.timestamp} author={item.author} viewerId={viewerId} />
320
+ ) : (
321
+ <AssistantMessage item={item} author={headed ? item.author : undefined} />
322
+ );
323
+ }
324
+
325
+ if (item.kind === "tool") {
326
+ return (
327
+ <ToolCallStep
328
+ type={item.call.type}
329
+ label={item.call.label}
330
+ status={item.call.status}
331
+ detail={item.call.detail}
332
+ output={item.call.output}
333
+ duration={item.call.duration}
334
+ part={item.part}
335
+ actions={item.part ? renderToolActions?.(item.part) : undefined}
336
+ />
337
+ );
338
+ }
339
+
340
+ if (item.kind === "tool_group") {
341
+ return (
342
+ <ToolCallGroup title={item.title}>
343
+ {item.calls.map((call, callIndex) => {
344
+ const part = item.parts?.[callIndex];
345
+ return (
346
+ <ToolCallStep
347
+ key={call.id}
348
+ type={call.type}
349
+ label={call.label}
350
+ status={call.status}
351
+ detail={call.detail}
352
+ output={call.output}
353
+ duration={call.duration}
354
+ part={part}
355
+ actions={part ? renderToolActions?.(part) : undefined}
356
+ />
357
+ );
358
+ })}
359
+ </ToolCallGroup>
360
+ );
361
+ }
362
+
363
+ if (item.kind === "status") return <StatusCard item={item} />;
364
+ if (item.kind === "artifact") return <ArtifactCard item={item} />;
365
+ return item.content;
366
+ }
367
+
285
368
  /**
286
369
  * AgentTimeline — unified mixed-content transcript for agent-backed sandbox
287
370
  * sessions. Renders messages, tool rows, status cards, and artifact handoffs
@@ -352,84 +435,29 @@ export function AgentTimeline({
352
435
  speakingAgent = item.author?.id;
353
436
  }
354
437
 
355
- const renderItem = (item: AgentTimelineItem): ReactNode => {
356
- if (item.kind === "message") {
357
- return item.role === "user" ? (
358
- <UserMessage content={item.content} timestamp={item.timestamp} author={item.author} viewerId={viewerId} />
359
- ) : (
360
- <AssistantMessage item={item} author={headedAgentMessages.has(item.id) ? item.author : undefined} />
361
- );
362
- }
363
-
364
- if (item.kind === "tool") {
365
- return (
366
- <ToolCallStep
367
- type={item.call.type}
368
- label={item.call.label}
369
- status={item.call.status}
370
- detail={item.call.detail}
371
- output={item.call.output}
372
- duration={item.call.duration}
373
- part={item.part}
374
- actions={item.part ? renderToolActions?.(item.part) : undefined}
375
- />
376
- );
377
- }
378
-
379
- if (item.kind === "tool_group") {
380
- return (
381
- <ToolCallGroup title={item.title}>
382
- {item.calls.map((call, callIndex) => {
383
- const part = item.parts?.[callIndex];
384
- return (
385
- <ToolCallStep
386
- key={call.id}
387
- type={call.type}
388
- label={call.label}
389
- status={call.status}
390
- detail={call.detail}
391
- output={call.output}
392
- duration={call.duration}
393
- part={part}
394
- actions={part ? renderToolActions?.(part) : undefined}
395
- />
396
- );
397
- })}
398
- </ToolCallGroup>
399
- );
400
- }
401
-
402
- if (item.kind === "status") return <StatusCard item={item} />;
403
- if (item.kind === "artifact") return <ArtifactCard item={item} />;
404
- return item.content;
405
- };
406
-
407
438
  return (
408
- <div className={cn("mx-auto flex w-full max-w-5xl flex-col px-4 py-4", className)}>
409
- {renderList.map((item, index) => {
410
- const kind = stepKind(item);
411
- const prev = index > 0 ? stepKind(renderList[index - 1]) : undefined;
412
- return (
413
- <div
414
- key={item.id}
415
- data-timeline-step={kind}
416
- className={cn(spacingBefore(prev, kind), kind === "tool" && ROW_BLEED)}
417
- >
418
- {renderItem(item)}
419
- </div>
420
- );
421
- })}
439
+ <AgentTimelineColumn className={className}>
440
+ {renderList.map((item, index) => (
441
+ <AgentTimelineStep
442
+ key={item.id}
443
+ item={item}
444
+ previous={index > 0 ? agentTimelineStepKind(renderList[index - 1]) : undefined}
445
+ headed={headedAgentMessages.has(item.id)}
446
+ renderToolActions={renderToolActions}
447
+ viewerId={viewerId}
448
+ />
449
+ ))}
422
450
  {collapsible ? (
423
451
  <button
424
452
  type="button"
425
453
  onClick={() => setExpanded((value) => !value)}
426
- className="mt-2 self-start text-xs font-medium text-muted-foreground transition-colors hover:text-foreground"
454
+ className="mt-2 self-start text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
427
455
  >
428
456
  {collapsed
429
457
  ? `Show ${hiddenCount} more step${hiddenCount === 1 ? "" : "s"}`
430
458
  : "Show less"}
431
459
  </button>
432
460
  ) : null}
433
- </div>
461
+ </AgentTimelineColumn>
434
462
  );
435
463
  }
package/src/chat/index.ts CHANGED
@@ -7,7 +7,12 @@ export type { ChatAuthor } from "../types/message";
7
7
  export { ThinkingIndicator, type ThinkingIndicatorProps } from "./thinking-indicator";
8
8
  export {
9
9
  AgentTimeline,
10
+ AgentTimelineColumn,
11
+ AgentTimelineStep,
12
+ agentTimelineStepKind,
10
13
  type AgentTimelineProps,
14
+ type AgentTimelineStepProps,
15
+ type AgentTimelineStepKind,
11
16
  type AgentTimelineItem,
12
17
  type AgentTimelineMessageItem,
13
18
  type AgentTimelineToolItem,
@@ -28,8 +28,8 @@ describe("a transcript without authors", () => {
28
28
  })
29
29
 
30
30
  it("renders UserMessage actions and application notes as before", () => {
31
- expect(html(<UserMessage content="Can I break my lease early?" actions={<button type="button">Copy</button>} />)).toMatchInlineSnapshot(`"<div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Can I break my lease early?</div></div><div class="flex flex-wrap items-center justify-end gap-1.5 text-xs text-muted-foreground"><button type="button">Copy</button></div></div></div>"`)
32
- expect(html(<UserMessage parts={segmentedParts} actions={<button type="button">Copy</button>} />)).toMatchInlineSnapshot(`"<div class="space-y-2"><div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">I signed the lease in March.</div></div></div></div><div role="note" aria-label="Application note" data-synthetic-text="" class="min-w-0 rounded-md border border-dashed border-border bg-muted/30 px-3 py-2 text-sm text-muted-foreground"><div class="mb-1 font-medium">Application note</div><div class="break-words whitespace-pre-wrap">Lease uploaded: lease.pdf</div></div><div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Here it is.</div></div></div></div><div class="flex flex-wrap items-center justify-end gap-1.5 text-xs text-muted-foreground"><button type="button">Copy</button></div></div>"`)
31
+ expect(html(<UserMessage content="Can I break my lease early?" actions={<button type="button">Copy</button>} />)).toMatchInlineSnapshot(`"<div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Can I break my lease early?</div></div><div class="flex flex-wrap items-center justify-end gap-1.5 text-sm text-muted-foreground"><button type="button">Copy</button></div></div></div>"`)
32
+ expect(html(<UserMessage parts={segmentedParts} actions={<button type="button">Copy</button>} />)).toMatchInlineSnapshot(`"<div class="space-y-2"><div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">I signed the lease in March.</div></div></div></div><div role="note" aria-label="Application note" data-synthetic-text="" class="min-w-0 rounded-md border border-dashed border-border bg-muted/30 px-3 py-2 text-sm text-muted-foreground"><div class="mb-1 font-medium">Application note</div><div class="break-words whitespace-pre-wrap">Lease uploaded: lease.pdf</div></div><div class="flex justify-end"><div class="group flex min-w-0 max-w-[78%] flex-col items-end gap-2"><div class="relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background"><div class="break-words whitespace-pre-wrap tangle-transcript-text text-[length:var(--transcript-font-size)] leading-[var(--transcript-line-height)]">Here it is.</div></div></div></div><div class="flex flex-wrap items-center justify-end gap-1.5 text-sm text-muted-foreground"><button type="button">Copy</button></div></div>"`)
33
33
  })
34
34
 
35
35
  it("renders UserMessage as before", () => {
@@ -31,7 +31,7 @@ function formatTime(date: Date): string {
31
31
 
32
32
  function MessageActions({ children, align = "end" }: { children: ReactNode; align?: "start" | "end" }) {
33
33
  return (
34
- <div className={`flex flex-wrap items-center ${align === "end" ? "justify-end" : "justify-start"} gap-1.5 text-xs text-muted-foreground`}>
34
+ <div className={`flex flex-wrap items-center ${align === "end" ? "justify-end" : "justify-start"} gap-1.5 text-sm text-muted-foreground`}>
35
35
  {children}
36
36
  </div>
37
37
  );
@@ -191,15 +191,17 @@ describe("each primitive renders its interaction helper", () => {
191
191
  expect(classes(screen.getByText(/Guests, staff/))).toContain("line-clamp-2");
192
192
  });
193
193
 
194
- it("SegmentedControl row: a well track, soft items, the selected state on aria-checked", () => {
194
+ it("SegmentedControl row: a quiet well track, soft items, a raised thumb on aria-checked and no ring", () => {
195
195
  const options = [{ value: "a", label: "A–Z" }, { value: "b", label: "Recent" }];
196
196
  render(<SegmentedControl aria-label="Sort" value="a" onValueChange={() => {}} options={options} />);
197
197
  const track = screen.getByRole("radiogroup");
198
198
  expect(classes(track)).toContain("bg-[var(--well)]");
199
- expect(classes(track)).toContain("border-[var(--field-border)]");
199
+ expect(classes(track)).toContain("border-border");
200
200
  expect(classes(track)).not.toContain("bg-card");
201
201
  for (const radio of screen.getAllByRole("radio")) {
202
- expectHelpers(radio, ixControlSoft, ixSelected);
202
+ expectHelpers(radio, ixControlSoft);
203
+ expect(classes(radio)).toContain("aria-checked:bg-card");
204
+ expect([...classes(radio)].some((token) => token.includes("--ix-sel-ring"))).toBe(false);
203
205
  for (const token of FOCUS_RING) expect(classes(radio)).toContain(token);
204
206
  expect(classes(radio)).not.toContain("bg-[var(--accent-surface)]");
205
207
  }
@@ -271,9 +271,10 @@ describe("SegmentedControl", () => {
271
271
  const radiogroup = screen.getByRole("radiogroup")
272
272
  expect(radiogroup.className).toContain("flex-wrap")
273
273
  expect(radiogroup.className).toContain("rounded-lg")
274
- // The row track is a field well, so it steps off whatever plane holds it.
274
+ // The row track is one quiet well: the hairline border, not a field's strong border.
275
275
  expect(radiogroup.className).toContain("bg-[var(--well)]")
276
- expect(radiogroup.className).toContain("border-[var(--field-border)]")
276
+ expect(radiogroup.className).toContain("border-border")
277
+ expect(radiogroup.className).not.toContain("border-[var(--field-border)]")
277
278
  })
278
279
 
279
280
  it("applies tabs variant classes with nowrap", () => {
@@ -6,9 +6,13 @@ import { ChevronLeft, ChevronRight } from "lucide-react"
6
6
  import * as React from "react"
7
7
  import { touchTarget } from "../lib/control-presentation"
8
8
  import { focusRing, focusRingInset } from "../lib/focus"
9
- import { ixControlSoft, ixSelected, ixTabUnderline } from "../lib/interaction"
9
+ import { ixControlSoft, ixTabUnderline } from "../lib/interaction"
10
10
  import { cn } from "../lib/utils"
11
11
 
12
+ /** The row variant's selected segment: a raised thumb on the well, not a tint inside a ring. */
13
+ const rowThumb =
14
+ "aria-checked:bg-card aria-checked:border-border aria-checked:shadow-[0_1px_2px_rgb(0_0_0/0.08)] hover:aria-checked:bg-card"
15
+
12
16
  /**
13
17
  * Visually lightweight segmented control for single-value selection.
14
18
  *
@@ -21,10 +25,13 @@ import { cn } from "../lib/utils"
21
25
  * console warning fires when both are omitted.
22
26
  *
23
27
  * Design rules baked into the default variant:
24
- * - The row track is a field well (`--well`, `--field-border`), so the
25
- * control reads as one inset group on whatever plane it sits on.
26
- * - Only the SELECTED segment shows a surface colour + accent text: the
27
- * shared selected state (`ixSelected`: tint plus an inset ring). A tab
28
+ * - The row track is one quiet well (`--well`, the hairline `border`), so
29
+ * the control reads as one inset group on whatever plane it sits on, and
30
+ * it is compact (36px) so it sits inside a 44px toolbar with air above
31
+ * and below instead of touching its edges.
32
+ * - Only the SELECTED segment shows a surface: a raised thumb (the card
33
+ * colour with a hairline and a soft shadow) with accent text. No ring is
34
+ * drawn around the track's segments, so the group never stacks rings. A tab
28
35
  * shows it as an underline instead (`ixTabUnderline`).
29
36
  * - Unselected segments have NO background — they're plain-text labels
30
37
  * that darken on hover. This keeps the selected segment as the
@@ -224,7 +231,7 @@ export function SegmentedControl<T extends string = string>({
224
231
  className={cn(
225
232
  "relative flex gap-1",
226
233
  variant === "row" &&
227
- "flex-wrap items-center rounded-lg border border-[var(--field-border)] bg-[var(--well)] p-1",
234
+ "flex-wrap items-center rounded-lg border border-border bg-[var(--well)] p-0.5",
228
235
  variant === "tabs" &&
229
236
  "flex-nowrap items-end border-b border-border pb-0 overflow-x-auto",
230
237
  className,
@@ -251,7 +258,7 @@ export function SegmentedControl<T extends string = string>({
251
258
  }}
252
259
  className={cn(
253
260
  "relative inline-flex items-center gap-2 whitespace-nowrap text-sm font-medium transition-[color,background-color,border-color,box-shadow]",
254
- variant === "row" && ["rounded-md border border-transparent px-3 py-1.5", focusRing, ixControlSoft, ixSelected],
261
+ variant === "row" && ["rounded-md border border-transparent px-3 py-1", focusRing, ixControlSoft, rowThumb],
255
262
  // The strip scrolls horizontally, which would clip an outer ring.
256
263
  // The border-b-2 slot stays transparent: the underline is ixTabUnderline's inset shadow.
257
264
  variant === "tabs" && ["shrink-0 rounded-none border-b-2 border-transparent -mb-px px-4 py-2", touchTarget, focusRingInset, ixTabUnderline],
@@ -80,7 +80,7 @@ export const InlineThinkingItem = memo(
80
80
  </div>
81
81
  </ExpandableContent>
82
82
  ) : (
83
- <div className="px-3 py-2.5 text-xs text-muted-foreground">
83
+ <div className="px-3 py-2.5 text-sm text-muted-foreground">
84
84
  No reasoning text provided.
85
85
  </div>
86
86
  )}
@@ -57,7 +57,7 @@ describe("InlineToolItem", () => {
57
57
  expect(container.querySelector(".tangle-text-shimmer")).not.toBeNull();
58
58
  });
59
59
 
60
- it("keeps the red dot and the collapsed error on failure", () => {
60
+ it("marks a failure on its glyph and keeps the collapsed error", () => {
61
61
  const { container } = render(
62
62
  <InlineToolItem
63
63
  part={part({ status: "error", error: "ENOENT: no such file", output: undefined })}
@@ -40,7 +40,7 @@ describe("RunRowShell", () => {
40
40
  expect(container.querySelector("[data-run-row-status]")).toBeNull();
41
41
  });
42
42
 
43
- it("renders the red dot and the collapsed error on error", () => {
43
+ it("marks a failure on the row's own glyph, with the collapsed error under it", () => {
44
44
  const { container } = renderShell("error", {
45
45
  collapsedError: "exit code 1",
46
46
  });
@@ -7,9 +7,10 @@ import { formatDuration } from "../utils/format";
7
7
  export type RunRowStatus = "running" | "success" | "error" | "idle";
8
8
 
9
9
  /**
10
- * Trailing status indicator shared by every run row. Only `error` draws a
11
- * mark (a red dot). Success is silence, and a running row carries its state in
12
- * the title — a `TextShimmer` sweep — so neither renders anything here.
10
+ * A red dot for a failed row, for rows composed outside the shell. The shell
11
+ * itself marks a failure on the row's own glyph, beside its name, never at the
12
+ * far edge. Success is silence, and a running row carries its state in the
13
+ * title — a `TextShimmer` sweep.
13
14
  */
14
15
  export function RunRowStatusDot({ status }: { status: RunRowStatus }) {
15
16
  if (status !== "error") return null;
@@ -132,7 +133,11 @@ export function RunRowShell({
132
133
  >
133
134
  <span
134
135
  aria-hidden
135
- className="flex h-[1.375rem] w-[1.375rem] shrink-0 items-center justify-center text-muted-foreground"
136
+ data-run-row-status={status === "error" ? "error" : undefined}
137
+ className={cn(
138
+ "flex h-[1.375rem] w-[1.375rem] shrink-0 items-center justify-center",
139
+ status === "error" ? "text-[var(--surface-danger-text)]" : "text-muted-foreground",
140
+ )}
136
141
  >
137
142
  <span
138
143
  data-run-row-glyph=""
@@ -166,7 +171,7 @@ export function RunRowShell({
166
171
  {description ? (
167
172
  <span
168
173
  className={cn(
169
- "hidden min-w-0 flex-1 truncate text-sm text-muted-foreground transition-colors group-hover:text-foreground sm:inline",
174
+ "min-w-0 flex-1 truncate text-sm text-muted-foreground transition-colors group-hover:text-foreground",
170
175
  descriptionMono && "font-mono",
171
176
  )}
172
177
  >
@@ -174,24 +179,21 @@ export function RunRowShell({
174
179
  </span>
175
180
  ) : null}
176
181
 
177
- <span className="ml-auto flex shrink-0 items-center gap-1.5">
178
- {!isRunning && durationMs != null ? (
179
- <span
180
- data-run-row-duration=""
181
- className="font-mono text-[10px] tabular-nums text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100"
182
- >
183
- {formatDuration(durationMs)}
184
- </span>
185
- ) : null}
186
- <RunRowStatusDot status={status} />
187
- </span>
182
+ {!isRunning && durationMs != null ? (
183
+ <span
184
+ data-run-row-duration=""
185
+ className="ml-auto shrink-0 font-mono text-sm tabular-nums text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100"
186
+ >
187
+ {formatDuration(durationMs)}
188
+ </span>
189
+ ) : null}
188
190
  </button>
189
191
  </Collapsible.Trigger>
190
192
 
191
193
  {collapsedError && !open ? (
192
194
  <div
193
195
  className={cn(
194
- "pb-1.5 pr-2 text-xs leading-snug text-[var(--surface-danger-text)]",
196
+ "pb-1.5 pr-2 text-sm leading-snug text-[var(--surface-danger-text)]",
195
197
  ERROR_INDENT,
196
198
  )}
197
199
  >