@tangle-network/sandbox-ui 0.6.0 → 0.6.1

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.js CHANGED
@@ -8,9 +8,9 @@ import {
8
8
  MessageList,
9
9
  ThinkingIndicator,
10
10
  UserMessage
11
- } from "./chunk-5F3VOGCT.js";
11
+ } from "./chunk-RKXIRRKQ.js";
12
12
  import "./chunk-CNWVHQFY.js";
13
- import "./chunk-LY32SP6X.js";
13
+ import "./chunk-ZMWWE5RF.js";
14
14
  import "./chunk-HRMUF35V.js";
15
15
  import "./chunk-MJUDMVRU.js";
16
16
  import "./chunk-BX6AQMUS.js";
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-BRBTD7RH.js";
11
11
  import {
12
12
  ChatContainer
13
- } from "./chunk-5F3VOGCT.js";
13
+ } from "./chunk-RKXIRRKQ.js";
14
14
  import {
15
15
  OpenUIArtifactRenderer
16
16
  } from "./chunk-OVNLOE3Y.js";
@@ -832,19 +832,19 @@ function RuntimePane({
832
832
  }
833
833
 
834
834
  // src/workspace/session-sidebar.tsx
835
- import { useMemo as useMemo3, useState as useState4 } from "react";
835
+ import { useCallback, useMemo as useMemo3, useRef as useRef3, useState as useState4 } from "react";
836
836
  import { ArrowLeft, FolderTree, MessageSquareText, Plus, Search as Search2, Settings, Sparkles } from "lucide-react";
837
837
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
838
- function statusClasses(status) {
838
+ function statusDot(status) {
839
839
  switch (status) {
840
840
  case "running":
841
- return "bg-[var(--brand-cool)] shadow-[0_0_0_4px_color-mix(in_srgb,var(--brand-cool)_18%,transparent)]";
841
+ return "bg-[var(--status-running)]";
842
842
  case "error":
843
- return "bg-[var(--status-danger)]";
843
+ return "bg-[var(--surface-danger-text)]";
844
844
  case "attention-needed":
845
- return "bg-[var(--status-warning)]";
845
+ return "bg-[var(--surface-warning-text)]";
846
846
  default:
847
- return "bg-[var(--text-dim)]";
847
+ return "bg-muted-foreground/40";
848
848
  }
849
849
  }
850
850
  function iconForLink(icon) {
@@ -887,24 +887,47 @@ function sortItems(items, sessionStatusById) {
887
887
  return rightUpdated - leftUpdated;
888
888
  });
889
889
  }
890
- function badgeClasses(tone = "neutral") {
890
+ function badgeTone(tone = "neutral") {
891
891
  switch (tone) {
892
892
  case "accent":
893
- return "border-[var(--border-accent)] bg-[var(--accent-surface-soft)] text-[var(--accent-text)]";
893
+ return "border-primary/30 bg-primary/10 text-primary";
894
894
  case "success":
895
- return "border-[var(--surface-success-border)] bg-[var(--surface-success-bg)] text-[var(--surface-success-text)]";
895
+ return "border-success/30 bg-success/10 text-success";
896
896
  case "warning":
897
- return "border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)]";
897
+ return "border-warning/30 bg-warning/10 text-warning";
898
898
  case "danger":
899
- return "border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] text-[var(--surface-danger-text)]";
899
+ return "border-destructive/30 bg-destructive/10 text-destructive";
900
900
  default:
901
- return "border-[var(--border-subtle)] bg-[var(--bg-section)] text-[var(--text-secondary)]";
901
+ return "border-border bg-muted text-muted-foreground";
902
902
  }
903
903
  }
904
904
  function navigateToHref(href) {
905
905
  if (!href || typeof window === "undefined") return;
906
906
  window.location.assign(href);
907
907
  }
908
+ function useResizable(defaultWidth, min, max, onChange) {
909
+ const [width, setWidth] = useState4(defaultWidth);
910
+ const dragging = useRef3(false);
911
+ const startX = useRef3(0);
912
+ const startW = useRef3(0);
913
+ const onPointerDown = useCallback((e) => {
914
+ dragging.current = true;
915
+ startX.current = e.clientX;
916
+ startW.current = width;
917
+ e.currentTarget.setPointerCapture(e.pointerId);
918
+ }, [width]);
919
+ const onPointerMove = useCallback((e) => {
920
+ if (!dragging.current) return;
921
+ const delta = e.clientX - startX.current;
922
+ const next = Math.min(max, Math.max(min, startW.current + delta));
923
+ setWidth(next);
924
+ onChange?.(next);
925
+ }, [min, max, onChange]);
926
+ const onPointerUp = useCallback(() => {
927
+ dragging.current = false;
928
+ }, []);
929
+ return { width, onPointerDown, onPointerMove, onPointerUp };
930
+ }
908
931
  function SessionSidebar({
909
932
  title,
910
933
  subtitle,
@@ -923,6 +946,11 @@ function SessionSidebar({
923
946
  activityMonitor,
924
947
  filters = [],
925
948
  defaultFilterId,
949
+ resizable = false,
950
+ defaultWidth = 256,
951
+ minWidth = 200,
952
+ maxWidth = 400,
953
+ onWidthChange,
926
954
  renderItemActions
927
955
  }) {
928
956
  const [query, setQuery] = useState4("");
@@ -958,154 +986,172 @@ function SessionSidebar({
958
986
  isActive: currentItemId === item.id
959
987
  })).length
960
988
  ])), [currentItemId, filters, orderedItems, sessionsById]);
