@tangle-network/ui 11.0.0 → 11.2.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 (53) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/{artifact-pane-DvJyPWV4.d.ts → artifact-pane-DpuWcAiF.d.ts} +10 -1
  3. package/dist/chat.d.ts +8 -2
  4. package/dist/chat.js +5 -5
  5. package/dist/{chunk-52Y3FMFI.js → chunk-3M7BPSSW.js} +1 -1
  6. package/dist/chunk-4ORVXSMU.js +507 -0
  7. package/dist/{chunk-LELGOLFV.js → chunk-GGDYWMFF.js} +15 -7
  8. package/dist/{chunk-CCM2KRQH.js → chunk-HW4ROISY.js} +1 -1
  9. package/dist/{chunk-KBOD47AW.js → chunk-J3YZIQNI.js} +2 -2
  10. package/dist/{chunk-CSAIKY36.js → chunk-LTEKI7YJ.js} +12 -7
  11. package/dist/{chunk-KHO7DYXH.js → chunk-OTZWQJ5W.js} +107 -72
  12. package/dist/{chunk-FJBTCTZM.js → chunk-P5F43A65.js} +1 -1
  13. package/dist/{chunk-SZ44QDA6.js → chunk-RADUPP44.js} +12 -5
  14. package/dist/{chunk-HHYUPAOJ.js → chunk-SRAKCVPO.js} +49 -81
  15. package/dist/{document-editor-pane-DyDEX_Zm.d.ts → document-editor-pane-C3cYEDWZ.d.ts} +2 -2
  16. package/dist/{document-editor-pane-WCTA3ZOE.js → document-editor-pane-OQNGM4RJ.js} +3 -3
  17. package/dist/editor.d.ts +3 -3
  18. package/dist/editor.js +3 -3
  19. package/dist/files.d.ts +5 -3
  20. package/dist/files.js +3 -3
  21. package/dist/hooks.js +4 -4
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.js +9 -9
  24. package/dist/markdown.js +1 -1
  25. package/dist/openui.js +2 -2
  26. package/dist/primitives.d.ts +1 -1
  27. package/dist/primitives.js +1 -1
  28. package/dist/run.d.ts +4 -3
  29. package/dist/run.js +5 -5
  30. package/dist/sdk-hooks.js +4 -4
  31. package/package.json +1 -1
  32. package/src/chat/agent-timeline.stories.tsx +11 -0
  33. package/src/chat/agent-timeline.test.tsx +34 -0
  34. package/src/chat/agent-timeline.tsx +65 -12
  35. package/src/chat/chat-container.tsx +5 -0
  36. package/src/editor/document-editor-pane.stories.tsx +74 -0
  37. package/src/editor/document-editor-pane.tsx +10 -3
  38. package/src/files/file-artifact-pane.tsx +14 -2
  39. package/src/files/file-preview.stories.tsx +22 -1
  40. package/src/files/file-preview.tsx +2 -2
  41. package/src/markdown/markdown.stories.tsx +55 -1
  42. package/src/markdown/markdown.test.tsx +23 -0
  43. package/src/markdown/markdown.tsx +1 -1
  44. package/src/primitives/artifact-pane.tsx +52 -26
  45. package/src/run/expandable-content.test.tsx +52 -0
  46. package/src/run/expandable-content.tsx +73 -0
  47. package/src/run/expanded-tool-detail.tsx +17 -12
  48. package/src/run/inline-thinking-item.stories.tsx +30 -1
  49. package/src/run/inline-thinking-item.tsx +34 -70
  50. package/src/run/inline-tool-item.tsx +30 -116
  51. package/src/run/run-row-shell.test.tsx +38 -0
  52. package/src/run/run-row-shell.tsx +191 -0
  53. package/dist/chunk-INMWNFAS.js +0 -369
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 11.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ac4eaf4: feat(files): host-aligned artifact surface props
8
+
9
+ - `ArtifactPane`: `headerClassName` + `hideTitleBlock` (header row collapses when empty).
10
+ - `FileArtifactPane`: threads both through all render paths; `headerActions` is `undefined` (not an empty fragment) when there are no actions.
11
+ - `DocumentEditorPane`: `previewClassName` now governs the whole preview box (gutter/border/surface/padding), enabling a full-bleed document body.
12
+ - `FilePreview`: text previews sit on `bg-card` for a white surface in light theme.
13
+
14
+ ### Patch Changes
15
+
16
+ - c5dfc7d: Use tokenized Tangle prose styling for markdown previews so light themes stay readable.
17
+
18
+ ## 11.1.0
19
+
20
+ ### Minor Changes
21
+
22
+ - ea6f23e: Unify the agent reasoning and tool rows onto one shared row shell: both keep a
23
+ consistent semantic lead icon with a small trailing status dot/spinner (status
24
+ no longer hijacks the icon), on a calm neutral badge that is uniform across
25
+ reasoning and tool rows. Expanded and open rows read as the same surface as
26
+ their collapsed siblings (no background elevation), the reasoning body inherits
27
+ the card surface and stays readable in dark mode, and the timeline spine dot is
28
+ centered on card rows. Add a per-row content clamp with "Show more/less" for
29
+ long reasoning text and tool output, and an opt-in `collapseAfter` on
30
+ `AgentTimeline` (threaded as `collapseTimelineAfter` on `ChatContainer`) that
31
+ collapses the timeline to the first N steps behind a "Show N more steps" toggle.
32
+
3
33
  ## 11.0.0
