@tangle-network/ui 11.6.0 → 11.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +43 -0
  3. package/dist/chat.d.ts +18 -8
  4. package/dist/chat.js +6 -5
  5. package/dist/{chunk-XROQW5J7.js → chunk-4ENFLPWQ.js} +1 -1
  6. package/dist/{chunk-XPYPZMYT.js → chunk-6RIX7M27.js} +1 -1
  7. package/dist/{chunk-R5GVQDL3.js → chunk-CVX53NCC.js} +7 -5
  8. package/dist/{chunk-ULDNFLIM.js → chunk-EIUE5GV2.js} +10 -14
  9. package/dist/chunk-L57WRIND.js +59 -0
  10. package/dist/chunk-LFVF2HFB.js +19 -0
  11. package/dist/{chunk-AZWDI2JG.js → chunk-UYTRNR7Z.js} +1 -1
  12. package/dist/{chunk-RKC3GXHE.js → chunk-VDCZHOOO.js} +99 -104
  13. package/dist/{chunk-J2G7KCYH.js → chunk-XT4JMYVB.js} +109 -67
  14. package/dist/hooks.js +6 -5
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.js +15 -10
  17. package/dist/primitives.d.ts +15 -1
  18. package/dist/primitives.js +5 -1
  19. package/dist/run.d.ts +22 -17
  20. package/dist/run.js +8 -6
  21. package/dist/sdk-hooks.js +6 -5
  22. package/dist/utils.d.ts +6 -0
  23. package/dist/utils.js +1 -1
  24. package/package.json +1 -1
  25. package/src/chat/agent-timeline.stories.tsx +163 -10
  26. package/src/chat/agent-timeline.test.tsx +114 -7
  27. package/src/chat/agent-timeline.tsx +120 -158
  28. package/src/chat/chat-container.test.tsx +59 -0
  29. package/src/chat/user-message.test.tsx +33 -0
  30. package/src/chat/user-message.tsx +13 -8
  31. package/src/primitives/index.ts +3 -0
  32. package/src/primitives/text-shimmer.test.tsx +34 -0
  33. package/src/primitives/text-shimmer.tsx +82 -0
  34. package/src/run/inline-thinking-item.stories.tsx +2 -2
  35. package/src/run/inline-thinking-item.tsx +2 -2
  36. package/src/run/inline-tool-item.test.tsx +76 -0
  37. package/src/run/inline-tool-item.tsx +9 -7
  38. package/src/run/run-group.tsx +4 -3
  39. package/src/run/run-row-shell.test.tsx +74 -4
  40. package/src/run/run-row-shell.tsx +81 -53
  41. package/src/run/tool-call-step.tsx +9 -7
  42. package/src/utils/tool-display.test.ts +53 -0
  43. package/src/utils/tool-display.ts +16 -15
  44. package/dist/chunk-LQS34IGP.js +0 -0
  45. /package/dist/{chunk-EJ5NBW7V.js → chunk-LDLOJKPC.js} +0 -0
@@ -2,18 +2,18 @@ import {
2
2
  useAutoScroll,
3
3
  useRunCollapseState,
4
4
  useRunGroups
5
- } from "./chunk-AZWDI2JG.js";
5
+ } from "./chunk-UYTRNR7Z.js";
6
6
  import {
7
7
  InlineThinkingItem,
8
8
  RunGroup
9
- } from "./chunk-R5GVQDL3.js";
9
+ } from "./chunk-CVX53NCC.js";
10
10
  import {
11
11
  ToolCallGroup,
12
12
  ToolCallStep
13
- } from "./chunk-J2G7KCYH.js";
13
+ } from "./chunk-XT4JMYVB.js";
14
14
  import {
15
15
  getToolDisplayMetadata
16
- } from "./chunk-ULDNFLIM.js";
16
+ } from "./chunk-EIUE5GV2.js";
17
17
  import {
18
18
  OpenUIArtifactRenderer
19
19
  } from "./chunk-3M7BPSSW.js";