961
- return /* @__PURE__ */ jsxs7("aside", { className: cn("flex w-64 shrink-0 flex-col border-r border-[var(--border-subtle)] bg-[var(--bg-card)]", className), children: [
962
- /* @__PURE__ */ jsxs7("div", { className: "border-b border-[var(--border-subtle)] px-3 py-3", children: [
963
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-2", children: [
964
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 min-w-0", children: [
965
- /* @__PURE__ */ jsx7("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-lg border border-[var(--border-accent)]/50 bg-[var(--accent-surface-soft)] text-[var(--accent-text)]", children: /* @__PURE__ */ jsx7(MessageSquareText, { className: "h-3.5 w-3.5" }) }),
966
- /* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
967
- /* @__PURE__ */ jsx7("div", { className: "truncate text-sm font-semibold tracking-[0.01em] text-[var(--text-primary)]", children: title }),
968
- subtitle && /* @__PURE__ */ jsx7("div", { className: "truncate text-[11px] text-[var(--text-muted)]", children: subtitle })
969
- ] })
989
+ const resize = useResizable(defaultWidth, minWidth, maxWidth, onWidthChange);
990
+ return /* @__PURE__ */ jsxs7(
991
+ "aside",
992
+ {
993
+ className: cn("relative flex shrink-0 flex-col border-r border-border bg-card", className),
994
+ style: { width: resizable ? resize.width : defaultWidth },
995
+ children: [
996
+ /* @__PURE__ */ jsxs7("div", { className: "border-b border-border px-3 py-2.5", children: [
997
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-2", children: [
998
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 min-w-0", children: [
999
+ /* @__PURE__ */ jsx7("div", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary", children: /* @__PURE__ */ jsx7(MessageSquareText, { className: "h-3 w-3" }) }),
1000
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
1001
+ /* @__PURE__ */ jsx7("div", { className: "truncate text-xs font-semibold text-foreground", children: title }),
1002
+ subtitle && /* @__PURE__ */ jsx7("div", { className: "truncate text-[10px] text-muted-foreground", children: subtitle })
1003
+ ] })
1004
+ ] }),
1005
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5 shrink-0", children: [
1006
+ runningCount > 0 && /* @__PURE__ */ jsx7("span", { className: "rounded-full bg-primary/10 px-1.5 py-px text-[10px] font-medium text-primary", children: runningCount }),
1007
+ onCreate && /* @__PURE__ */ jsx7(
1008
+ "button",
1009
+ {
1010
+ type: "button",
1011
+ onClick: onCreate,
1012
+ title: createLabel,
1013
+ className: "flex h-6 w-6 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
1014
+ children: /* @__PURE__ */ jsx7(Plus, { className: "h-3 w-3" })
1015
+ }
1016
+ )
1017
+ ] })
1018
+ ] }),
1019
+ enableSearch && items.length > 0 && /* @__PURE__ */ jsxs7("div", { className: "relative mt-2", children: [
1020
+ /* @__PURE__ */ jsx7(Search2, { className: "pointer-events-none absolute left-2 top-1/2 h-3 w-3 -translate-y-1/2 text-muted-foreground" }),
1021
+ /* @__PURE__ */ jsx7(
1022
+ "input",
1023
+ {
1024
+ value: query,
1025
+ onChange: (event) => setQuery(event.target.value),
1026
+ placeholder: searchPlaceholder,
1027
+ "aria-label": searchPlaceholder,
1028
+ className: "h-7 w-full rounded-md border border-border bg-background pl-7 pr-2 text-xs text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
1029
+ }
1030
+ )
1031
+ ] }),
1032
+ filters.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mt-1.5 flex flex-wrap gap-1", children: filters.map((filter) => {
1033
+ const isSelected = activeFilterId === filter.id;
1034
+ return /* @__PURE__ */ jsxs7(
1035
+ "button",
1036
+ {
1037
+ type: "button",
1038
+ onClick: () => setActiveFilterId(filter.id),
1039
+ className: cn(
1040
+ "inline-flex items-center gap-1 rounded-full border px-2 py-px text-[10px] font-medium transition-colors",
1041
+ isSelected ? "border-primary/30 bg-primary/10 text-primary" : "border-border text-muted-foreground hover:text-foreground"
1042
+ ),
1043
+ children: [
1044
+ /* @__PURE__ */ jsx7("span", { children: filter.label }),
1045
+ /* @__PURE__ */ jsx7("span", { className: "text-[9px] opacity-60", children: filterCounts[filter.id] ?? 0 })
1046
+ ]
1047
+ },
1048
+ filter.id
1049
+ );
1050
+ }) })
970
1051
  ] }),