4
34
 
5
35
  ### Patch Changes
@@ -14,11 +14,20 @@ interface ArtifactPaneProps {
14
14
  children?: ReactNode;
15
15
  className?: string;
16
16
  contentClassName?: string;
17
+ /** Extra classes for the header band (e.g. to align its surface with the host chrome). */
18
+ headerClassName?: string;
19
+ /**
20
+ * Suppress the eyebrow/title/subtitle/meta block. Use when the host already
21
+ * shows the artifact's identity elsewhere (e.g. a surrounding path row), so the
22
+ * pane keeps only its tabs, toolbar, and header actions. The whole header row
23
+ * collapses when nothing else would render in it.
24
+ */
25
+ hideTitleBlock?: boolean;
17
26
  }
18
27
  /**
19
28
  * ArtifactPane — shared frame for files, previews, documents, inspectors, and
20
29
  * other artifact-like surfaces inside sandbox applications.
21
30
  */
22
- declare function ArtifactPane({ eyebrow, title, subtitle, meta, headerActions, tabs, toolbar, footer, emptyState, children, className, contentClassName, }: ArtifactPaneProps): react_jsx_runtime.JSX.Element;
31
+ declare function ArtifactPane({ eyebrow, title, subtitle, meta, headerActions, tabs, toolbar, footer, emptyState, children, className, contentClassName, headerClassName, hideTitleBlock, }: ArtifactPaneProps): react_jsx_runtime.JSX.Element;
23
32
 
24
33
  export { ArtifactPane as A, type ArtifactPaneProps as a };
package/dist/chat.d.ts CHANGED
@@ -42,12 +42,15 @@ interface ChatContainerProps {
42
42
  /** Optional actions rendered beside individual tool items in the `timeline`
43
43
  * presentation, which has no run/message grouping (hence part-only). */
44
44
  renderTimelineToolActions?: (part: ToolPart) => ReactNode;
45
+ /** In the `timeline` presentation, collapse to the first N spine rows behind
46
+ * a "Show N more steps" toggle. Omit to always show every row. */
47
+ collapseTimelineAfter?: number;
45
48
  }
46
49
  /**
47
50
  * Chat transcript container: message list + auto-scroll.
48
51
  * Orchestrates useRunGroups, useRunCollapseState, and useAutoScroll.
49
52
  */
50
- declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, branding, className, renderToolDetail, presentation, onOpenUIAction, enableOpenUI, renderRunActions, renderUserMessageActions, renderToolActions, renderTimelineToolActions, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
53
+ declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, branding, className, renderToolDetail, presentation, onOpenUIAction, enableOpenUI, renderRunActions, renderUserMessageActions, renderToolActions, renderTimelineToolActions, collapseTimelineAfter, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
51
54
 
