@tangle-network/sandbox-ui 0.6.1 → 0.9.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 (68) hide show
  1. package/README.md +5 -6
  2. package/dist/auth.d.ts +10 -6
  3. package/dist/auth.js +3 -3
  4. package/dist/{chat-container-Cg-GwyiK.d.ts → chat-container-f4yEs6KN.d.ts} +9 -1
  5. package/dist/chat.d.ts +12 -2
  6. package/dist/chat.js +10 -10
  7. package/dist/{chunk-WBQ7VULC.js → chunk-34A66VBG.js} +7 -7
  8. package/dist/{chunk-JP725R4W.js → chunk-34I7UFSX.js} +2 -2
  9. package/dist/{chunk-CNWVHQFY.js → chunk-54SQQMMM.js} +6 -24
  10. package/dist/{chunk-DLCFZDGX.js → chunk-5UM2XMEJ.js} +39 -14
  11. package/dist/{chunk-YYGECNZZ.js → chunk-66EZOYZR.js} +3 -3
  12. package/dist/{chunk-6V4XVKFY.js → chunk-7YWFOGKQ.js} +344 -338
  13. package/dist/{chunk-DCPYTL4W.js → chunk-D4CZWJCD.js} +72 -148
  14. package/dist/{chunk-XTPAWK7L.js → chunk-DI3NZ5ZX.js} +15 -51
  15. package/dist/{chunk-MXRQ4MJE.js → chunk-DXMIEK4K.js} +34 -23
  16. package/dist/{chunk-ZMWWE5RF.js → chunk-EXSOPXIY.js} +141 -123
  17. package/dist/{chunk-GW4GRAWJ.js → chunk-GSZA3TSY.js} +18 -12
  18. package/dist/{chunk-W4LM3QYZ.js → chunk-HB5Y37YU.js} +8 -8
  19. package/dist/{chunk-RKXIRRKQ.js → chunk-JLKYXLFN.js} +70 -66
  20. package/dist/{chunk-BRBTD7RH.js → chunk-MA7YKRUP.js} +28 -18
  21. package/dist/{chunk-TSE423UF.js → chunk-MKTSMWVD.js} +6 -6
  22. package/dist/{chunk-MJUDMVRU.js → chunk-MT5FJ3ZT.js} +17 -17
  23. package/dist/{chunk-565V6JTN.js → chunk-OHPW55EV.js} +60 -99
  24. package/dist/chunk-OKLQVY3Y.js +139 -0
  25. package/dist/{chunk-OVNLOE3Y.js → chunk-PLTZB5BC.js} +41 -41
  26. package/dist/{chunk-E2XT3G52.js → chunk-QC4BJEG6.js} +136 -137
  27. package/dist/{chunk-KH5UDAJ2.js → chunk-QDH5GEGY.js} +58 -54
  28. package/dist/{chunk-33W2TLUL.js → chunk-QID2OOMG.js} +12 -3
  29. package/dist/{chunk-FJSVPBKY.js → chunk-S7OXQTST.js} +17 -3
  30. package/dist/chunk-T7HMZEVO.js +216 -0
  31. package/dist/{chunk-FNYJFCGU.js → chunk-U6QTHMY6.js} +145 -256
  32. package/dist/{chunk-YS66Q3RC.js → chunk-US6JKJKH.js} +2 -2
  33. package/dist/chunk-VX3XOUEB.js +63 -0
  34. package/dist/{chunk-TDYQBLL5.js → chunk-ZMNSRDMH.js} +6 -6
  35. package/dist/dashboard.d.ts +156 -4
  36. package/dist/dashboard.js +885 -8
  37. package/dist/{document-editor-pane-DWWUTTTZ.js → document-editor-pane-TLPVRBBU.js} +3 -3
  38. package/dist/editor.d.ts +9 -8
  39. package/dist/editor.js +3 -3
  40. package/dist/files.js +3 -3
  41. package/dist/globals.css +4787 -69
  42. package/dist/hooks.d.ts +1 -1
  43. package/dist/hooks.js +7 -7
  44. package/dist/index.d.ts +4 -4
  45. package/dist/index.js +28 -28
  46. package/dist/markdown.js +1 -1
  47. package/dist/openui.js +5 -5
  48. package/dist/pages.d.ts +114 -5
  49. package/dist/pages.js +1978 -365
  50. package/dist/primitives.d.ts +5 -2
  51. package/dist/primitives.js +10 -10
  52. package/dist/run.js +4 -4
  53. package/dist/sdk-hooks.d.ts +2 -3
  54. package/dist/sdk-hooks.js +5 -5
  55. package/dist/styles.css +4787 -69
  56. package/dist/template-card-BAtvcAkU.d.ts +18 -0
  57. package/dist/terminal.d.ts +3 -1
  58. package/dist/terminal.js +66 -32
  59. package/dist/tokens.css +289 -237
  60. package/dist/{usage-chart-XCoB_7Xu.d.ts → usage-chart-SSiOgeQI.d.ts} +3 -1
  61. package/dist/{use-pty-session-COzVkhtc.d.ts → use-pty-session-0AOuwXgq.d.ts} +2 -0
  62. package/dist/{index-BT_-ecpc.d.ts → variant-list-CsS6ydgm.d.ts} +16 -7
  63. package/dist/workspace.d.ts +2 -2
  64. package/dist/workspace.js +13 -13
  65. package/package.json +18 -3
  66. package/tailwind.config.cjs +3 -2
  67. package/dist/chunk-3HW53XTH.js +0 -228
  68. package/dist/chunk-OKCIKTXQ.js +0 -63
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  ArtifactPane
3
- } from "./chunk-W4LM3QYZ.js";
3
+ } from "./chunk-HB5Y37YU.js";
4
4
  import {
5
5
  Markdown
6
- } from "./chunk-3HW53XTH.js";
6
+ } from "./chunk-T7HMZEVO.js";
7
7
  import {
8
8
  cn
9
9
  } from "./chunk-RQHJBTEU.js";