971
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2 shrink-0", children: [
972
- runningCount > 0 && /* @__PURE__ */ jsx7("span", { className: "rounded-full border border-[var(--border-accent)] bg-[var(--accent-surface-soft)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--accent-text)]", children: runningCount }),
973
- onCreate && /* @__PURE__ */ jsx7(
1052
+ /* @__PURE__ */ jsx7("nav", { "aria-label": "Sessions", className: "flex-1 overflow-y-auto px-1.5 py-1.5", children: visibleItems.length === 0 ? /* @__PURE__ */ jsx7("div", { className: "rounded-md border border-dashed border-border px-3 py-3 text-xs text-muted-foreground", children: query.trim() ? `No sessions match "${query.trim()}".` : emptyMessage }) : /* @__PURE__ */ jsx7("ul", { className: "space-y-px", children: visibleItems.map((item) => {
1053
+ const session = sessionsById.get(item.id) ?? null;
1054
+ const isActive = currentItemId === item.id;
1055
+ const status = session?.status ?? item.status;
1056
+ const visibleBadges = [
1057
+ ...item.isPinned ? [{ id: `${item.id}-pinned`, label: "Pinned", tone: "accent" }] : [],
1058
+ ...item.badges ?? []
1059
+ ];
1060
+ return /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsxs7(
1061
+ "div",
1062
+ {
1063
+ className: cn(
1064
+ "group relative flex items-center gap-2 rounded-md px-2 py-1.5 transition-colors",
1065
+ isActive ? "bg-accent text-accent-foreground shadow-[inset_2px_0_0_hsl(var(--primary))]" : "text-foreground hover:bg-accent/50"
1066
+ ),
1067
+ children: [
1068
+ /* @__PURE__ */ jsxs7(
1069
+ "button",
1070
+ {
1071
+ type: "button",
1072
+ onClick: () => {
1073
+ if (onSelectItem) {
1074
+ onSelectItem(item);
1075
+ return;
1076
+ }
1077
+ navigateToHref(item.href);
1078
+ },
1079
+ "aria-current": isActive ? "page" : void 0,
1080
+ className: "min-w-0 flex flex-1 items-center gap-2 text-left",
1081
+ children: [
1082
+ /* @__PURE__ */ jsx7("span", { className: cn("h-1.5 w-1.5 shrink-0 rounded-full", statusDot(status)) }),
1083
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
1084
+ /* @__PURE__ */ jsx7("div", { className: cn(
1085
+ "truncate text-xs",
1086
+ isActive ? "font-semibold" : "font-medium"
1087
+ ), children: item.title }),
1088
+ item.subtitle && /* @__PURE__ */ jsx7("div", { className: "truncate text-[10px] leading-tight text-muted-foreground", children: item.subtitle })
1089
+ ] })
1090
+ ]
1091
+ }
1092
+ ),
1093
+ /* @__PURE__ */ jsxs7("div", { className: "flex shrink-0 items-center gap-1", children: [
1094
+ visibleBadges.length > 0 && visibleBadges.slice(0, 1).map((badge) => /* @__PURE__ */ jsx7(
1095
+ "span",
1096
+ {
1097
+ className: cn(
1098
+ "rounded-full border px-1.5 py-px text-[8px] font-semibold uppercase",
1099
+ badgeTone(badge.tone)
1100
+ ),
1101
+ children: badge.label
1102
+ },
1103
+ badge.id
1104
+ )),
1105
+ session?.isForeground && /* @__PURE__ */ jsx7("span", { className: "h-1.5 w-1.5 rounded-full bg-primary animate-pulse", title: "Live" }),
1106
+ renderItemActions ? /* @__PURE__ */ jsx7(
1107
+ "div",
1108
+ {
1109
+ className: "opacity-0 transition-opacity group-hover:opacity-100",
1110
+ onClick: (event) => event.stopPropagation(),
1111
+ children: renderItemActions(item, { session, isActive })
1112
+ }
1113
+ ) : null
1114
+ ] })
1115
+ ]
1116
+ }
1117
+ ) }, item.id);
1118
+ }) }) }),
1119
+ activityMonitor && /* @__PURE__ */ jsx7("div", { className: "border-t border-border px-2 py-1.5", children: activityMonitor }),
1120
+ links.length > 0 && /* @__PURE__ */ jsx7("nav", { "aria-label": "Workspace sections", className: "border-t border-border px-1.5 py-1.5", children: /* @__PURE__ */ jsx7("div", { className: "space-y-px", children: links.map((link) => {
1121
+ const Icon = iconForLink(link.icon);
1122
+ return /* @__PURE__ */ jsxs7(
974
1123
  "button",
975
1124
  {
976
1125
  type: "button",
977
- onClick: onCreate,
978
- title: createLabel,
979
- className: "flex h-6 w-6 items-center justify-center rounded-md border border-[var(--border-default)] bg-[var(--bg-section)] text-[var(--text-muted)] transition-colors hover:border-[var(--border-accent)] hover:bg-[var(--accent-surface-soft)] hover:text-[var(--accent-text)]",
980
- children: /* @__PURE__ */ jsx7(Plus, { className: "h-3.5 w-3.5" })
981
- }
982
- )
983
- ] })
984
- ] }),
985
- enableSearch && items.length > 0 && /* @__PURE__ */ jsxs7("div", { className: "relative mt-2.5", children: [
986
- /* @__PURE__ */ jsx7(Search2, { className: "pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-[var(--text-dim)]" }),
987
- /* @__PURE__ */ jsx7(
988
- "input",
1126
+ onClick: () => {
1127
+ if (onSelectLink) {
1128
+ onSelectLink(link);
1129
+ return;
1130
+ }
1131
+ navigateToHref(link.href);
1132
+ },
1133
+ className: "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
1134
+ children: [
1135
+ /* @__PURE__ */ jsx7(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
1136
+ /* @__PURE__ */ jsx7("span", { className: "truncate", children: link.label })
1137
+ ]
1138
+ },
1139
+ link.id
1140
+ );
1141
+ }) }) }),
1142
+ resizable && /* @__PURE__ */ jsx7(
1143
+ "div",
989
1144
  {
990
- value: query,
991
- onChange: (event) => setQuery(event.target.value),
992
- placeholder: searchPlaceholder,
993
- "aria-label": searchPlaceholder,
994
- className: "h-8 w-full rounded-[var(--radius-md)] border border-[var(--border-subtle)] bg-[var(--bg-section)] pl-8 pr-3 text-xs text-[var(--text-primary)] placeholder:text-[var(--text-dim)] focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--border-accent)]"
1145
+ className: "absolute top-0 right-0 bottom-0 w-1 cursor-col-resize hover:bg-primary/20 active:bg-primary/30 transition-colors",
1146
+ onPointerDown: resize.onPointerDown,
1147
+ onPointerMove: resize.onPointerMove,
1148
+ onPointerUp: resize.onPointerUp,
1149
+ title: "Drag to resize"
995
1150
  }
996
1151
  )