52
55
  interface MessageListProps {
53
56
  groups: GroupedMessage[];
@@ -174,12 +177,15 @@ interface AgentTimelineProps {
174
177
  /** Optional actions rendered beside each tool item (e.g. "open in artifacts").
175
178
  * Receives the source tool part carried on the item. */
176
179
  renderToolActions?: (part: ToolPart) => ReactNode;
180
+ /** When set, collapse the timeline to the first N spine rows behind a
181
+ * "Show N more steps" toggle. Omit to always show every row. */
182
+ collapseAfter?: number;
177
183
  }
178
184
  /**
179
185
  * AgentTimeline — unified mixed-content timeline for agent-backed sandbox
180
186
  * sessions. Renders messages, tool steps, status cards, and artifact handoffs in
181
187
  * a single execution narrative.
182
188
  */
183
- declare function AgentTimeline({ items, isThinking, emptyState, className, renderToolActions, }: AgentTimelineProps): react_jsx_runtime.JSX.Element | null;
189
+ declare function AgentTimeline({ items, isThinking, emptyState, className, renderToolActions, collapseAfter, }: AgentTimelineProps): react_jsx_runtime.JSX.Element | null;
184
190
 
185
191
  export { AgentTimeline, type AgentTimelineArtifactItem, type AgentTimelineCustomItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, MessageList, type MessageListProps, type MessageRole, ThinkingIndicator, type ThinkingIndicatorProps, UserMessage, type UserMessageProps };
package/dist/chat.js CHANGED
@@ -5,17 +5,17 @@ import {
5
5
  MessageList,
6
6
  ThinkingIndicator,
7
7
  UserMessage
8
- } from "./chunk-KHO7DYXH.js";
8
+ } from "./chunk-OTZWQJ5W.js";
9
9
  import "./chunk-AZWDI2JG.js";
10
- import "./chunk-HHYUPAOJ.js";
11
- import "./chunk-INMWNFAS.js";
10
+ import "./chunk-SRAKCVPO.js";
11
+ import "./chunk-4ORVXSMU.js";
12
12
  import "./chunk-ULDNFLIM.js";
13
13
  import "./chunk-AAUNOHVL.js";
14
- import "./chunk-52Y3FMFI.js";
14
+ import "./chunk-3M7BPSSW.js";
15
15
  import "./chunk-GYPQXTJU.js";
16
16
  import "./chunk-MKTSMWVD.js";
17
17
  import "./chunk-ZRVH3WCA.js";
18
- import "./chunk-FJBTCTZM.js";
18
+ import "./chunk-P5F43A65.js";
19
19
  import "./chunk-WUQDUBJG.js";
20
20
  import "./chunk-RQHJBTEU.js";
21
21
  export {
@@ -17,7 +17,7 @@ import {
17
17
  } from "./chunk-MKTSMWVD.js";
18
18
  import {
19
19
  Markdown
20
- } from "./chunk-FJBTCTZM.js";
20
+ } from "./chunk-P5F43A65.js";
21
21
  import {
22
22
  CodeBlock
23
23
  } from "./chunk-WUQDUBJG.js";
