@tangle-network/ui 5.1.0 → 6.0.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,18 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 6.0.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [e199bc7]
8
+ - @tangle-network/brand@0.7.0
9
+
10
+ ## 5.2.0
11
+
12
+ ### Minor Changes
13
+
14
+ - b0bf106: Single tool-call row implementation. `ToolCallStep` (the timeline/feed row used by `AgentTimeline` and `ToolCallFeed`) is now a thin adapter over the canonical `InlineToolItem` — it maps its flat `label`/`status`/`detail`/`output`/`duration` props onto a `ToolPart` and delegates rendering. The duplicate bespoke row markup is deleted, so every transcript (`RunGroup`, `AgentTimeline`, `ToolCallFeed`) shares one row component and one look. `InlineToolItem` gains optional `title`/`description` overrides for callers that supply explicit labels. No public API changes.
15
+
3
16
  ## 5.1.0
4
17
 
5
18
  ### Minor Changes
package/dist/chat.js CHANGED
@@ -6,12 +6,11 @@ import {
6
6
  MessageList,
7
7
  ThinkingIndicator,
8
8
  UserMessage
9
- } from "./chunk-FKDZOA4S.js";
10
- import "./chunk-54SQQMMM.js";
11
- import "./chunk-TAWY3KOH.js";
12
- import "./chunk-3O4XJCOE.js";
13
- import "./chunk-4CLN43XT.js";
14
- import "./chunk-BX6AQMUS.js";
9
+ } from "./chunk-SJ6IL4HI.js";
10
+ import "./chunk-AZWDI2JG.js";
11
+ import "./chunk-LASW7CYH.js";
12
+ import "./chunk-EOGJX2TU.js";
13
+ import "./chunk-ULDNFLIM.js";
15
14
  import "./chunk-AAUNOHVL.js";
16
15
  import "./chunk-52Y3FMFI.js";
17
16
  import "./chunk-GYPQXTJU.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getToolCategory
3
- } from "./chunk-BX6AQMUS.js";
3
+ } from "./chunk-ULDNFLIM.js";
4
4
 
5
5
  // src/hooks/use-run-groups.ts
6
6
  import { useMemo } from "react";