@@ -92,9 +92,9 @@ function getFileColor(name) {
92
92
  case "xlsx":
93
93
  return "text-emerald-400";
94
94
  case "md":
95
- return "text-[var(--text-secondary)]";
95
+ return "text-foreground";
96
96
  default:
97
- return "text-[var(--text-muted)]";
97
+ return "text-muted-foreground";
98
98
  }
99
99
  }
100
100
  function TreeNode({ node, depth, selectedPath, onSelect, defaultExpanded }) {
@@ -108,25 +108,27 @@ function TreeNode({ node, depth, selectedPath, onSelect, defaultExpanded }) {
108
108
  onSelect?.(node.path, node);
109
109
  };
110
110
  const Icon = isDir ? expanded ? FolderOpen : Folder : getFileIcon(node.name);
111
- const iconColor = isDir ? "text-[var(--brand-cool)]" : getFileColor(node.name);
111
+ const iconColor = isDir ? "text-primary" : getFileColor(node.name);
112
112
  return /* @__PURE__ */ jsxs("div", { children: [
113
113
  /* @__PURE__ */ jsxs(
114
114
  "button",
115
115
  {
116
- onClick: handleClick,
116
+ type: "button",
117
117
  className: cn(
118
- "flex items-center gap-1.5 w-full text-left px-2 py-1 rounded-[var(--radius-sm)] text-sm transition-colors",
119
- "hover:bg-[var(--bg-hover)]",
120
- isSelected && "bg-[var(--brand-cool)]/10 text-[var(--text-primary)]",
121
- !isSelected && "text-[var(--text-secondary)]"
118
+ "flex items-center gap-1.5 w-full text-left px-2 py-[2px] cursor-pointer text-[13px] transition-colors",
119
+ "appearance-none bg-transparent border-none",
120
+ "hover:bg-accent",
121
+ isSelected ? "bg-primary/15 text-foreground" : "text-foreground"
122
122
  ),
123
123
  style: { paddingLeft: `${depth * 16 + 8}px` },
124
+ onClick: handleClick,
125
+ "aria-expanded": isDir ? expanded : void 0,
124
126
  children: [
125
127
  isDir && /* @__PURE__ */ jsx(
126
128
  ChevronRight,
127
129
  {
128
130
  className: cn(
129
- "h-3 w-3 shrink-0 text-[var(--text-muted)] transition-transform",
131
+ "h-3 w-3 shrink-0 text-muted-foreground transition-transform",
130
132
  expanded && "rotate-90"
131
133
  )
132
134
  }
@@ -134,7 +136,7 @@ function TreeNode({ node, depth, selectedPath, onSelect, defaultExpanded }) {
134
136
  !isDir && /* @__PURE__ */ jsx("span", { className: "w-3" }),
135
137
  /* @__PURE__ */ jsx(Icon, { className: cn("h-4 w-4 shrink-0", iconColor) }),
136
138
  /* @__PURE__ */ jsx("span", { className: "truncate", children: node.name }),
137
- node.size !== void 0 && !isDir && /* @__PURE__ */ jsx("span", { className: "text-[var(--text-muted)] text-xs ml-auto tabular-nums", children: formatSize(node.size) })
139
+ node.size !== void 0 && !isDir && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs ml-auto tabular-nums", children: formatSize(node.size) })
138
140
  ]
139
141
  }
140
142
  ),
@@ -171,7 +173,7 @@ function FileTree({
171
173
  if (!visibleRoot) {
172
174
  return null;
173
175
  }
174
- return /* @__PURE__ */ jsx("div", { className: cn("text-sm font-[var(--font-sans)]", className), children: visibleRoot.children ? visibleRoot.children.sort((a, b) => {
176
+ return /* @__PURE__ */ jsx("div", { className: cn("text-sm font-sans", className), children: visibleRoot.children ? visibleRoot.children.sort((a, b) => {
175
177
  if (a.type !== b.type) return a.type === "directory" ? -1 : 1;
176
178
  return a.name.localeCompare(b.name);
177
179
  }).map((child) => /* @__PURE__ */ jsx(
@@ -209,11 +211,12 @@ function getPreviewType(filename, mimeType) {
209
211
  if (mimeType?.startsWith("image/") || ["png", "jpg", "jpeg", "gif", "svg", "webp"].includes(ext)) return "image";
210
212
  if (["csv"].includes(ext)) return "csv";
211
213
  if (["xlsx", "xls"].includes(ext)) return "spreadsheet";
212
- if (["py", "ts", "js", "tsx", "jsx", "sh", "bash"].includes(ext)) return "code";
214
+ if (["py", "ts", "js", "tsx", "jsx", "sh", "bash"].includes(ext) || ["profile", "bashrc", "bash_logout", "env", "gitignore"].includes(ext)) return "code";
213
215
  if (["json"].includes(ext)) return "json";
214
216
  if (["yaml", "yml"].includes(ext)) return "yaml";
215
217
  if (["md", "markdown"].includes(ext)) return "markdown";
216
218
  if (["txt", "log", "text"].includes(ext)) return "text";
219
+ if (mimeType?.startsWith("text/plain")) return "text";
217
220
  return "unknown";
218
221
  }
219
222
  function getPreviewLabel(previewType) {
@@ -243,15 +246,15 @@ function getPreviewLabel(previewType) {
243
246
  function CodePreview({ content, filename }) {
244
247
  const lines = content.split("\n");
245
248
  const language = filename.split(".").pop()?.toUpperCase() || "TXT";
246
- return /* @__PURE__ */ jsxs2("div", { className: "relative bg-[var(--bg-input)] rounded-[var(--radius-md)] border border-[var(--border-subtle)] overflow-hidden", children: [
247
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between gap-3 border-b border-[var(--border-subtle)] px-4 py-2.5", children: [
249
+ return /* @__PURE__ */ jsxs2("div", { className: "relative bg-background rounded-[var(--radius-md)] border border-border overflow-hidden", children: [
250
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between gap-3 border-b border-border px-4 py-2.5", children: [
248
251
  /* @__PURE__ */ jsxs2("div", { className: "flex gap-1.5", children: [
249
252
  /* @__PURE__ */ jsx2("div", { className: "w-3 h-3 rounded-full bg-[#FF5F57]" }),
250
253
  /* @__PURE__ */ jsx2("div", { className: "w-3 h-3 rounded-full bg-[#FEBC2E]" }),
251
254
  /* @__PURE__ */ jsx2("div", { className: "w-3 h-3 rounded-full bg-[#8E59FF]" })
252
255
  ] }),
253
- /* @__PURE__ */ jsx2("div", { className: "ml-2 min-w-0 flex-1 truncate text-xs font-[var(--font-mono)] text-[var(--text-muted)]", children: filename }),
254
- /* @__PURE__ */ jsxs2("div", { className: "inline-flex items-center gap-2 rounded-[var(--radius-full)] border border-[var(--border-subtle)] bg-[var(--bg-card)] px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-[var(--text-muted)]", children: [
256
+ /* @__PURE__ */ jsx2("div", { className: "ml-2 min-w-0 flex-1 truncate text-xs font-mono text-muted-foreground", children: filename }),
257
+ /* @__PURE__ */ jsxs2("div", { className: "inline-flex items-center gap-2 rounded-[var(--radius-full)] border border-border bg-card px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground", children: [
255
258
  /* @__PURE__ */ jsx2("span", { children: language }),
256
259
  /* @__PURE__ */ jsx2("span", { className: "h-1 w-1 rounded-full bg-[var(--border-hover)]" }),
257
260
  /* @__PURE__ */ jsxs2("span", { children: [
@@ -260,9 +263,9 @@ function CodePreview({ content, filename }) {
260
263
  ] })
261
264
  ] })
262
265
  ] }),
263
- /* @__PURE__ */ jsx2("div", { className: "overflow-auto max-h-[70vh]", children: /* @__PURE__ */ jsx2("table", { className: "w-full", children: /* @__PURE__ */ jsx2("tbody", { children: lines.map((line, i) => /* @__PURE__ */ jsxs2("tr", { className: "hover:bg-[var(--bg-hover)]", children: [
264
- /* @__PURE__ */ jsx2("td", { className: "text-right pr-4 pl-4 py-0 select-none text-[var(--text-muted)] text-xs font-[var(--font-mono)] w-10 align-top leading-[1.55]", children: i + 1 }),
265
- /* @__PURE__ */ jsx2("td", { className: "pr-4 py-0 font-[var(--font-mono)] text-[13px] text-[var(--text-secondary)] leading-[1.55] whitespace-pre", children: line || " " })
266
+ /* @__PURE__ */ jsx2("div", { className: "overflow-auto max-h-[70vh]", children: /* @__PURE__ */ jsx2("table", { className: "w-full", children: /* @__PURE__ */ jsx2("tbody", { children: lines.map((line, i) => /* @__PURE__ */ jsxs2("tr", { className: "hover:bg-accent", children: [
267
+ /* @__PURE__ */ jsx2("td", { className: "text-right pr-4 pl-4 py-0 select-none text-muted-foreground text-xs font-mono w-10 align-top leading-[1.55]", children: i + 1 }),
268
+ /* @__PURE__ */ jsx2("td", { className: "pr-4 py-0 font-mono text-[13px] text-foreground leading-[1.55] whitespace-pre", children: line || " " })
266
269
  ] }, i)) }) }) })
267
270
  ] });
268
271
  }
@@ -299,19 +302,19 @@ function CsvPreview({ content }) {
299
302
  const rows = lines.slice(1).map(
300
303
  (line) => parseCsvRow(line).map((cell) => cell.replace(/^"|"$/g, ""))
301
304
  );
302
- return /* @__PURE__ */ jsx2("div", { className: "overflow-auto max-h-[70vh] rounded-[var(--radius-md)] border border-[var(--border-subtle)]", children: /* @__PURE__ */ jsxs2("table", { className: "w-full text-sm", children: [
303
- /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { className: "bg-[var(--bg-elevated)] sticky top-0", children: headers.map((h, i) => /* @__PURE__ */ jsx2(
305
+ return /* @__PURE__ */ jsx2("div", { className: "overflow-auto max-h-[70vh] rounded-[var(--radius-md)] border border-border", children: /* @__PURE__ */ jsxs2("table", { className: "w-full text-sm", children: [
306
+ /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { className: "bg-muted/50 sticky top-0", children: headers.map((h, i) => /* @__PURE__ */ jsx2(
304
307
  "th",
305
308
  {
306
- className: "px-3 py-2 text-left text-xs font-semibold text-[var(--text-secondary)] border-b border-[var(--border-subtle)] whitespace-nowrap",
309
+ className: "px-3 py-2 text-left text-xs font-semibold text-foreground border-b border-border whitespace-nowrap",
307
310
  children: h
308
311
  },
309
312
  i
310
313
  )) }) }),
311
- /* @__PURE__ */ jsx2("tbody", { children: rows.map((row, i) => /* @__PURE__ */ jsx2("tr", { className: "border-b border-[var(--border-subtle)] hover:bg-[var(--bg-hover)]", children: row.map((cell, j) => /* @__PURE__ */ jsx2(
314
+ /* @__PURE__ */ jsx2("tbody", { children: rows.map((row, i) => /* @__PURE__ */ jsx2("tr", { className: "border-b border-border hover:bg-accent", children: row.map((cell, j) => /* @__PURE__ */ jsx2(
312
315
  "td",
313
316
  {
314
- className: "px-3 py-1.5 text-[var(--text-secondary)] font-[var(--font-mono)] text-xs whitespace-nowrap",
317
+ className: "px-3 py-1.5 text-foreground font-mono text-xs whitespace-nowrap",
315
318
  children: cell
316
319
  },
317
320
  j
@@ -319,10 +322,10 @@ function CsvPreview({ content }) {
319
322
  ] }) });
320
323
  }
321
324
  function ImagePreview({ src, filename }) {
322
- return /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-center p-4 bg-[var(--bg-input)] rounded-[var(--radius-md)] border border-[var(--border-subtle)]", children: /* @__PURE__ */ jsx2("img", { src, alt: filename, className: "max-w-full max-h-[70vh] object-contain rounded" }) });
325
+ return /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-center p-4 bg-background rounded-[var(--radius-md)] border border-border", children: /* @__PURE__ */ jsx2("img", { src, alt: filename, className: "max-w-full max-h-[70vh] object-contain rounded" }) });
323
326
  }
324
327
  function PdfPreview({ blobUrl, filename }) {
325
- return /* @__PURE__ */ jsx2("div", { className: "rounded-[var(--radius-md)] border border-[var(--border-subtle)] overflow-hidden bg-[var(--bg-input)]", children: /* @__PURE__ */ jsx2(
328
+ return /* @__PURE__ */ jsx2("div", { className: "rounded-[var(--radius-md)] border border-border overflow-hidden bg-background", children: /* @__PURE__ */ jsx2(
326
329
  "iframe",
327
330
  {
328
331
  src: blobUrl,
@@ -332,25 +335,25 @@ function PdfPreview({ blobUrl, filename }) {
332
335
  ) });
333
336
  }
334
337
  function TextPreview({ content }) {
335
- return /* @__PURE__ */ jsx2("pre", { className: "bg-[var(--bg-input)] rounded-[var(--radius-md)] border border-[var(--border-subtle)] p-4 overflow-auto max-h-[70vh] text-sm text-[var(--text-secondary)] font-[var(--font-mono)] leading-[1.55]", children: content });
338
+ return /* @__PURE__ */ jsx2("pre", { className: "bg-background rounded-[var(--radius-md)] border border-border p-4 overflow-auto max-h-[70vh] text-sm text-foreground font-mono leading-[1.55]", children: content });
336
339
  }
337
340
  function UnsupportedPreview({
338
341
  filename,
339
342
  title,
340
343
  description
341
344
  }) {
342
- return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center justify-center rounded-[var(--radius-md)] border border-dashed border-[var(--border-subtle)] bg-[var(--bg-input)] px-6 py-16 text-center text-[var(--text-muted)]", children: [
345
+ return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center justify-center rounded-[var(--radius-md)] border border-dashed border-border bg-background px-6 py-16 text-center text-muted-foreground", children: [
343
346
  /* @__PURE__ */ jsx2(FileText2, { className: "mb-3 h-12 w-12 opacity-30" }),
344
- /* @__PURE__ */ jsx2("p", { className: "text-sm text-[var(--text-secondary)]", children: title }),
347
+ /* @__PURE__ */ jsx2("p", { className: "text-sm text-foreground", children: title }),
345
348
  /* @__PURE__ */ jsx2("p", { className: "mt-1 max-w-md text-xs", children: description }),
346
349
  /* @__PURE__ */ jsx2("p", { className: "mt-4 text-[11px] uppercase tracking-[0.12em]", children: filename })
347
350
  ] });
348
351
  }
349
352
  function MarkdownPreview({ content }) {
350
- return /* @__PURE__ */ jsx2("div", { className: "rounded-[var(--radius-md)] border border-[var(--border-subtle)] bg-[var(--bg-input)] p-5", children: /* @__PURE__ */ jsx2(Markdown, { className: "prose-sm max-w-none", children: content }) });
353
+ return /* @__PURE__ */ jsx2("div", { className: "rounded-[var(--radius-md)] border border-border bg-background p-5", children: /* @__PURE__ */ jsx2(Markdown, { className: "prose-sm max-w-none", children: content }) });
351
354
  }
352
355
  function EmptyPreview({ filename }) {
353
- return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center justify-center py-16 text-[var(--text-muted)]", children: [
356
+ return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center justify-center py-16 text-muted-foreground", children: [
354
357
  /* @__PURE__ */ jsx2(FileText2, { className: "h-12 w-12 mb-3 opacity-30" }),
355
358
  /* @__PURE__ */ jsxs2("p", { className: "text-sm", children: [
356
359
  "Cannot preview ",
@@ -373,10 +376,10 @@ function FilePreview({
373
376
  const previewLabel = getPreviewLabel(previewType);
374
377
  const hasRenderableSource = Boolean(content) || Boolean(blobUrl) || previewType === "unknown" || previewType === "spreadsheet";
375
378
  return /* @__PURE__ */ jsxs2("div", { className: cn("flex flex-col h-full", className), children: [
376
- !hideHeader && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-[var(--border-subtle)] shrink-0", children: [
379
+ !hideHeader && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border shrink-0", children: [
377
380
  /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
378
- /* @__PURE__ */ jsx2("div", { className: "truncate text-sm font-medium text-[var(--text-primary)]", children: filename }),
379
- /* @__PURE__ */ jsx2("div", { className: "mt-0.5 text-[11px] uppercase tracking-[0.12em] text-[var(--text-muted)]", children: previewLabel })
381
+ /* @__PURE__ */ jsx2("div", { className: "truncate text-sm font-medium text-foreground", children: filename }),
382
+ /* @__PURE__ */ jsx2("div", { className: "mt-0.5 text-[11px] uppercase tracking-[0.12em] text-muted-foreground", children: previewLabel })
380
383
  ] }),
381
384
  onDownload && /* @__PURE__ */ jsx2(
382
385
  "button",
@@ -384,7 +387,7 @@ function FilePreview({
384
387
  type: "button",
385
388
  onClick: onDownload,
386
389
  "aria-label": `Download ${filename}`,
387
- className: "p-1.5 rounded-[var(--radius-sm)] hover:bg-[var(--bg-hover)] text-[var(--text-muted)] hover:text-[var(--text-secondary)] transition-colors",
390
+ className: "p-1.5 rounded-[var(--radius-sm)] hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
388
391
  children: /* @__PURE__ */ jsx2(Download, { className: "h-4 w-4" })
389
392
  }
390
393
  ),
@@ -394,7 +397,7 @@ function FilePreview({
394
397
  type: "button",
395
398
  onClick: onClose,
396
399
  "aria-label": `Close ${filename}`,
397
- className: "p-1.5 rounded-[var(--radius-sm)] hover:bg-[var(--bg-hover)] text-[var(--text-muted)] hover:text-[var(--text-secondary)] transition-colors",
400
+ className: "p-1.5 rounded-[var(--radius-sm)] hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
398
401
  children: /* @__PURE__ */ jsx2(X, { className: "h-4 w-4" })
399
402
  }
400
403
  )
@@ -402,10 +405,10 @@ function FilePreview({
402
405
  /* @__PURE__ */ jsxs2("div", { className: "flex-1 overflow-auto p-3", children: [
403
406
  previewType === "pdf" && blobUrl && /* @__PURE__ */ jsx2(PdfPreview, { blobUrl, filename }),
404
407
  previewType === "image" && blobUrl && /* @__PURE__ */ jsx2(ImagePreview, { src: blobUrl, filename }),
405
- previewType === "csv" && content && /* @__PURE__ */ jsx2(CsvPreview, { content }),
406
- (previewType === "code" || previewType === "json" || previewType === "yaml") && content && /* @__PURE__ */ jsx2(CodePreview, { content, filename }),
407
- previewType === "text" && content && /* @__PURE__ */ jsx2(TextPreview, { content }),
408
- previewType === "markdown" && content && /* @__PURE__ */ jsx2(MarkdownPreview, { content }),
408
+ previewType === "csv" && typeof content === "string" && /* @__PURE__ */ jsx2(CsvPreview, { content }),
409
+ (previewType === "code" || previewType === "json" || previewType === "yaml") && typeof content === "string" && /* @__PURE__ */ jsx2(CodePreview, { content, filename }),
410
+ previewType === "text" && typeof content === "string" && /* @__PURE__ */ jsx2(TextPreview, { content }),
411
+ previewType === "markdown" && typeof content === "string" && /* @__PURE__ */ jsx2(MarkdownPreview, { content }),
409
412
  previewType === "spreadsheet" && /* @__PURE__ */ jsx2(
410
413
  UnsupportedPreview,
411
414
  {
@@ -414,8 +417,9 @@ function FilePreview({
414
417
  description: "Download the workbook or convert it to CSV when you need an inline preview."
415
418
  }
416
419
  ),
417
- previewType === "unknown" && /* @__PURE__ */ jsx2(EmptyPreview, { filename }),
418
- !hasRenderableSource && /* @__PURE__ */ jsx2(
420
+ previewType === "unknown" && typeof content !== "string" && /* @__PURE__ */ jsx2(EmptyPreview, { filename }),
421
+ previewType === "unknown" && typeof content === "string" && /* @__PURE__ */ jsx2(TextPreview, { content }),
422
+ !hasRenderableSource && typeof content !== "string" && /* @__PURE__ */ jsx2(
419
423
  UnsupportedPreview,
420
424
  {
421
425
  filename,
@@ -438,15 +442,15 @@ function getTabIcon(name) {
438
442
  }
439
443
  function FileTabs({ tabs, activeId, onSelect, onClose, className }) {
440
444
  if (tabs.length === 0) return null;
441
- return /* @__PURE__ */ jsx3("div", { className: cn("flex items-center border-b border-[var(--border-subtle)] bg-[var(--bg-dark)] overflow-x-auto", className), children: tabs.map((tab) => {
445
+ return /* @__PURE__ */ jsx3("div", { className: cn("flex items-center border-b border-border bg-background overflow-x-auto", className), children: tabs.map((tab) => {
442
446
  const isActive = tab.id === activeId;
443
447
  const Icon = getTabIcon(tab.name);
444
448
  return /* @__PURE__ */ jsxs3(
445
449
  "div",
446
450
  {
447
451
  className: cn(
448
- "group flex items-center border-r border-[var(--border-subtle)] shrink-0",
449
- isActive ? "bg-[var(--bg-card)] text-[var(--text-primary)] border-b-2 border-b-[var(--brand-cool)]" : "text-[var(--text-muted)] hover:bg-[var(--bg-elevated)]"
452
+ "group flex items-center border-r border-border shrink-0",
453
+ isActive ? "bg-card text-foreground border-b-2 border-b-primary" : "text-muted-foreground hover:bg-muted/50"
450
454
  ),
451
455
  children: [
452
456
  /* @__PURE__ */ jsxs3(
@@ -454,11 +458,11 @@ function FileTabs({ tabs, activeId, onSelect, onClose, className }) {
454
458
  {
455
459
  type: "button",
456
460
  onClick: () => onSelect(tab.id),
457
- className: "flex min-w-0 items-center gap-1.5 px-3 py-1.5 text-xs transition-colors hover:text-[var(--text-secondary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--brand-cool)]/60",
461
+ className: "flex min-w-0 items-center gap-1.5 px-3 py-1.5 text-xs transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary/60",
458
462
  children: [
459
463
  /* @__PURE__ */ jsx3(Icon, { className: "h-3 w-3 shrink-0" }),
460
464
  /* @__PURE__ */ jsx3("span", { className: "max-w-[120px] truncate", children: tab.name }),
461
- tab.dirty && /* @__PURE__ */ jsx3("span", { className: "h-1.5 w-1.5 rounded-full bg-[var(--brand-cool)]" })
465
+ tab.dirty && /* @__PURE__ */ jsx3("span", { className: "h-1.5 w-1.5 rounded-full bg-primary" })
462
466
  ]
463
467
  }
464
468
  ),
@@ -468,7 +472,7 @@ function FileTabs({ tabs, activeId, onSelect, onClose, className }) {
468
472
  type: "button",
469
473
  "aria-label": `Close ${tab.name}`,
470
474
  onClick: () => onClose(tab.id),
471
- className: "mr-1 rounded p-0.5 opacity-0 transition-opacity hover:bg-[var(--bg-hover)] focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-cool)]/60 group-hover:opacity-100",
475
+ className: "mr-1 rounded p-0.5 opacity-0 transition-opacity hover:bg-accent focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 group-hover:opacity-100",
472
476
  children: /* @__PURE__ */ jsx3(X2, { className: "h-2.5 w-2.5" })
473
477
  }
474
478
  )
@@ -484,7 +488,7 @@ import { lazy, Suspense } from "react";
484
488
  import { Download as Download2, X as X3 } from "lucide-react";
485
489
  import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
486
490
  var LazyDocumentEditorPane = lazy(async () => {
487
- const module = await import("./document-editor-pane-DWWUTTTZ.js");
491
+ const module = await import("./document-editor-pane-TLPVRBBU.js");
488
492
  return { default: module.DocumentEditorPane };
489
493
  });
490
494
  function FileArtifactPane({
@@ -525,7 +529,7 @@ function FileArtifactPane({
525
529
  type: "button",
526
530
  "aria-label": `Download ${filename}`,
527
531
  onClick: onDownload,
528
- className: "rounded-[var(--radius-sm)] p-1.5 text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-cool)]/60",
532
+ className: "rounded-[var(--radius-sm)] p-1.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
529
533
  children: /* @__PURE__ */ jsx4(Download2, { className: "h-4 w-4" })
530
534
  }
531
535
  ),
@@ -535,7 +539,7 @@ function FileArtifactPane({
535
539
  type: "button",
536
540
  "aria-label": `Close ${filename}`,
537
541
  onClick: onClose,
538
- className: "rounded-[var(--radius-sm)] p-1.5 text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-cool)]/60",
542
+ className: "rounded-[var(--radius-sm)] p-1.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
539
543
  children: /* @__PURE__ */ jsx4(X3, { className: "h-4 w-4" })
540
544
  }
541
545
  )
@@ -556,7 +560,7 @@ function FileArtifactPane({
556
560
  className,
557
561
  tabs: paneTabs,
558
562
  headerActions,
559
- children: /* @__PURE__ */ jsx4("div", { className: "flex min-h-[12rem] items-center justify-center rounded-[var(--radius-lg)] border border-dashed border-[var(--border-subtle)] bg-[var(--bg-section)] text-sm text-[var(--text-muted)]", children: "Loading editor\u2026" })
563
+ children: /* @__PURE__ */ jsx4("div", { className: "flex min-h-[12rem] items-center justify-center rounded-[var(--radius-lg)] border border-dashed border-border bg-muted text-sm text-muted-foreground", children: "Loading editor\u2026" })
560
564
  }
561
565
  ),
562
566
  children: /* @__PURE__ */ jsx4(
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  ToolCallGroup,
3
3
  ToolCallStep
4
- } from "./chunk-MJUDMVRU.js";
4
+ } from "./chunk-MT5FJ3ZT.js";
5
5
  import {
6
6
  Markdown
7
- } from "./chunk-3HW53XTH.js";
7
+ } from "./chunk-T7HMZEVO.js";
8
8
  import {
9
9
  cn
10
10
  } from "./chunk-RQHJBTEU.js";
@@ -54,7 +54,7 @@ function parseToolEvent(event) {
54
54
  const toolName = data.name || data.tool || "unknown";
55
55
  const input = data.input;
56
56
  return {
57
- id: data.id || data.toolUseId || crypto.randomUUID(),
57
+ id: data.id || data.toolUseId || createId(),
58
58
  type: mapToolName(toolName),
59
59
  label: formatToolLabel(toolName, input),
60
60
  status: "running",
@@ -73,6 +73,15 @@ function parseToolEvent(event) {
73
73
  }
74
74
  return null;
75
75
  }
76
+ function createId() {
77
+ if (typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.randomUUID === "function") {
78
+ try {
79
+ return globalThis.crypto.randomUUID();
80
+ } catch {
81
+ }
82
+ }
83
+ return `tool_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
84
+ }
76
85
  function mapToolName(name) {
77
86
  const lower = name.toLowerCase();
78
87
  if (lower.includes("bash") || lower.includes("terminal") || lower.includes("exec")) return "bash";
@@ -8,12 +8,18 @@ function useAuth({
8
8
  const [user, setUser] = React.useState(null);
9
9
  const [isLoading, setIsLoading] = React.useState(true);
10
10
  const [error, setError] = React.useState(null);
11
+ const retryTimerRef = React.useRef(null);
12
+ const abortRef = React.useRef(null);
11
13
  const fetchSession = React.useCallback(async () => {
14
+ abortRef.current?.abort();
15
+ const controller = new AbortController();
16
+ abortRef.current = controller;
12
17
  setIsLoading(true);
13
18
  setError(null);
14
19
  try {
15
20
  const res = await fetch(`${apiBaseUrl}/auth/session`, {
16
- credentials: "include"
21
+ credentials: "include",
22
+ signal: controller.signal
17
23
  });
18
24
  if (!res.ok) {
19
25
  throw new Error("Not authenticated");
@@ -25,17 +31,25 @@ function useAuth({
25
31
  setUser(null);
26
32
  }
27
33
  } catch (err) {
34
+ if (err.name === "AbortError") return;
28
35
  setError(err instanceof Error ? err : new Error("Unknown error"));
29
36
  setUser(null);
30
37
  if (shouldRetryOnError) {
31
- setTimeout(fetchSession, 5e3);
38
+ if (retryTimerRef.current) clearTimeout(retryTimerRef.current);
39
+ retryTimerRef.current = setTimeout(fetchSession, 5e3);
32
40
  }
33
41
  } finally {
34
- setIsLoading(false);
42
+ if (!controller.signal.aborted) {
43
+ setIsLoading(false);
44
+ }
35
45
  }
36
46
  }, [apiBaseUrl, shouldRetryOnError]);
37
47
  React.useEffect(() => {
38
48
  fetchSession();
49
+ return () => {
50
+ abortRef.current?.abort();
51
+ if (retryTimerRef.current) clearTimeout(retryTimerRef.current);
52
+ };
39
53
  }, [fetchSession]);
40
54
  React.useEffect(() => {
41
55
  if (!revalidateOnFocus) return;
@@ -0,0 +1,216 @@
1
+ import {
2
+ cn
3
+ } from "./chunk-RQHJBTEU.js";
4
+
5
+ // src/markdown/code-block.tsx
6
+ import {
7
+ memo,
8
+ useCallback,
9
+ useEffect,
10
+ useRef,
11
+ useState
12
+ } from "react";
13
+ import SyntaxHighlighter from "react-syntax-highlighter";
14
+ import { Check, Copy } from "lucide-react";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
16
+ function getSyntaxTheme() {
17
+ const el = typeof document !== "undefined" ? document.documentElement : null;
18
+ const v = (name, fallback) => el ? getComputedStyle(el).getPropertyValue(name).trim() || fallback : fallback;
19
+ const comment = v("--syntax-comment", "#6B7094");
20
+ const keyword = v("--syntax-keyword", "#A78FFF");
21
+ const string = v("--syntax-string", "#10b981");
22
+ const fn = v("--syntax-function", "#6D9FFF");
23
+ const number = v("--syntax-number", "#FFB347");
24
+ const meta = v("--syntax-meta", "#8263FF");
25
+ const error = v("--syntax-error", "#FF4D6D");
26
+ const variable = v("--syntax-variable", "#C4C0D8");
27
+ const fg = v("--syntax-foreground", "#E8E6F6");
28
+ return {
29
+ "hljs-comment": { color: comment, fontStyle: "italic" },
30
+ "hljs-quote": { color: comment, fontStyle: "italic" },
31
+ "hljs-doctag": { color: comment },
32
+ "hljs-keyword": { color: keyword },
33
+ "hljs-selector-tag": { color: keyword },
34
+ "hljs-literal": { color: keyword },
35
+ "hljs-type": { color: keyword },
36
+ "hljs-class": { color: keyword },
37
+ "hljs-string": { color: string },
38
+ "hljs-template-tag": { color: string },
39
+ "hljs-template-variable": { color: string },
40
+ "hljs-addition": { color: string },
41
+ "hljs-regexp": { color: string },
42
+ "hljs-title": { color: fn },
43
+ "hljs-section": { color: fn },
44
+ "hljs-built_in": { color: fn },
45
+ "hljs-name": { color: fn },
46
+ "hljs-function": { color: fn },
47
+ "hljs-selector-id": { color: fn },
48
+ "hljs-selector-class": { color: fn },
49
+ "hljs-attribute": { color: fn },
50
+ "hljs-number": { color: number },
51
+ "hljs-symbol": { color: number },
52
+ "hljs-bullet": { color: number },
53
+ "hljs-link": { color: number, textDecoration: "underline" },
54
+ "hljs-meta": { color: meta },
55
+ "hljs-selector-pseudo": { color: meta },
56
+ "hljs-deletion": { color: error },
57
+ "hljs-params": { color: variable },
58
+ "hljs-variable": { color: variable },
59
+ "hljs-tag": { color: variable },
60
+ "hljs-attr": { color: variable },
61
+ "hljs-subst": { color: variable },
62
+ "hljs-strong": { fontWeight: "bold" },
63
+ "hljs-emphasis": { fontStyle: "italic" },
64
+ "hljs": { color: fg, background: "transparent" }
65
+ };
66
+ }
67
+ var LIGHT_THEMES = /* @__PURE__ */ new Set(["vault", "dawn"]);
68
+ function detectLightTheme() {
69
+ return typeof document !== "undefined" && LIGHT_THEMES.has(document.documentElement.getAttribute("data-sandbox-theme") ?? "");
70
+ }
71
+ function useIsLightTheme() {
72
+ const [isLight, setIsLight] = useState(detectLightTheme);
73
+ useEffect(() => {
74
+ if (typeof document === "undefined") return;
75
+ setIsLight(detectLightTheme());
76
+ const observer = new MutationObserver(() => setIsLight(detectLightTheme()));
77
+ observer.observe(document.documentElement, {
78
+ attributes: true,
79
+ attributeFilter: ["data-sandbox-theme"]
80
+ });
81
+ return () => observer.disconnect();
82
+ }, []);
83
+ return isLight;
84
+ }
85
+ var CodeBlock = memo(
86
+ ({ code, language, showLineNumbers = false, light: lightProp, className, children, ...props }) => {
87
+ const isLight = useIsLightTheme();
88
+ const light = lightProp ?? isLight;
89
+ const theme = getSyntaxTheme();
90
+ const bg = "bg-card border-border";
91
+ const headerBg = light ? "bg-muted/50 border-border" : "bg-background border-border";
92
+ const langColor = "text-muted-foreground";
93
+ return /* @__PURE__ */ jsxs(
94
+ "div",
95
+ {
96
+ className: cn("group relative overflow-hidden rounded-lg border font-mono", bg, className),
97
+ ...props,
98
+ children: [
99
+ language && /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between border-b px-3 py-1", headerBg), children: [
100
+ /* @__PURE__ */ jsx("span", { className: cn("text-[calc(var(--font-size-xs)-1px)] font-mono font-medium uppercase tracking-widest", langColor), children: language }),
101
+ children
102
+ ] }),
103
+ !language && children && /* @__PURE__ */ jsx("div", { className: "absolute right-2 top-2 z-10 flex items-center gap-2 opacity-0 transition-opacity group-hover:opacity-100", children }),
104
+ /* @__PURE__ */ jsx(
105
+ SyntaxHighlighter,
106
+ {
107
+ language: language ?? "text",
108
+ style: theme,
109
+ showLineNumbers,
110
+ lineNumberStyle: {
111
+ color: light ? "#8B92B8" : "#4A4D6A",
112
+ minWidth: "2.5em",
113
+ paddingRight: "1em"
114
+ },
115
+ customStyle: {
116
+ margin: 0,
117
+ padding: "var(--code-padding-y, 0.625rem) var(--code-padding-x, 0.75rem)",
118
+ background: "transparent",
119
+ fontSize: "var(--code-font-size, 0.8125rem)",
120
+ lineHeight: "var(--code-line-height, 1.5)",
121
+ overflowX: "auto"
122
+ },
123
+ codeTagProps: { style: { fontFamily: "var(--font-mono, 'JetBrains Mono', ui-monospace, monospace)" } },
124
+ wrapLines: false,
125
+ children: code
126
+ }
127
+ )
128
+ ]
129
+ }
130
+ );
131
+ }
132
+ );
133
+ CodeBlock.displayName = "CodeBlock";
134
+ var CopyButton = memo(({ text }) => {
135
+ const [copied, setCopied] = useState(false);
136
+ const timerRef = useRef(null);
137
+ useEffect(() => {
138
+ return () => {
139
+ if (timerRef.current) clearTimeout(timerRef.current);
140
+ };
141
+ }, []);
142
+ const handleCopy = useCallback(async () => {
143
+ try {
144
+ await navigator.clipboard.writeText(text);
145
+ setCopied(true);
146
+ if (timerRef.current) clearTimeout(timerRef.current);
147
+ timerRef.current = setTimeout(() => setCopied(false), 2e3);
148
+ } catch (err) {
149
+ console.warn("Clipboard write failed:", err);
150
+ }
151
+ }, [text]);
152
+ return /* @__PURE__ */ jsx(
153
+ "button",
154
+ {
155
+ onClick: handleCopy,
156
+ className: "flex items-center justify-center w-6 h-6 rounded-md bg-muted border border-border hover:border-primary/20 transition-colors",
157
+ title: "Copy to clipboard",
158
+ children: copied ? /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5 text-emerald-500" }) : /* @__PURE__ */ jsx(Copy, { className: "w-3.5 h-3.5 text-muted-foreground" })
159
+ }
160
+ );
161
+ });
162
+ CopyButton.displayName = "CopyButton";
163
+
164
+ // src/markdown/markdown.tsx
165
+ import { memo as memo2 } from "react";
166
+ import ReactMarkdown from "react-markdown";
167
+ import remarkGfm from "remark-gfm";
168
+ import rehypeSanitize from "rehype-sanitize";
169
+ import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
170
+ var Markdown = memo2(({ children, className }) => {
171
+ return /* @__PURE__ */ jsx2(
172
+ "div",
173
+ {
174
+ className: cn("prose prose-sm dark:prose-invert max-w-none", className),
175
+ children: /* @__PURE__ */ jsx2(
176
+ ReactMarkdown,
177
+ {
178
+ remarkPlugins: [remarkGfm],
179
+ rehypePlugins: [rehypeSanitize],
180
+ components: {
181
+ pre({ children: preChildren }) {
182
+ return /* @__PURE__ */ jsx2(Fragment, { children: preChildren });
183
+ },
184
+ code({ className: codeClass, children: codeChildren, ...rest }) {
185
+ const match = /language-(\w+)/.exec(codeClass || "");
186
+ const language = match?.[1];
187
+ const code = String(codeChildren).replace(/\n$/, "");
188
+ if (!language && !code.includes("\n")) {
189
+ return /* @__PURE__ */ jsx2(
190
+ "code",
191
+ {
192
+ className: cn(
193
+ "px-1.5 py-0.5 rounded border border-border bg-card text-[var(--code-keyword)] text-[0.85em] font-mono",
194
+ codeClass
195
+ ),
196
+ ...rest,
197
+ children: codeChildren
198
+ }
199
+ );
200
+ }
201
+ return /* @__PURE__ */ jsx2(CodeBlock, { code, language, children: /* @__PURE__ */ jsx2(CopyButton, { text: code }) });
202
+ }
203
+ },
204
+ children
205
+ }
206
+ )
207
+ }
208
+ );
209
+ });
210
+ Markdown.displayName = "Markdown";
211
+
212
+ export {
213
+ CodeBlock,
214
+ CopyButton,
215
+ Markdown
216
+ };