@@ -0,0 +1,507 @@
1
+ import {
2
+ formatDuration,
3
+ getToolCategory,
4
+ getToolDisplayMetadata,
5
+ getToolErrorText
6
+ } from "./chunk-ULDNFLIM.js";
7
+ import {
8
+ CommandPreview,
9
+ DiffPreview,
10
+ GlobResultsPreview,
11
+ GrepResultsPreview,
12
+ QuestionPreview,
13
+ WebSearchPreview,
14
+ WriteFilePreview
15
+ } from "./chunk-AAUNOHVL.js";
16
+ import {
17
+ CodeBlock
18
+ } from "./chunk-WUQDUBJG.js";
19
+ import {
20
+ cn
21
+ } from "./chunk-RQHJBTEU.js";
22
+
23
+ // src/run/expanded-tool-detail.tsx
24
+ import { memo } from "react";
25
+ import {
26
+ ArrowRight,
27
+ ArrowLeft,
28
+ AlertCircle,
29
+ Loader2,
30
+ FileText
31
+ } from "lucide-react";
32
+
33
+ // src/run/expandable-content.tsx
34
+ import { useEffect, useRef, useState } from "react";
35
+ import { jsx, jsxs } from "react/jsx-runtime";
36
+ function ExpandableContent({
37
+ children,
38
+ collapsedMaxPx = 180,
39
+ fadeClassName = "from-muted",
40
+ className
41
+ }) {
42
+ const [expanded, setExpanded] = useState(false);
43
+ const [overflowing, setOverflowing] = useState(false);
44
+ const contentRef = useRef(null);
45
+ useEffect(() => {
46
+ const el = contentRef.current;
47
+ if (!el) return;
48
+ const measure = () => setOverflowing(el.scrollHeight > collapsedMaxPx + 4);
49
+ measure();
50
+ if (typeof ResizeObserver === "undefined") return;
51
+ const observer = new ResizeObserver(measure);
52
+ observer.observe(el);
53
+ return () => observer.disconnect();
54
+ }, [collapsedMaxPx]);
55
+ const clamped = overflowing && !expanded;
56
+ return /* @__PURE__ */ jsxs("div", { className, children: [
57
+ /* @__PURE__ */ jsxs(
58
+ "div",
59
+ {
60
+ ref: contentRef,
61
+ className: "relative overflow-hidden",
62
+ style: clamped ? { maxHeight: collapsedMaxPx } : void 0,
63
+ children: [
64
+ children,
65
+ clamped ? /* @__PURE__ */ jsx(
66
+ "div",
67
+ {
68
+ className: cn(
69
+ "pointer-events-none absolute inset-x-0 bottom-0 h-10 bg-gradient-to-t to-transparent",
70
+ fadeClassName
71
+ )
72
+ }
73
+ ) : null
74
+ ]
75
+ }
76
+ ),
77
+ overflowing ? /* @__PURE__ */ jsx(
78
+ "button",
79
+ {
80
+ type: "button",
81
+ onClick: () => setExpanded((value) => !value),
82
+ className: "mt-1 text-[11px] font-medium text-muted-foreground transition-colors hover:text-foreground",
83
+ children: expanded ? "Show less" : "Show more"
84
+ }
85
+ ) : null
86
+ ] });
87
+ }
88
+
89
+ // src/run/expanded-tool-detail.tsx
90
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
91
+ var EXT_LANG = {
92
+ ts: "typescript",
93
+ tsx: "tsx",
94
+ js: "javascript",
95
+ jsx: "jsx",
96
+ rs: "rust",
97
+ py: "python",
98
+ go: "go",
99
+ rb: "ruby",
100
+ json: "json",
101
+ yaml: "yaml",
102
+ yml: "yaml",
103
+ toml: "toml",
104
+ md: "markdown",
105
+ css: "css",
106
+ scss: "scss",
107
+ html: "html",
108
+ sh: "bash",
109
+ bash: "bash",
110
+ zsh: "bash",
111
+ sql: "sql",
112
+ sol: "solidity",
113
+ proto: "protobuf"
114
+ };
115
+ function langFromPath(path) {
116
+ if (!path) return void 0;
117
+ const ext = path.split(".").pop()?.toLowerCase();
118
+ return ext ? EXT_LANG[ext] : void 0;
119
+ }
120
+ function formatOutput(value) {
121
+ if (value == null) return "";
122
+ if (typeof value === "string") return value;
123
+ try {
124
+ return JSON.stringify(value, null, 2);
125
+ } catch {
126
+ return String(value);
127
+ }
128
+ }
129
+ var ExpandedToolDetail = memo(({ part }) => {
130
+ const meta = getToolDisplayMetadata(part);
131
+ const { status, input, output, error } = part.state;
132
+ if (meta.displayVariant === "command") {
133
+ return /* @__PURE__ */ jsx2(CommandPreview, { part });
134
+ }
135
+ if (meta.displayVariant === "write-file") {
136
+ return /* @__PURE__ */ jsx2(WriteFilePreview, { part });
137
+ }
138
+ if (meta.displayVariant === "grep") {
139
+ return /* @__PURE__ */ jsx2(GrepResultsPreview, { part });
140
+ }
141
+ if (meta.displayVariant === "glob") {
142
+ return /* @__PURE__ */ jsx2(GlobResultsPreview, { part });
143
+ }
144
+ if (meta.displayVariant === "web-search") {
145
+ return /* @__PURE__ */ jsx2(WebSearchPreview, { part });
146
+ }
147
+ if (meta.displayVariant === "question") {
148
+ return /* @__PURE__ */ jsx2(QuestionPreview, { part });
149
+ }
150
+ if (meta.displayVariant === "diff") {
151
+ return /* @__PURE__ */ jsx2(DiffPreview, { part });
152
+ }
153
+ if (meta.displayVariant === "read-file") {
154
+ return /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card shadow-[var(--shadow-card)]", children: [
155
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2.5 border-b border-border bg-card px-3 py-2", children: [
156
+ /* @__PURE__ */ jsx2("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-[var(--border-accent)] bg-muted text-primary", children: /* @__PURE__ */ jsx2(FileText, { className: "h-3.5 w-3.5" }) }),
157
+ /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex items-center gap-2", children: [
158
+ /* @__PURE__ */ jsx2("span", { className: "text-xs font-semibold text-foreground", children: "Read file" }),
159
+ meta.targetPath ? /* @__PURE__ */ jsx2("span", { className: "truncate text-xs font-mono text-muted-foreground", children: meta.targetPath }) : null
160
+ ] })
161
+ ] }),
162
+ /* @__PURE__ */ jsxs2("div", { className: "space-y-2 px-3 py-2.5", children: [
163
+ typeof output === "string" ? /* @__PURE__ */ jsx2(CodeBlock, { code: output, language: langFromPath(meta.targetPath) ?? "text", className: "rounded-[var(--radius-md)]" }) : /* @__PURE__ */ jsx2("div", { className: "rounded-[var(--radius-md)] border border-dashed border-border bg-muted px-3 py-4 text-sm text-muted-foreground", children: "No readable file content was returned." }),
164
+ error ? /* @__PURE__ */ jsx2("div", { className: "rounded-[var(--radius-md)] border border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-3 py-3 text-sm text-[var(--surface-danger-text)]", children: error }) : null
165
+ ] })
166
+ ] });
167
+ }
168
+ const inputStr = formatOutput(input);
169
+ const outputStr = formatOutput(output);
170
+ return /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
171
+ inputStr && /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card", children: [
172
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2", children: [
173
+ /* @__PURE__ */ jsx2(ArrowRight, { className: "h-3 w-3 text-primary" }),
174
+ /* @__PURE__ */ jsx2("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground", children: "Input" })
175
+ ] }),
176
+ /* @__PURE__ */ jsx2(CodeBlock, { code: inputStr, language: "json", className: "rounded-none border-0" })
177
+ ] }),
178
+ status === "completed" && outputStr && /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card", children: [
179
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2", children: [
180
+ /* @__PURE__ */ jsx2(ArrowLeft, { className: "h-3 w-3 text-primary" }),
181
+ /* @__PURE__ */ jsx2("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground", children: "Output" })
182
+ ] }),
183
+ /* @__PURE__ */ jsx2(ExpandableContent, { fadeClassName: "from-card", children: /* @__PURE__ */ jsx2(
184
+ CodeBlock,
185
+ {
186
+ code: outputStr.length > 2e3 ? outputStr.slice(0, 2e3) + "\n...(truncated)" : outputStr,
187
+ language: "json",
188
+ className: "rounded-none border-0"
189
+ }
190
+ ) })
191
+ ] }),
192
+ error && /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-[var(--surface-danger-border)]", children: [
193
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-3 py-2", children: [
194
+ /* @__PURE__ */ jsx2(AlertCircle, { className: "h-3 w-3 text-[var(--surface-danger-text)]" }),
195
+ /* @__PURE__ */ jsx2("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-[var(--surface-danger-text)]", children: "Error" })
196
+ ] }),
197
+ /* @__PURE__ */ jsx2(ExpandableContent, { fadeClassName: "from-[var(--surface-danger-bg)]", children: /* @__PURE__ */ jsx2("pre", { className: "bg-[var(--surface-danger-bg)] p-3 text-xs font-mono whitespace-pre-wrap break-all text-[var(--surface-danger-text)]", children: error }) })
198
+ ] }),
199
+ (status === "pending" || status === "running") && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 rounded-[var(--radius-md)] border border-border bg-muted px-3 py-3 text-xs text-muted-foreground", children: [
200
+ /* @__PURE__ */ jsx2(Loader2, { className: cn("h-3 w-3 animate-spin text-primary") }),
201
+ "Running\u2026"
202
+ ] })
203
+ ] });
204
+ });
205
+ ExpandedToolDetail.displayName = "ExpandedToolDetail";
206
+
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
+ // src/run/inline-tool-item.tsx
220
+ import { memo as memo2 } from "react";
221
+ import {
222
+ Terminal,
223
+ FileEdit,
224
+ FileSearch,
225
+ Search,
226
+ PencilLine,
227
+ Bot,
228
+ Globe,
229
+ ClipboardList,
230
+ Settings
231
+ } from "lucide-react";
232
+
233
+ // src/run/run-row-shell.tsx
234
+ import { useState as useState3 } from "react";
235
+ import * as Collapsible from "@radix-ui/react-collapsible";
236
+ import { Loader2 as Loader22, ChevronRight } from "lucide-react";
237
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
238
+ function RunRowStatusDot({ status }) {
239
+ if (status === "running") {
240
+ return /* @__PURE__ */ jsx4(Loader22, { className: "h-3 w-3 shrink-0 animate-spin text-[var(--accent-text)]" });
241
+ }
242
+ if (status === "success") {
243
+ return /* @__PURE__ */ jsx4("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-success-text)]" });
244
+ }
245
+ if (status === "error") {
246
+ return /* @__PURE__ */ jsx4("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-danger-text)]" });
247
+ }
248
+ return null;
249
+ }
250
+ var SHAPE_CLASS = {
251
+ single: "rounded-[var(--radius-lg)]",
252
+ first: "rounded-t-[var(--radius-lg)] rounded-b-[var(--radius-sm)]",
253
+ middle: "rounded-[var(--radius-sm)]",
254
+ last: "rounded-t-[var(--radius-sm)] rounded-b-[var(--radius-lg)]"
255
+ };
256
+ function RunRowShell({
257
+ icon,
258
+ title,
259
+ description,
260
+ descriptionMono = false,
261
+ status = "idle",
262
+ startTime,
263
+ durationMs,
264
+ groupPosition = "single",
265
+ collapsedError,
266
+ actions,
267
+ open: openProp,
268
+ onOpenChange,
269
+ defaultOpen = false,
270
+ className,
271
+ contentClassName,
272
+ children
273
+ }) {
274
+ const [openState, setOpenState] = useState3(defaultOpen);
275
+ const isControlled = openProp !== void 0;
276
+ const open = isControlled ? openProp : openState;
277
+ const setOpen = (next) => {
278
+ if (!isControlled) setOpenState(next);
279
+ onOpenChange?.(next);
280
+ };
281
+ const isRunning = status === "running";
282
+ const expandable = children != null;
283
+ return /* @__PURE__ */ jsx4(Collapsible.Root, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-2", children: [
284
+ /* @__PURE__ */ jsxs3(
285
+ "div",
286
+ {
287
+ className: cn(
288
+ "min-w-0 flex-1 overflow-hidden border transition-colors",
289
+ "border-[var(--border-subtle)] bg-[var(--md3-surface-container)]",
290
+ expandable && "hover:border-border",
291
+ open && "border-border",
292
+ SHAPE_CLASS[groupPosition],
293
+ className
294
+ ),
295
+ children: [
296
+ /* @__PURE__ */ jsx4(Collapsible.Trigger, { asChild: true, disabled: !expandable, children: /* @__PURE__ */ jsxs3(
297
+ "button",
298
+ {
299
+ type: "button",
300
+ className: cn(
301
+ "flex w-full items-center gap-2.5 px-3 py-2 text-left",
302
+ expandable ? "cursor-pointer" : "cursor-default"
303
+ ),
304
+ children: [
305
+ /* @__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 }),
306
+ /* @__PURE__ */ jsx4("span", { className: "shrink-0 whitespace-nowrap text-xs font-medium text-foreground", children: title }),
307
+ description ? /* @__PURE__ */ jsx4(
308
+ "span",
309
+ {
310
+ className: cn(
311
+ "hidden min-w-0 flex-1 truncate text-xs text-muted-foreground sm:inline",
312
+ descriptionMono && "font-mono"
313
+ ),
314
+ children: description
315
+ }
316
+ ) : null,
317
+ /* @__PURE__ */ jsxs3("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
318
+ 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,
319
+ /* @__PURE__ */ jsx4(RunRowStatusDot, { status }),
320
+ expandable ? /* @__PURE__ */ jsx4(
321
+ ChevronRight,
322
+ {
323
+ className: cn(
324
+ "h-3 w-3 shrink-0 text-muted-foreground transition-transform",
325
+ open && "rotate-90"
326
+ )
327
+ }
328
+ ) : null
329
+ ] })
330
+ ]
331
+ }
332
+ ) }),
333
+ collapsedError && !open ? /* @__PURE__ */ jsx4("div", { className: "border-t border-border px-3 py-2 text-xs text-[var(--surface-danger-text)]", children: collapsedError }) : null,
334
+ 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
335
+ ]
336
+ }
337
+ ),
338
+ actions ? /* @__PURE__ */ jsx4(
339
+ "div",
340
+ {
341
+ className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1",
342
+ onClick: (event) => event.stopPropagation(),
343
+ children: actions
344
+ }
345
+ ) : null
346
+ ] }) });
347
+ }
348
+
349
+ // src/run/inline-tool-item.tsx
350
+ import { jsx as jsx5 } from "react/jsx-runtime";
351
+ var TOOL_CATEGORY_ICON_MAP = {
352
+ command: Terminal,
353
+ write: FileEdit,
354
+ read: FileSearch,
355
+ search: Search,
356
+ edit: PencilLine,
357
+ task: Bot,
358
+ web: Globe,
359
+ todo: ClipboardList,
360
+ other: Settings
361
+ };
362
+ function toRowStatus(status) {
363
+ if (status === "pending" || status === "running") return "running";
364
+ if (status === "error") return "error";
365
+ return "success";
366
+ }
367
+ var InlineToolItem = memo2(
368
+ ({
369
+ part,
370
+ renderToolDetail,
371
+ groupPosition = "single",
372
+ className,
373
+ contentClassName,
374
+ actions,
375
+ title: titleOverride,
376
+ description: descriptionOverride
377
+ }) => {
378
+ const meta = getToolDisplayMetadata(part);
379
+ const title = titleOverride ?? meta.title;
380
+ const description = descriptionOverride ?? meta.description;
381
+ const errorText = getToolErrorText(part);
382
+ const startTime = part.state.time?.start;
383
+ const endTime = part.state.time?.end;
384
+ const durationMs = startTime != null && endTime != null ? endTime - startTime : void 0;
385
+ const category = getToolCategory(part.tool);
386
+ const DefaultIcon = TOOL_CATEGORY_ICON_MAP[category] ?? Settings;
387
+ return /* @__PURE__ */ jsx5(
388
+ RunRowShell,
389
+ {
390
+ icon: /* @__PURE__ */ jsx5(DefaultIcon, { className: "h-3.5 w-3.5" }),
391
+ title,
392
+ description,
393
+ descriptionMono: true,
394
+ status: toRowStatus(part.state.status),
395
+ startTime,
396
+ durationMs,
397
+ groupPosition,
398
+ collapsedError: errorText ?? void 0,
399
+ actions,
400
+ className,
401
+ contentClassName: cn("p-2", contentClassName),
402
+ children: renderToolDetail?.(part) ?? /* @__PURE__ */ jsx5(ExpandedToolDetail, { part })
403
+ }
404
+ );
405
+ }
406
+ );
407
+ InlineToolItem.displayName = "InlineToolItem";
408
+
409
+ // src/run/tool-call-step.tsx
410
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
411
+ var EXT_LANGUAGE = {
412
+ ts: "typescript",
413
+ tsx: "typescript",
414
+ js: "javascript",
415
+ jsx: "javascript",
416
+ mjs: "javascript",
417
+ cjs: "javascript",
418
+ css: "css",
419
+ scss: "scss",
420
+ json: "json",
421
+ jsonc: "json",
422
+ md: "markdown",
423
+ mdx: "markdown",
424
+ py: "python",
425
+ sh: "bash",
426
+ bash: "bash",
427
+ zsh: "bash",
428
+ html: "html",
429
+ htm: "html",
430
+ yaml: "yaml",
431
+ yml: "yaml",
432
+ toml: "toml",
433
+ rs: "rust",
434
+ go: "go",
435
+ sql: "sql",
436
+ xml: "xml"
437
+ };
438
+ function inferLanguage(detail, language) {
439
+ if (language) return language;
440
+ if (!detail) return void 0;
441
+ const ext = detail.split(".").pop()?.toLowerCase();
442
+ return ext ? EXT_LANGUAGE[ext] : void 0;
443
+ }
444
+ var STATUS_MAP = {
445
+ running: "running",
446
+ success: "completed",
447
+ error: "error"
448
+ };
449
+ function ToolCallStep({
450
+ type,
451
+ label,
452
+ status,
453
+ detail,
454
+ output,
455
+ language,
456
+ duration,
457
+ className,
458
+ actions,
459
+ part
460
+ }) {
461
+ const resolvedPart = part ?? {
462
+ type: "tool",
463
+ id: `${type}:${label}`,
464
+ tool: type,
465
+ state: {
466
+ status: STATUS_MAP[status],
467
+ input: detail ? { detail } : void 0,
468
+ output,
469
+ time: duration != null ? { start: 0, end: duration } : void 0
470
+ }
471
+ };
472
+ const lang = inferLanguage(detail, language);
473
+ return /* @__PURE__ */ jsx6(
474
+ InlineToolItem,
475
+ {
476
+ part: resolvedPart,
477
+ title: label,
478
+ description: detail,
479
+ className,
480
+ actions,
481
+ renderToolDetail: part ? void 0 : output ? () => /* @__PURE__ */ jsx6(
482
+ CodeBlock,
483
+ {
484
+ code: output,
485
+ language: lang,
486
+ className: "max-h-72 overflow-auto text-xs"
487
+ }
488
+ ) : () => null
489
+ }
490
+ );
491
+ }
492
+ function ToolCallGroup({ title, children, className }) {
493
+ return /* @__PURE__ */ jsxs4("div", { className: ["my-2 space-y-2", className].filter(Boolean).join(" "), children: [
494
+ title && /* @__PURE__ */ jsx6("div", { className: "mb-1 px-1 text-xs font-medium uppercase tracking-wider text-muted-foreground", children: title }),
495
+ children
496
+ ] });
497
+ }
498
+
499
+ export {
500
+ ExpandableContent,
501
+ ExpandedToolDetail,
502
+ LiveDuration,
503
+ RunRowShell,
504
+ InlineToolItem,
505
+ ToolCallStep,
506
+ ToolCallGroup
507
+ };