@tangle-network/sandbox-ui 0.59.0 → 0.61.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/dist/chat.d.ts CHANGED
@@ -225,6 +225,16 @@ interface AgentSessionControlsProps {
225
225
  */
226
226
  declare function AgentSessionControls({ harness, profile, model, reasoning, trailing, className, context, layout, menuPlacement, }: AgentSessionControlsProps): react_jsx_runtime.JSX.Element | null;
227
227
 
228
+ /** A staged attachment shown as a chip above the input. */
229
+ interface ComposerFile {
230
+ id: string;
231
+ name: string;
232
+ size?: number;
233
+ kind: "file" | "folder";
234
+ /** File count for a folder chip. */
235
+ fileCount?: number;
236
+ status: "pending" | "uploading" | "ready" | "error";
237
+ }
228
238
  interface AgentComposerProps {
229
239
  /** Composer text (controlled). */
230
240
  value: string;
@@ -232,10 +242,15 @@ interface AgentComposerProps {
232
242
  /** Fired on Enter (without Shift) or the send button. */
233
243
  onSubmit: () => void;
234
244
  placeholder?: string;
235
- /** Disables typing and sending — e.g. while a turn is streaming. */
245
+ /** Disables typing and sending — e.g. while restoring. */
236
246
  disabled?: boolean;
237
- /** Spins the send button and blocks submit, without disabling the textarea. */
247
+ /**
248
+ * A turn is in flight. Spins the send button; paired with `onCancel` it
249
+ * becomes a Stop button instead, so the user can interrupt the stream.
250
+ */
238
251
  busy?: boolean;
252
+ /** Stop the in-flight turn. With `busy`, replaces send with a Stop button. */
253
+ onCancel?: () => void;
239
254
  /**
240
255
  * Agent backend. Present → sandbox-backed (the harness pill shows and snaps
241
256
  * with the model); omitted → router-backed (no harness, just model/effort).
@@ -247,8 +262,29 @@ interface AgentComposerProps {
247
262
  reasoning?: AgentSessionReasoningControl;
248
263
  /** Forwarded to the control strip (chat hides shell-only harnesses). */
249
264
  context?: "chat" | "all";
265
+ /**
266
+ * Override the built-in control strip with custom controls. When set, the
267
+ * `harness`/`profile`/`model`/`reasoning` props are ignored and this node is
268
+ * rendered in the control row instead — for apps that compose their own
269
+ * pickers. Omit to use the canonical strip.
270
+ */
271
+ controls?: React.ReactNode;
250
272
  /** Extra content left of the send button (token meter, cost, status). */
251
273
  trailing?: React.ReactNode;
274
+ /**
275
+ * Attachments are opt-in: pass `onAttach` to show the attach button, accept
276
+ * drag-and-drop onto the composer, and render `attachments` as chips.
277
+ */
278
+ onAttach?: (files: FileList) => void;
279
+ /** Show a folder-attach button; falls back to `onAttach` if unset. */
280
+ onAttachFolder?: (files: FileList) => void;
281
+ attachments?: ReadonlyArray<ComposerFile>;
282
+ onRemoveFile?: (id: string) => void;
283
+ accept?: string;
284
+ dropTitle?: string;
285
+ dropDescription?: string;
286
+ /** Cmd/Ctrl+L focuses the input and shows a hint. Default false. */
287
+ focusShortcut?: boolean;
252
288
  /** Minimum textarea rows before it grows. Default 2. */
253
289
  minRows?: number;
254
290
  /** Max pixel height before the textarea scrolls. Default 200. */
@@ -264,8 +300,13 @@ interface AgentComposerProps {
264
300
  * snap the harness↔model pair automatically; which controls appear is driven
265
301
  * purely by which control objects are passed, so the same component is the
266
302
  * router-backed composer (no harness) and the sandbox-backed one (with harness).
303
+ *
304
+ * Opt-in extras make it the superset of every app's hand-rolled composer:
305
+ * file/folder attachments with drag-and-drop + chips, a streaming Stop button
306
+ * (`busy` + `onCancel`), a `controls` override slot for bespoke picker rows, and
307
+ * a Cmd/Ctrl+L focus shortcut.
267
308
  */
268
- declare function AgentComposer({ value, onChange, onSubmit, placeholder, disabled, busy, harness, profile, model, reasoning, context, trailing, minRows, maxHeight, className, sendLabel, autoFocus, }: AgentComposerProps): react_jsx_runtime.JSX.Element;
309
+ declare function AgentComposer({ value, onChange, onSubmit, placeholder, disabled, busy, onCancel, harness, profile, model, reasoning, context, controls, trailing, onAttach, onAttachFolder, attachments, onRemoveFile, accept, dropTitle, dropDescription, focusShortcut, minRows, maxHeight, className, sendLabel, autoFocus, }: AgentComposerProps): react_jsx_runtime.JSX.Element;
269
310
 
270
311
  /**
271
312
  * Whether `harness` can run `modelId`. Router-backed harnesses, and provider-less
@@ -379,4 +420,4 @@ declare function createFetchTransport(opts: {
379
420
  fetchImpl?: typeof fetch;
380
421
  }): ArtifactAgentDockTransport;
381
422
 
382
- export { AgentComposer, type AgentComposerProps, type AgentProfileCapability, type AgentProfileDraft, type AgentProfileOption, AgentProfilePicker, type AgentProfilePickerProps, AgentSessionControls, type AgentSessionControlsProps, type AgentSessionHarnessControl, type AgentSessionModelControl, type AgentSessionProfileControl, type AgentSessionReasoningControl, ArtifactAgentDock, type ArtifactAgentDockProps, type ArtifactAgentDockTransport, type ArtifactDockMessage, type ArtifactDockStreamEvent, type ArtifactKind, type ArtifactScope, DEFAULT_REASONING_LEVEL_OPTIONS, type ReasoningLevel, type ReasoningLevelOption, ReasoningLevelPicker, type ReasoningLevelPickerProps, createFetchTransport, isModelCompatibleWithHarness, snapModelToHarness };
423
+ export { AgentComposer, type AgentComposerProps, type AgentProfileCapability, type AgentProfileDraft, type AgentProfileOption, AgentProfilePicker, type AgentProfilePickerProps, AgentSessionControls, type AgentSessionControlsProps, type AgentSessionHarnessControl, type AgentSessionModelControl, type AgentSessionProfileControl, type AgentSessionReasoningControl, ArtifactAgentDock, type ArtifactAgentDockProps, type ArtifactAgentDockTransport, type ArtifactDockMessage, type ArtifactDockStreamEvent, type ArtifactKind, type ArtifactScope, type ComposerFile, DEFAULT_REASONING_LEVEL_OPTIONS, type ReasoningLevel, type ReasoningLevelOption, ReasoningLevelPicker, type ReasoningLevelPickerProps, createFetchTransport, isModelCompatibleWithHarness, snapModelToHarness };
package/dist/chat.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  modelProvider,
18
18
  snapHarnessToModel,
19
19
  snapModelToHarness
20
- } from "./chunk-4XOZGMJC.js";
20
+ } from "./chunk-V5JZOO3W.js";
21
21
  import "./chunk-HU4B2M4K.js";
22
22
  import "./chunk-SF6LPMMN.js";
23
23
  import "./chunk-EI44GEQ5.js";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-3J6FG3FJ.js";
4
4
  import {
5
5
  PortsList
6
- } from "./chunk-D7JJLG4L.js";
6
+ } from "./chunk-OQZQFSWM.js";
7
7
  import {
8
8
  TerminalView
9
9
  } from "./chunk-VIREDUBF.js";
@@ -589,12 +589,24 @@ function RailExpandable({
589
589
  onClick: onNavigate,
590
590
  ...item.prefetch !== void 0 ? { prefetch: item.prefetch } : {},
591
591
  className: cn(
592
- "flex h-8 items-center gap-2 rounded-md px-2.5 text-[12px] transition-colors",
592
+ "flex h-8 min-w-0 items-center gap-2 rounded-md px-2.5 text-[12px] transition-colors",
593
593
  active ? "bg-[var(--accent-surface-strong)] font-medium text-[var(--accent-text)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-foreground"
594
594
  ),
595
595
  children: [
596
596
  FIcon ? /* @__PURE__ */ jsx3(FIcon, { className: "h-4 w-4 shrink-0" }) : null,
597
- /* @__PURE__ */ jsx3("span", { className: "truncate", children: item.label })
597
+ /* @__PURE__ */ jsx3(
598
+ "span",
599
+ {
600
+ className: cn("min-w-0 flex-1 truncate", item.isLoading && "shimmer-text"),
601
+ ...item.isLoading ? { role: "status", "aria-label": "Agent responding" } : {},
602
+ children: item.label
603
+ }
604
+ ),
605
+ item.isLoading ? /* @__PURE__ */ jsxs2("span", { className: "responding-ellipsis", "aria-hidden": "true", children: [
606
+ /* @__PURE__ */ jsx3("span", {}),
607
+ /* @__PURE__ */ jsx3("span", {}),
608
+ /* @__PURE__ */ jsx3("span", {})
609
+ ] }) : null
598
610
  ]
599
611
  },
600
612
  item.id
@@ -730,9 +730,17 @@ function GearSection({
730
730
  }
731
731
 
732
732
  // src/chat/agent-composer.tsx
733
- import { ArrowUp, Loader2 } from "lucide-react";
733
+ import {
734
+ ArrowUp,
735
+ Folder,
736
+ Loader2,
737
+ Paperclip,
738
+ Square,
739
+ Upload,
740
+ X
741
+ } from "lucide-react";
734
742
  import * as React2 from "react";
735
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
743
+ import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
736
744
  function AgentComposer({
737
745
  value,
738
746
  onChange,
@@ -740,12 +748,22 @@ function AgentComposer({
740
748
  placeholder = "Send a message\u2026",
741
749
  disabled,
742
750
  busy,
751
+ onCancel,
743
752
  harness,
744
753
  profile,
745
754
  model,
746
755
  reasoning,
747
756
  context = "chat",
757
+ controls,
748
758
  trailing,
759
+ onAttach,
760
+ onAttachFolder,
761
+ attachments = [],
762
+ onRemoveFile,
763
+ accept,
764
+ dropTitle = "Drop files to add context",
765
+ dropDescription = "They attach to your next message.",
766
+ focusShortcut = false,
749
767
  minRows = 2,
750
768
  maxHeight = 200,
751
769
  className,
@@ -753,6 +771,10 @@ function AgentComposer({
753
771
  autoFocus
754
772
  }) {
755
773
  const textareaRef = React2.useRef(null);
774
+ const fileInputRef = React2.useRef(null);
775
+ const folderInputRef = React2.useRef(null);
776
+ const [dragOver, setDragOver] = React2.useState(false);
777
+ const dragDepth = React2.useRef(0);
756
778
  const resize = React2.useCallback(
757
779
  (el) => {
758
780
  el.style.height = "auto";
@@ -763,81 +785,247 @@ function AgentComposer({
763
785
  React2.useEffect(() => {
764
786
  if (textareaRef.current) resize(textareaRef.current);
765
787
  }, [value, resize]);
788
+ React2.useEffect(() => {
789
+ if (!focusShortcut || disabled) return;
790
+ function onKeyDown(event) {
791
+ if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "l") {
792
+ event.preventDefault();
793
+ textareaRef.current?.focus();
794
+ }
795
+ }
796
+ document.addEventListener("keydown", onKeyDown);
797
+ return () => document.removeEventListener("keydown", onKeyDown);
798
+ }, [focusShortcut, disabled]);
766
799
  const canSend = !disabled && !busy && value.trim().length > 0;
767
800
  const submit = () => {
768
801
  if (!canSend) return;
769
802
  onSubmit();
770
803
  };
771
- return /* @__PURE__ */ jsxs4(
772
- "div",
773
- {
774
- "data-testid": "agent-composer",
775
- className: cn(
776
- "flex flex-col gap-2 rounded-2xl border border-[var(--md3-outline-variant)] bg-surface-container-high p-2.5 shadow-sm transition-colors",
777
- "focus-within:border-primary/60",
778
- disabled && "opacity-60",
779
- className
780
- ),
781
- children: [
782
- /* @__PURE__ */ jsx4(
783
- "textarea",
784
- {
785
- ref: textareaRef,
786
- rows: minRows,
787
- value,
788
- disabled,
789
- autoFocus,
790
- onChange: (event) => onChange(event.target.value),
791
- onInput: (event) => resize(event.currentTarget),
792
- onKeyDown: (event) => {
793
- if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing && event.keyCode !== 229) {
794
- event.preventDefault();
795
- submit();
796
- }
797
- },
798
- placeholder,
799
- className: cn(
800
- "w-full resize-none bg-transparent px-2 py-1 text-sm leading-relaxed text-foreground outline-none",
801
- "placeholder:text-muted-foreground"
802
- )
803
- }
804
+ const dropEnabled = Boolean(onAttach);
805
+ const handleDragEnter = (event) => {
806
+ if (!dropEnabled) return;
807
+ event.preventDefault();
808
+ event.stopPropagation();
809
+ dragDepth.current++;
810
+ if (event.dataTransfer?.types.includes("Files")) setDragOver(true);
811
+ };
812
+ const handleDragLeave = (event) => {
813
+ if (!dropEnabled) return;
814
+ event.preventDefault();
815
+ event.stopPropagation();
816
+ dragDepth.current--;
817
+ if (dragDepth.current <= 0) {
818
+ dragDepth.current = 0;
819
+ setDragOver(false);
820
+ }
821
+ };
822
+ const handleDragOver = (event) => {
823
+ if (!dropEnabled) return;
824
+ event.preventDefault();
825
+ event.stopPropagation();
826
+ if (event.dataTransfer) event.dataTransfer.dropEffect = "copy";
827
+ };
828
+ const handleDrop = (event) => {
829
+ if (!dropEnabled) return;
830
+ event.preventDefault();
831
+ event.stopPropagation();
832
+ dragDepth.current = 0;
833
+ setDragOver(false);
834
+ const files = event.dataTransfer?.files;
835
+ if (files?.length) onAttach?.(files);
836
+ };
837
+ const folderChips = attachments.filter((file) => file.kind === "folder");
838
+ const fileChips = attachments.filter((file) => file.kind !== "folder");
839
+ const attachButtonClass = cn(
840
+ "flex size-8 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors",
841
+ "hover:bg-surface-container-highest hover:text-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
842
+ "disabled:cursor-not-allowed disabled:opacity-50"
843
+ );
844
+ return /* @__PURE__ */ jsxs4("div", { className: cn("relative", className), children: [
845
+ dragOver && /* @__PURE__ */ jsx4("div", { className: "pointer-events-none absolute inset-0 z-10 flex items-center justify-center rounded-2xl border-2 border-dashed border-primary/50 bg-surface-container-high/95", children: /* @__PURE__ */ jsxs4("div", { className: "text-center", children: [
846
+ /* @__PURE__ */ jsx4("span", { className: "mx-auto mb-2 flex size-11 items-center justify-center rounded-xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx4(Upload, { className: "size-5" }) }),
847
+ /* @__PURE__ */ jsx4("p", { className: "font-semibold text-foreground text-sm", children: dropTitle }),
848
+ /* @__PURE__ */ jsx4("p", { className: "mt-0.5 text-muted-foreground text-xs", children: dropDescription })
849
+ ] }) }),
850
+ /* @__PURE__ */ jsxs4(
851
+ "div",
852
+ {
853
+ "data-testid": "agent-composer",
854
+ onDragEnter: handleDragEnter,
855
+ onDragLeave: handleDragLeave,
856
+ onDragOver: handleDragOver,
857
+ onDrop: handleDrop,
858
+ className: cn(
859
+ "flex flex-col gap-2 rounded-2xl border border-[var(--md3-outline-variant)] bg-surface-container-high p-2.5 shadow-sm transition-colors",
860
+ "focus-within:border-primary/60",
861
+ disabled && "opacity-60"
804
862
  ),
805
- /* @__PURE__ */ jsxs4("div", { className: "flex items-end gap-2", children: [
806
- /* @__PURE__ */ jsx4(
807
- AgentSessionControls,
863
+ children: [
864
+ attachments.length > 0 && /* @__PURE__ */ jsx4("div", { className: "flex flex-wrap gap-1.5", children: [...folderChips, ...fileChips].map((file) => /* @__PURE__ */ jsxs4(
865
+ "span",
808
866
  {
809
- className: "min-w-0 flex-1",
810
- context,
811
- harness,
812
- profile,
813
- model,
814
- reasoning
815
- }
816
- ),
817
- trailing && /* @__PURE__ */ jsx4("div", { className: "flex shrink-0 items-center gap-2", children: trailing }),
867
+ className: cn(
868
+ "inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs",
869
+ file.status === "error" ? "border-[var(--status-error,#ff4d6d)]/40 text-[var(--status-error,#ff4d6d)]" : "border-[var(--md3-outline-variant)] bg-surface-container text-foreground"
870
+ ),
871
+ children: [
872
+ file.kind === "folder" ? /* @__PURE__ */ jsx4(Folder, { className: "size-3 shrink-0" }) : /* @__PURE__ */ jsx4(Paperclip, { className: "size-3 shrink-0" }),
873
+ /* @__PURE__ */ jsx4("span", { className: "max-w-[150px] truncate", children: file.name }),
874
+ file.fileCount !== void 0 && /* @__PURE__ */ jsxs4("span", { className: "text-muted-foreground", children: [
875
+ "(",
876
+ file.fileCount,
877
+ ")"
878
+ ] }),
879
+ file.status === "uploading" && /* @__PURE__ */ jsx4(Loader2, { className: "size-3 animate-spin" }),
880
+ onRemoveFile && /* @__PURE__ */ jsx4(
881
+ "button",
882
+ {
883
+ type: "button",
884
+ "aria-label": `Remove ${file.name}`,
885
+ onClick: () => onRemoveFile(file.id),
886
+ className: "rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
887
+ children: /* @__PURE__ */ jsx4(X, { className: "size-3" })
888
+ }
889
+ )
890
+ ]
891
+ },
892
+ file.id
893
+ )) }),
818
894
  /* @__PURE__ */ jsx4(
819
- "button",
895
+ "textarea",
820
896
  {
821
- type: "button",
822
- onClick: submit,
823
- disabled: !canSend,
824
- "aria-label": sendLabel,
897
+ ref: textareaRef,
898
+ rows: minRows,
899
+ value,
900
+ disabled,
901
+ autoFocus,
902
+ onChange: (event) => onChange(event.target.value),
903
+ onInput: (event) => resize(event.currentTarget),
904
+ onKeyDown: (event) => {
905
+ if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing && event.keyCode !== 229) {
906
+ event.preventDefault();
907
+ submit();
908
+ }
909
+ },
910
+ placeholder,
911
+ "aria-label": "Message input",
825
912
  className: cn(
826
- "ml-auto flex size-9 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground",
827
- "transition-opacity hover:opacity-90 disabled:opacity-40"
828
- ),
829
- children: busy ? /* @__PURE__ */ jsx4(Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsx4(ArrowUp, { className: "size-4" })
913
+ "w-full resize-none bg-transparent px-2 py-1 text-sm leading-relaxed text-foreground outline-none",
914
+ "placeholder:text-muted-foreground"
915
+ )
830
916
  }
831
- )
832
- ] })
833
- ]
834
- }
835
- );
917
+ ),
918
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-end gap-2", children: [
919
+ /* @__PURE__ */ jsx4("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: controls ?? /* @__PURE__ */ jsx4(
920
+ AgentSessionControls,
921
+ {
922
+ context,
923
+ harness,
924
+ profile,
925
+ model,
926
+ reasoning
927
+ }
928
+ ) }),
929
+ onAttach && /* @__PURE__ */ jsxs4(Fragment, { children: [
930
+ /* @__PURE__ */ jsx4(
931
+ "button",
932
+ {
933
+ type: "button",
934
+ onClick: () => fileInputRef.current?.click(),
935
+ disabled,
936
+ "aria-label": "Attach files",
937
+ title: "Attach files",
938
+ className: attachButtonClass,
939
+ children: /* @__PURE__ */ jsx4(Paperclip, { className: "size-4" })
940
+ }
941
+ ),
942
+ /* @__PURE__ */ jsx4(
943
+ "input",
944
+ {
945
+ ref: fileInputRef,
946
+ type: "file",
947
+ multiple: true,
948
+ className: "hidden",
949
+ accept,
950
+ onChange: (event) => {
951
+ if (event.target.files?.length) onAttach(event.target.files);
952
+ event.target.value = "";
953
+ }
954
+ }
955
+ )
956
+ ] }),
957
+ onAttachFolder && /* @__PURE__ */ jsxs4(Fragment, { children: [
958
+ /* @__PURE__ */ jsx4(
959
+ "button",
960
+ {
961
+ type: "button",
962
+ onClick: () => folderInputRef.current?.click(),
963
+ disabled,
964
+ "aria-label": "Attach folder",
965
+ title: "Attach folder",
966
+ className: attachButtonClass,
967
+ children: /* @__PURE__ */ jsx4(Folder, { className: "size-4" })
968
+ }
969
+ ),
970
+ /* @__PURE__ */ jsx4(
971
+ "input",
972
+ {
973
+ ref: folderInputRef,
974
+ type: "file",
975
+ multiple: true,
976
+ className: "hidden",
977
+ onChange: (event) => {
978
+ if (event.target.files?.length)
979
+ (onAttachFolder ?? onAttach)?.(event.target.files);
980
+ event.target.value = "";
981
+ },
982
+ ...{ webkitdirectory: "" }
983
+ }
984
+ )
985
+ ] }),
986
+ trailing && /* @__PURE__ */ jsx4("div", { className: "flex shrink-0 items-center gap-2", children: trailing }),
987
+ busy && onCancel ? /* @__PURE__ */ jsx4(
988
+ "button",
989
+ {
990
+ type: "button",
991
+ onClick: onCancel,
992
+ "aria-label": "Stop response",
993
+ className: cn(
994
+ "flex size-9 shrink-0 items-center justify-center rounded-full",
995
+ "bg-[var(--status-error,#ff4d6d)]/15 text-[var(--status-error,#ff4d6d)] transition-colors",
996
+ "hover:bg-[var(--status-error,#ff4d6d)]/25"
997
+ ),
998
+ children: /* @__PURE__ */ jsx4(Square, { className: "size-3.5 fill-current" })
999
+ }
1000
+ ) : /* @__PURE__ */ jsx4(
1001
+ "button",
1002
+ {
1003
+ type: "button",
1004
+ onClick: submit,
1005
+ disabled: !canSend,
1006
+ "aria-label": sendLabel,
1007
+ className: cn(
1008
+ "flex size-9 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground",
1009
+ "transition-opacity hover:opacity-90 disabled:opacity-40"
1010
+ ),
1011
+ children: busy ? /* @__PURE__ */ jsx4(Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsx4(ArrowUp, { className: "size-4" })
1012
+ }
1013
+ )
1014
+ ] })
1015
+ ]
1016
+ }
1017
+ ),
1018
+ focusShortcut && /* @__PURE__ */ jsx4("div", { className: "mt-1.5 flex justify-end px-1", children: /* @__PURE__ */ jsxs4("span", { className: "text-muted-foreground text-xs", children: [
1019
+ /* @__PURE__ */ jsx4("kbd", { className: "rounded border border-[var(--md3-outline-variant)] bg-surface-container px-1 py-0.5 text-[10px]", children: "Cmd" }),
1020
+ /* @__PURE__ */ jsx4("kbd", { className: "ml-0.5 rounded border border-[var(--md3-outline-variant)] bg-surface-container px-1 py-0.5 text-[10px]", children: "L" }),
1021
+ /* @__PURE__ */ jsx4("span", { className: "ml-1", children: "to focus" })
1022
+ ] }) })
1023
+ ] });
836
1024
  }
837
1025
 
838
1026
  // src/chat/artifact-agent-dock.tsx
839
1027
  import * as React3 from "react";
840
- import { Sparkles as Sparkles2, Send, Square, X } from "lucide-react";
1028
+ import { Sparkles as Sparkles2, Send, Square as Square2, X as X2 } from "lucide-react";
841
1029
  import { ChatMessage } from "@tangle-network/ui/chat";
842
1030
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
843
1031
  function defaultScopeLabel(scope) {
@@ -1029,7 +1217,7 @@ function ArtifactAgentDock({
1029
1217
  onClick: () => onOpenChange(false),
1030
1218
  "aria-label": "Close artifact chat",
1031
1219
  className: "rounded-md p-1 text-muted-foreground transition-colors hover:bg-surface-container-high hover:text-foreground",
1032
- children: /* @__PURE__ */ jsx5(X, { className: "h-4 w-4" })
1220
+ children: /* @__PURE__ */ jsx5(X2, { className: "h-4 w-4" })
1033
1221
  }
1034
1222
  )
1035
1223
  ] }),
@@ -1078,7 +1266,7 @@ function ArtifactAgentDock({
1078
1266
  onClick: cancel,
1079
1267
  "aria-label": "Cancel",
1080
1268
  className: "inline-flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-surface-container-high hover:text-foreground",
1081
- children: /* @__PURE__ */ jsx5(Square, { className: "h-4 w-4" })
1269
+ children: /* @__PURE__ */ jsx5(Square2, { className: "h-4 w-4" })
1082
1270
  }
1083
1271
  ) : /* @__PURE__ */ jsx5(
1084
1272
  "button",
@@ -183,6 +183,8 @@ interface RailExpandableSubItem {
183
183
  }>;
184
184
  href: string;
185
185
  prefetch?: "none" | "intent" | "render" | "viewport";
186
+ /** Show a live working indicator on the row while the item is busy. */
187
+ isLoading?: boolean;
186
188
  }
187
189
  interface RailExpandableProps {
188
190
  icon: React.ComponentType<{
package/dist/dashboard.js CHANGED
@@ -54,7 +54,7 @@ import {
54
54
  canAdminSandbox,
55
55
  parseInsufficientBalance,
56
56
  useSidebar
57
- } from "./chunk-D7JJLG4L.js";
57
+ } from "./chunk-OQZQFSWM.js";
58
58
  import {
59
59
  BillingDashboard,
60
60
  InfoPanel,
package/dist/globals.css CHANGED
@@ -663,14 +663,30 @@
663
663
  width: calc(var(--spacing) * 3);
664
664
  height: calc(var(--spacing) * 3);
665
665
  }
666
+ .size-3\.5 {
667
+ width: calc(var(--spacing) * 3.5);
668
+ height: calc(var(--spacing) * 3.5);
669
+ }
666
670
  .size-4 {
667
671
  width: calc(var(--spacing) * 4);
668
672
  height: calc(var(--spacing) * 4);
669
673
  }
674
+ .size-5 {
675
+ width: calc(var(--spacing) * 5);
676
+ height: calc(var(--spacing) * 5);
677
+ }
678
+ .size-8 {
679
+ width: calc(var(--spacing) * 8);
680
+ height: calc(var(--spacing) * 8);
681
+ }
670
682
  .size-9 {
671
683
  width: calc(var(--spacing) * 9);
672
684
  height: calc(var(--spacing) * 9);
673
685
  }
686
+ .size-11 {
687
+ width: calc(var(--spacing) * 11);
688
+ height: calc(var(--spacing) * 11);
689
+ }
674
690
  .\!h-2 {
675
691
  height: calc(var(--spacing) * 2) !important;
676
692
  }
@@ -1878,6 +1894,12 @@
1878
1894
  .border-\[var\(--md3-outline-variant\)\] {
1879
1895
  border-color: var(--md3-outline-variant);
1880
1896
  }
1897
+ .border-\[var\(--status-error\,\#ff4d6d\)\]\/40 {
1898
+ border-color: var(--status-error,#ff4d6d);
1899
+ @supports (color: color-mix(in lab, red, red)) {
1900
+ border-color: color-mix(in oklab, var(--status-error,#ff4d6d) 40%, transparent);
1901
+ }
1902
+ }
1881
1903
  .border-\[var\(--status-running\)\]\/30 {
1882
1904
  border-color: var(--status-running);
1883
1905
  @supports (color: color-mix(in lab, red, red)) {
@@ -2010,6 +2032,12 @@
2010
2032
  border-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
2011
2033
  }
2012
2034
  }
2035
+ .border-primary\/50 {
2036
+ border-color: color-mix(in srgb, hsl(var(--primary)) 50%, transparent);
2037
+ @supports (color: color-mix(in lab, red, red)) {
2038
+ border-color: color-mix(in oklab, var(--color-primary) 50%, transparent);
2039
+ }
2040
+ }
2013
2041
  .border-primary\/60 {
2014
2042
  border-color: color-mix(in srgb, hsl(var(--primary)) 60%, transparent);
2015
2043
  @supports (color: color-mix(in lab, red, red)) {
@@ -2175,6 +2203,12 @@
2175
2203
  .bg-\[var\(--md3-outline-variant\)\] {
2176
2204
  background-color: var(--md3-outline-variant);
2177
2205
  }
2206
+ .bg-\[var\(--status-error\,\#ff4d6d\)\]\/15 {
2207
+ background-color: var(--status-error,#ff4d6d);
2208
+ @supports (color: color-mix(in lab, red, red)) {
2209
+ background-color: color-mix(in oklab, var(--status-error,#ff4d6d) 15%, transparent);
2210
+ }
2211
+ }
2178
2212
  .bg-\[var\(--status-running\)\] {
2179
2213
  background-color: var(--status-running);
2180
2214
  }
@@ -2469,6 +2503,12 @@
2469
2503
  .bg-surface-container-high {
2470
2504
  background-color: var(--color-surface-container-high);
2471
2505
  }
2506
+ .bg-surface-container-high\/95 {
2507
+ background-color: var(--color-surface-container-high);
2508
+ @supports (color: color-mix(in lab, red, red)) {
2509
+ background-color: color-mix(in oklab, var(--color-surface-container-high) 95%, transparent);
2510
+ }
2511
+ }
2472
2512
  .bg-surface-container-highest {
2473
2513
  background-color: var(--color-surface-container-highest);
2474
2514
  }
@@ -3189,6 +3229,9 @@
3189
3229
  .text-\[var\(--md3-primary\)\] {
3190
3230
  color: var(--md3-primary);
3191
3231
  }
3232
+ .text-\[var\(--status-error\,\#ff4d6d\)\] {
3233
+ color: var(--status-error,#ff4d6d);
3234
+ }
3192
3235
  .text-\[var\(--surface-danger-text\)\] {
3193
3236
  color: var(--surface-danger-text);
3194
3237
  }
@@ -4072,6 +4115,16 @@
4072
4115
  }
4073
4116
  }
4074
4117
  }
4118
+ .hover\:bg-\[var\(--status-error\,\#ff4d6d\)\]\/25 {
4119
+ &:hover {
4120
+ @media (hover: hover) {
4121
+ background-color: var(--status-error,#ff4d6d);
4122
+ @supports (color: color-mix(in lab, red, red)) {
4123
+ background-color: color-mix(in oklab, var(--status-error,#ff4d6d) 25%, transparent);
4124
+ }
4125
+ }
4126
+ }
4127
+ }
4075
4128
  .hover\:bg-\[var\(--surface-danger-bg\)\] {
4076
4129
  &:hover {
4077
4130
  @media (hover: hover) {
@@ -6004,6 +6057,56 @@
6004
6057
  background-size: 200% 100%;
6005
6058
  animation: shimmer 2s infinite;
6006
6059
  }
6060
+ .shimmer-text {
6061
+ background-image: linear-gradient(
6062
+ 90deg,
6063
+ hsl(var(--muted-foreground)) 0%,
6064
+ hsl(var(--muted-foreground)) 28%,
6065
+ var(--accent-text) 50%,
6066
+ hsl(var(--muted-foreground)) 72%,
6067
+ hsl(var(--muted-foreground)) 100%
6068
+ );
6069
+ background-size: 200% 100%;
6070
+ -webkit-background-clip: text;
6071
+ background-clip: text;
6072
+ -webkit-text-fill-color: transparent;
6073
+ animation: shimmer 1.3s linear infinite;
6074
+ }
6075
+ @media (prefers-reduced-motion: reduce) {
6076
+ .shimmer-text {
6077
+ animation: none;
6078
+ }
6079
+ }
6080
+ .responding-ellipsis {
6081
+ display: inline-flex;
6082
+ width: 1.25rem;
6083
+ margin-left: auto;
6084
+ flex-shrink: 0;
6085
+ align-items: center;
6086
+ justify-content: center;
6087
+ gap: 0.1875rem;
6088
+ color: hsl(var(--primary));
6089
+ }
6090
+ .responding-ellipsis > span {
6091
+ width: 0.25rem;
6092
+ height: 0.25rem;
6093
+ border-radius: 9999px;
6094
+ background: currentColor;
6095
+ opacity: 0.6;
6096
+ animation: responding-ellipsis 0.8s ease-in-out infinite;
6097
+ }
6098
+ .responding-ellipsis > span:nth-child(2) {
6099
+ animation-delay: 0.15s;
6100
+ }
6101
+ .responding-ellipsis > span:nth-child(3) {
6102
+ animation-delay: 0.3s;
6103
+ }
6104
+ @media (prefers-reduced-motion: reduce) {
6105
+ .responding-ellipsis > span {
6106
+ animation: none;
6107
+ opacity: 0.8;
6108
+ }
6109
+ }
6007
6110
  .animate-in {
6008
6111
  animation: fade-in 0.25s ease-out;
6009
6112
  }
@@ -6038,6 +6141,16 @@
6038
6141
  background-position: 200% 0;
6039
6142
  }
6040
6143
  }
6144
+ @keyframes responding-ellipsis {
6145
+ 0%, 80%, 100% {
6146
+ opacity: 0.6;
6147
+ transform: translateY(0);
6148
+ }
6149
+ 40% {
6150
+ opacity: 1;
6151
+ transform: translateY(-1.5px);
6152
+ }
6153
+ }
6041
6154
  @keyframes fade-in {
6042
6155
  from {
6043
6156
  opacity: 0;
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { AgentWorkbench, ApprovalConfidenceStat, ApprovalItem, ApprovalQueue, Ap
5
5
  export { ArtifactView, BRAND_PRISM_THEME, CodeSurface, CodeSurfaceProps, CodeView, CodeViewProps, DiffStats, DiffView, DiffViewProps, FileBreadcrumb, FileBreadcrumbProps, GitStatusBadge, PanelHeader, PanelHeaderProps, PillTabItem, PillTabs, PillTabsProps, PreviewView, PreviewViewProps, SandboxArtifact, SandboxArtifactPane, SandboxArtifactPaneProps, SandboxArtifactTerminal, buildUnifiedPatch, computeDiffStats, resolveLanguage } from './workbench.js';
6
6
  export { OpenUIAction, OpenUIActionsNode, OpenUIArtifactRenderer, OpenUIArtifactRendererProps, OpenUIBadgeNode, OpenUICardNode, OpenUICodeNode, OpenUIComponentNode, OpenUIGridNode, OpenUIHeadingNode, OpenUIKeyValueNode, OpenUIMarkdownNode, OpenUIPrimitive, OpenUISeparatorNode, OpenUIStackNode, OpenUIStatNode, OpenUITableNode, OpenUITextNode } from '@tangle-network/ui/openui';
7
7
  export { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, ChatContainer, ChatContainerProps, ChatInput, ChatInputProps, ChatMessage, ChatMessageProps, MessageList, MessageListProps, MessageRole, PendingFile, ThinkingIndicator, ThinkingIndicatorProps, UserMessage, UserMessageProps } from '@tangle-network/ui/chat';
8
- export { AgentComposer, AgentComposerProps, AgentProfileCapability, AgentProfileDraft, AgentProfileOption, AgentProfilePicker, AgentProfilePickerProps, AgentSessionControls, AgentSessionControlsProps, AgentSessionHarnessControl, AgentSessionModelControl, AgentSessionProfileControl, AgentSessionReasoningControl, ArtifactAgentDock, ArtifactAgentDockProps, ArtifactAgentDockTransport, ArtifactDockMessage, ArtifactDockStreamEvent, ArtifactKind, ArtifactScope, DEFAULT_REASONING_LEVEL_OPTIONS, ReasoningLevel, ReasoningLevelOption, ReasoningLevelPicker, ReasoningLevelPickerProps, createFetchTransport, isModelCompatibleWithHarness, snapModelToHarness } from './chat.js';
8
+ export { AgentComposer, AgentComposerProps, AgentProfileCapability, AgentProfileDraft, AgentProfileOption, AgentProfilePicker, AgentProfilePickerProps, AgentSessionControls, AgentSessionControlsProps, AgentSessionHarnessControl, AgentSessionModelControl, AgentSessionProfileControl, AgentSessionReasoningControl, ArtifactAgentDock, ArtifactAgentDockProps, ArtifactAgentDockTransport, ArtifactDockMessage, ArtifactDockStreamEvent, ArtifactKind, ArtifactScope, ComposerFile, DEFAULT_REASONING_LEVEL_OPTIONS, ReasoningLevel, ReasoningLevelOption, ReasoningLevelPicker, ReasoningLevelPickerProps, createFetchTransport, isModelCompatibleWithHarness, snapModelToHarness } from './chat.js';
9
9
  export { ExpandedToolDetail, ExpandedToolDetailProps, InlineThinkingItem, InlineThinkingItemProps, InlineToolItem, InlineToolItemProps, LiveDuration, RunGroup, RunGroupProps } from '@tangle-network/ui/run';
10
10
  export { CommandPreview, DiffPreview, GlobResultsPreview, GrepResultsPreview, QuestionPreview, WebSearchPreview, WriteFilePreview } from '@tangle-network/ui/tool-previews';
11
11
  export { FileArtifactPane, FileArtifactPaneProps, FileNode, FilePreview, FilePreviewProps, FileTabData, FileTabs, FileTabsProps, FileTree, FileTreeProps, FileTreeVisibilityOptions, RichFileTree, RichFileTreeGitEntry, RichFileTreeGitStatus, RichFileTreeProps, RichFileTreeThemeVars, filterFileTree } from '@tangle-network/ui/files';
package/dist/index.js CHANGED
@@ -92,7 +92,7 @@ import {
92
92
  modelProvider,
93
93
  snapHarnessToModel,
94
94
  snapModelToHarness
95
- } from "./chunk-4XOZGMJC.js";
95
+ } from "./chunk-V5JZOO3W.js";
96
96
  import {
97
97
  TOOL_CATEGORY_ICONS,
98
98
  cn,
@@ -149,7 +149,7 @@ import {
149
149
  buildUnifiedPatch,
150
150
  computeDiffStats,
151
151
  resolveLanguage
152
- } from "./chunk-MKX3F55O.js";
152
+ } from "./chunk-J36F6LD2.js";
153
153
  import {
154
154
  FileArtifactPane,
155
155
  FilePreview,
@@ -214,7 +214,7 @@ import {
214
214
  canAdminSandbox,
215
215
  parseInsufficientBalance,
216
216
  useSidebar
217
- } from "./chunk-D7JJLG4L.js";
217
+ } from "./chunk-OQZQFSWM.js";
218
218
  import {
219
219
  BillingDashboard,
220
220
  InfoPanel,
package/dist/styles.css CHANGED
@@ -663,14 +663,30 @@
663
663
  width: calc(var(--spacing) * 3);
664
664
  height: calc(var(--spacing) * 3);
665
665
  }
666
+ .size-3\.5 {
667
+ width: calc(var(--spacing) * 3.5);
668
+ height: calc(var(--spacing) * 3.5);
669
+ }
666
670
  .size-4 {
667
671
  width: calc(var(--spacing) * 4);
668
672
  height: calc(var(--spacing) * 4);
669
673
  }
674
+ .size-5 {
675
+ width: calc(var(--spacing) * 5);
676
+ height: calc(var(--spacing) * 5);
677
+ }
678
+ .size-8 {
679
+ width: calc(var(--spacing) * 8);
680
+ height: calc(var(--spacing) * 8);
681
+ }
670
682
  .size-9 {
671
683
  width: calc(var(--spacing) * 9);
672
684
  height: calc(var(--spacing) * 9);
673
685
  }
686
+ .size-11 {
687
+ width: calc(var(--spacing) * 11);
688
+ height: calc(var(--spacing) * 11);
689
+ }
674
690
  .\!h-2 {
675
691
  height: calc(var(--spacing) * 2) !important;
676
692
  }
@@ -1878,6 +1894,12 @@
1878
1894
  .border-\[var\(--md3-outline-variant\)\] {
1879
1895
  border-color: var(--md3-outline-variant);
1880
1896
  }
1897
+ .border-\[var\(--status-error\,\#ff4d6d\)\]\/40 {
1898
+ border-color: var(--status-error,#ff4d6d);
1899
+ @supports (color: color-mix(in lab, red, red)) {
1900
+ border-color: color-mix(in oklab, var(--status-error,#ff4d6d) 40%, transparent);
1901
+ }
1902
+ }
1881
1903
  .border-\[var\(--status-running\)\]\/30 {
1882
1904
  border-color: var(--status-running);
1883
1905
  @supports (color: color-mix(in lab, red, red)) {
@@ -2010,6 +2032,12 @@
2010
2032
  border-color: color-mix(in oklab, var(--color-primary) 40%, transparent);
2011
2033
  }
2012
2034
  }
2035
+ .border-primary\/50 {
2036
+ border-color: color-mix(in srgb, hsl(var(--primary)) 50%, transparent);
2037
+ @supports (color: color-mix(in lab, red, red)) {
2038
+ border-color: color-mix(in oklab, var(--color-primary) 50%, transparent);
2039
+ }
2040
+ }
2013
2041
  .border-primary\/60 {
2014
2042
  border-color: color-mix(in srgb, hsl(var(--primary)) 60%, transparent);
2015
2043
  @supports (color: color-mix(in lab, red, red)) {
@@ -2175,6 +2203,12 @@
2175
2203
  .bg-\[var\(--md3-outline-variant\)\] {
2176
2204
  background-color: var(--md3-outline-variant);
2177
2205
  }
2206
+ .bg-\[var\(--status-error\,\#ff4d6d\)\]\/15 {
2207
+ background-color: var(--status-error,#ff4d6d);
2208
+ @supports (color: color-mix(in lab, red, red)) {
2209
+ background-color: color-mix(in oklab, var(--status-error,#ff4d6d) 15%, transparent);
2210
+ }
2211
+ }
2178
2212
  .bg-\[var\(--status-running\)\] {
2179
2213
  background-color: var(--status-running);
2180
2214
  }
@@ -2469,6 +2503,12 @@
2469
2503
  .bg-surface-container-high {
2470
2504
  background-color: var(--color-surface-container-high);
2471
2505
  }
2506
+ .bg-surface-container-high\/95 {
2507
+ background-color: var(--color-surface-container-high);
2508
+ @supports (color: color-mix(in lab, red, red)) {
2509
+ background-color: color-mix(in oklab, var(--color-surface-container-high) 95%, transparent);
2510
+ }
2511
+ }
2472
2512
  .bg-surface-container-highest {
2473
2513
  background-color: var(--color-surface-container-highest);
2474
2514
  }
@@ -3189,6 +3229,9 @@
3189
3229
  .text-\[var\(--md3-primary\)\] {
3190
3230
  color: var(--md3-primary);
3191
3231
  }
3232
+ .text-\[var\(--status-error\,\#ff4d6d\)\] {
3233
+ color: var(--status-error,#ff4d6d);
3234
+ }
3192
3235
  .text-\[var\(--surface-danger-text\)\] {
3193
3236
  color: var(--surface-danger-text);
3194
3237
  }
@@ -4072,6 +4115,16 @@
4072
4115
  }
4073
4116
  }
4074
4117
  }
4118
+ .hover\:bg-\[var\(--status-error\,\#ff4d6d\)\]\/25 {
4119
+ &:hover {
4120
+ @media (hover: hover) {
4121
+ background-color: var(--status-error,#ff4d6d);
4122
+ @supports (color: color-mix(in lab, red, red)) {
4123
+ background-color: color-mix(in oklab, var(--status-error,#ff4d6d) 25%, transparent);
4124
+ }
4125
+ }
4126
+ }
4127
+ }
4075
4128
  .hover\:bg-\[var\(--surface-danger-bg\)\] {
4076
4129
  &:hover {
4077
4130
  @media (hover: hover) {
@@ -6004,6 +6057,56 @@
6004
6057
  background-size: 200% 100%;
6005
6058
  animation: shimmer 2s infinite;
6006
6059
  }
6060
+ .shimmer-text {
6061
+ background-image: linear-gradient(
6062
+ 90deg,
6063
+ hsl(var(--muted-foreground)) 0%,
6064
+ hsl(var(--muted-foreground)) 28%,
6065
+ var(--accent-text) 50%,
6066
+ hsl(var(--muted-foreground)) 72%,
6067
+ hsl(var(--muted-foreground)) 100%
6068
+ );
6069
+ background-size: 200% 100%;
6070
+ -webkit-background-clip: text;
6071
+ background-clip: text;
6072
+ -webkit-text-fill-color: transparent;
6073
+ animation: shimmer 1.3s linear infinite;
6074
+ }
6075
+ @media (prefers-reduced-motion: reduce) {
6076
+ .shimmer-text {
6077
+ animation: none;
6078
+ }
6079
+ }
6080
+ .responding-ellipsis {
6081
+ display: inline-flex;
6082
+ width: 1.25rem;
6083
+ margin-left: auto;
6084
+ flex-shrink: 0;
6085
+ align-items: center;
6086
+ justify-content: center;
6087
+ gap: 0.1875rem;
6088
+ color: hsl(var(--primary));
6089
+ }
6090
+ .responding-ellipsis > span {
6091
+ width: 0.25rem;
6092
+ height: 0.25rem;
6093
+ border-radius: 9999px;
6094
+ background: currentColor;
6095
+ opacity: 0.6;
6096
+ animation: responding-ellipsis 0.8s ease-in-out infinite;
6097
+ }
6098
+ .responding-ellipsis > span:nth-child(2) {
6099
+ animation-delay: 0.15s;
6100
+ }
6101
+ .responding-ellipsis > span:nth-child(3) {
6102
+ animation-delay: 0.3s;
6103
+ }
6104
+ @media (prefers-reduced-motion: reduce) {
6105
+ .responding-ellipsis > span {
6106
+ animation: none;
6107
+ opacity: 0.8;
6108
+ }
6109
+ }
6007
6110
  .animate-in {
6008
6111
  animation: fade-in 0.25s ease-out;
6009
6112
  }
@@ -6038,6 +6141,16 @@
6038
6141
  background-position: 200% 0;
6039
6142
  }
6040
6143
  }
6144
+ @keyframes responding-ellipsis {
6145
+ 0%, 80%, 100% {
6146
+ opacity: 0.6;
6147
+ transform: translateY(0);
6148
+ }
6149
+ 40% {
6150
+ opacity: 1;
6151
+ transform: translateY(-1.5px);
6152
+ }
6153
+ }
6041
6154
  @keyframes fade-in {
6042
6155
  from {
6043
6156
  opacity: 0;
package/dist/workbench.js CHANGED
@@ -12,9 +12,9 @@ import {
12
12
  buildUnifiedPatch,
13
13
  computeDiffStats,
14
14
  resolveLanguage
15
- } from "./chunk-MKX3F55O.js";
15
+ } from "./chunk-J36F6LD2.js";
16
16
  import "./chunk-3J6FG3FJ.js";
17
- import "./chunk-D7JJLG4L.js";
17
+ import "./chunk-OQZQFSWM.js";
18
18
  import "./chunk-OMUIPJQZ.js";
19
19
  import "./chunk-VIREDUBF.js";
20
20
  import "./chunk-77WVVJA4.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.59.0",
3
+ "version": "0.61.0",
4
4
  "description": "Unified UI component library for Tangle Sandbox — primitives, chat, dashboard, terminal, editor, and workspace components",
5
5
  "repository": {
6
6
  "type": "git",