@tangle-network/sandbox-ui 0.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 (70) hide show
  1. package/README.md +68 -0
  2. package/dist/auth.d.ts +57 -0
  3. package/dist/auth.js +14 -0
  4. package/dist/branding-DCi5VEik.d.ts +13 -0
  5. package/dist/button-BidTtuRS.d.ts +15 -0
  6. package/dist/chat.d.ts +121 -0
  7. package/dist/chat.js +25 -0
  8. package/dist/chunk-2UHPE5T7.js +201 -0
  9. package/dist/chunk-4EIWPJMJ.js +545 -0
  10. package/dist/chunk-6MQIDUPA.js +502 -0
  11. package/dist/chunk-B26TQ7SA.js +47 -0
  12. package/dist/chunk-E6FS7R4X.js +109 -0
  13. package/dist/chunk-GRYHFH5O.js +110 -0
  14. package/dist/chunk-HMND7JPA.js +868 -0
  15. package/dist/chunk-HRMUF35V.js +19 -0
  16. package/dist/chunk-HYEAX3DC.js +822 -0
  17. package/dist/chunk-KMXV7DDX.js +174 -0
  18. package/dist/chunk-KYY2X6LY.js +318 -0
  19. package/dist/chunk-L6ZDH5F4.js +334 -0
  20. package/dist/chunk-LTFK464G.js +103 -0
  21. package/dist/chunk-M34OA6PQ.js +233 -0
  22. package/dist/chunk-M6VLC32S.js +219 -0
  23. package/dist/chunk-MCGKDCOR.js +173 -0
  24. package/dist/chunk-NI2EI43H.js +294 -0
  25. package/dist/chunk-OU4TRNQZ.js +173 -0
  26. package/dist/chunk-QD4QE5P5.js +40 -0
  27. package/dist/chunk-QSQBDR3N.js +180 -0
  28. package/dist/chunk-RQHJBTEU.js +10 -0
  29. package/dist/chunk-U62G5TS7.js +472 -0
  30. package/dist/chunk-ZOL2TR5M.js +475 -0
  31. package/dist/dashboard.d.ts +111 -0
  32. package/dist/dashboard.js +26 -0
  33. package/dist/editor.d.ts +196 -0
  34. package/dist/editor.js +713 -0
  35. package/dist/expanded-tool-detail-OkXGqTHe.d.ts +52 -0
  36. package/dist/files.d.ts +66 -0
  37. package/dist/files.js +11 -0
  38. package/dist/hooks.d.ts +22 -0
  39. package/dist/hooks.js +107 -0
  40. package/dist/index.d.ts +107 -0
  41. package/dist/index.js +551 -0
  42. package/dist/markdown.d.ts +55 -0
  43. package/dist/markdown.js +17 -0
  44. package/dist/pages.d.ts +89 -0
  45. package/dist/pages.js +1181 -0
  46. package/dist/parts-CyGkM6Fp.d.ts +50 -0
  47. package/dist/primitives.d.ts +189 -0
  48. package/dist/primitives.js +161 -0
  49. package/dist/run-CtFZ6s-D.d.ts +41 -0
  50. package/dist/run.d.ts +14 -0
  51. package/dist/run.js +29 -0
  52. package/dist/sidecar-CFU2W9j1.d.ts +8 -0
  53. package/dist/stores.d.ts +28 -0
  54. package/dist/stores.js +49 -0
  55. package/dist/terminal.d.ts +44 -0
  56. package/dist/terminal.js +160 -0
  57. package/dist/tool-call-feed-D5Ume-Pt.d.ts +66 -0
  58. package/dist/tool-display-BvsVW_Ur.d.ts +32 -0
  59. package/dist/types.d.ts +6 -0
  60. package/dist/types.js +0 -0
  61. package/dist/usage-chart-DINgSVL5.d.ts +60 -0
  62. package/dist/use-sidecar-auth-Bb0-w3lX.d.ts +339 -0
  63. package/dist/utils.d.ts +28 -0
  64. package/dist/utils.js +28 -0
  65. package/dist/workspace.d.ts +113 -0
  66. package/dist/workspace.js +15 -0
  67. package/package.json +174 -0
  68. package/src/styles/globals.css +230 -0
  69. package/src/styles/tokens.css +73 -0
  70. package/tailwind.config.cjs +99 -0