@@ -0,0 +1,366 @@
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
+ import { jsx, jsxs } from "react/jsx-runtime";
33
+ var EXT_LANG = {
34
+ ts: "typescript",
35
+ tsx: "tsx",
36
+ js: "javascript",
37
+ jsx: "jsx",
38
+ rs: "rust",
39
+ py: "python",
40
+ go: "go",
41
+ rb: "ruby",
42
+ json: "json",
43
+ yaml: "yaml",
44
+ yml: "yaml",
45
+ toml: "toml",
46
+ md: "markdown",
47
+ css: "css",
48
+ scss: "scss",
49
+ html: "html",
50
+ sh: "bash",
51
+ bash: "bash",
52
+ zsh: "bash",
53
+ sql: "sql",
54
+ sol: "solidity",
55
+ proto: "protobuf"
56
+ };
57
+ function langFromPath(path) {
58
+ if (!path) return void 0;
59
+ const ext = path.split(".").pop()?.toLowerCase();
60
+ return ext ? EXT_LANG[ext] : void 0;
61
+ }
62
+ function formatOutput(value) {
63
+ if (value == null) return "";
64
+ if (typeof value === "string") return value;
65
+ try {
66
+ return JSON.stringify(value, null, 2);
67
+ } catch {
68
+ return String(value);
69
+ }
70
+ }
71
+ var ExpandedToolDetail = memo(({ part }) => {
72
+ const meta = getToolDisplayMetadata(part);
73
+ const { status, input, output, error } = part.state;
74
+ if (meta.displayVariant === "command") {
75
+ return /* @__PURE__ */ jsx(CommandPreview, { part });
76
+ }
77
+ if (meta.displayVariant === "write-file") {
78
+ return /* @__PURE__ */ jsx(WriteFilePreview, { part });
79
+ }
80
+ if (meta.displayVariant === "grep") {
81
+ return /* @__PURE__ */ jsx(GrepResultsPreview, { part });
82
+ }
83
+ if (meta.displayVariant === "glob") {
84
+ return /* @__PURE__ */ jsx(GlobResultsPreview, { part });
85
+ }
86
+ if (meta.displayVariant === "web-search") {
87
+ return /* @__PURE__ */ jsx(WebSearchPreview, { part });
88
+ }
89
+ if (meta.displayVariant === "question") {
90
+ return /* @__PURE__ */ jsx(QuestionPreview, { part });
91
+ }
92
+ if (meta.displayVariant === "diff") {
93
+ return /* @__PURE__ */ jsx(DiffPreview, { part });
94
+ }
95
+ if (meta.displayVariant === "read-file") {
96
+ return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card shadow-[var(--shadow-card)]", children: [
97
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5 border-b border-border bg-card px-3 py-2", children: [
98
+ /* @__PURE__ */ jsx("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__ */ jsx(FileText, { className: "h-3.5 w-3.5" }) }),
99
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex items-center gap-2", children: [
100
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-foreground", children: "Read file" }),
101
+ meta.targetPath ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs font-mono text-muted-foreground", children: meta.targetPath }) : null
102
+ ] })
103
+ ] }),
104
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 px-3 py-2.5", children: [
105
+ typeof output === "string" ? /* @__PURE__ */ jsx(CodeBlock, { code: output, language: langFromPath(meta.targetPath) ?? "text", className: "rounded-[var(--radius-md)]" }) : /* @__PURE__ */ jsx("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." }),
106
+ error ? /* @__PURE__ */ jsx("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
107
+ ] })
108
+ ] });
109
+ }
110
+ const inputStr = formatOutput(input);
111
+ const outputStr = formatOutput(output);
112
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
113
+ inputStr && /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card", children: [
114
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2", children: [
115
+ /* @__PURE__ */ jsx(ArrowRight, { className: "h-3 w-3 text-primary" }),
116
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground", children: "Input" })
117
+ ] }),
118
+ /* @__PURE__ */ jsx(CodeBlock, { code: inputStr, language: "json", className: "rounded-none border-0" })
119
+ ] }),
120
+ status === "completed" && outputStr && /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-border bg-card", children: [
121
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-border bg-background px-3 py-2", children: [
122
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "h-3 w-3 text-primary" }),
123
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-muted-foreground", children: "Output" })
124
+ ] }),
125
+ /* @__PURE__ */ jsx(
126
+ CodeBlock,
127
+ {
128
+ code: outputStr.length > 2e3 ? outputStr.slice(0, 2e3) + "\n...(truncated)" : outputStr,
129
+ language: "json",
130
+ className: "rounded-none border-0"
131
+ }
132
+ )
133
+ ] }),
134
+ error && /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-[var(--radius-lg)] border border-[var(--surface-danger-border)]", children: [
135
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-b border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-3 py-2", children: [
136
+ /* @__PURE__ */ jsx(AlertCircle, { className: "h-3 w-3 text-[var(--surface-danger-text)]" }),
137
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium uppercase tracking-[0.08em] text-[var(--surface-danger-text)]", children: "Error" })
138
+ ] }),
139
+ /* @__PURE__ */ jsx("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 })
140
+ ] }),
141
+ (status === "pending" || status === "running") && /* @__PURE__ */ jsxs("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: [
142
+ /* @__PURE__ */ jsx(Loader2, { className: cn("h-3 w-3 animate-spin text-primary") }),
143
+ "Running\u2026"
144
+ ] })
145
+ ] });
146
+ });
147
+ ExpandedToolDetail.displayName = "ExpandedToolDetail";
148
+
149
+ // src/run/run-item-primitives.tsx
150
+ import { useEffect, useState } from "react";
151
+ import { jsx as jsx2 } from "react/jsx-runtime";
152
+ function LiveDuration({ startTime }) {
153
+ const [elapsed, setElapsed] = useState(Date.now() - startTime);
154
+ useEffect(() => {
155
+ const id = setInterval(() => setElapsed(Date.now() - startTime), 100);
156
+ return () => clearInterval(id);
157
+ }, [startTime]);
158
+ return /* @__PURE__ */ jsx2("span", { className: "text-xs font-mono text-neutral-400 dark:text-neutral-500 tabular-nums", children: formatDuration(elapsed) });
159
+ }
160
+
161
+ // src/run/inline-tool-item.tsx
162
+ import { memo as memo2, useState as useState2 } from "react";
163
+ import * as Collapsible from "@radix-ui/react-collapsible";
164
+ import {
165
+ Loader2 as Loader22,
166
+ CheckCircle2,
167
+ AlertCircle as AlertCircle2,
168
+ ChevronDown,
169
+ ChevronRight,
170
+ Terminal,
171
+ FileEdit,
172
+ FileSearch,
173
+ Search,
174
+ PencilLine,
175
+ Bot,
176
+ Globe,
177
+ ClipboardList,
178
+ Settings
179
+ } from "lucide-react";
180
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
181
+ var TOOL_CATEGORY_ICON_MAP = {
182
+ command: Terminal,
183
+ write: FileEdit,
184
+ read: FileSearch,
185
+ search: Search,
186
+ edit: PencilLine,
187
+ task: Bot,
188
+ web: Globe,
189
+ todo: ClipboardList,
190
+ other: Settings
191
+ };
192
+ var InlineToolItem = memo2(
193
+ ({
194
+ part,
195
+ renderToolDetail,
196
+ groupPosition = "single",
197
+ className,
198
+ contentClassName,
199
+ actions,
200
+ title: titleOverride,
201
+ description: descriptionOverride
202
+ }) => {
203
+ const [open, setOpen] = useState2(false);
204
+ const meta = getToolDisplayMetadata(part);
205
+ const title = titleOverride ?? meta.title;
206
+ const description = descriptionOverride ?? meta.description;
207
+ const { status } = part.state;
208
+ const errorText = getToolErrorText(part);
209
+ const isRunning = status === "pending" || status === "running";
210
+ const isError = status === "error";
211
+ const isComplete = status === "completed";
212
+ const startTime = part.state.time?.start;
213
+ const endTime = part.state.time?.end;
214
+ const durationMs = startTime && endTime ? endTime - startTime : void 0;
215
+ const category = getToolCategory(part.tool);
216
+ const DefaultIcon = TOOL_CATEGORY_ICON_MAP[category] ?? Settings;
217
+ const shapeClass = {
218
+ single: "rounded-[var(--radius-lg)]",
219
+ first: "rounded-t-[var(--radius-lg)] rounded-b-[var(--radius-sm)]",
220
+ middle: "rounded-[var(--radius-sm)]",
221
+ last: "rounded-t-[var(--radius-sm)] rounded-b-[var(--radius-lg)]"
222
+ }[groupPosition];
223
+ return /* @__PURE__ */ jsxs2(Collapsible.Root, { open, onOpenChange: setOpen, children: [
224
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-2", children: [
225
+ /* @__PURE__ */ jsx3(Collapsible.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
226
+ "button",
227
+ {
228
+ className: cn(
229
+ "w-full border text-left transition-colors",
230
+ "border-[var(--border-subtle)] bg-card/40 hover:border-border hover:bg-accent/25",
231
+ open && "border-border bg-accent/20",
232
+ shapeClass,
233
+ className
234
+ ),
235
+ children: [
236
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-2.5 py-1.5", children: [
237
+ /* @__PURE__ */ jsx3("div", { className: cn(
238
+ "shrink-0",
239
+ isRunning && "text-primary",
240
+ isComplete && "text-[var(--surface-success-text)]",
241
+ isError && "text-[var(--surface-danger-text)]",
242
+ !isRunning && !isComplete && !isError && "text-muted-foreground"
243
+ ), children: isRunning ? /* @__PURE__ */ jsx3(Loader22, { className: "h-3.5 w-3.5 animate-spin" }) : isComplete ? /* @__PURE__ */ jsx3(CheckCircle2, { className: "h-3.5 w-3.5" }) : isError ? /* @__PURE__ */ jsx3(AlertCircle2, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx3(DefaultIcon, { className: "h-3.5 w-3.5" }) }),
244
+ /* @__PURE__ */ jsx3("span", { className: "truncate text-xs font-medium text-foreground", children: title }),
245
+ description ? /* @__PURE__ */ jsx3("span", { className: "hidden truncate text-xs font-mono text-muted-foreground sm:inline", children: description }) : null,
246
+ /* @__PURE__ */ jsxs2("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
247
+ isRunning && startTime ? /* @__PURE__ */ jsx3(LiveDuration, { startTime }) : null,
248
+ !isRunning && durationMs != null ? /* @__PURE__ */ jsx3("span", { className: "text-[10px] font-mono tabular-nums text-muted-foreground", children: formatDuration(durationMs) }) : null,
249
+ isError ? /* @__PURE__ */ jsx3("span", { className: "rounded-full border border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-1.5 py-px text-[10px] font-semibold uppercase text-[var(--surface-danger-text)]", children: "Failed" }) : null,
250
+ isRunning ? /* @__PURE__ */ jsx3("span", { className: "rounded-full border border-[var(--border-accent)] bg-primary/10 px-1.5 py-px text-[10px] font-semibold uppercase text-primary", children: "Running" }) : null,
251
+ open ? /* @__PURE__ */ jsx3(ChevronDown, { className: "h-3 w-3 text-muted-foreground" }) : /* @__PURE__ */ jsx3(ChevronRight, { className: "h-3 w-3 text-muted-foreground" })
252
+ ] })
253
+ ] }),
254
+ errorText && !open ? /* @__PURE__ */ jsx3("div", { className: "border-t border-border px-3 py-2 text-xs text-red-200", children: errorText }) : null
255
+ ]
256
+ }
257
+ ) }),
258
+ actions ? /* @__PURE__ */ jsx3(
259
+ "div",
260
+ {
261
+ className: "flex shrink-0 flex-wrap items-center justify-end gap-1.5 pt-1",
262
+ onClick: (event) => event.stopPropagation(),
263
+ children: actions
264
+ }
265
+ ) : null
266
+ ] }),
267
+ /* @__PURE__ */ jsx3(Collapsible.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx3("div", { className: cn("mt-1.5 ml-2.5 border-l-2 border-primary/15 pl-3.5", contentClassName), children: renderToolDetail?.(part) ?? /* @__PURE__ */ jsx3(ExpandedToolDetail, { part }) }) })
268
+ ] });
269
+ }
270
+ );
271
+ InlineToolItem.displayName = "InlineToolItem";
272
+
273
+ // src/run/tool-call-step.tsx
274
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
275
+ var EXT_LANGUAGE = {
276
+ ts: "typescript",
277
+ tsx: "typescript",
278
+ js: "javascript",
279
+ jsx: "javascript",
280
+ mjs: "javascript",
281
+ cjs: "javascript",
282
+ css: "css",
283
+ scss: "scss",
284
+ json: "json",
285
+ jsonc: "json",
286
+ md: "markdown",
287
+ mdx: "markdown",
288
+ py: "python",
289
+ sh: "bash",
290
+ bash: "bash",
291
+ zsh: "bash",
292
+ html: "html",
293
+ htm: "html",
294
+ yaml: "yaml",
295
+ yml: "yaml",
296
+ toml: "toml",
297
+ rs: "rust",
298
+ go: "go",
299
+ sql: "sql",
300
+ xml: "xml"
301
+ };
302
+ function inferLanguage(detail, language) {
303
+ if (language) return language;
304
+ if (!detail) return void 0;
305
+ const ext = detail.split(".").pop()?.toLowerCase();
306
+ return ext ? EXT_LANGUAGE[ext] : void 0;
307
+ }
308
+ var STATUS_MAP = {
309
+ running: "running",
310
+ success: "completed",
311
+ error: "error"
312
+ };
313
+ function ToolCallStep({
314
+ type,
315
+ label,
316
+ status,
317
+ detail,
318
+ output,
319
+ language,
320
+ duration,
321
+ className
322
+ }) {
323
+ const part = {
324
+ type: "tool",
325
+ id: `${type}:${label}`,
326
+ tool: type,
327
+ state: {
328
+ status: STATUS_MAP[status],
329
+ input: detail ? { detail } : void 0,
330
+ output,
331
+ time: duration != null ? { start: 0, end: duration } : void 0
332
+ }
333
+ };
334
+ const lang = inferLanguage(detail, language);
335
+ return /* @__PURE__ */ jsx4(
336
+ InlineToolItem,
337
+ {
338
+ part,
339
+ title: label,
340
+ description: detail,
341
+ className,
342
+ renderToolDetail: output ? () => /* @__PURE__ */ jsx4(
343
+ CodeBlock,
344
+ {
345
+ code: output,
346
+ language: lang,
347
+ className: "max-h-72 overflow-auto text-xs"
348
+ }
349
+ ) : () => null
350
+ }
351
+ );
352
+ }
353
+ function ToolCallGroup({ title, children, className }) {
354
+ return /* @__PURE__ */ jsxs3("div", { className: ["my-2 space-y-2", className].filter(Boolean).join(" "), children: [
355
+ title && /* @__PURE__ */ jsx4("div", { className: "mb-1 px-1 text-xs font-medium uppercase tracking-wider text-muted-foreground", children: title }),
356
+ children
357
+ ] });
358
+ }
359
+
360
+ export {
361
+ ExpandedToolDetail,
362
+ LiveDuration,
363
+ InlineToolItem,
364
+ ToolCallStep,
365
+ ToolCallGroup
366
+ };