997
- ] }),
998
- filters.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mt-2 flex flex-wrap gap-1", children: filters.map((filter) => {
999
- const isSelected = activeFilterId === filter.id;
1000
- return /* @__PURE__ */ jsxs7(
1001
- "button",
1002
- {
1003
- type: "button",
1004
- onClick: () => setActiveFilterId(filter.id),
1005
- className: cn(
1006
- "inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] font-medium transition-colors",
1007
- isSelected ? "border-[var(--border-accent)] bg-[var(--accent-surface-soft)] text-[var(--accent-text)]" : "border-[var(--border-subtle)] bg-transparent text-[var(--text-muted)] hover:text-[var(--text-secondary)]"
1008
- ),
1009
- children: [
1010
- /* @__PURE__ */ jsx7("span", { children: filter.label }),
1011
- /* @__PURE__ */ jsx7("span", { className: "text-[9px] opacity-70", children: filterCounts[filter.id] ?? 0 })
1012
- ]
1013
- },
1014
- filter.id
1015
- );
1016
- }) })
1017
- ] }),
1018
- /* @__PURE__ */ jsx7("nav", { "aria-label": "Sessions", className: "flex-1 overflow-y-auto px-2 py-2", children: visibleItems.length === 0 ? /* @__PURE__ */ jsx7("div", { className: "rounded-[var(--radius-md)] border border-dashed border-[var(--border-subtle)] bg-[var(--bg-section)] px-3 py-4 text-xs text-[var(--text-muted)]", children: query.trim() ? `No sessions match "${query.trim()}".` : emptyMessage }) : /* @__PURE__ */ jsx7("ul", { className: "space-y-1", children: visibleItems.map((item) => {
1019
- const session = sessionsById.get(item.id) ?? null;
1020
- const isActive = currentItemId === item.id;
1021
- const status = session?.status ?? item.status;
1022
- const visibleBadges = [
1023
- ...item.isPinned ? [{ id: `${item.id}-pinned`, label: "Pinned", tone: "accent" }] : [],
1024
- ...item.badges ?? []
1025
- ];
1026
- return /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsxs7(
1027
- "div",
1028
- {
1029
- className: cn(
1030
- "group flex items-start gap-2 rounded-[var(--radius-md)] border px-2 py-2 transition-colors",
1031
- isActive ? "border-[var(--border-accent)] bg-[var(--accent-surface-soft)] shadow-[var(--shadow-card)]" : "border-[var(--border-subtle)] bg-transparent hover:border-[var(--border-default)] hover:bg-[var(--bg-section)]"
1032
- ),
1033
- children: [
1034
- /* @__PURE__ */ jsxs7(
1035
- "button",
1036
- {
1037
- type: "button",
1038
- onClick: () => {
1039
- if (onSelectItem) {
1040
- onSelectItem(item);
1041
- return;
1042
- }
1043
- navigateToHref(item.href);
1044
- },
1045
- "aria-current": isActive ? "page" : void 0,
1046
- className: "min-w-0 flex flex-1 items-start gap-2.5 text-left",
1047
- children: [
1048
- /* @__PURE__ */ jsx7("span", { className: cn("mt-[5px] h-2 w-2 shrink-0 rounded-full", statusClasses(status)) }),
1049
- /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
1050
- /* @__PURE__ */ jsx7("div", { className: "truncate text-xs font-medium text-[var(--text-primary)]", children: item.title }),
1051
- item.subtitle && /* @__PURE__ */ jsx7("div", { className: "mt-0.5 truncate text-[11px] leading-tight text-[var(--text-muted)]", children: item.subtitle }),
1052
- visibleBadges.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mt-1.5 flex flex-wrap items-center gap-1", children: visibleBadges.map((badge) => /* @__PURE__ */ jsx7(
1053
- "span",
1054
- {
1055
- className: cn(
1056
- "inline-flex items-center rounded-full border px-1.5 py-0.5 text-[9px] font-medium uppercase tracking-[0.06em]",
1057
- badgeClasses(badge.tone)
1058
- ),
1059
- children: badge.label
1060
- },
1061
- badge.id
1062
- )) })
1063
- ] })
1064
- ]
1065
- }
1066
- ),
1067
- /* @__PURE__ */ jsxs7("div", { className: "flex shrink-0 items-center gap-2", children: [
1068
- session?.isForeground && /* @__PURE__ */ jsx7(Badge, { className: "rounded-full border-[var(--border-subtle)] bg-[var(--bg-section)] text-[10px] uppercase tracking-[0.14em] text-[var(--text-secondary)]", children: "Live" }),
1069
- renderItemActions ? /* @__PURE__ */ jsx7(
1070
- "div",
1071
- {
1072
- className: "opacity-70 transition-opacity hover:opacity-100 group-hover:opacity-100",
1073
- onClick: (event) => event.stopPropagation(),
1074
- children: renderItemActions(item, {
1075
- session,
1076
- isActive
1077
- })
1078
- }
1079
- ) : null
1080
- ] })
1081
- ]
1082
- }
1083
- ) }, item.id);
1084
- }) }) }),
1085
- activityMonitor && /* @__PURE__ */ jsx7("div", { className: "border-t border-[var(--border-subtle)] px-2 py-2", children: activityMonitor }),
1086
- links.length > 0 && /* @__PURE__ */ jsx7("nav", { "aria-label": "Workspace sections", className: "border-t border-[var(--border-subtle)] px-2 py-2", children: /* @__PURE__ */ jsx7("div", { className: "space-y-0.5", children: links.map((link) => {
1087
- const Icon = iconForLink(link.icon);
1088
- return /* @__PURE__ */ jsxs7(
1089
- "button",
1090
- {
1091
- type: "button",
1092
- onClick: () => {
1093
- if (onSelectLink) {
1094
- onSelectLink(link);
1095
- return;
1096
- }
1097
- navigateToHref(link.href);
1098
- },
1099
- className: "flex w-full items-center gap-2 rounded-[var(--radius-sm)] px-2 py-1.5 text-left text-xs text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-section)] hover:text-[var(--text-primary)]",
1100
- children: [
1101
- /* @__PURE__ */ jsx7(Icon, { className: "h-3.5 w-3.5 shrink-0" }),
1102
- /* @__PURE__ */ jsx7("span", { className: "truncate", children: link.label })
1103
- ]
1104
- },
1105
- link.id
1106
- );
1107
- }) }) })
1108
- ] });
1152
+ ]
1153
+ }
1154
+ );
1109
1155
  }