@@ -45,10 +45,17 @@ var UserMessage = memo(
45
45
  ({ message: _message, parts, content, timestamp, actions }) => {
46
46
  const text = content ?? (parts ?? []).filter((p) => p.type === "text").map((p) => p.text).join("\n");
47
47
  if (!text.trim()) return null;
48
- return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: "flex max-w-[78%] flex-col items-end gap-2", children: [
49
- /* @__PURE__ */ jsxs("div", { className: "w-full rounded-2xl border border-border bg-muted/50 px-4 py-3", children: [
50
- timestamp ? /* @__PURE__ */ jsx("div", { className: "mb-1.5 text-right text-[var(--font-size-xs)] text-muted-foreground", children: formatTime(timestamp) }) : null,
51
- /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)] text-foreground", children: text })
48
+ return /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxs("div", { className: "group flex max-w-[78%] flex-col items-end gap-2", children: [
49
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full rounded-2xl bg-muted/50 px-4 py-3", children: [
50
+ timestamp ? /* @__PURE__ */ jsx(
51
+ "span",
52
+ {
53
+ "data-user-message-time": "",
54
+ className: "pointer-events-none absolute right-full top-1/2 mr-3 -translate-y-1/2 whitespace-nowrap text-[var(--font-size-xs)] text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
55
+ children: formatTime(timestamp)
56
+ }
57
+ ) : null,
58
+ /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[1.5] text-foreground", children: text })
52
59
  ] }),
53
60
  actions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center justify-end gap-1.5 text-xs text-muted-foreground", children: actions }) : null
54
61
  ] }) });