@@ -0,0 +1,502 @@
1
+ import {
2
+ CodeBlock,
3
+ CopyButton,
4
+ Markdown
5
+ } from "./chunk-LTFK464G.js";
6
+ import {
7
+ formatDuration,
8
+ truncateText
9
+ } from "./chunk-HRMUF35V.js";
10
+ import {
11
+ getToolCategory,
12
+ getToolDisplayMetadata,
13
+ getToolErrorText
14
+ } from "./chunk-QSQBDR3N.js";
15
+ import {
16
+ cn
17
+ } from "./chunk-RQHJBTEU.js";
18
+
19
+ // src/tool-previews/command-preview.tsx
20
+ import { memo, useState } from "react";
21
+ import {
22
+ Terminal,
23
+ ChevronDown,
24
+ ChevronRight,
25
+ Loader2
26
+ } from "lucide-react";
27
+ import { jsx, jsxs } from "react/jsx-runtime";
28
+ function extractCommandOutput(output) {
29
+ if (!output) return { stdout: "", stderr: "", exitCode: 0 };
30
+ if (typeof output === "string") return { stdout: output, stderr: "", exitCode: 0 };
31
+ if (typeof output === "object" && output !== null) {
32
+ const obj = output;
33
+ return {
34
+ stdout: String(obj.stdout ?? obj.output ?? ""),
35
+ stderr: String(obj.stderr ?? ""),
36
+ exitCode: Number(obj.exitCode ?? obj.exit_code ?? obj.code ?? 0)
37
+ };
38
+ }
39
+ return { stdout: String(output), stderr: "", exitCode: 0 };
40
+ }
41
+ var CommandPreview = memo(({ part }) => {
42
+ const [expanded, setExpanded] = useState(true);
43
+ const input = part.state.input;
44
+ const command = typeof input?.command === "string" ? input.command : String(input ?? "");
45
+ const output = part.state.status === "completed" ? extractCommandOutput(part.state.output) : null;
46
+ const isError = output ? output.exitCode !== 0 : part.state.status === "error";
47
+ const errorText = part.state.error;
48
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg overflow-hidden border border-neutral-200/50 dark:border-neutral-700/50", children: [
49
+ /* @__PURE__ */ jsxs(
50
+ "button",
51
+ {
52
+ onClick: () => setExpanded((e) => !e),
53
+ className: "w-full flex items-center gap-2 px-3 py-2 bg-neutral-100/80 dark:bg-neutral-800/80 hover:bg-neutral-100 dark:hover:bg-neutral-800 transition-colors text-left",
54
+ children: [
55
+ /* @__PURE__ */ jsx(Terminal, { className: "w-3.5 h-3.5 text-neutral-400 shrink-0" }),
56
+ /* @__PURE__ */ jsx("code", { className: "text-xs font-mono text-neutral-800 dark:text-neutral-200 truncate flex-1", children: command }),
57
+ output && /* @__PURE__ */ jsx(
58
+ "span",
59
+ {
60
+ className: cn(
61
+ "text-xs font-mono px-1.5 py-0.5 rounded",
62
+ isError ? "bg-red-100/50 dark:bg-red-900/50 text-red-500 dark:text-red-400" : "bg-green-100/50 dark:bg-green-900/50 text-green-600 dark:text-green-400"
63
+ ),
64
+ children: output.exitCode
65
+ }
66
+ ),
67
+ expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3 text-neutral-400 dark:text-neutral-500" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-neutral-400 dark:text-neutral-500" })
68
+ ]
69
+ }
70
+ ),
71
+ expanded && /* @__PURE__ */ jsxs("div", { className: "max-h-80 overflow-y-auto bg-neutral-50/60 dark:bg-neutral-900/60", children: [
72
+ output?.stdout && /* @__PURE__ */ jsx("pre", { className: "p-3 text-xs font-mono text-neutral-600 dark:text-neutral-300 whitespace-pre-wrap break-all", children: output.stdout }),
73
+ output?.stderr && /* @__PURE__ */ jsx("pre", { className: "p-3 text-xs font-mono text-red-500/80 dark:text-red-400/80 whitespace-pre-wrap break-all border-t border-neutral-200/30 dark:border-neutral-700/30", children: output.stderr }),
74
+ errorText && /* @__PURE__ */ jsx("pre", { className: "p-3 text-xs font-mono text-red-500 dark:text-red-400 whitespace-pre-wrap break-all", children: errorText }),
75
+ part.state.status === "running" && /* @__PURE__ */ jsxs("div", { className: "p-3 flex items-center gap-2 text-xs text-neutral-400 dark:text-neutral-500", children: [
76
+ /* @__PURE__ */ jsx(Loader2, { className: "w-3 h-3 animate-spin" }),
77
+ "Running..."
78
+ ] })
79
+ ] })
80
+ ] });
81
+ });
82
+ CommandPreview.displayName = "CommandPreview";
83
+
84
+ // src/tool-previews/write-file-preview.tsx
85
+ import { memo as memo2 } from "react";
86
+ import { FileEdit } from "lucide-react";
87
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
88
+ function extractWriteContent(input) {
89
+ if (!input || typeof input !== "object") return null;
90
+ const obj = input;
91
+ const path = String(obj.file_path ?? obj.path ?? obj.filePath ?? "unknown");
92
+ const content = String(obj.content ?? obj.contents ?? obj.data ?? "");
93
+ return { path, content };
94
+ }
95
+ function getLanguageFromPath(path) {
96
+ const ext = path.split(".").pop()?.toLowerCase();
97
+ const map = {
98
+ ts: "typescript",
99
+ tsx: "tsx",
100
+ js: "javascript",
101
+ jsx: "jsx",
102
+ rs: "rust",
103
+ py: "python",
104
+ go: "go",
105
+ rb: "ruby",
106
+ json: "json",
107
+ yaml: "yaml",
108
+ yml: "yaml",
109
+ toml: "toml",
110
+ md: "markdown",
111
+ css: "css",
112
+ scss: "scss",
113
+ html: "html",
114
+ sh: "bash",
115
+ bash: "bash",
116
+ zsh: "bash",
117
+ sql: "sql",
118
+ sol: "solidity",
119
+ proto: "protobuf"
120
+ };
121
+ return ext ? map[ext] : void 0;
122
+ }
123
+ var WriteFilePreview = memo2(({ part }) => {
124
+ const write = extractWriteContent(part.state.input);
125
+ if (!write) return null;
126
+ const lineCount = write.content.split("\n").length;
127
+ const language = getLanguageFromPath(write.path);
128
+ return /* @__PURE__ */ jsxs2("div", { className: "rounded-lg overflow-hidden border border-neutral-200/50 dark:border-neutral-700/50", children: [
129
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-3 py-2 bg-neutral-100/80 dark:bg-neutral-800/80", children: [
130
+ /* @__PURE__ */ jsx2(FileEdit, { className: "w-3.5 h-3.5 text-neutral-400 shrink-0" }),
131
+ /* @__PURE__ */ jsx2("span", { className: "text-xs font-mono text-neutral-600 dark:text-neutral-300 truncate flex-1", children: write.path }),
132
+ /* @__PURE__ */ jsxs2("span", { className: "text-xs text-neutral-400 dark:text-neutral-500", children: [
133
+ "+",
134
+ lineCount,
135
+ " line",
136
+ lineCount !== 1 ? "s" : ""
137
+ ] })
138
+ ] }),
139
+ /* @__PURE__ */ jsx2(CodeBlock, { code: write.content, language, className: "rounded-none", children: /* @__PURE__ */ jsx2(CopyButton, { text: write.content }) })
140
+ ] });
141
+ });
142
+ WriteFilePreview.displayName = "WriteFilePreview";
143
+
144
+ // src/run/expanded-tool-detail.tsx
145
+ import { memo as memo3 } from "react";
146
+ import {
147
+ ArrowRight,
148
+ ArrowLeft,
149
+ AlertCircle,
150
+ Loader2 as Loader22
151
+ } from "lucide-react";
152
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
153
+ function formatOutput(value) {
154
+ if (value == null) return "";
155
+ if (typeof value === "string") return value;
156
+ try {
157
+ return JSON.stringify(value, null, 2);
158
+ } catch {
159
+ return String(value);
160
+ }
161
+ }
162
+ var ExpandedToolDetail = memo3(({ part }) => {
163
+ const meta = getToolDisplayMetadata(part);
164
+ const { status, input, output, error } = part.state;
165
+ if (meta.displayVariant === "command") {
166
+ return /* @__PURE__ */ jsx3(CommandPreview, { part });
167
+ }
168
+ if (meta.displayVariant === "write-file") {
169
+ return /* @__PURE__ */ jsx3(WriteFilePreview, { part });
170
+ }
171
+ const inputStr = formatOutput(input);
172
+ const outputStr = formatOutput(output);
173
+ return /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
174
+ inputStr && /* @__PURE__ */ jsxs3("div", { className: "rounded-lg overflow-hidden border border-neutral-200/50 dark:border-neutral-700/50", children: [
175
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-neutral-100/80 dark:bg-neutral-800/80", children: [
176
+ /* @__PURE__ */ jsx3(ArrowRight, { className: "w-3 h-3 text-neutral-400" }),
177
+ /* @__PURE__ */ jsx3("span", { className: "text-xs text-neutral-500 dark:text-neutral-400", children: "Input" })
178
+ ] }),
179
+ /* @__PURE__ */ jsx3(CodeBlock, { code: inputStr, language: "json", className: "rounded-none" })
180
+ ] }),
181
+ status === "completed" && outputStr && /* @__PURE__ */ jsxs3("div", { className: "rounded-lg overflow-hidden border border-neutral-200/50 dark:border-neutral-700/50", children: [
182
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-neutral-100/80 dark:bg-neutral-800/80", children: [
183
+ /* @__PURE__ */ jsx3(ArrowLeft, { className: "w-3 h-3 text-neutral-400" }),
184
+ /* @__PURE__ */ jsx3("span", { className: "text-xs text-neutral-500 dark:text-neutral-400", children: "Output" })
185
+ ] }),
186
+ /* @__PURE__ */ jsx3(
187
+ CodeBlock,
188
+ {
189
+ code: outputStr.length > 2e3 ? outputStr.slice(0, 2e3) + "\n...(truncated)" : outputStr,
190
+ language: "json",
191
+ className: "rounded-none"
192
+ }
193
+ )
194
+ ] }),
195
+ error && /* @__PURE__ */ jsxs3("div", { className: "rounded-lg overflow-hidden border border-red-300/50 dark:border-red-900/50", children: [
196
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-red-100/30 dark:bg-red-900/30", children: [
197
+ /* @__PURE__ */ jsx3(AlertCircle, { className: "w-3 h-3 text-red-500 dark:text-red-400" }),
198
+ /* @__PURE__ */ jsx3("span", { className: "text-xs text-red-500 dark:text-red-400", children: "Error" })
199
+ ] }),
200
+ /* @__PURE__ */ jsx3("pre", { className: "p-3 text-xs font-mono text-red-600 dark:text-red-300 whitespace-pre-wrap break-all bg-neutral-50/60 dark:bg-neutral-900/60", children: error })
201
+ ] }),
202
+ (status === "pending" || status === "running") && /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 px-3 py-2 text-xs text-neutral-400 dark:text-neutral-500", children: [
203
+ /* @__PURE__ */ jsx3(Loader22, { className: "w-3 h-3 animate-spin" }),
204
+ "Running..."
205
+ ] })
206
+ ] });
207
+ });
208
+ ExpandedToolDetail.displayName = "ExpandedToolDetail";
209
+
210
+ // src/run/run-item-primitives.tsx
211
+ import { useEffect, useState as useState2 } from "react";
212
+ import { jsx as jsx4 } from "react/jsx-runtime";
213
+ function LiveDuration({ startTime }) {
214
+ const [elapsed, setElapsed] = useState2(Date.now() - startTime);
215
+ useEffect(() => {
216
+ const id = setInterval(() => setElapsed(Date.now() - startTime), 100);
217
+ return () => clearInterval(id);
218
+ }, [startTime]);
219
+ return /* @__PURE__ */ jsx4("span", { className: "text-xs font-mono text-neutral-400 dark:text-neutral-500 tabular-nums", children: formatDuration(elapsed) });
220
+ }
221
+
222
+ // src/run/inline-tool-item.tsx
223
+ import { memo as memo4, useState as useState3 } from "react";
224
+ import * as Collapsible from "@radix-ui/react-collapsible";
225
+ import {
226
+ Loader2 as Loader23,
227
+ CheckCircle2,
228
+ AlertCircle as AlertCircle2,
229
+ ChevronDown as ChevronDown2,
230
+ ChevronRight as ChevronRight2,
231
+ Terminal as Terminal2,
232
+ FileEdit as FileEdit2,
233
+ FileSearch,
234
+ Search,
235
+ PencilLine,
236
+ Bot,
237
+ Globe,
238
+ ClipboardList,
239
+ Settings
240
+ } from "lucide-react";
241
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
242
+ var TOOL_CATEGORY_ICON_MAP = {
243
+ command: Terminal2,
244
+ write: FileEdit2,
245
+ read: FileSearch,
246
+ search: Search,
247
+ edit: PencilLine,
248
+ task: Bot,
249
+ web: Globe,
250
+ todo: ClipboardList,
251
+ other: Settings
252
+ };
253
+ var InlineToolItem = memo4(
254
+ ({ part, renderToolDetail }) => {
255
+ const [open, setOpen] = useState3(false);
256
+ const meta = getToolDisplayMetadata(part);
257
+ const { status } = part.state;
258
+ const errorText = getToolErrorText(part);
259
+ const isRunning = status === "pending" || status === "running";
260
+ const isError = status === "error";
261
+ const isComplete = status === "completed";
262
+ const startTime = part.state.time?.start;
263
+ const endTime = part.state.time?.end;
264
+ const durationMs = startTime && endTime ? endTime - startTime : void 0;
265
+ const category = getToolCategory(part.tool);
266
+ const DefaultIcon = TOOL_CATEGORY_ICON_MAP[category] ?? Settings;
267
+ return /* @__PURE__ */ jsxs4(Collapsible.Root, { open, onOpenChange: setOpen, children: [
268
+ /* @__PURE__ */ jsx5(Collapsible.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs4(
269
+ "button",
270
+ {
271
+ className: cn(
272
+ "w-full flex items-center gap-2 px-3 py-1.5 text-left",
273
+ "rounded-md transition-colors text-xs",
274
+ "hover:bg-neutral-100/60 dark:hover:bg-neutral-800/60",
275
+ open && "bg-neutral-100/40 dark:bg-neutral-800/40"
276
+ ),
277
+ children: [
278
+ isRunning ? /* @__PURE__ */ jsx5(Loader23, { className: "w-4 h-4 shrink-0 animate-spin text-blue-500 dark:text-blue-400" }) : isComplete ? /* @__PURE__ */ jsx5(CheckCircle2, { className: "w-4 h-4 shrink-0 text-green-500 dark:text-green-400" }) : isError ? /* @__PURE__ */ jsx5(AlertCircle2, { className: "w-4 h-4 shrink-0 text-red-500 dark:text-red-400" }) : /* @__PURE__ */ jsx5(DefaultIcon, { className: "w-4 h-4 shrink-0 text-neutral-400 dark:text-neutral-400" }),
279
+ /* @__PURE__ */ jsx5("span", { className: "font-medium text-neutral-800 dark:text-neutral-200 shrink-0", children: meta.title }),
280
+ meta.description && /* @__PURE__ */ jsx5("span", { className: "text-neutral-400 dark:text-neutral-500 truncate flex-1 font-mono", children: meta.description }),
281
+ !meta.description && /* @__PURE__ */ jsx5("span", { className: "flex-1" }),
282
+ isRunning && startTime && /* @__PURE__ */ jsx5(LiveDuration, { startTime }),
283
+ !isRunning && durationMs != null && /* @__PURE__ */ jsx5("span", { className: "text-xs font-mono text-neutral-400 dark:text-neutral-500 tabular-nums", children: formatDuration(durationMs) }),
284
+ errorText && /* @__PURE__ */ jsx5("span", { className: "text-xs text-red-500 dark:text-red-400 truncate max-w-32", children: errorText }),
285
+ open ? /* @__PURE__ */ jsx5(ChevronDown2, { className: "w-3 h-3 text-neutral-400 dark:text-neutral-500 shrink-0" }) : /* @__PURE__ */ jsx5(ChevronRight2, { className: "w-3 h-3 text-neutral-400 dark:text-neutral-500 shrink-0" })
286
+ ]
287
+ }
288
+ ) }),
289
+ /* @__PURE__ */ jsx5(Collapsible.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx5("div", { className: "ml-6 mt-1 mb-2", children: renderToolDetail?.(part) ?? /* @__PURE__ */ jsx5(ExpandedToolDetail, { part }) }) })
290
+ ] });
291
+ }
292
+ );
293
+ InlineToolItem.displayName = "InlineToolItem";
294
+
295
+ // src/run/inline-thinking-item.tsx
296
+ import { memo as memo5, useState as useState4 } from "react";
297
+ import * as Collapsible2 from "@radix-ui/react-collapsible";
298
+ import { Brain, ChevronDown as ChevronDown3, ChevronRight as ChevronRight3 } from "lucide-react";
299
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
300
+ var InlineThinkingItem = memo5(({ part }) => {
301
+ const [open, setOpen] = useState4(false);
302
+ const startTime = part.time?.start;
303
+ const endTime = part.time?.end;
304
+ const durationMs = startTime && endTime ? endTime - startTime : void 0;
305
+ const isActive = startTime != null && endTime == null;
306
+ const preview = part.text ? truncateText(part.text, 100) : void 0;
307
+ return /* @__PURE__ */ jsxs5(Collapsible2.Root, { open, onOpenChange: setOpen, children: [
308
+ /* @__PURE__ */ jsx6(Collapsible2.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs5(
309
+ "button",
310
+ {
311
+ className: cn(
312
+ "w-full flex items-center gap-2 px-3 py-1.5 text-left",
313
+ "rounded-md transition-colors text-xs",
314
+ "hover:bg-neutral-100/60 dark:hover:bg-neutral-800/60",
315
+ open && "bg-neutral-100/40 dark:bg-neutral-800/40"
316
+ ),
317
+ children: [
318
+ /* @__PURE__ */ jsx6(
319
+ Brain,
320
+ {
321
+ className: cn(
322
+ "w-4 h-4 shrink-0",
323
+ isActive ? "text-purple-500 dark:text-purple-400 animate-pulse" : "text-neutral-400 dark:text-neutral-400"
324
+ )
325
+ }
326
+ ),
327
+ /* @__PURE__ */ jsx6("span", { className: "font-medium text-neutral-800 dark:text-neutral-200 shrink-0", children: isActive ? "Thinking..." : "Thought" }),
328
+ preview && !open && /* @__PURE__ */ jsx6("span", { className: "text-neutral-400 dark:text-neutral-500 truncate flex-1", children: preview }),
329
+ !preview && /* @__PURE__ */ jsx6("span", { className: "flex-1" }),
330
+ isActive && startTime && /* @__PURE__ */ jsx6(LiveDuration, { startTime }),
331
+ !isActive && durationMs != null && /* @__PURE__ */ jsx6("span", { className: "text-xs font-mono text-neutral-400 dark:text-neutral-500 tabular-nums", children: formatDuration(durationMs) }),
332
+ open ? /* @__PURE__ */ jsx6(ChevronDown3, { className: "w-3 h-3 text-neutral-400 dark:text-neutral-500 shrink-0" }) : /* @__PURE__ */ jsx6(ChevronRight3, { className: "w-3 h-3 text-neutral-400 dark:text-neutral-500 shrink-0" })
333
+ ]
334
+ }
335
+ ) }),
336
+ /* @__PURE__ */ jsx6(Collapsible2.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: part.text && /* @__PURE__ */ jsx6("div", { className: "ml-6 mt-1 mb-2 p-3 rounded-md bg-neutral-100/40 dark:bg-neutral-800/40 text-xs text-neutral-600 dark:text-neutral-300", children: /* @__PURE__ */ jsx6(Markdown, { children: part.text }) }) })
337
+ ] });
338
+ });
339
+ InlineThinkingItem.displayName = "InlineThinkingItem";
340
+
341
+ // src/run/run-group.tsx
342
+ import { memo as memo6, useMemo } from "react";
343
+ import * as Collapsible3 from "@radix-ui/react-collapsible";
344
+ import {
345
+ Bot as Bot2,
346
+ Loader2 as Loader24,
347
+ ChevronDown as ChevronDown4,
348
+ ChevronRight as ChevronRight4,
349
+ Terminal as Terminal3,
350
+ FileEdit as FileEdit3,
351
+ FileSearch as FileSearch2,
352
+ Search as Search2,
353
+ PencilLine as PencilLine2,
354
+ Globe as Globe2,
355
+ ClipboardList as ClipboardList2,
356
+ Settings as Settings2
357
+ } from "lucide-react";
358
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
359
+ var DEFAULT_BRANDING = {
360
+ label: "Agent",
361
+ accentClass: "text-blue-500 dark:text-blue-400",
362
+ bgClass: "bg-blue-500/5 dark:bg-blue-500/10",
363
+ containerBgClass: "bg-neutral-50/40 dark:bg-neutral-900/40",
364
+ borderClass: "border-blue-500/15 dark:border-blue-500/20",
365
+ iconClass: "",
366
+ textClass: "text-blue-500 dark:text-blue-400"
367
+ };
368
+ var CATEGORY_ICON_MAP = {
369
+ command: Terminal3,
370
+ write: FileEdit3,
371
+ read: FileSearch2,
372
+ search: Search2,
373
+ edit: PencilLine2,
374
+ task: Bot2,
375
+ web: Globe2,
376
+ todo: ClipboardList2,
377
+ other: Settings2
378
+ };
379
+ function CategoryBadges({ categories }) {
380
+ const sorted = useMemo(() => Array.from(categories).sort(), [categories]);
381
+ if (sorted.length === 0) return null;
382
+ return /* @__PURE__ */ jsx7("div", { className: "flex items-center gap-1", children: sorted.map((cat) => {
383
+ const Icon = CATEGORY_ICON_MAP[cat] ?? Settings2;
384
+ return /* @__PURE__ */ jsx7("span", { title: cat, children: /* @__PURE__ */ jsx7(Icon, { className: "w-3 h-3 text-neutral-400 dark:text-neutral-500" }) }, cat);
385
+ }) });
386
+ }
387
+ var RunGroup = memo6(
388
+ ({
389
+ run,
390
+ partMap,
391
+ collapsed,
392
+ onToggle,
393
+ branding = DEFAULT_BRANDING,
394
+ renderToolDetail
395
+ }) => {
396
+ const allParts = useMemo(() => {
397
+ const parts = [];
398
+ for (const msg of run.messages) {
399
+ const msgParts = partMap[msg.id] ?? [];
400
+ msgParts.forEach((part, index) => {
401
+ parts.push({ part, msgId: msg.id, index });
402
+ });
403
+ }
404
+ return parts;
405
+ }, [run.messages, partMap]);
406
+ const { stats, isStreaming } = run;
407
+ return /* @__PURE__ */ jsxs6(Collapsible3.Root, { open: !collapsed, onOpenChange: () => onToggle(), children: [
408
+ /* @__PURE__ */ jsx7(Collapsible3.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
409
+ "button",
410
+ {
411
+ className: cn(
412
+ "w-full flex items-center gap-2 px-3 py-2 text-left",
413
+ "rounded-lg transition-colors",
414
+ "hover:bg-neutral-100/60 dark:hover:bg-neutral-800/60",
415
+ branding.bgClass,
416
+ collapsed && branding.borderClass && `border ${branding.borderClass}`,
417
+ !collapsed && "border border-transparent"
418
+ ),
419
+ children: [
420
+ /* @__PURE__ */ jsx7(
421
+ Bot2,
422
+ {
423
+ className: cn("w-4 h-4 shrink-0", branding.accentClass)
424
+ }
425
+ ),
426
+ /* @__PURE__ */ jsx7(
427
+ "span",
428
+ {
429
+ className: cn("text-xs font-medium shrink-0", branding.textClass),
430
+ children: branding.label
431
+ }
432
+ ),
433
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3 flex-1 min-w-0", children: [
434
+ stats.toolCount > 0 && /* @__PURE__ */ jsxs6("span", { className: "text-xs text-neutral-400 dark:text-neutral-500", children: [
435
+ stats.toolCount,
436
+ " tool",
437
+ stats.toolCount !== 1 ? "s" : ""
438
+ ] }),
439
+ stats.thinkingDurationMs > 0 && /* @__PURE__ */ jsxs6("span", { className: "text-xs text-neutral-400 dark:text-neutral-500", children: [
440
+ formatDuration(stats.thinkingDurationMs),
441
+ " thinking"
442
+ ] }),
443
+ /* @__PURE__ */ jsx7(CategoryBadges, { categories: stats.toolCategories })
444
+ ] }),
445
+ isStreaming && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5", children: [
446
+ /* @__PURE__ */ jsx7(Loader24, { className: "w-3 h-3 text-blue-500 dark:text-blue-400 animate-spin" }),
447
+ /* @__PURE__ */ jsx7("span", { className: "text-xs text-blue-500 dark:text-blue-400", children: "Running" })
448
+ ] }),
449
+ !collapsed ? /* @__PURE__ */ jsx7(ChevronDown4, { className: "w-3.5 h-3.5 text-neutral-400 dark:text-neutral-500 shrink-0" }) : /* @__PURE__ */ jsx7(ChevronRight4, { className: "w-3.5 h-3.5 text-neutral-400 dark:text-neutral-500 shrink-0" })
450
+ ]
451
+ }
452
+ ) }),
453
+ collapsed && run.summaryText && /* @__PURE__ */ jsx7("div", { className: "px-3 py-2 text-xs text-neutral-500 dark:text-neutral-400 line-clamp-2", children: run.summaryText }),
454
+ /* @__PURE__ */ jsx7(Collapsible3.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: /* @__PURE__ */ jsx7(
455
+ "div",
456
+ {
457
+ className: cn(
458
+ "mt-1 space-y-0.5 rounded-lg p-2",
459
+ branding.containerBgClass
460
+ ),
461
+ children: allParts.map(({ part, msgId, index }) => {
462
+ const key = `${msgId}-${index}`;
463
+ if (part.type === "tool") {
464
+ return /* @__PURE__ */ jsx7(
465
+ InlineToolItem,
466
+ {
467
+ part,
468
+ renderToolDetail
469
+ },
470
+ key
471
+ );
472
+ }
473
+ if (part.type === "reasoning") {
474
+ return /* @__PURE__ */ jsx7(
475
+ InlineThinkingItem,
476
+ {
477
+ part
478
+ },
479
+ key
480
+ );
481
+ }
482
+ if (part.type === "text" && !part.synthetic && part.text.trim()) {
483
+ return /* @__PURE__ */ jsx7("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx7(Markdown, { children: part.text }) }, key);
484
+ }
485
+ return null;
486
+ })
487
+ }
488
+ ) })
489
+ ] });
490
+ }
491
+ );
492
+ RunGroup.displayName = "RunGroup";
493
+
494
+ export {
495
+ CommandPreview,
496
+ WriteFilePreview,
497
+ ExpandedToolDetail,
498
+ LiveDuration,
499
+ InlineToolItem,
500
+ InlineThinkingItem,
501
+ RunGroup
502
+ };
@@ -0,0 +1,47 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-RQHJBTEU.js";
4
+
5
+ // src/primitives/avatar.tsx
6
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
7
+ import * as React from "react";
8
+ import { jsx } from "react/jsx-runtime";
9
+ var Avatar = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
10
+ AvatarPrimitive.Root,
11
+ {
12
+ ref,
13
+ className: cn(
14
+ "relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
15
+ className
16
+ ),
17
+ ...props
18
+ }
19
+ ));
20
+ Avatar.displayName = AvatarPrimitive.Root.displayName;
21
+ var AvatarImage = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
22
+ AvatarPrimitive.Image,
23
+ {
24
+ ref,
25
+ className: cn("aspect-square h-full w-full", className),
26
+ ...props
27
+ }
28
+ ));
29
+ AvatarImage.displayName = AvatarPrimitive.Image.displayName;
30
+ var AvatarFallback = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
31
+ AvatarPrimitive.Fallback,
32
+ {
33
+ ref,
34
+ className: cn(
35
+ "flex h-full w-full items-center justify-center rounded-full bg-muted font-medium text-sm",
36
+ className
37
+ ),
38
+ ...props
39
+ }
40
+ ));
41
+ AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
42
+
43
+ export {
44
+ Avatar,
45
+ AvatarImage,
46
+ AvatarFallback
47
+ };
@@ -0,0 +1,109 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-RQHJBTEU.js";
4
+
5
+ // src/primitives/button.tsx
6
+ import { Slot } from "@radix-ui/react-slot";
7
+ import { cva } from "class-variance-authority";
8
+ import * as React from "react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ var buttonVariants = cva(
11
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg font-medium text-sm transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
12
+ {
13
+ variants: {
14
+ variant: {
15
+ default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 active:scale-[0.98]",
16
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90 active:scale-[0.98]",
17
+ outline: "border border-border bg-transparent hover:bg-accent hover:text-accent-foreground active:scale-[0.98]",
18
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80 active:scale-[0.98]",
19
+ ghost: "hover:bg-accent hover:text-accent-foreground",
20
+ link: "text-primary underline-offset-4 hover:underline",
21
+ sandbox: "bg-gradient-to-r from-purple-600 to-violet-500 text-white shadow-lg shadow-purple-500/25 hover:from-purple-700 hover:to-violet-600 hover:shadow-purple-500/40 active:scale-[0.98]"
22
+ },
23
+ size: {
24
+ default: "h-10 px-4 py-2",
25
+ sm: "h-9 rounded-md px-3 text-xs",
26
+ lg: "h-12 rounded-lg px-8 text-base",
27
+ xl: "h-14 rounded-xl px-10 text-lg",
28
+ icon: "h-10 w-10"
29
+ }
30
+ },
31
+ defaultVariants: {
32
+ variant: "default",
33
+ size: "default"
34
+ }
35
+ }
36
+ );
37
+ var Button = React.forwardRef(
38
+ ({
39
+ className,
40
+ variant,
41
+ size,
42
+ asChild = false,
43
+ loading = false,
44
+ disabled,
45
+ children,
46
+ ...props
47
+ }, ref) => {
48
+ const Comp = asChild ? Slot : "button";
49
+ if (asChild) {
50
+ return /* @__PURE__ */ jsx(
51
+ Comp,
52
+ {
53
+ className: cn(buttonVariants({ variant, size, className })),
54
+ ref,
55
+ ...props,
56
+ children
57
+ }
58
+ );
59
+ }
60
+ return /* @__PURE__ */ jsxs(
61
+ Comp,
62
+ {
63
+ className: cn(buttonVariants({ variant, size, className })),
64
+ ref,
65
+ disabled: disabled || loading,
66
+ ...props,
67
+ children: [
68
+ loading && /* @__PURE__ */ jsxs(
69
+ "svg",
70
+ {
71
+ className: "mr-2 -ml-1 h-4 w-4 animate-spin",
72
+ fill: "none",
73
+ viewBox: "0 0 24 24",
74
+ children: [
75
+ /* @__PURE__ */ jsx("title", { children: "Loading spinner" }),
76
+ /* @__PURE__ */ jsx(
77
+ "circle",
78
+ {
79
+ className: "opacity-25",
80
+ cx: "12",
81
+ cy: "12",
82
+ r: "10",
83
+ stroke: "currentColor",
84
+ strokeWidth: "4"
85
+ }
86
+ ),
87
+ /* @__PURE__ */ jsx(
88
+ "path",
89
+ {
90
+ className: "opacity-75",
91
+ fill: "currentColor",
92
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
93
+ }
94
+ )
95
+ ]
96
+ }
97
+ ),
98
+ children
99
+ ]
100
+ }
101
+ );
102
+ }
103
+ );
104
+ Button.displayName = "Button";
105
+
106
+ export {
107
+ buttonVariants,
108
+ Button
109
+ };