1110
1156
 
1111
1157
  // src/workspace/session-activity-monitor.tsx
@@ -1113,15 +1159,15 @@ import { Activity, AlertCircle as AlertCircle2, LoaderCircle, MessageSquareText
1113
1159
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1114
1160
  function SessionStatusDot({ session }) {
1115
1161
  if (session.status === "error") {
1116
- return /* @__PURE__ */ jsx8(AlertCircle2, { className: "h-3 w-3 text-[var(--surface-danger-text)]" });
1162
+ return /* @__PURE__ */ jsx8(AlertCircle2, { className: "h-3 w-3 text-destructive" });
1117
1163
  }
1118
1164
  if (session.status === "running") {
1119
- return /* @__PURE__ */ jsx8(LoaderCircle, { className: "h-3 w-3 animate-spin text-[var(--brand-cool)]" });
1165
+ return /* @__PURE__ */ jsx8(LoaderCircle, { className: "h-3 w-3 animate-spin text-primary" });
1120
1166
  }
1121
1167
  if (session.status === "attention-needed") {
1122
- return /* @__PURE__ */ jsx8(Activity, { className: "h-3 w-3 text-[var(--surface-warning-text)]" });
1168
+ return /* @__PURE__ */ jsx8(Activity, { className: "h-3 w-3 text-warning" });
1123
1169
  }
1124
- return /* @__PURE__ */ jsx8("span", { className: "h-1.5 w-1.5 rounded-full bg-[var(--text-dim)]" });
1170
+ return /* @__PURE__ */ jsx8("span", { className: "h-1.5 w-1.5 rounded-full bg-muted-foreground/40" });
1125
1171
  }
1126
1172
  function navigateToSession(session) {
1127
1173
  if (!session.href || typeof window === "undefined") return;
@@ -1141,38 +1187,38 @@ function SessionActivityMonitor({
1141
1187
  const sessionLookup = Object.keys(sessionsById).length > 0 ? sessionsById : Object.fromEntries(trackedSessions.map((session) => [session.sessionId, session]));
1142
1188
  if (projectActivity.length === 0) {
1143
1189
  if (compact) return null;
1144
- return /* @__PURE__ */ jsx8("div", { className: cn("rounded-[var(--radius-md)] border border-[var(--border-subtle)] bg-[var(--depth-2)] px-3 py-2 text-xs text-[var(--text-muted)]", className), children: emptyMessage });
1190
+ return /* @__PURE__ */ jsx8("div", { className: cn("rounded-md border border-dashed border-border bg-muted px-3 py-2.5 text-xs text-muted-foreground", className), children: emptyMessage });
1145
1191
  }
1146
1192
  return /* @__PURE__ */ jsxs8("div", { className: cn("space-y-1.5", className), children: [
1147
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between px-0.5", children: [
1148
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-[0.14em] text-[var(--text-muted)]", children: [
1193
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between", children: [
1194
+ /* @__PURE__ */ jsxs8("span", { className: "flex items-center gap-1.5 text-[10px] font-medium uppercase tracking-wider text-muted-foreground", children: [
1149
1195
  /* @__PURE__ */ jsx8(Activity, { className: "h-3 w-3" }),
1150
1196
  "Active"
1151
1197
  ] }),
1152
- totalRunning > 0 && /* @__PURE__ */ jsx8("span", { className: "rounded-full border border-[var(--border-accent)] bg-[var(--accent-surface-soft)] px-1.5 py-px text-[10px] font-medium text-[var(--accent-text)]", children: totalRunning })
1198
+ totalRunning > 0 && /* @__PURE__ */ jsx8("span", { className: "rounded-full bg-primary/10 px-1.5 py-px text-[10px] font-medium text-primary", children: totalRunning })
1153
1199
  ] }),
1154
1200
  /* @__PURE__ */ jsx8("div", { className: "space-y-1", children: projectActivity.map((project) => {
1155
1201
  const label = resolveProjectLabel?.(project.projectId, project.projectLabel) ?? project.projectLabel ?? String(project.projectId);
1156
1202
  return /* @__PURE__ */ jsxs8(
1157
1203
  "div",
1158
1204
  {
1159
- className: "rounded-[var(--radius-md)] border border-[var(--border-subtle)] bg-[var(--depth-2)]",
1205
+ className: "rounded-md border border-border bg-muted",
1160
1206
  children: [
1161
1207
  /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between gap-2 px-2.5 py-1.5", children: [
1162
1208
  /* @__PURE__ */ jsxs8("div", { className: "min-w-0", children: [
1163
- /* @__PURE__ */ jsx8("div", { className: "truncate text-xs font-medium text-[var(--text-primary)]", children: label }),
1164
- /* @__PURE__ */ jsxs8("div", { className: "text-[10px] text-[var(--text-muted)]", children: [
1209
+ /* @__PURE__ */ jsx8("div", { className: "truncate text-xs font-medium text-foreground", children: label }),
1210
+ /* @__PURE__ */ jsxs8("div", { className: "text-[10px] text-muted-foreground", children: [
1165
1211
  project.activeSessionCount,
1166
1212
  " session",
1167
1213
  project.activeSessionCount === 1 ? "" : "s"
1168
1214
  ] })
1169
1215
  ] }),
1170
- project.runningSessionIds.length > 0 && /* @__PURE__ */ jsxs8("span", { className: "shrink-0 text-[10px] text-[var(--text-muted)]", children: [
1216
+ project.runningSessionIds.length > 0 && /* @__PURE__ */ jsxs8("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: [
1171
1217
  project.runningSessionIds.length,
1172
1218
  " live"
1173
1219
  ] })
1174
1220
  ] }),
1175
- !compact && project.runningSessionIds.length > 0 && /* @__PURE__ */ jsx8("div", { className: "border-t border-[var(--border-subtle)] px-1.5 py-1", children: project.runningSessionIds.map((sessionId) => {
1221
+ !compact && project.runningSessionIds.length > 0 && /* @__PURE__ */ jsx8("div", { className: "border-t border-border px-1 py-0.5", children: project.runningSessionIds.map((sessionId) => {
1176
1222
  const session = sessionLookup[sessionId];
1177
1223
  if (!session) return null;
1178
1224
  return /* @__PURE__ */ jsxs8(
@@ -1186,11 +1232,11 @@ function SessionActivityMonitor({
1186
1232
  }
1187
1233
  navigateToSession(session);
1188
1234
  },
1189
- className: "flex w-full items-center gap-2 rounded-[var(--radius-sm)] px-2 py-1 text-left transition-colors hover:bg-[var(--bg-hover)]",
1235
+ className: "flex w-full items-center gap-2 rounded-sm px-2 py-1 text-left transition-colors hover:bg-accent",
1190
1236
  children: [
1191
1237
  /* @__PURE__ */ jsx8(SessionStatusDot, { session }),
1192
- /* @__PURE__ */ jsx8("span", { className: "min-w-0 truncate text-xs text-[var(--text-primary)]", children: session.title ?? "Untitled" }),
1193
- /* @__PURE__ */ jsx8(MessageSquareText2, { className: "ml-auto h-3 w-3 shrink-0 text-[var(--text-dim)]" })
1238
+ /* @__PURE__ */ jsx8("span", { className: "min-w-0 truncate text-xs text-foreground", children: session.title ?? "Untitled" }),
1239
+ /* @__PURE__ */ jsx8(MessageSquareText2, { className: "ml-auto h-3 w-3 shrink-0 text-muted-foreground" })
1194
1240
  ]
1195
1241
  },
1196
1242
  sessionId
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  InlineThinkingItem,
8
8
  RunGroup
9
- } from "./chunk-LY32SP6X.js";
9
+ } from "./chunk-ZMWWE5RF.js";
10
10
  import {
11
11
  ToolCallGroup,
12
12
  ToolCallStep
@@ -898,44 +898,32 @@ var InlineThinkingItem = memo10(
898
898
  "button",
899
899
  {
900
900
  className: cn(
901
- "w-full rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)] text-left transition-colors",
902
- "hover:border-[var(--border-accent-hover)] hover:bg-[var(--bg-hover)]/35",
903
- open && "border-[var(--border-accent)] bg-[var(--bg-hover)]/30",
901
+ "w-full rounded-[var(--radius-lg)] border text-left transition-colors",
902
+ isActive ? "border-primary/30 bg-primary/10" : "border-border bg-muted hover:bg-accent",
903
+ open && !isActive && "bg-accent",
904
904
  className
905
905
  ),
906
- children: /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-3 px-3 py-3", children: [
907
- /* @__PURE__ */ jsx12(
908
- "div",
909
- {
910
- className: cn(
911
- "flex h-8 w-8 shrink-0 items-center justify-center rounded-[var(--radius-md)] border",
912
- isActive ? "border-[var(--border-accent)] bg-[var(--accent-surface-soft)] text-[var(--accent-text)] shadow-[var(--shadow-glow)]" : "border-[var(--border-subtle)] bg-[var(--bg-section)] text-[var(--text-muted)]"
913
- ),
914
- children: /* @__PURE__ */ jsx12(Brain, { className: cn("h-4 w-4", isActive && "animate-pulse") })
915
- }
916
- ),
917
- /* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
918
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
919
- /* @__PURE__ */ jsx12("span", { className: "text-sm font-medium text-[var(--text-primary)]", children: isActive ? "Thinking\u2026" : "Reasoning" }),
920
- !isActive && durationMs != null ? /* @__PURE__ */ jsx12("span", { className: "rounded-full border border-[var(--border-subtle)] bg-[var(--bg-section)] px-2 py-0.5 text-[11px] font-[var(--font-mono)] text-[var(--text-muted)]", children: formatDuration(durationMs) }) : null,
921
- isActive && startTime ? /* @__PURE__ */ jsx12(LiveDuration, { startTime }) : null
922
- ] }),
923
- preview && !open ? /* @__PURE__ */ jsx12("div", { className: "mt-1 truncate text-xs text-[var(--text-muted)]", children: preview }) : null
924
- ] }),
925
- open ? /* @__PURE__ */ jsx12(ChevronDown3, { className: "h-3.5 w-3.5 shrink-0 text-[var(--text-muted)]" }) : /* @__PURE__ */ jsx12(ChevronRight3, { className: "h-3.5 w-3.5 shrink-0 text-[var(--text-muted)]" })
906
+ children: /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2.5 px-3 py-2", children: [
907
+ /* @__PURE__ */ jsx12(Brain, { className: cn("h-4 w-4 shrink-0", isActive ? "text-primary animate-pulse" : "text-muted-foreground") }),
908
+ /* @__PURE__ */ jsx12("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx12("span", { className: "truncate text-xs text-foreground", children: preview ?? (isActive ? "Thinking\u2026" : "Reasoning") }) }),
909
+ /* @__PURE__ */ jsxs11("div", { className: "flex shrink-0 items-center gap-2", children: [
910
+ isActive && startTime ? /* @__PURE__ */ jsx12(LiveDuration, { startTime }) : null,
911
+ !isActive && durationMs != null ? /* @__PURE__ */ jsx12("span", { className: "text-[10px] font-mono tabular-nums text-muted-foreground", children: formatDuration(durationMs) }) : null,
912
+ open ? /* @__PURE__ */ jsx12(ChevronDown3, { className: "h-3 w-3 text-muted-foreground" }) : /* @__PURE__ */ jsx12(ChevronRight3, { className: "h-3 w-3 text-muted-foreground" })
913
+ ] })
926
914
  ] })
927
915
  }
928
916
  ) }),
929
- /* @__PURE__ */ jsx12(Collapsible2.Content, { className: "overflow-hidden data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: part.text ? /* @__PURE__ */ jsx12(
917
+ /* @__PURE__ */ jsx12(Collapsible2.Content, { className: "overflow-hidden rounded-b-[var(--radius-lg)] data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp", children: part.text ? /* @__PURE__ */ jsx12(
930
918
  "div",
931
919
  {
932
920
  className: cn(
933
- "border-t border-[var(--border-subtle)] px-4 py-4 text-sm text-[var(--text-secondary)]",
921
+ "max-h-60 overflow-y-auto border-t border-border bg-card px-3 py-3 text-sm leading-relaxed text-foreground",
934
922
  contentClassName
935
923
  ),
936
924
  children: /* @__PURE__ */ jsx12(Markdown, { children: part.text })
937
925
  }
938
- ) : /* @__PURE__ */ jsx12("div", { className: "border-t border-[var(--border-subtle)] px-4 py-3 text-sm text-[var(--text-muted)]", children: "No reasoning text was provided." }) })
926
+ ) : /* @__PURE__ */ jsx12("div", { className: "border-t border-border px-3 py-2.5 text-xs text-muted-foreground", children: "No reasoning text provided." }) })
939
927
  ] });
940
928
  }
941
929
  );
@@ -48,10 +48,6 @@ interface InlineThinkingItemProps {
48
48
  className?: string;
49
49
  contentClassName?: string;
50
50
  }
51
- /**
52
- * Minimal collapsible display for thinking/reasoning parts.
53
- * Shows "Thinking..." with optional preview text and duration.
54
- */
55
51
  declare const InlineThinkingItem: React.MemoExoticComponent<({ part, defaultOpen, autoCollapse, className, contentClassName, }: InlineThinkingItemProps) => react_jsx_runtime.JSX.Element>;
56
52
 
57
53
  interface ExpandedToolDetailProps {
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { C as ChatContainer, a as ChatContainerProps, b as ChatInput, c as ChatI
9
9
  export { C as Collaborator, a as ConnectionState, D as DocumentEditorBackend, b as DocumentEditorMode, c as DocumentEditorPane, d as DocumentEditorPaneCollaborationConfig, e as DocumentEditorPaneProps, E as EditorContextValue, f as EditorProvider, g as EditorProviderProps, h as EditorUser, u as useEditorContext } from './document-editor-pane-A70-EhdQ.js';
10
10
  export { CollaboratorsList, EditorToolbar, TiptapEditor, TiptapEditorProps, useAwareness, useCollaboratorPresence, useCollaborators, useDocumentChanges, useEditorConnection, useYjsState } from './editor.js';
11
11
  export { F as FeedSegment, T as ToolCallData, a as ToolCallFeed, b as ToolCallFeedProps, c as ToolCallGroup, d as ToolCallGroupProps, e as ToolCallStatus, f as ToolCallStep, g as ToolCallStepProps, h as ToolCallType, p as parseToolEvent } from './tool-call-feed-Bs3MyQMT.js';
12
- export { E as ExpandedToolDetail, I as InlineThinkingItem, c as InlineToolItem, R as RunGroup, e as RunGroupProps } from './expanded-tool-detail-DM5M_T9h.js';
12
+ export { E as ExpandedToolDetail, I as InlineThinkingItem, c as InlineToolItem, R as RunGroup, e as RunGroupProps } from './expanded-tool-detail-Dh99mcbY.js';
13
13
  import * as React$1 from 'react';
14
14
  import { b as ToolPart } from './parts-CyGkM6Fp.js';
15
15
  export { R as ReasoningPart, S as SessionMessage, a as SessionPart, T as TextPart, c as ToolState, d as ToolStatus, e as ToolTime } from './parts-CyGkM6Fp.js';
package/dist/index.js CHANGED
@@ -102,7 +102,7 @@ import {
102
102
  StatusBar,
103
103
  TerminalPanel,
104
104
  WorkspaceLayout
105
- } from "./chunk-WSR2NB2H.js";
105
+ } from "./chunk-E2XT3G52.js";
106
106
  import "./chunk-OEX7NZE3.js";
107
107
  import {
108
108
  EmptyState,
@@ -116,7 +116,7 @@ import {
116
116
  MessageList,
117
117
  ThinkingIndicator,
118
118
  UserMessage
119
- } from "./chunk-5F3VOGCT.js";
119
+ } from "./chunk-RKXIRRKQ.js";
120
120
  import {
121
121
  useAutoScroll,
122
122
  useRunCollapseState,
@@ -134,7 +134,7 @@ import {
134
134
  RunGroup,
135
135
  WebSearchPreview,
136
136
  WriteFilePreview
137
- } from "./chunk-LY32SP6X.js";
137
+ } from "./chunk-ZMWWE5RF.js";
138
138
  import {
139
139
  formatDuration,
140
140
  truncateText
package/dist/run.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { E as ExpandedToolDetail, a as ExpandedToolDetailProps, I as InlineThinkingItem, b as InlineThinkingItemProps, c as InlineToolItem, d as InlineToolItemProps, R as RunGroup, e as RunGroupProps } from './expanded-tool-detail-DM5M_T9h.js';
1
+ export { E as ExpandedToolDetail, a as ExpandedToolDetailProps, I as InlineThinkingItem, b as InlineThinkingItemProps, c as InlineToolItem, d as InlineToolItemProps, R as RunGroup, e as RunGroupProps } from './expanded-tool-detail-Dh99mcbY.js';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  export { F as FeedSegment, T as ToolCallData, a as ToolCallFeed, b as ToolCallFeedProps, c as ToolCallGroup, d as ToolCallGroupProps, e as ToolCallStatus, f as ToolCallStep, g as ToolCallStepProps, h as ToolCallType, p as parseToolEvent } from './tool-call-feed-Bs3MyQMT.js';
4
4
  import 'react';
package/dist/run.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  InlineToolItem,
9
9
  LiveDuration,
10
10
  RunGroup
11
- } from "./chunk-LY32SP6X.js";
11
+ } from "./chunk-ZMWWE5RF.js";
12
12
  import "./chunk-HRMUF35V.js";
13
13
  import {
14
14
  ToolCallGroup,
package/dist/tokens.css CHANGED
@@ -47,7 +47,7 @@
47
47
  --hsl-secondary: 243 25% 19%;
48
48
  --hsl-secondary-foreground: 240 16% 90%;
49
49
  --hsl-muted: 242 22% 16%;
50
- --hsl-muted-foreground: 233 17% 55%;
50
+ --hsl-muted-foreground: 233 17% 62%;
51
51
  --hsl-accent: 245 28% 21%;
52
52
  --hsl-accent-foreground: 240 16% 92%;
53
53
  --hsl-destructive: 348 90% 60%;
@@ -169,9 +169,9 @@
169
169
 
170
170
  /* Text */
171
171
  --text-primary: hsl(var(--hsl-foreground));
172
- --text-secondary: hsl(244 18% 86%);
173
- --text-muted: #6B7094;
174
- --text-dim: #4A4D6A;
172
+ --text-secondary: hsl(244 18% 88%);
173
+ --text-muted: #8B90B8;
174
+ --text-dim: #6B70A0;
175
175
 
176
176
  /* Brand accents — Tangle exact */
177
177
  --brand-primary: #4a3aff;
@@ -214,12 +214,17 @@ interface SessionSidebarProps {
214
214
  activityMonitor?: ReactNode;
215
215
  filters?: SessionSidebarFilter[];
216
216
  defaultFilterId?: string;
217
+ resizable?: boolean;
218
+ defaultWidth?: number;
219
+ minWidth?: number;
220
+ maxWidth?: number;
221
+ onWidthChange?: (width: number) => void;
217
222
  renderItemActions?: (item: SessionSidebarItem, options: {
218
223
  session: ActiveSessionRecord | null;
219
224
  isActive: boolean;
220
225
  }) => ReactNode;
221
226
  }
222
- declare function SessionSidebar({ title, subtitle, projectId, items, currentItemId, createLabel, onCreate, onSelectItem, onSelectLink, links, className, emptyMessage, searchPlaceholder, enableSearch, activityMonitor, filters, defaultFilterId, renderItemActions, }: SessionSidebarProps): react_jsx_runtime.JSX.Element;
227
+ declare function SessionSidebar({ title, subtitle, projectId, items, currentItemId, createLabel, onCreate, onSelectItem, onSelectLink, links, className, emptyMessage, searchPlaceholder, enableSearch, activityMonitor, filters, defaultFilterId, resizable, defaultWidth, minWidth, maxWidth, onWidthChange, renderItemActions, }: SessionSidebarProps): react_jsx_runtime.JSX.Element;
223
228
 
224
229
  interface SessionActivityMonitorProps {
225
230
  className?: string;
package/dist/workspace.js CHANGED
@@ -10,12 +10,12 @@ import {
10
10
  StatusBar,
11
11
  TerminalPanel,
12
12
  WorkspaceLayout
13
- } from "./chunk-WSR2NB2H.js";
13
+ } from "./chunk-E2XT3G52.js";
14
14
  import "./chunk-OEX7NZE3.js";
15
15
  import "./chunk-BRBTD7RH.js";
16
- import "./chunk-5F3VOGCT.js";
16
+ import "./chunk-RKXIRRKQ.js";
17
17
  import "./chunk-CNWVHQFY.js";
18
- import "./chunk-LY32SP6X.js";
18
+ import "./chunk-ZMWWE5RF.js";
19
19
  import "./chunk-HRMUF35V.js";
20
20
  import "./chunk-MJUDMVRU.js";
21
21
  import "./chunk-BX6AQMUS.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
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",