@@ -146,55 +153,56 @@ function ThinkingIndicator({ className }) {
146
153
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
147
154
  var TONE_STYLES = {
148
155
  default: {
149
- dot: "bg-[var(--border-hover)]",
150
156
  card: "border-border bg-card",
151
157
  text: "text-foreground",
152
158
  icon: CircleDot
153
159
  },
154
160
  info: {
155
- dot: "bg-[var(--surface-info-text)]",
156
161
  card: "border-[var(--surface-info-border)] bg-[var(--surface-info-bg)]",
157
162
  text: "text-[var(--surface-info-text)]",
158
163
  icon: Info
159
164
  },
160
165
  success: {
161
- dot: "bg-[var(--surface-success-text)]",
162
166
  card: "border-[var(--surface-success-border)] bg-[var(--surface-success-bg)]",
163
167
  text: "text-[var(--surface-success-text)]",
164
168
  icon: CheckCircle2
165
169
  },
166
170
  warning: {
167
- dot: "bg-[var(--surface-warning-text)]",
168
171
  card: "border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)]",
169
172
  text: "text-[var(--surface-warning-text)]",
170
173
  icon: AlertTriangle
171
174
  },
172
175
  error: {
173
- dot: "bg-[var(--surface-danger-text)]",
174
176
  card: "border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)]",
175
177
  text: "text-[var(--surface-danger-text)]",
176
178
  icon: AlertTriangle
177
179
  }
178
180
  };
179
- function formatTime2(date) {
180
- return date.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit" });
181
+ function stepKind(item) {
182
+ if (item.kind === "message") return item.role === "user" ? "user" : "prose";
183
+ if (item.kind === "status" || item.kind === "artifact") return "card";
184
+ return "tool";
181
185
  }
182
- var CARD_ROW_DOT = "mt-[calc((2.5rem-var(--timeline-dot-size))/2)]";
183
- function AgentTimelineRow({ isLast, accentClassName, dotClassName = "mt-2", children }) {
184
- return /* @__PURE__ */ jsxs3("div", { className: "grid grid-cols-[1.25rem_minmax(0,1fr)] gap-x-4", children: [
185
- /* @__PURE__ */ jsxs3("div", { className: "relative flex justify-center", children: [
186
- !isLast && /* @__PURE__ */ jsx4("span", { className: "absolute top-4 bottom-[-0.75rem] left-1/2 w-px -translate-x-1/2 bg-border" }),
187
- /* @__PURE__ */ jsx4("span", { className: cn("relative h-[var(--timeline-dot-size)] w-[var(--timeline-dot-size)] rounded-full ring-4 ring-[var(--bg-root)]", dotClassName, accentClassName) })
188
- ] }),
189
- /* @__PURE__ */ jsx4("div", { className: "min-w-0 pb-3", children })
190
- ] });
186
+ function spacingBefore(prev, next) {
187
+ if (prev === void 0) return "";
188
+ if (prev === "user" || next === "user") return "mt-4";
189
+ if (prev === "card" || next === "card") return "mt-2";
190
+ if (prev === "tool" || next === "tool") return "mt-1";
191
+ return "mt-3";
191
192
  }
193
+ var ROW_BLEED = "-mx-3";
192
194
  function AssistantMessage({ item }) {
193
- return /* @__PURE__ */ jsxs3("div", { className: "-mt-0.5", children: [
194
- item.timestamp && /* @__PURE__ */ jsx4("div", { className: "mb-2 text-[var(--font-size-xs)] text-muted-foreground", children: formatTime2(item.timestamp) }),
195
- item.content && /* @__PURE__ */ jsx4(Markdown, { className: "tangle-prose text-[var(--font-size-base)] leading-[var(--line-height-base)]", children: item.content }),
196
- item.isStreaming && /* @__PURE__ */ jsx4("span", { className: "ml-0.5 inline-block h-4 w-2 animate-pulse rounded-sm bg-primary align-text-bottom" }),
197
- item.toolCalls && /* @__PURE__ */ jsx4("div", { className: "mt-3", children: item.toolCalls }),
195
+ return /* @__PURE__ */ jsxs3("div", { children: [
196
+ item.content && /* @__PURE__ */ jsx4(Markdown, { className: "tangle-prose text-[var(--font-size-base)] leading-[1.5]", children: item.content }),
197
+ item.isStreaming && /* @__PURE__ */ jsx4(
198
+ "span",
199
+ {
200
+ "aria-hidden": true,
201
+ "data-streaming-caret": "",
202
+ className: "ml-0.5 inline-block h-[1em] w-0.5 animate-pulse rounded-full bg-muted-foreground align-text-bottom"
203
+ }
204
+ ),
205
+ item.toolCalls && /* @__PURE__ */ jsx4("div", { className: "mt-1", children: item.toolCalls }),
198
206
  item.after && /* @__PURE__ */ jsx4("div", { className: "mt-3 border-t border-border pt-3", children: item.after })
199
207
  ] });
200
208
  }
@@ -252,101 +260,88 @@ function AgentTimeline({
252
260
  }
253
261
  const renderedItems = isThinking ? [...items, { id: "__thinking__", kind: "custom", content: /* @__PURE__ */ jsx4(ThinkingIndicator, {}) }] : items;
254
262
  const isUserMessage = (item) => item.kind === "message" && item.role === "user";
255
- const timelineItems = renderedItems.filter((item) => !isUserMessage(item));
263
+ const stepItems = renderedItems.filter((item) => !isUserMessage(item));
256
264
  const limit = collapseAfter ?? Infinity;
257
- const collapsible = timelineItems.length > limit;
265
+ const collapsible = stepItems.length > limit;
258
266
  const collapsed = collapsible && !expanded;
259
267
  let renderList = renderedItems;
260
268
  let hiddenCount = 0;
261
269
  if (collapsed) {
262
270
  const visible = [];
263
- let spineCount = 0;
271
+ let stepCount = 0;
264
272
  for (const item of renderedItems) {
265
- if (spineCount >= limit) break;
273
+ if (stepCount >= limit) break;
266
274
  visible.push(item);
267
- if (!isUserMessage(item)) spineCount += 1;
275
+ if (!isUserMessage(item)) stepCount += 1;
268
276
  }
269
277
  renderList = visible;
270
- hiddenCount = timelineItems.length - limit;
278
+ hiddenCount = stepItems.length - limit;
271
279
  }
272
- const visibleSpine = renderList.filter((item) => !isUserMessage(item));
273
- const lastSpineItem = collapsible ? void 0 : visibleSpine[visibleSpine.length - 1];
274
- return /* @__PURE__ */ jsxs3("div", { className: cn("mx-auto w-full max-w-5xl px-4 py-4", className), children: [
275
- renderList.map((item) => {
276
- if (item.kind === "message" && item.role === "user") {
277
- return /* @__PURE__ */ jsx4("div", { className: "mt-6 mb-4 first:mt-0", children: /* @__PURE__ */ jsx4(UserMessage, { content: item.content, timestamp: item.timestamp }) }, item.id);
278
- }
279
- const isLast = item === lastSpineItem;
280
- if (item.kind === "message") {
281
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--brand-glow)]", children: /* @__PURE__ */ jsx4(AssistantMessage, { item }) }, item.id);
282
- }
283
- if (item.kind === "tool") {
284
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", dotClassName: CARD_ROW_DOT, children: /* @__PURE__ */ jsx4(
285
- ToolCallStep,
286
- {
287
- type: item.call.type,
288
- label: item.call.label,
289
- status: item.call.status,
290
- detail: item.call.detail,
291
- output: item.call.output,
292
- duration: item.call.duration,
293
- part: item.part,
294
- actions: item.part ? renderToolActions?.(item.part) : void 0
295
- }
296
- ) }, item.id);
297
- }
298
- if (item.kind === "tool_group") {
299
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", dotClassName: CARD_ROW_DOT, children: /* @__PURE__ */ jsx4(ToolCallGroup, { title: item.title, children: item.calls.map((call, callIndex) => {
300
- const part = item.parts?.[callIndex];
301
- return /* @__PURE__ */ jsx4(
302
- ToolCallStep,
303
- {
304
- type: call.type,
305
- label: call.label,
306
- status: call.status,
307
- detail: call.detail,
308
- output: call.output,
309
- duration: call.duration,
310
- part,
311
- actions: part ? renderToolActions?.(part) : void 0
312
- },
313
- call.id
314
- );
315
- }) }) }, item.id);
316
- }
317
- if (item.kind === "status") {
318
- return /* @__PURE__ */ jsx4(
319
- AgentTimelineRow,
320
- {
321
- isLast,
322
- accentClassName: TONE_STYLES[item.tone ?? "default"].dot,
323
- children: /* @__PURE__ */ jsx4(StatusCard, { item })
324
- },
325
- item.id
326
- );
327
- }
328
- if (item.kind === "artifact") {
280
+ const renderItem = (item) => {
281
+ if (item.kind === "message") {
282
+ return item.role === "user" ? /* @__PURE__ */ jsx4(UserMessage, { content: item.content, timestamp: item.timestamp }) : /* @__PURE__ */ jsx4(AssistantMessage, { item });
283
+ }
284
+ if (item.kind === "tool") {
285
+ return /* @__PURE__ */ jsx4(
286
+ ToolCallStep,
287
+ {
288
+ type: item.call.type,
289
+ label: item.call.label,
290
+ status: item.call.status,
291
+ detail: item.call.detail,
292
+ output: item.call.output,
293
+ duration: item.call.duration,
294
+ part: item.part,
295
+ actions: item.part ? renderToolActions?.(item.part) : void 0
296
+ }
297
+ );
298
+ }
299
+ if (item.kind === "tool_group") {
300
+ return /* @__PURE__ */ jsx4(ToolCallGroup, { title: item.title, children: item.calls.map((call, callIndex) => {
301
+ const part = item.parts?.[callIndex];
329
302
  return /* @__PURE__ */ jsx4(
330
- AgentTimelineRow,
303
+ ToolCallStep,
331
304
  {
332
- isLast,
333
- accentClassName: TONE_STYLES[item.tone ?? "default"].dot,
334
- children: /* @__PURE__ */ jsx4(ArtifactCard, { item })
305
+ type: call.type,
306
+ label: call.label,
307
+ status: call.status,
308
+ detail: call.detail,
309
+ output: call.output,
310
+ duration: call.duration,
311
+ part,
312
+ actions: part ? renderToolActions?.(part) : void 0
335
313
  },
336
- item.id
314
+ call.id
337
315
  );
338
- }
339
- return /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast, accentClassName: "bg-[var(--border-hover)]", dotClassName: CARD_ROW_DOT, children: item.content }, item.id);
316
+ }) });
317
+ }
318
+ if (item.kind === "status") return /* @__PURE__ */ jsx4(StatusCard, { item });
319
+ if (item.kind === "artifact") return /* @__PURE__ */ jsx4(ArtifactCard, { item });
320
+ return item.content;
321
+ };
322
+ return /* @__PURE__ */ jsxs3("div", { className: cn("mx-auto flex w-full max-w-5xl flex-col px-4 py-4", className), children: [
323
+ renderList.map((item, index) => {
324
+ const kind = stepKind(item);
325
+ const prev = index > 0 ? stepKind(renderList[index - 1]) : void 0;
326
+ return /* @__PURE__ */ jsx4(
327
+ "div",
328
+ {
329
+ "data-timeline-step": kind,
330
+ className: cn(spacingBefore(prev, kind), kind === "tool" && ROW_BLEED),
331
+ children: renderItem(item)
332
+ },
333
+ item.id
334
+ );
340
335
  }),
341
- collapsible ? /* @__PURE__ */ jsx4(AgentTimelineRow, { isLast: true, accentClassName: "bg-[var(--border-hover)]", children: /* @__PURE__ */ jsx4(
336
+ collapsible ? /* @__PURE__ */ jsx4(
342
337
  "button",
343
338
  {
344
339
  type: "button",
345
340
  onClick: () => setExpanded((value) => !value),
346
- className: "text-xs font-medium text-muted-foreground transition-colors hover:text-foreground",
341
+ className: "mt-2 self-start text-xs font-medium text-muted-foreground transition-colors hover:text-foreground",
347
342
  children: collapsed ? `Show ${hiddenCount} more step${hiddenCount === 1 ? "" : "s"}` : "Show less"
348
343
  }
349
- ) }) : null
344
+ ) : null
350
345
  ] });
