@tangle-network/sandbox-ui 0.91.5 → 0.92.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.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  snapHarnessToModel,
20
20
  snapModelToHarness,
21
21
  validateComposerFiles
22
- } from "./chunk-QMY3XVH3.js";
22
+ } from "./chunk-GUULFESL.js";
23
23
  import "./chunk-TK46XFLM.js";
24
24
  import {
25
25
  MENTION_PILL_CLASS
@@ -1561,17 +1561,19 @@ function AgentComposer({
1561
1561
  }
1562
1562
  )
1563
1563
  ] }),
1564
- /* @__PURE__ */ jsx4("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: controls ?? /* @__PURE__ */ jsx4(
1565
- AgentSessionControls,
1566
- {
1567
- context,
1568
- harness,
1569
- profile,
1570
- model,
1571
- reasoning
1572
- }
1573
- ) }),
1574
- trailing && /* @__PURE__ */ jsx4("div", { className: "flex shrink-0 items-center gap-2", children: trailing }),
1564
+ /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-1 items-center gap-2 overflow-x-auto overscroll-x-contain [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: [
1565
+ controls ?? /* @__PURE__ */ jsx4(
1566
+ AgentSessionControls,
1567
+ {
1568
+ context,
1569
+ harness,
1570
+ profile,
1571
+ model,
1572
+ reasoning
1573
+ }
1574
+ ),
1575
+ trailing && /* @__PURE__ */ jsx4("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: trailing })
1576
+ ] }),
1575
1577
  busy && onCancel ? /* @__PURE__ */ jsx4(
1576
1578
  "button",
1577
1579
  {
@@ -2323,11 +2323,22 @@ function DashboardLayout({ defaultPanelOpen, defaultMode, labeledRail, defaultRa
2323
2323
  }
2324
2324
 
2325
2325
  // src/dashboard/sidebar-layout.tsx
2326
- import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
2326
+ import * as React10 from "react";
2327
+ import { Fragment as Fragment10, jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
2327
2328
  var HIDE_BELOW_CLASS = {
2328
2329
  md: "max-md:hidden",
2329
2330
  lg: "max-lg:hidden"
2330
2331
  };
2332
+ var SHOW_BELOW_CLASS = {
2333
+ md: "md:hidden",
2334
+ lg: "lg:hidden"
2335
+ };
2336
+ function MenuIcon2({ className }) {
2337
+ return /* @__PURE__ */ jsx15("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx15("path", { d: "M3 6h18M3 12h18M3 18h18" }) });
2338
+ }
2339
+ function CloseIcon({ className }) {
2340
+ return /* @__PURE__ */ jsx15("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx15("path", { d: "M18 6 6 18M6 6l12 12" }) });
2341
+ }
2331
2342
  function DefaultLink3({
2332
2343
  href,
2333
2344
  to,
@@ -2370,6 +2381,94 @@ function SidebarLayoutInner({
2370
2381
  } : void 0;
2371
2382
  const hasProfile = user !== void 0 || onLogout !== void 0 || onSettingsClick !== void 0;
2372
2383
  const showLabels = railLabels && !railCollapsed;
2384
+ const [mobileNavOpen, setMobileNavOpen] = React10.useState(false);
2385
+ const closeMobileNav = React10.useCallback(() => setMobileNavOpen(false), []);
2386
+ function renderNavItems({
2387
+ showLabels: showLabels2,
2388
+ onNavigate
2389
+ }) {
2390
+ return navItems.map((item) => {
2391
+ if (item.expandable) {
2392
+ return /* @__PURE__ */ jsx15(
2393
+ RailExpandable,
2394
+ {
2395
+ icon: item.icon,
2396
+ label: item.label,
2397
+ href: item.href,
2398
+ isActive: activeId === item.id,
2399
+ showLabel: showLabels2,
2400
+ subItems: item.subItems,
2401
+ loadSubItems: item.loadSubItems,
2402
+ activeSubIds: item.subActiveIds,
2403
+ emptyLabel: item.emptyLabel,
2404
+ defaultOpen: item.defaultOpen,
2405
+ onNavigate,
2406
+ LinkComponent
2407
+ },
2408
+ item.id
2409
+ );
2410
+ }
2411
+ if (item.flyoutItems && item.flyoutItems.length > 0) {
2412
+ const activeSet = new Set(item.flyoutActiveIds ?? []);
2413
+ return /* @__PURE__ */ jsx15(
2414
+ RailFlyout,
2415
+ {
2416
+ icon: item.icon,
2417
+ label: item.label,
2418
+ title: item.label,
2419
+ showLabel: showLabels2,
2420
+ isActive: activeId === item.id || item.flyoutItems.some((f) => activeSet.has(f.id)),
2421
+ children: item.flyoutItems.map((f) => {
2422
+ const FIcon = f.icon;
2423
+ const active = activeSet.has(f.id);
2424
+ return /* @__PURE__ */ jsxs14(
2425
+ Link,
2426
+ {
2427
+ href: f.href,
2428
+ to: f.href,
2429
+ onClick: onNavigate,
2430
+ ...f.prefetch !== void 0 ? { prefetch: f.prefetch } : {},
2431
+ className: cn(
2432
+ "flex h-9 items-center gap-2.5 rounded-lg px-2.5 text-sm transition-colors",
2433
+ active ? "bg-[var(--accent-surface-strong)] font-medium text-[var(--accent-text)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-[var(--accent-text)]"
2434
+ ),
2435
+ children: [
2436
+ /* @__PURE__ */ jsx15(FIcon, { className: "h-4 w-4 shrink-0" }),
2437
+ /* @__PURE__ */ jsx15("span", { className: "truncate", children: f.label })
2438
+ ]
2439
+ },
2440
+ f.id
2441
+ );
2442
+ })
2443
+ },
2444
+ item.id
2445
+ );
2446
+ }
2447
+ return item.togglesPanel ? /* @__PURE__ */ jsx15(
2448
+ RailButton,
2449
+ {
2450
+ icon: item.icon,
2451
+ label: item.label,
2452
+ badge: item.badge,
2453
+ isActive: panelOpen,
2454
+ onClick: () => {
2455
+ togglePanel();
2456
+ onNavigate?.();
2457
+ },
2458
+ showLabel: showLabels2
2459
+ },
2460
+ item.id
2461
+ ) : /* @__PURE__ */ jsx15(RailButton, { icon: item.icon, label: item.label, badge: item.badge, isActive: activeId === item.id, showLabel: showLabels2, variant: item.variant, asChild: true, children: /* @__PURE__ */ jsx15(
2462
+ Link,
2463
+ {
2464
+ href: item.href,
2465
+ to: item.href,
2466
+ onClick: onNavigate,
2467
+ ...item.prefetch !== void 0 ? { prefetch: item.prefetch } : {}
2468
+ }
2469
+ ) }, item.id);
2470
+ });
2471
+ }
2373
2472
  return /* @__PURE__ */ jsxs14("div", { className: cn("min-h-screen bg-surface text-foreground", className), children: [
2374
2473
  /* @__PURE__ */ jsx15("div", { className: cn(hideBelow && HIDE_BELOW_CLASS[hideBelow]), children: /* @__PURE__ */ jsxs14(Sidebar, { className: sidebarClassName, children: [
2375
2474
  /* @__PURE__ */ jsxs14(SidebarRail, { children: [
@@ -2385,84 +2484,7 @@ function SidebarLayoutInner({
2385
2484
  children: railHeaderContent
2386
2485
  }
2387
2486
  ),
2388
- /* @__PURE__ */ jsx15(SidebarRailNav, { className: cn(showLabels ? "px-2" : void 0, expandOnEmptyClick && "cursor-pointer"), onClick: expandOnEmptyClick, children: navItems.map((item) => {
2389
- if (item.expandable) {
2390
- return /* @__PURE__ */ jsx15(
2391
- RailExpandable,
2392
- {
2393
- icon: item.icon,
2394
- label: item.label,
2395
- href: item.href,
2396
- isActive: activeId === item.id,
2397
- showLabel: showLabels,
2398
- subItems: item.subItems,
2399
- loadSubItems: item.loadSubItems,
2400
- activeSubIds: item.subActiveIds,
2401
- emptyLabel: item.emptyLabel,
2402
- defaultOpen: item.defaultOpen,
2403
- onNavigate: handleNavClick,
2404
- LinkComponent
2405
- },
2406
- item.id
2407
- );
2408
- }
2409
- if (item.flyoutItems && item.flyoutItems.length > 0) {
2410
- const activeSet = new Set(item.flyoutActiveIds ?? []);
2411
- return /* @__PURE__ */ jsx15(
2412
- RailFlyout,
2413
- {
2414
- icon: item.icon,
2415
- label: item.label,
2416
- title: item.label,
2417
- showLabel: showLabels,
2418
- isActive: activeId === item.id || item.flyoutItems.some((f) => activeSet.has(f.id)),
2419
- children: item.flyoutItems.map((f) => {
2420
- const FIcon = f.icon;
2421
- const active = activeSet.has(f.id);
2422
- return /* @__PURE__ */ jsxs14(
2423
- Link,
2424
- {
2425
- href: f.href,
2426
- to: f.href,
2427
- onClick: handleNavClick,
2428
- ...f.prefetch !== void 0 ? { prefetch: f.prefetch } : {},
2429
- className: cn(
2430
- "flex h-9 items-center gap-2.5 rounded-lg px-2.5 text-sm transition-colors",
2431
- active ? "bg-[var(--accent-surface-strong)] font-medium text-[var(--accent-text)]" : "text-muted-foreground hover:bg-[var(--accent-surface-soft)] hover:text-[var(--accent-text)]"
2432
- ),
2433
- children: [
2434
- /* @__PURE__ */ jsx15(FIcon, { className: "h-4 w-4 shrink-0" }),
2435
- /* @__PURE__ */ jsx15("span", { className: "truncate", children: f.label })
2436
- ]
2437
- },
2438
- f.id
2439
- );
2440
- })
2441
- },
2442
- item.id
2443
- );
2444
- }
2445
- return item.togglesPanel ? /* @__PURE__ */ jsx15(
2446
- RailButton,
2447
- {
2448
- icon: item.icon,
2449
- label: item.label,
2450
- badge: item.badge,
2451
- isActive: panelOpen,
2452
- onClick: togglePanel,
2453
- showLabel: showLabels
2454
- },
2455
- item.id
2456
- ) : /* @__PURE__ */ jsx15(RailButton, { icon: item.icon, label: item.label, badge: item.badge, isActive: activeId === item.id, showLabel: showLabels, variant: item.variant, asChild: true, children: /* @__PURE__ */ jsx15(
2457
- Link,
2458
- {
2459
- href: item.href,
2460
- to: item.href,
2461
- onClick: handleNavClick,
2462
- ...item.prefetch !== void 0 ? { prefetch: item.prefetch } : {}
2463
- }
2464
- ) }, item.id);
2465
- }) }),
2487
+ /* @__PURE__ */ jsx15(SidebarRailNav, { className: cn(showLabels ? "px-2" : void 0, expandOnEmptyClick && "cursor-pointer"), onClick: expandOnEmptyClick, children: renderNavItems({ showLabels, onNavigate: handleNavClick }) }),
2466
2488
  (railFooter !== void 0 || hasProfile) && /* @__PURE__ */ jsxs14(SidebarRailFooter, { className: cn("border-t border-[var(--md3-outline-variant)] pt-2", showLabels && "items-stretch px-2"), children: [
2467
2489
  railFooter,
2468
2490
  hasProfile && /* @__PURE__ */ jsx15(
@@ -2483,7 +2505,171 @@ function SidebarLayoutInner({
2483
2505
  ] }),
2484
2506
  panel != null && /* @__PURE__ */ jsx15(SidebarPanel, { children: panel })
2485
2507
  ] }) }),
2486
- /* @__PURE__ */ jsx15(SidebarContent, { className: contentClassName, children })
2508
+ /* @__PURE__ */ jsxs14(SidebarContent, { className: contentClassName, children: [
2509
+ hideBelow && /* @__PURE__ */ jsxs14(
2510
+ "header",
2511
+ {
2512
+ className: cn(
2513
+ "flex h-14 shrink-0 items-center gap-1 border-b border-[var(--md3-outline-variant)] bg-surface px-2",
2514
+ SHOW_BELOW_CLASS[hideBelow]
2515
+ ),
2516
+ children: [
2517
+ /* @__PURE__ */ jsx15(
2518
+ "button",
2519
+ {
2520
+ type: "button",
2521
+ "aria-label": "Open navigation",
2522
+ "aria-expanded": mobileNavOpen,
2523
+ "aria-controls": "sidebar-mobile-nav",
2524
+ "aria-haspopup": "dialog",
2525
+ onClick: () => setMobileNavOpen(true),
2526
+ className: "flex size-10 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-[var(--accent-surface-soft)] hover:text-foreground",
2527
+ children: /* @__PURE__ */ jsx15(MenuIcon2, { className: "size-5" })
2528
+ }
2529
+ ),
2530
+ /* @__PURE__ */ jsx15("div", { className: "flex min-w-0 flex-1 items-center", children: railHeaderContent ?? (logo !== void 0 ? /* @__PURE__ */ jsx15(Link, { href: logoHref, to: logoHref, className: "flex min-w-0 items-center", children: logo }) : null) }),
2531
+ hasProfile && /* @__PURE__ */ jsx15(
2532
+ ProfileAvatar,
2533
+ {
2534
+ user: user ?? void 0,
2535
+ isLoading,
2536
+ onLogout,
2537
+ onSettingsClick,
2538
+ settingsHref,
2539
+ appearance,
2540
+ LinkComponent: Link,
2541
+ children: profileMenuItems
2542
+ }
2543
+ )
2544
+ ]
2545
+ }
2546
+ ),
2547
+ children
2548
+ ] }),
2549
+ hideBelow && mobileNavOpen && /* @__PURE__ */ jsx15(
2550
+ MobileNavDrawer,
2551
+ {
2552
+ breakpoint: hideBelow,
2553
+ onClose: closeMobileNav,
2554
+ header: railHeaderContent ?? logo,
2555
+ footer: railFooter !== void 0 || hasProfile ? /* @__PURE__ */ jsxs14(Fragment10, { children: [
2556
+ railFooter,
2557
+ hasProfile && /* @__PURE__ */ jsx15(
2558
+ ProfileAvatar,
2559
+ {
2560
+ user: user ?? void 0,
2561
+ isLoading,
2562
+ onLogout,
2563
+ onSettingsClick,
2564
+ settingsHref,
2565
+ showDetails: true,
2566
+ appearance,
2567
+ LinkComponent: Link,
2568
+ children: profileMenuItems
2569
+ }
2570
+ )
2571
+ ] }) : null,
2572
+ panel,
2573
+ children: renderNavItems({
2574
+ showLabels: true,
2575
+ onNavigate: () => {
2576
+ handleNavClick?.();
2577
+ closeMobileNav();
2578
+ }
2579
+ })
2580
+ }
2581
+ )
2582
+ ] });
2583
+ }
2584
+ function MobileNavDrawer({
2585
+ breakpoint,
2586
+ onClose,
2587
+ header,
2588
+ footer,
2589
+ panel,
2590
+ children
2591
+ }) {
2592
+ const panelRef = React10.useRef(null);
2593
+ React10.useEffect(() => {
2594
+ const onKeyDown = (event) => {
2595
+ if (event.key === "Escape") {
2596
+ event.stopPropagation();
2597
+ onClose();
2598
+ return;
2599
+ }
2600
+ if (event.key !== "Tab") return;
2601
+ const root = panelRef.current;
2602
+ if (!root) return;
2603
+ const focusable = root.querySelectorAll(
2604
+ 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])'
2605
+ );
2606
+ if (focusable.length === 0) return;
2607
+ const first = focusable[0];
2608
+ const last = focusable[focusable.length - 1];
2609
+ if (event.shiftKey && document.activeElement === first) {
2610
+ event.preventDefault();
2611
+ last.focus();
2612
+ } else if (!event.shiftKey && document.activeElement === last) {
2613
+ event.preventDefault();
2614
+ first.focus();
2615
+ }
2616
+ };
2617
+ document.addEventListener("keydown", onKeyDown, true);
2618
+ return () => document.removeEventListener("keydown", onKeyDown, true);
2619
+ }, [onClose]);
2620
+ React10.useEffect(() => {
2621
+ const previous = document.body.style.overflow;
2622
+ document.body.style.overflow = "hidden";
2623
+ return () => {
2624
+ document.body.style.overflow = previous;
2625
+ };
2626
+ }, []);
2627
+ React10.useEffect(() => {
2628
+ panelRef.current?.querySelector("button,a[href]")?.focus();
2629
+ }, []);
2630
+ return /* @__PURE__ */ jsxs14("div", { className: cn("fixed inset-0 z-50", SHOW_BELOW_CLASS[breakpoint]), children: [
2631
+ /* @__PURE__ */ jsx15(
2632
+ "button",
2633
+ {
2634
+ type: "button",
2635
+ "aria-label": "Close navigation",
2636
+ tabIndex: -1,
2637
+ onClick: onClose,
2638
+ className: "absolute inset-0 bg-black/50"
2639
+ }
2640
+ ),
2641
+ /* @__PURE__ */ jsxs14(
2642
+ "div",
2643
+ {
2644
+ ref: panelRef,
2645
+ id: "sidebar-mobile-nav",
2646
+ role: "dialog",
2647
+ "aria-modal": "true",
2648
+ "aria-label": "Navigation",
2649
+ style: { width: SIDEBAR_MOBILE_WIDTH },
2650
+ className: "absolute inset-y-0 left-0 flex max-w-[85vw] flex-col border-r border-[var(--md3-outline-variant)] bg-surface-container-low shadow-xl",
2651
+ children: [
2652
+ /* @__PURE__ */ jsxs14("div", { className: "flex h-14 shrink-0 items-center gap-1 border-b border-[var(--md3-outline-variant)] px-2", children: [
2653
+ /* @__PURE__ */ jsx15("div", { className: "flex min-w-0 flex-1 items-center", children: header }),
2654
+ /* @__PURE__ */ jsx15(
2655
+ "button",
2656
+ {
2657
+ type: "button",
2658
+ "aria-label": "Close navigation",
2659
+ onClick: onClose,
2660
+ className: "flex size-9 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-[var(--accent-surface-soft)] hover:text-foreground",
2661
+ children: /* @__PURE__ */ jsx15(CloseIcon, { className: "size-5" })
2662
+ }
2663
+ )
2664
+ ] }),
2665
+ /* @__PURE__ */ jsxs14("nav", { "aria-label": "Sections", className: "flex min-h-0 flex-1 flex-col gap-0.5 overflow-y-auto px-2 py-2", children: [
2666
+ children,
2667
+ panel != null && /* @__PURE__ */ jsx15("div", { className: "mt-2 border-t border-[var(--md3-outline-variant)] pt-2", children: panel })
2668
+ ] }),
2669
+ footer != null && /* @__PURE__ */ jsx15("div", { className: "shrink-0 border-t border-[var(--md3-outline-variant)] px-2 py-2", children: footer })
2670
+ ]
2671
+ }
2672
+ )
2487
2673
  ] });
2488
2674
  }
2489
2675
  function SidebarLayout({
@@ -2523,7 +2709,7 @@ import {
2523
2709
  DropdownMenuSeparator as DropdownMenuSeparator4,
2524
2710
  DropdownMenuTrigger as DropdownMenuTrigger4
2525
2711
  } from "@tangle-network/ui/primitives";
2526
- import { Fragment as Fragment10, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
2712
+ import { Fragment as Fragment11, jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
2527
2713
  function ProfileSelector({
2528
2714
  profiles,
2529
2715
  selectedId,
@@ -2557,7 +2743,7 @@ function ProfileSelector({
2557
2743
  ]
2558
2744
  }
2559
2745
  ),
2560
- builtinProfiles.length > 0 && /* @__PURE__ */ jsxs15(Fragment10, { children: [
2746
+ builtinProfiles.length > 0 && /* @__PURE__ */ jsxs15(Fragment11, { children: [
2561
2747
  /* @__PURE__ */ jsx16(DropdownMenuSeparator4, {}),
2562
2748
  /* @__PURE__ */ jsx16(DropdownMenuLabel2, { children: "Built-in Profiles" }),
2563
2749
  builtinProfiles.map((profile) => /* @__PURE__ */ jsxs15(
@@ -2582,7 +2768,7 @@ function ProfileSelector({
2582
2768
  profile.id
2583
2769
  ))
2584
2770
  ] }),
2585
- customProfiles.length > 0 && /* @__PURE__ */ jsxs15(Fragment10, { children: [
2771
+ customProfiles.length > 0 && /* @__PURE__ */ jsxs15(Fragment11, { children: [
2586
2772
  /* @__PURE__ */ jsx16(DropdownMenuSeparator4, {}),
2587
2773
  /* @__PURE__ */ jsx16(DropdownMenuLabel2, { children: "Custom Profiles" }),
2588
2774
  customProfiles.map((profile) => /* @__PURE__ */ jsxs15(
@@ -2619,7 +2805,7 @@ function ProfileSelector({
2619
2805
  profile.id
2620
2806
  ))
2621
2807
  ] }),
2622
- (onCreateClick || onManageClick) && /* @__PURE__ */ jsxs15(Fragment10, { children: [
2808
+ (onCreateClick || onManageClick) && /* @__PURE__ */ jsxs15(Fragment11, { children: [
2623
2809
  /* @__PURE__ */ jsx16(DropdownMenuSeparator4, {}),
2624
2810
  onCreateClick && /* @__PURE__ */ jsxs15(
2625
2811
  DropdownMenuItem4,
@@ -2714,7 +2900,7 @@ function ProfileComparison({
2714
2900
  }
2715
2901
 
2716
2902
  // src/dashboard/metric-area-chart.tsx
2717
- import * as React10 from "react";
2903
+ import * as React11 from "react";
2718
2904
  import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
2719
2905
  var TONE_VARS = {
2720
2906
  primary: "var(--brand-primary, hsl(var(--primary)))",
@@ -2761,7 +2947,7 @@ function MetricAreaChart({
2761
2947
  emptyState,
2762
2948
  className
2763
2949
  }) {
2764
- const gradientId = React10.useId();
2950
+ const gradientId = React11.useId();
2765
2951
  const width = 400;
2766
2952
  const values = points.map((p) => p.value).filter((v) => v !== null);
2767
2953
  const latest = values.length > 0 ? values[values.length - 1] : null;
@@ -2821,7 +3007,7 @@ function MetricAreaChart({
2821
3007
  /* @__PURE__ */ jsx17("stop", { offset: "0%", stopColor: color, stopOpacity: 0.28 }),
2822
3008
  /* @__PURE__ */ jsx17("stop", { offset: "100%", stopColor: color, stopOpacity: 0.02 })
2823
3009
  ] }) }),
2824
- segments.map((segment) => /* @__PURE__ */ jsxs16(React10.Fragment, { children: [
3010
+ segments.map((segment) => /* @__PURE__ */ jsxs16(React11.Fragment, { children: [
2825
3011
  /* @__PURE__ */ jsx17("path", { d: segment.area, fill: `url(#${gradientId})` }),
2826
3012
  /* @__PURE__ */ jsx17(
2827
3013
  "path",
@@ -2861,7 +3047,7 @@ import {
2861
3047
  } from "lucide-react";
2862
3048
  import { Button as Button3 } from "@tangle-network/ui/primitives";
2863
3049
  import { Badge as Badge2 } from "@tangle-network/ui/primitives";
2864
- import { Fragment as Fragment12, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3050
+ import { Fragment as Fragment13, jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
2865
3051
  var statusConfig = {
2866
3052
  pending: {
2867
3053
  icon: Clock3,
@@ -2984,7 +3170,7 @@ function VariantList({
2984
3170
  children: outcomeConfig[variant.outcome].label
2985
3171
  }
2986
3172
  ),
2987
- variant.status === "completed" && variant.outcome === "pending_review" && onAccept && onReject && /* @__PURE__ */ jsxs17(Fragment12, { children: [
3173
+ variant.status === "completed" && variant.outcome === "pending_review" && onAccept && onReject && /* @__PURE__ */ jsxs17(Fragment13, { children: [
2988
3174
  /* @__PURE__ */ jsxs17(
2989
3175
  Button3,
2990
3176
  {
@@ -3046,14 +3232,14 @@ function VariantList({
3046
3232
 
3047
3233
  // src/dashboard/system-logs.tsx
3048
3234
  import { Terminal as Terminal2 } from "lucide-react";
3049
- import { useEffect as useEffect5, useRef as useRef4, useState as useState6 } from "react";
3235
+ import { useEffect as useEffect6, useRef as useRef5, useState as useState7 } from "react";
3050
3236
  import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
3051
3237
  function SystemLogsViewer({ apiUrl, token, className }) {
3052
- const [logs, setLogs] = useState6([]);
3053
- const [error, setError] = useState6(null);
3054
- const [isFollowing, setIsFollowing] = useState6(true);
3055
- const scrollRef = useRef4(null);
3056
- useEffect5(() => {
3238
+ const [logs, setLogs] = useState7([]);
3239
+ const [error, setError] = useState7(null);
3240
+ const [isFollowing, setIsFollowing] = useState7(true);
3241
+ const scrollRef = useRef5(null);
3242
+ useEffect6(() => {
3057
3243
  let timeoutId;
3058
3244
  let backoff = 2e3;
3059
3245
  const controller = new AbortController();
@@ -3089,7 +3275,7 @@ function SystemLogsViewer({ apiUrl, token, className }) {
3089
3275
  clearTimeout(timeoutId);
3090
3276
  };
3091
3277
  }, [apiUrl, token]);
3092
- useEffect5(() => {
3278
+ useEffect6(() => {
3093
3279
  if (isFollowing && scrollRef.current) {
3094
3280
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
3095
3281
  }
@@ -3296,14 +3482,14 @@ function GitPanel({ status, log, loading = false, onRefresh, className }) {
3296
3482
  }
3297
3483
 
3298
3484
  // src/dashboard/ports-list.tsx
3299
- import * as React12 from "react";
3485
+ import * as React13 from "react";
3300
3486
  import { Copy as Copy3, Check as Check5, Globe, Plus as Plus4, Trash2 as Trash23 } from "lucide-react";
3301
3487
  import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
3302
3488
  function PortsList({ ports, onExposePort, onRemovePort, isExposing = false, className }) {
3303
- const [newPort, setNewPort] = React12.useState("");
3304
- const [copiedPort, setCopiedPort] = React12.useState(null);
3305
- const copyTimerRef = React12.useRef(null);
3306
- React12.useEffect(() => {
3489
+ const [newPort, setNewPort] = React13.useState("");
3490
+ const [copiedPort, setCopiedPort] = React13.useState(null);
3491
+ const copyTimerRef = React13.useRef(null);
3492
+ React13.useEffect(() => {
3307
3493
  return () => {
3308
3494
  if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
3309
3495
  };
@@ -3397,7 +3583,7 @@ function PortsList({ ports, onExposePort, onRemovePort, isExposing = false, clas
3397
3583
  }
3398
3584
 
3399
3585
  // src/dashboard/process-list.tsx
3400
- import * as React13 from "react";
3586
+ import * as React14 from "react";
3401
3587
  import { Activity as Activity3, Plus as Plus5, Skull, Terminal as Terminal3 } from "lucide-react";
3402
3588
  import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
3403
3589
  function formatUptime(startedAt) {
@@ -3409,7 +3595,7 @@ function formatUptime(startedAt) {
3409
3595
  return `${Math.floor(ms / 36e5)}h ${Math.floor(ms % 36e5 / 6e4)}m`;
3410
3596
  }
3411
3597
  function ProcessList({ processes, onSpawn, onKill, loading = false, className }) {
3412
- const [newCommand, setNewCommand] = React13.useState("");
3598
+ const [newCommand, setNewCommand] = React14.useState("");
3413
3599
  const handleSpawn = () => {
3414
3600
  const cmd = newCommand.trim();
3415
3601
  if (cmd) {
@@ -3482,11 +3668,11 @@ function ProcessList({ processes, onSpawn, onKill, loading = false, className })
3482
3668
  }
3483
3669
 
3484
3670
  // src/dashboard/network-config.tsx
3485
- import * as React14 from "react";
3671
+ import * as React15 from "react";
3486
3672
  import { Network as Network2, Plus as Plus6, Trash2 as Trash24, ShieldAlert } from "lucide-react";
3487
3673
  import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
3488
3674
  function NetworkConfig({ config, onUpdate, loading = false, className }) {
3489
- const [newCidr, setNewCidr] = React14.useState("");
3675
+ const [newCidr, setNewCidr] = React15.useState("");
3490
3676
  const isValidCidr = (value) => {
3491
3677
  const match = value.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/);
3492
3678
  if (!match) return false;
@@ -3590,9 +3776,9 @@ function NetworkConfig({ config, onUpdate, loading = false, className }) {
3590
3776
  }
3591
3777
 
3592
3778
  // src/dashboard/backend-config.tsx
3593
- import * as React15 from "react";
3779
+ import * as React16 from "react";
3594
3780
  import { Bot, Plus as Plus7, RefreshCw as RefreshCw2, Trash2 as Trash25, Server, Wrench } from "lucide-react";
3595
- import { Fragment as Fragment13, jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
3781
+ import { Fragment as Fragment14, jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
3596
3782
  function BackendConfig({
3597
3783
  status,
3598
3784
  mcpServers,
@@ -3602,10 +3788,10 @@ function BackendConfig({
3602
3788
  loading = false,
3603
3789
  className
3604
3790
  }) {
3605
- const [showAddMcp, setShowAddMcp] = React15.useState(false);
3606
- const [mcpName, setMcpName] = React15.useState("");
3607
- const [mcpCommand, setMcpCommand] = React15.useState("");
3608
- const [mcpArgs, setMcpArgs] = React15.useState("");
3791
+ const [showAddMcp, setShowAddMcp] = React16.useState(false);
3792
+ const [mcpName, setMcpName] = React16.useState("");
3793
+ const [mcpCommand, setMcpCommand] = React16.useState("");
3794
+ const [mcpArgs, setMcpArgs] = React16.useState("");
3609
3795
  const handleAddMcp = () => {
3610
3796
  const name = mcpName.trim();
3611
3797
  const command = mcpCommand.trim();
@@ -3652,7 +3838,7 @@ function BackendConfig({
3652
3838
  ), children: status.running ? "Running" : "Stopped" }) }),
3653
3839
  /* @__PURE__ */ jsx25("dt", { className: "text-muted-foreground", children: "Model" }),
3654
3840
  /* @__PURE__ */ jsx25("dd", { className: "font-mono text-xs", children: status.model ?? "Default" }),
3655
- status.provider && /* @__PURE__ */ jsxs24(Fragment13, { children: [
3841
+ status.provider && /* @__PURE__ */ jsxs24(Fragment14, { children: [
3656
3842
  /* @__PURE__ */ jsx25("dt", { className: "text-muted-foreground", children: "Provider" }),
3657
3843
  /* @__PURE__ */ jsx25("dd", { className: "font-mono text-xs", children: status.provider })
3658
3844
  ] })
@@ -3763,7 +3949,7 @@ function BackendConfig({
3763
3949
  }
3764
3950
 
3765
3951
  // src/dashboard/snapshot-list.tsx
3766
- import * as React16 from "react";
3952
+ import * as React17 from "react";
3767
3953
  import { Camera, Clock as Clock5, HardDrive as HardDrive2, Plus as Plus8, RotateCcw } from "lucide-react";
3768
3954
  import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
3769
3955
  function formatBytes(bytes) {
@@ -3780,8 +3966,8 @@ function formatDate(dateStr) {
3780
3966
  return d.toLocaleDateString(void 0, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
3781
3967
  }
3782
3968
  function SnapshotList({ snapshots, onCreate, onRestore, onSaveAsTemplate, loading = false, className }) {
3783
- const [showCreate, setShowCreate] = React16.useState(false);
3784
- const [tags, setTags] = React16.useState("");
3969
+ const [showCreate, setShowCreate] = React17.useState(false);
3970
+ const [tags, setTags] = React17.useState("");
3785
3971
  const handleCreate = () => {
3786
3972
  const tagList = tags.trim() ? tags.trim().split(",").map((t) => t.trim()).filter(Boolean) : void 0;
3787
3973
  onCreate(tagList);
@@ -3898,7 +4084,7 @@ function SnapshotList({ snapshots, onCreate, onRestore, onSaveAsTemplate, loadin
3898
4084
  }
3899
4085
 
3900
4086
  // src/dashboard/promo-banner.tsx
3901
- import { Fragment as Fragment14, jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
4087
+ import { Fragment as Fragment15, jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
3902
4088
  function PromoBanner({
3903
4089
  title,
3904
4090
  description,
@@ -3913,7 +4099,7 @@ function PromoBanner({
3913
4099
  "mt-6 inline-flex items-center gap-2 rounded-md border border-white/20 bg-[var(--btn-primary-bg)] px-4 py-2 text-sm font-medium text-[var(--btn-primary-text)] transition-colors",
3914
4100
  disabled ? "opacity-50 cursor-not-allowed" : "hover:bg-[var(--btn-primary-hover)]"
3915
4101
  );
3916
- const buttonContent = /* @__PURE__ */ jsxs26(Fragment14, { children: [
4102
+ const buttonContent = /* @__PURE__ */ jsxs26(Fragment15, { children: [
3917
4103
  buttonLabel,
3918
4104
  /* @__PURE__ */ jsxs26("svg", { "aria-hidden": "true", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "h-4 w-4", children: [
3919
4105
  /* @__PURE__ */ jsx27("path", { d: "M5 12h14" }),
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-3J6FG3FJ.js";
4
4
  import {
5
5
  PortsList
6
- } from "./chunk-H237JF3H.js";
6
+ } from "./chunk-UB3V2YAZ.js";
7
7
  import {
8
8
  TerminalView
9
9
  } from "./chunk-WYMAC3T3.js";
package/dist/dashboard.js CHANGED
@@ -54,7 +54,7 @@ import {
54
54
  canAdminSandbox,
55
55
  parseInsufficientBalance,
56
56
  useSidebar
57
- } from "./chunk-H237JF3H.js";
57
+ } from "./chunk-UB3V2YAZ.js";
58
58
  import {
59
59
  BillingDashboard,
60
60
  InfoPanel,
package/dist/globals.css CHANGED
@@ -707,6 +707,10 @@
707
707
  width: calc(var(--spacing) * 9);
708
708
  height: calc(var(--spacing) * 9);
709
709
  }
710
+ .size-10 {
711
+ width: calc(var(--spacing) * 10);
712
+ height: calc(var(--spacing) * 10);
713
+ }
710
714
  .size-11 {
711
715
  width: calc(var(--spacing) * 11);
712
716
  height: calc(var(--spacing) * 11);
@@ -1221,6 +1225,9 @@
1221
1225
  .max-w-\[85\%\] {
1222
1226
  max-width: 85%;
1223
1227
  }
1228
+ .max-w-\[85vw\] {
1229
+ max-width: 85vw;
1230
+ }
1224
1231
  .max-w-\[90vw\] {
1225
1232
  max-width: 90vw;
1226
1233
  }
@@ -1445,6 +1452,9 @@
1445
1452
  .resize-y {
1446
1453
  resize: vertical;
1447
1454
  }
1455
+ .\[scrollbar-width\:none\] {
1456
+ scrollbar-width: none;
1457
+ }
1448
1458
  .\[scrollbar-gutter\:stable\] {
1449
1459
  scrollbar-gutter: stable;
1450
1460
  }
@@ -1685,6 +1695,9 @@
1685
1695
  .overflow-y-auto {
1686
1696
  overflow-y: auto;
1687
1697
  }
1698
+ .overscroll-x-contain {
1699
+ overscroll-behavior-x: contain;
1700
+ }
1688
1701
  .rounded {
1689
1702
  border-radius: 0.25rem;
1690
1703
  }
@@ -3476,6 +3489,10 @@
3476
3489
  --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
3477
3490
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
3478
3491
  }
3492
+ .shadow-xl {
3493
+ --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
3494
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
3495
+ }
3479
3496
  .ring {
3480
3497
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
3481
3498
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -3654,6 +3671,9 @@
3654
3671
  -webkit-user-select: none;
3655
3672
  user-select: none;
3656
3673
  }
3674
+ .\[-ms-overflow-style\:none\] {
3675
+ -ms-overflow-style: none;
3676
+ }
3657
3677
  .ring-inset {
3658
3678
  --tw-ring-inset: inset;
3659
3679
  }
@@ -4569,6 +4589,9 @@
4569
4589
  .md\:flex {
4570
4590
  display: flex;
4571
4591
  }
4592
+ .md\:hidden {
4593
+ display: none;
4594
+ }
4572
4595
  .md\:grid-cols-2 {
4573
4596
  grid-template-columns: repeat(2, minmax(0, 1fr));
4574
4597
  }
@@ -4687,6 +4710,9 @@
4687
4710
  .\[\&\:\:-moz-range-track\]\:bg-border::-moz-range-track {
4688
4711
  background-color: var(--color-border);
4689
4712
  }
4713
+ .\[\&\:\:-webkit-scrollbar\]\:hidden::-webkit-scrollbar {
4714
+ display: none;
4715
+ }
4690
4716
  .\[\&\:\:-webkit-slider-runnable-track\]\:h-1\.5::-webkit-slider-runnable-track {
4691
4717
  height: calc(var(--spacing) * 1.5);
4692
4718
  }
package/dist/index.js CHANGED
@@ -91,7 +91,7 @@ import {
91
91
  snapHarnessToModel,
92
92
  snapModelToHarness,
93
93
  validateComposerFiles
94
- } from "./chunk-QMY3XVH3.js";
94
+ } from "./chunk-GUULFESL.js";
95
95
  import {
96
96
  TOOL_CATEGORY_ICONS,
97
97
  cn,
@@ -152,7 +152,7 @@ import {
152
152
  buildUnifiedPatch,
153
153
  computeDiffStats,
154
154
  resolveLanguage
155
- } from "./chunk-S6J6JIIP.js";
155
+ } from "./chunk-UKQOHN73.js";
156
156
  import {
157
157
  FileArtifactPane,
158
158
  FilePreview,
@@ -217,7 +217,7 @@ import {
217
217
  canAdminSandbox,
218
218
  parseInsufficientBalance,
219
219
  useSidebar
220
- } from "./chunk-H237JF3H.js";
220
+ } from "./chunk-UB3V2YAZ.js";
221
221
  import {
222
222
  BillingDashboard,
223
223
  InfoPanel,
package/dist/styles.css CHANGED
@@ -707,6 +707,10 @@
707
707
  width: calc(var(--spacing) * 9);
708
708
  height: calc(var(--spacing) * 9);
709
709
  }
710
+ .size-10 {
711
+ width: calc(var(--spacing) * 10);
712
+ height: calc(var(--spacing) * 10);
713
+ }
710
714
  .size-11 {
711
715
  width: calc(var(--spacing) * 11);
712
716
  height: calc(var(--spacing) * 11);
@@ -1221,6 +1225,9 @@
1221
1225
  .max-w-\[85\%\] {
1222
1226
  max-width: 85%;
1223
1227
  }
1228
+ .max-w-\[85vw\] {
1229
+ max-width: 85vw;
1230
+ }
1224
1231
  .max-w-\[90vw\] {
1225
1232
  max-width: 90vw;
1226
1233
  }
@@ -1445,6 +1452,9 @@
1445
1452
  .resize-y {
1446
1453
  resize: vertical;
1447
1454
  }
1455
+ .\[scrollbar-width\:none\] {
1456
+ scrollbar-width: none;
1457
+ }
1448
1458
  .\[scrollbar-gutter\:stable\] {
1449
1459
  scrollbar-gutter: stable;
1450
1460
  }
@@ -1685,6 +1695,9 @@
1685
1695
  .overflow-y-auto {
1686
1696
  overflow-y: auto;
1687
1697
  }
1698
+ .overscroll-x-contain {
1699
+ overscroll-behavior-x: contain;
1700
+ }
1688
1701
  .rounded {
1689
1702
  border-radius: 0.25rem;
1690
1703
  }
@@ -3476,6 +3489,10 @@
3476
3489
  --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
3477
3490
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
3478
3491
  }
3492
+ .shadow-xl {
3493
+ --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
3494
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
3495
+ }
3479
3496
  .ring {
3480
3497
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
3481
3498
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -3654,6 +3671,9 @@
3654
3671
  -webkit-user-select: none;
3655
3672
  user-select: none;
3656
3673
  }
3674
+ .\[-ms-overflow-style\:none\] {
3675
+ -ms-overflow-style: none;
3676
+ }
3657
3677
  .ring-inset {
3658
3678
  --tw-ring-inset: inset;
3659
3679
  }
@@ -4569,6 +4589,9 @@
4569
4589
  .md\:flex {
4570
4590
  display: flex;
4571
4591
  }
4592
+ .md\:hidden {
4593
+ display: none;
4594
+ }
4572
4595
  .md\:grid-cols-2 {
4573
4596
  grid-template-columns: repeat(2, minmax(0, 1fr));
4574
4597
  }
@@ -4687,6 +4710,9 @@
4687
4710
  .\[\&\:\:-moz-range-track\]\:bg-border::-moz-range-track {
4688
4711
  background-color: var(--color-border);
4689
4712
  }
4713
+ .\[\&\:\:-webkit-scrollbar\]\:hidden::-webkit-scrollbar {
4714
+ display: none;
4715
+ }
4690
4716
  .\[\&\:\:-webkit-slider-runnable-track\]\:h-1\.5::-webkit-slider-runnable-track {
4691
4717
  height: calc(var(--spacing) * 1.5);
4692
4718
  }
package/dist/workbench.js CHANGED
@@ -12,9 +12,9 @@ import {
12
12
  buildUnifiedPatch,
13
13
  computeDiffStats,
14
14
  resolveLanguage
15
- } from "./chunk-S6J6JIIP.js";
15
+ } from "./chunk-UKQOHN73.js";
16
16
  import "./chunk-3J6FG3FJ.js";
17
- import "./chunk-H237JF3H.js";
17
+ import "./chunk-UB3V2YAZ.js";
18
18
  import "./chunk-OMUIPJQZ.js";
19
19
  import "./chunk-WYMAC3T3.js";
20
20
  import "./chunk-KEYPUGS3.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.91.5",
3
+ "version": "0.92.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",