351
346
  }
352
347
 
@@ -693,7 +688,7 @@ function ChatMessage({
693
688
  children: [
694
689
  !hideRoleLabel && /* @__PURE__ */ jsxs5("div", { className: cn("flex items-center gap-2 px-1", isUser && "flex-row-reverse"), children: [
695
690
  /* @__PURE__ */ jsx6("span", { className: "font-medium text-foreground text-xs", children: isUser ? userLabel : assistantLabel }),
696
- timestamp && /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground text-xs", children: formatTime3(timestamp) })
691
+ timestamp && /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground text-xs", children: formatTime2(timestamp) })
697
692
  ] }),
698
693
  /* @__PURE__ */ jsxs5(
699
694
  "div",
@@ -716,7 +711,7 @@ function ChatMessage({
716
711
  }
717
712
  );
718
713
  }
719
- function formatTime3(date) {
714
+ function formatTime2(date) {
720
715
  return date.toLocaleTimeString(void 0, {
721
716
  hour: "numeric",
722
717
  minute: "2-digit"
@@ -3,7 +3,7 @@ import {
3
3
  getToolCategory,
4
4
  getToolDisplayMetadata,
5
5
  getToolErrorText
6
- } from "./chunk-ULDNFLIM.js";
6
+ } from "./chunk-EIUE5GV2.js";
7
7
  import {
8
8
  CommandPreview,
9
9
  DiffPreview,
@@ -13,6 +13,9 @@ import {
13
13
  WebSearchPreview,
14
14
  WriteFilePreview
15
15
  } from "./chunk-AAUNOHVL.js";
16
+ import {
17
+ TextShimmer
18
+ } from "./chunk-L57WRIND.js";
16
19
  import {
17
20
  CodeBlock
18
21
  } from "./chunk-WUQDUBJG.js";
@@ -204,34 +207,20 @@ var ExpandedToolDetail = memo(({ part }) => {
204
207
  });
205
208
  ExpandedToolDetail.displayName = "ExpandedToolDetail";
206
209
 
207
- // src/run/run-item-primitives.tsx
208
- import { useEffect as useEffect2, useState as useState2 } from "react";
209
- import { jsx as jsx3 } from "react/jsx-runtime";
210
- function LiveDuration({ startTime }) {
211
- const [elapsed, setElapsed] = useState2(Date.now() - startTime);
212
- useEffect2(() => {
213
- const id = setInterval(() => setElapsed(Date.now() - startTime), 100);
214
- return () => clearInterval(id);
215
- }, [startTime]);
216
- return /* @__PURE__ */ jsx3("span", { className: "text-xs font-mono text-neutral-400 dark:text-neutral-500 tabular-nums", children: formatDuration(elapsed) });
217
- }
218
-
219
210
  // src/run/run-row-shell.tsx
220
- import { useState as useState3 } from "react";
211
+ import { useState as useState2 } from "react";
221
212
  import * as Collapsible from "@radix-ui/react-collapsible";
222
- import { Loader2 as Loader22, ChevronRight } from "lucide-react";
223
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
213
+ import { ChevronRight } from "lucide-react";
214
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
224
215
  function RunRowStatusDot({ status }) {
225
- if (status === "running") {
226
- return /* @__PURE__ */ jsx4(Loader22, { className: "h-3 w-3 shrink-0 animate-spin text-[var(--accent-text)]" });
227
- }
228
- if (status === "success") {
229
- return /* @__PURE__ */ jsx4("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-success-text)]" });
230
- }
231
- if (status === "error") {
232
- return /* @__PURE__ */ jsx4("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-danger-text)]" });
233
- }
234
- return null;
216
+ if (status !== "error") return null;
217
+ return /* @__PURE__ */ jsx3(
218
+ "span",
219
+ {
220
+ "data-run-row-status": "error",
221
+ className: "h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-danger-text)]"
222
+ }
223
+ );
235
224
  }
236
225
  var SHAPE_CLASS = {
237
226
  single: "rounded-[var(--radius-lg)]",
@@ -239,13 +228,14 @@ var SHAPE_CLASS = {
239
228
  middle: "rounded-[var(--radius-sm)]",
240
229
  last: "rounded-t-[var(--radius-sm)] rounded-b-[var(--radius-lg)]"
241
230
  };
231
+ var HEADER_INSET = "px-2 py-1";
232
+ var ERROR_INDENT = "pl-[2.375rem]";
242
233
  function RunRowShell({
243
234
  icon,
244
235
  title,
245
236
  description,
246
237
  descriptionMono = false,
247
238
  status = "idle",
248
- startTime,
249
239
  durationMs,
250
240
  groupPosition = "single",
251
241
  collapsedError,
@@ -257,7 +247,7 @@ function RunRowShell({
257
247
  contentClassName,
258
248
  children
259
249
  }) {
260
- const [openState, setOpenState] = useState3(defaultOpen);
250
+ const [openState, setOpenState] = useState2(defaultOpen);
261
251
  const isControlled = openProp !== void 0;
262
252
  const open = isControlled ? openProp : openState;
263
253
  const setOpen = (next) => {
@@ -266,62 +256,110 @@ function RunRowShell({
266
256
  };
267
257
  const isRunning = status === "running";
268
258
  const expandable = children != null;
269
- return /* @__PURE__ */ jsx4(Collapsible.Root, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-2", children: [
259
+ return /* @__PURE__ */ jsx3(Collapsible.Root, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-2", children: [
270
260
  /* @__PURE__ */ jsxs3(
271
261
  "div",
272
262
  {
263
+ "data-run-row": "",
264
+ "data-state": open ? "open" : "closed",
273
265
  className: cn(
274
- "min-w-0 flex-1 overflow-hidden border transition-colors",
275
- "border-[var(--border-subtle)] bg-[var(--md3-surface-container)]",
276
- expandable && "hover:border-border",
277
- open && "border-border",
266
+ "group min-w-0 flex-1 overflow-hidden border transition-colors",
267
+ open ? "border-border bg-[var(--md3-surface-container)]" : "border-transparent bg-transparent",
268
+ expandable && !open && "hover:bg-[var(--md3-surface-container)]",
278
269
  SHAPE_CLASS[groupPosition],
279
270
  className
280
271
  ),
281
272
  children: [
282
- /* @__PURE__ */ jsx4(Collapsible.Trigger, { asChild: true, disabled: !expandable, children: /* @__PURE__ */ jsxs3(
273
+ /* @__PURE__ */ jsx3(Collapsible.Trigger, { asChild: true, disabled: !expandable, children: /* @__PURE__ */ jsxs3(
283
274
  "button",
284
275
  {
285
276
  type: "button",
286
277
  className: cn(
287
- "flex w-full items-center gap-2.5 px-3 py-2 text-left",
278
+ "flex w-full items-center gap-2 text-left",
279
+ HEADER_INSET,
288
280
  expandable ? "cursor-pointer" : "cursor-default"
289
281
  ),
290
282
  children: [
291
- /* @__PURE__ */ jsx4("span", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-border bg-muted text-muted-foreground", children: icon }),
292
- /* @__PURE__ */ jsx4("span", { className: "shrink-0 whitespace-nowrap text-xs font-medium text-foreground", children: title }),
293
- description ? /* @__PURE__ */ jsx4(
283
+ /* @__PURE__ */ jsxs3(
284
+ "span",
285
+ {
286
+ "aria-hidden": true,
287
+ className: "flex h-[1.375rem] w-[1.375rem] shrink-0 items-center justify-center text-muted-foreground",
288
+ children: [
289
+ /* @__PURE__ */ jsx3(
290
+ "span",
291
+ {
292
+ "data-run-row-glyph": "",
293
+ className: cn(
294
+ "flex items-center justify-center",
295
+ expandable && "group-hover:hidden",
296
+ open && "hidden"
297
+ ),
298
+ children: icon
299
+ }
300
+ ),
301
+ expandable ? /* @__PURE__ */ jsx3(
302
+ ChevronRight,
303
+ {
304
+ "data-run-row-chevron": "",
305
+ className: cn(
306
+ "hidden h-3.5 w-3.5 transition-transform group-hover:block",
307
+ open && "block rotate-90"
308
+ )
309
+ }
310
+ ) : null
311
+ ]
312
+ }
313
+ ),
314
+ /* @__PURE__ */ jsx3(
315
+ "span",
316
+ {
317
+ className: cn(
318
+ "shrink-0 whitespace-nowrap text-sm font-normal text-muted-foreground transition-colors group-hover:text-foreground",
319
+ open && "text-foreground"
320
+ ),
321
+ children: title
322
+ }
323
+ ),
324
+ description ? /* @__PURE__ */ jsx3(
294
325
  "span",
295
326
  {
296
327
  className: cn(
297
- "hidden min-w-0 flex-1 truncate text-xs text-muted-foreground sm:inline",
328
+ "hidden min-w-0 flex-1 truncate text-sm text-muted-foreground transition-colors group-hover:text-foreground sm:inline",
298
329
  descriptionMono && "font-mono"
299
330
  ),
300
331
  children: description
301
332
  }
302
333
  ) : null,
303
- /* @__PURE__ */ jsxs3("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
304
- isRunning && startTime != null ? /* @__PURE__ */ jsx4(LiveDuration, { startTime }) : durationMs != null ? /* @__PURE__ */ jsx4("span", { className: "text-[10px] font-mono tabular-nums text-muted-foreground", children: formatDuration(durationMs) }) : null,
305
- /* @__PURE__ */ jsx4(RunRowStatusDot, { status }),
306
- expandable ? /* @__PURE__ */ jsx4(
307
- ChevronRight,
334
+ /* @__PURE__ */ jsxs3("span", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
335
+ !isRunning && durationMs != null ? /* @__PURE__ */ jsx3(
336
+ "span",
308
337
  {
309
- className: cn(
310
- "h-3 w-3 shrink-0 text-muted-foreground transition-transform",
311
- open && "rotate-90"
312
- )
338
+ "data-run-row-duration": "",
339
+ className: "font-mono text-[10px] tabular-nums text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
340
+ children: formatDuration(durationMs)
313
341
  }
314
- ) : null
342
+ ) : null,
343
+ /* @__PURE__ */ jsx3(RunRowStatusDot, { status })
315
344
  ] })
316
345
  ]
317
346
  }
318
347
  ) }),
319
- collapsedError && !open ? /* @__PURE__ */ jsx4("div", { className: "border-t border-border px-3 py-2 text-xs text-[var(--surface-danger-text)]", children: collapsedError }) : null,
320
- expandable ? /* @__PURE__ */ jsx4(Collapsible.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx4("div", { className: cn("border-t border-border", contentClassName), children }) }) : null
348
+ collapsedError && !open ? /* @__PURE__ */ jsx3(
349
+ "div",
350
+ {
351
+ className: cn(
352
+ "pb-1.5 pr-2 text-xs leading-snug text-[var(--surface-danger-text)]",
353
+ ERROR_INDENT
354
+ ),
355
+ children: collapsedError
356
+ }
357
+ ) : null,
358
+ expandable ? /* @__PURE__ */ jsx3(Collapsible.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx3("div", { className: cn("border-t border-border", contentClassName), children }) }) : null
321
359
  ]
322
360
  }
323
361
  ),
324
- actions ? /* @__PURE__ */ jsx4(
362
+ actions ? /* @__PURE__ */ jsx3(
325
363
  "div",
326
364
  {
327
365
  className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1",
@@ -345,7 +383,7 @@ import {
345
383
  ClipboardList,
346
384
  Settings
347
385
  } from "lucide-react";
348
- import { jsx as jsx5 } from "react/jsx-runtime";
386
+ import { jsx as jsx4 } from "react/jsx-runtime";
349
387
  var TOOL_CATEGORY_ICON_MAP = {
350
388
  command: Terminal,
351
389
  write: FileEdit,
@@ -382,22 +420,22 @@ var InlineToolItem = memo2(
382
420
  const durationMs = startTime != null && endTime != null ? endTime - startTime : void 0;
383
421
  const category = getToolCategory(part.tool);
384
422
  const DefaultIcon = TOOL_CATEGORY_ICON_MAP[category] ?? Settings;
385
- return /* @__PURE__ */ jsx5(
423
+ const status = toRowStatus(part.state.status);
424
+ return /* @__PURE__ */ jsx4(
386
425
  RunRowShell,
387
426
  {
388
- icon: /* @__PURE__ */ jsx5(DefaultIcon, { className: "h-3.5 w-3.5" }),
389
- title,
427
+ icon: /* @__PURE__ */ jsx4(DefaultIcon, { className: "h-3.5 w-3.5" }),
428
+ title: status === "running" ? /* @__PURE__ */ jsx4(TextShimmer, { children: title }) : title,
390
429
  description,
391
430
  descriptionMono: true,
392
- status: toRowStatus(part.state.status),
393
- startTime,
431
+ status,
394
432
  durationMs,
395
433
  groupPosition,
396
434
  collapsedError: errorText ?? void 0,
397
435
  actions,
398
436
  className,
399
437
  contentClassName: cn("p-2", contentClassName),
400
- children: renderToolDetail?.(part) ?? /* @__PURE__ */ jsx5(ExpandedToolDetail, { part })
438
+ children: renderToolDetail?.(part) ?? /* @__PURE__ */ jsx4(ExpandedToolDetail, { part })
401
439
  }
402
440
  );
403
441
  }
@@ -405,7 +443,7 @@ var InlineToolItem = memo2(
405
443
  InlineToolItem.displayName = "InlineToolItem";
406
444
 
407
445
  // src/run/tool-call-step.tsx
408
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
446
+ import { jsx as jsx5 } from "react/jsx-runtime";
409
447
  var EXT_LANGUAGE = {
410
448
  ts: "typescript",
411
449
  tsx: "typescript",
@@ -468,7 +506,7 @@ function ToolCallStep({
468
506
  }
469
507
  };
470
508
  const lang = inferLanguage(detail, language);
471
- return /* @__PURE__ */ jsx6(
509
+ return /* @__PURE__ */ jsx5(
472
510
  InlineToolItem,
473
511
  {
474
512
  part: resolvedPart,
@@ -476,7 +514,7 @@ function ToolCallStep({
476
514
  description: detail,
477
515
  className,
478
516
  actions,
479
- renderToolDetail: part ? void 0 : output ? () => /* @__PURE__ */ jsx6(
517
+ renderToolDetail: part ? void 0 : output ? () => /* @__PURE__ */ jsx5(
480
518
  CodeBlock,
481
519
  {
482
520
  code: output,
@@ -488,16 +526,20 @@ function ToolCallStep({
488
526
  );
489
527
  }
490
528
  function ToolCallGroup({ title, children, className }) {
491
- return /* @__PURE__ */ jsxs4("div", { className: ["my-2 space-y-2", className].filter(Boolean).join(" "), children: [
492
- title && /* @__PURE__ */ jsx6("div", { className: "mb-1 px-1 text-xs font-medium uppercase tracking-wider text-muted-foreground", children: title }),
493
- children
494
- ] });
529
+ return /* @__PURE__ */ jsx5(
530
+ "div",
531
+ {
532
+ role: "group",
533
+ "aria-label": title,
534
+ className: cn("flex flex-col gap-1", className),
535
+ children
536
+ }
537
+ );
495
538
  }
496
539
 
497
540
  export {
498
541
  ExpandableContent,
499
542
  ExpandedToolDetail,
500
- LiveDuration,
501
543
  RunRowStatusDot,
502
544
  RunRowShell,
503
545
  InlineToolItem,
package/dist/hooks.js CHANGED
@@ -11,17 +11,18 @@ import {
11
11
  useSSEStream,
12
12
  useSdkSession,
13
13
  useToolCallStream
14
- } from "./chunk-XROQW5J7.js";
14
+ } from "./chunk-4ENFLPWQ.js";
15
15
  import "./chunk-OEX7NZE3.js";
16
16
  import {
17
17
  useAutoScroll,
18
18
  useRunCollapseState,
19
19
  useRunGroups
20
- } from "./chunk-AZWDI2JG.js";
21
- import "./chunk-XPYPZMYT.js";
22
- import "./chunk-J2G7KCYH.js";
23
- import "./chunk-ULDNFLIM.js";
20
+ } from "./chunk-UYTRNR7Z.js";
21
+ import "./chunk-6RIX7M27.js";
22
+ import "./chunk-XT4JMYVB.js";
23
+ import "./chunk-EIUE5GV2.js";
24
24
  import "./chunk-AAUNOHVL.js";
25
+ import "./chunk-L57WRIND.js";
25
26
  import "./chunk-ZRVH3WCA.js";
26
27
  import "./chunk-P5F43A65.js";
27
28
  import "./chunk-WUQDUBJG.js";
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { B as Button, a as ButtonProps, b as buttonVariants } from './button-CMQuQEW_.js';
2
- export { Avatar, AvatarFallback, AvatarImage, Badge, BadgeProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, EmptyStateProps, FilterField, FilterFieldProps, InlineCode, InlineCodeProps, Input, InputProps, Label, Metric, MetricProps, MetricStrip, MetricStripProps, PageHeader, PageHeaderProps, Progress, SegmentedControl, SegmentedControlOption, SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SidebarDropZone, SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, StatCard, StatCardProps, StatusPill, StatusPillProps, StatusTone, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, Textarea, TextareaProps, ThemeToggle, Toast, ToastContainer, ToastProvider, Toolbar, ToolbarProps, UploadFile, UploadProgress, UploadProgressProps, badgeVariants, useTheme, useToast } from './primitives.js';
2
+ export { Avatar, AvatarFallback, AvatarImage, Badge, BadgeProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, EmptyStateProps, FilterField, FilterFieldProps, InlineCode, InlineCodeProps, Input, InputProps, Label, Metric, MetricProps, MetricStrip, MetricStripProps, PageHeader, PageHeaderProps, Progress, SegmentedControl, SegmentedControlOption, SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SidebarDropZone, SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, StatCard, StatCardProps, StatusPill, StatusPillProps, StatusTone, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, TextShimmerProps, Textarea, TextareaProps, ThemeToggle, Toast, ToastContainer, ToastProvider, Toolbar, ToolbarProps, UploadFile, UploadProgress, UploadProgressProps, badgeVariants, useTheme, useToast } from './primitives.js';
3
3
  export { Logo, LogoProps, TangleKnot } from '@tangle-network/brand';
4
4
  export { A as ArtifactPane, a as ArtifactPaneProps } from './artifact-pane-DpuWcAiF.js';
5
5
  export { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, ChatContainer, ChatContainerProps, ChatMessage, ChatMessageProps, MessageList, MessageListProps, MessageRole, ThinkingIndicator, ThinkingIndicatorProps, UserMessage, UserMessageProps } from './chat.js';