@lukeashford/aurelius 3.9.0 → 4.1.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/index.mjs CHANGED
@@ -92,6 +92,147 @@ Input.displayName = "Input";
92
92
  import React4, { createContext, useContext } from "react";
93
93
  import { Check } from "lucide-react";
94
94
 
95
+ // src/utils/clipboard.ts
96
+ async function copyToClipboard(text) {
97
+ if (typeof navigator !== "undefined" && navigator.clipboard) {
98
+ try {
99
+ await navigator.clipboard.writeText(text);
100
+ return true;
101
+ } catch {
102
+ }
103
+ }
104
+ if (typeof document === "undefined") {
105
+ return false;
106
+ }
107
+ const textArea = document.createElement("textarea");
108
+ textArea.value = text;
109
+ textArea.setAttribute("readonly", "");
110
+ textArea.setAttribute("aria-hidden", "true");
111
+ textArea.style.position = "fixed";
112
+ textArea.style.opacity = "0";
113
+ textArea.style.pointerEvents = "none";
114
+ document.body.appendChild(textArea);
115
+ try {
116
+ textArea.select();
117
+ return document.execCommand("copy");
118
+ } catch {
119
+ return false;
120
+ } finally {
121
+ document.body.removeChild(textArea);
122
+ }
123
+ }
124
+
125
+ // src/utils/hooks.ts
126
+ import { useCallback, useEffect, useRef, useState } from "react";
127
+ function composeRefs(...refs) {
128
+ return (node) => {
129
+ for (const ref of refs) {
130
+ if (!ref) {
131
+ continue;
132
+ }
133
+ if (typeof ref === "function") {
134
+ ref(node);
135
+ } else {
136
+ ;
137
+ ref.current = node;
138
+ }
139
+ }
140
+ };
141
+ }
142
+ var scrollLockCount = 0;
143
+ var scrollLockOriginalOverflow = null;
144
+ var scrollLockOriginalPaddingRight = null;
145
+ function useScrollLock(isLocked) {
146
+ useEffect(() => {
147
+ if (!isLocked || typeof document === "undefined") {
148
+ return;
149
+ }
150
+ if (scrollLockCount === 0) {
151
+ scrollLockOriginalOverflow = document.body.style.overflow;
152
+ scrollLockOriginalPaddingRight = document.body.style.paddingRight;
153
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
154
+ document.body.style.overflow = "hidden";
155
+ if (scrollbarWidth > 0) {
156
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
157
+ }
158
+ }
159
+ scrollLockCount++;
160
+ return () => {
161
+ scrollLockCount--;
162
+ if (scrollLockCount === 0) {
163
+ document.body.style.overflow = scrollLockOriginalOverflow ?? "";
164
+ document.body.style.paddingRight = scrollLockOriginalPaddingRight ?? "";
165
+ scrollLockOriginalOverflow = null;
166
+ scrollLockOriginalPaddingRight = null;
167
+ }
168
+ };
169
+ }, [isLocked]);
170
+ }
171
+ function useEscapeKey(onEscape, isActive = true) {
172
+ useEffect(() => {
173
+ if (!isActive || typeof window === "undefined") {
174
+ return;
175
+ }
176
+ const handler = (e) => {
177
+ if (e.key === "Escape") {
178
+ onEscape();
179
+ }
180
+ };
181
+ window.addEventListener("keydown", handler);
182
+ return () => window.removeEventListener("keydown", handler);
183
+ }, [onEscape, isActive]);
184
+ }
185
+ function useClickOutside(ref, handler, isActive = true) {
186
+ useEffect(() => {
187
+ if (!isActive || typeof document === "undefined") {
188
+ return;
189
+ }
190
+ const listener = (event) => {
191
+ const node = ref.current;
192
+ if (node && !node.contains(event.target)) {
193
+ handler(event);
194
+ }
195
+ };
196
+ document.addEventListener("mousedown", listener);
197
+ return () => document.removeEventListener("mousedown", listener);
198
+ }, [ref, handler, isActive]);
199
+ }
200
+ function useCopyToClipboard(resetMs = 2e3) {
201
+ const [copied, setCopied] = useState(false);
202
+ const timerRef = useRef(null);
203
+ const mountedRef = useRef(true);
204
+ useEffect(() => {
205
+ mountedRef.current = true;
206
+ return () => {
207
+ mountedRef.current = false;
208
+ if (timerRef.current !== null) {
209
+ clearTimeout(timerRef.current);
210
+ timerRef.current = null;
211
+ }
212
+ };
213
+ }, []);
214
+ const copy = useCallback(async (text) => {
215
+ const ok = await copyToClipboard(text);
216
+ if (!mountedRef.current) {
217
+ return ok;
218
+ }
219
+ if (ok) {
220
+ setCopied(true);
221
+ if (timerRef.current !== null) {
222
+ clearTimeout(timerRef.current);
223
+ }
224
+ timerRef.current = setTimeout(() => {
225
+ timerRef.current = null;
226
+ if (mountedRef.current) {
227
+ setCopied(false);
228
+ }
229
+ }, resetMs);
230
+ }
231
+ return ok;
232
+ }, [resetMs]);
233
+ return { copied, copy };
234
+ }
235
+
95
236
  // src/components/Skeleton.tsx
96
237
  import React3 from "react";
97
238
  var Skeleton = React3.forwardRef(
@@ -116,8 +257,7 @@ function slotLoading(loading, path) {
116
257
  return false;
117
258
  }
118
259
  if (Array.isArray(path)) {
119
- const [section, field] = path;
120
- return !!loading[section]?.[field];
260
+ return !!loading.header?.[path[1]];
121
261
  }
122
262
  return !!loading[path];
123
263
  }
@@ -1393,29 +1533,28 @@ var Select = React20.forwardRef(
1393
1533
  Select.displayName = "Select";
1394
1534
 
1395
1535
  // src/components/Checkbox.tsx
1396
- import React21, { useCallback } from "react";
1536
+ import React21, { useCallback as useCallback2, useId } from "react";
1397
1537
  var checkmarkSvg = `url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='%231A1A1A' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")`;
1398
1538
  var Checkbox = React21.forwardRef(
1399
- ({ className, label, id, ...rest }, ref) => {
1400
- const inputId = id || rest.name || Math.random().toString(36).substr(2, 9);
1401
- const setRef = useCallback((node) => {
1402
- if (node) {
1403
- if (node.checked) {
1404
- node.style.backgroundImage = checkmarkSvg;
1405
- }
1406
- }
1407
- if (typeof ref === "function") {
1408
- ref(node);
1409
- } else if (ref) {
1410
- ref.current = node;
1539
+ ({ className, label, id, onChange, ...rest }, ref) => {
1540
+ const generatedId = useId();
1541
+ const inputId = id || rest.name || generatedId;
1542
+ const initBackground = useCallback2((node) => {
1543
+ if (node && node.checked) {
1544
+ node.style.backgroundImage = checkmarkSvg;
1411
1545
  }
1412
- }, [ref]);
1546
+ }, []);
1547
+ const handleChange = useCallback2((e) => {
1548
+ e.currentTarget.style.backgroundImage = e.currentTarget.checked ? checkmarkSvg : "none";
1549
+ onChange?.(e);
1550
+ }, [onChange]);
1413
1551
  return /* @__PURE__ */ React21.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React21.createElement(
1414
1552
  "input",
1415
1553
  {
1554
+ ...rest,
1416
1555
  type: "checkbox",
1417
1556
  id: inputId,
1418
- ref: setRef,
1557
+ ref: composeRefs(initBackground, ref),
1419
1558
  className: cx(
1420
1559
  "appearance-none h-4 w-4 border border-ash bg-graphite",
1421
1560
  "checked:bg-gold checked:border-gold",
@@ -1429,16 +1568,7 @@ var Checkbox = React21.forwardRef(
1429
1568
  backgroundSize: "contain",
1430
1569
  backgroundRepeat: "no-repeat"
1431
1570
  },
1432
- onChange: (e) => {
1433
- const input = e.currentTarget;
1434
- if (input.checked) {
1435
- input.style.backgroundImage = checkmarkSvg;
1436
- } else {
1437
- input.style.backgroundImage = "none";
1438
- }
1439
- rest.onChange?.(e);
1440
- },
1441
- ...rest
1571
+ onChange: handleChange
1442
1572
  }
1443
1573
  ), label && /* @__PURE__ */ React21.createElement(
1444
1574
  "label",
@@ -1453,29 +1583,44 @@ var Checkbox = React21.forwardRef(
1453
1583
  Checkbox.displayName = "Checkbox";
1454
1584
 
1455
1585
  // src/components/Radio.tsx
1456
- import React22, { useCallback as useCallback2 } from "react";
1586
+ import React22, { useCallback as useCallback3, useId as useId2 } from "react";
1457
1587
  var radioDotSvg = `url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='%231A1A1A' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")`;
1458
1588
  var Radio = React22.forwardRef(
1459
- ({ className, label, id, ...rest }, ref) => {
1460
- const inputId = id || rest.name || Math.random().toString(36).substr(2, 9);
1461
- const setRef = useCallback2((node) => {
1462
- if (node) {
1463
- if (node.checked) {
1464
- node.style.backgroundImage = radioDotSvg;
1465
- }
1589
+ ({ className, label, id, onChange, ...rest }, ref) => {
1590
+ const generatedId = useId2();
1591
+ const inputId = id || rest.name || generatedId;
1592
+ const initBackground = useCallback3((node) => {
1593
+ if (node && node.checked) {
1594
+ node.style.backgroundImage = radioDotSvg;
1466
1595
  }
1467
- if (typeof ref === "function") {
1468
- ref(node);
1469
- } else if (ref) {
1470
- ref.current = node;
1596
+ }, []);
1597
+ const handleChange = useCallback3((e) => {
1598
+ const input = e.currentTarget;
1599
+ if (input.checked) {
1600
+ input.style.backgroundImage = radioDotSvg;
1601
+ if (input.name) {
1602
+ const escaped = typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(input.name) : input.name.replace(/["\\\]]/g, "\\$&");
1603
+ const radios = input.ownerDocument.querySelectorAll(
1604
+ `input[type="radio"][name="${escaped}"]`
1605
+ );
1606
+ radios.forEach((radio) => {
1607
+ if (radio !== input) {
1608
+ radio.style.backgroundImage = "none";
1609
+ }
1610
+ });
1611
+ }
1612
+ } else {
1613
+ input.style.backgroundImage = "none";
1471
1614
  }
1472
- }, [ref]);
1615
+ onChange?.(e);
1616
+ }, [onChange]);
1473
1617
  return /* @__PURE__ */ React22.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React22.createElement(
1474
1618
  "input",
1475
1619
  {
1620
+ ...rest,
1476
1621
  type: "radio",
1477
1622
  id: inputId,
1478
- ref: setRef,
1623
+ ref: composeRefs(initBackground, ref),
1479
1624
  className: cx(
1480
1625
  "appearance-none h-4 w-4 border border-ash rounded-full bg-graphite",
1481
1626
  "checked:bg-gold checked:border-gold",
@@ -1489,26 +1634,7 @@ var Radio = React22.forwardRef(
1489
1634
  backgroundSize: "contain",
1490
1635
  backgroundRepeat: "no-repeat"
1491
1636
  },
1492
- onChange: (e) => {
1493
- const input = e.currentTarget;
1494
- if (input.checked) {
1495
- input.style.backgroundImage = radioDotSvg;
1496
- if (input.name) {
1497
- const radios = document.querySelectorAll(
1498
- `input[type="radio"][name="${input.name}"]`
1499
- );
1500
- radios.forEach((radio) => {
1501
- if (radio !== input) {
1502
- radio.style.backgroundImage = "none";
1503
- }
1504
- });
1505
- }
1506
- } else {
1507
- input.style.backgroundImage = "none";
1508
- }
1509
- rest.onChange?.(e);
1510
- },
1511
- ...rest
1637
+ onChange: handleChange
1512
1638
  }
1513
1639
  ), label && /* @__PURE__ */ React22.createElement(
1514
1640
  "label",
@@ -1523,7 +1649,7 @@ var Radio = React22.forwardRef(
1523
1649
  Radio.displayName = "Radio";
1524
1650
 
1525
1651
  // src/components/Switch.tsx
1526
- import React23, { useCallback as useCallback3, useRef, useState } from "react";
1652
+ import React23, { useCallback as useCallback4, useRef as useRef2, useState as useState2 } from "react";
1527
1653
  var Switch = React23.forwardRef(
1528
1654
  ({
1529
1655
  checked: controlledChecked,
@@ -1534,11 +1660,11 @@ var Switch = React23.forwardRef(
1534
1660
  label,
1535
1661
  ...rest
1536
1662
  }, ref) => {
1537
- const [internalChecked, setInternalChecked] = useState(defaultChecked);
1663
+ const [internalChecked, setInternalChecked] = useState2(defaultChecked);
1538
1664
  const isControlled = controlledChecked !== void 0;
1539
1665
  const checked = isControlled ? controlledChecked : internalChecked;
1540
- const buttonRef = useRef(null);
1541
- const setRefs = useCallback3(
1666
+ const buttonRef = useRef2(null);
1667
+ const setRefs = useCallback4(
1542
1668
  (node) => {
1543
1669
  buttonRef.current = node;
1544
1670
  if (typeof ref === "function") {
@@ -1608,7 +1734,7 @@ var Switch = React23.forwardRef(
1608
1734
  Switch.displayName = "Switch";
1609
1735
 
1610
1736
  // src/components/Slider.tsx
1611
- import React24, { useCallback as useCallback4, useRef as useRef2, useState as useState2 } from "react";
1737
+ import React24, { useCallback as useCallback5, useRef as useRef3, useState as useState3 } from "react";
1612
1738
  var SIZE_TRACK = {
1613
1739
  sm: "h-1",
1614
1740
  md: "h-2",
@@ -1635,13 +1761,13 @@ var Slider = React24.forwardRef(
1635
1761
  className,
1636
1762
  ...props
1637
1763
  }, ref) => {
1638
- const [internalValue, setInternalValue] = useState2(defaultValue);
1639
- const [isDragging, setIsDragging] = useState2(false);
1640
- const trackRef = useRef2(null);
1764
+ const [internalValue, setInternalValue] = useState3(defaultValue);
1765
+ const [isDragging, setIsDragging] = useState3(false);
1766
+ const trackRef = useRef3(null);
1641
1767
  const isControlled = controlledValue !== void 0;
1642
1768
  const value = isControlled ? controlledValue : internalValue;
1643
1769
  const percentage = (value - min) / (max - min) * 100;
1644
- const updateValue = useCallback4(
1770
+ const updateValue = useCallback5(
1645
1771
  (clientX) => {
1646
1772
  if (!trackRef.current || disabled) {
1647
1773
  return;
@@ -1997,16 +2123,21 @@ var Progress = React28.forwardRef(
1997
2123
  Progress.displayName = "Progress";
1998
2124
 
1999
2125
  // src/components/Toast.tsx
2000
- import React29, { createContext as createContext2, useCallback as useCallback5, useContext as useContext2, useEffect, useState as useState3 } from "react";
2126
+ import React29, { createContext as createContext2, useCallback as useCallback6, useContext as useContext2, useEffect as useEffect2, useState as useState4 } from "react";
2001
2127
  import { createPortal } from "react-dom";
2002
2128
  import { AlertCircle, AlertTriangle as AlertTriangle2, CheckCircle as CheckCircle2, Info as Info2, X as X2 } from "lucide-react";
2129
+ var toastCounter = 0;
2130
+ function createToastId() {
2131
+ toastCounter += 1;
2132
+ return `toast-${Date.now().toString(36)}-${toastCounter}`;
2133
+ }
2003
2134
  var ToastContext = createContext2(null);
2004
2135
  function useToast() {
2005
2136
  const context = useContext2(ToastContext);
2006
2137
  if (!context) {
2007
2138
  throw new Error("useToast must be used within a ToastProvider");
2008
2139
  }
2009
- const toast = useCallback5(
2140
+ const toast = useCallback6(
2010
2141
  (options) => {
2011
2142
  return context.addToast(options);
2012
2143
  },
@@ -2022,14 +2153,14 @@ var ToastProvider = ({
2022
2153
  position = "bottom-right",
2023
2154
  defaultDuration = 5e3
2024
2155
  }) => {
2025
- const [toasts, setToasts] = useState3([]);
2026
- const [mounted, setMounted] = useState3(false);
2027
- useEffect(() => {
2156
+ const [toasts, setToasts] = useState4([]);
2157
+ const [mounted, setMounted] = useState4(false);
2158
+ useEffect2(() => {
2028
2159
  setMounted(true);
2029
2160
  }, []);
2030
- const addToast = useCallback5(
2161
+ const addToast = useCallback6(
2031
2162
  (toast) => {
2032
- const id = Math.random().toString(36).substr(2, 9);
2163
+ const id = createToastId();
2033
2164
  const newToast = {
2034
2165
  ...toast,
2035
2166
  id,
@@ -2040,33 +2171,33 @@ var ToastProvider = ({
2040
2171
  },
2041
2172
  [defaultDuration]
2042
2173
  );
2043
- const removeToast = useCallback5((id) => {
2174
+ const removeToast = useCallback6((id) => {
2044
2175
  setToasts((prev) => prev.filter((t) => t.id !== id));
2045
2176
  }, []);
2046
2177
  return /* @__PURE__ */ React29.createElement(ToastContext.Provider, { value: { toasts, addToast, removeToast, position } }, children, mounted && /* @__PURE__ */ React29.createElement(ToastViewport, null));
2047
2178
  };
2048
2179
  ToastProvider.displayName = "ToastProvider";
2180
+ var POSITION_CLASSES = {
2181
+ "top-right": "top-4 right-4",
2182
+ "top-left": "top-4 left-4",
2183
+ "bottom-right": "bottom-4 right-4",
2184
+ "bottom-left": "bottom-4 left-4",
2185
+ "top-center": "top-4 left-1/2 -translate-x-1/2",
2186
+ "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
2187
+ };
2049
2188
  var ToastViewport = () => {
2050
2189
  const context = useContext2(ToastContext);
2051
2190
  if (!context) {
2052
2191
  return null;
2053
2192
  }
2054
2193
  const { toasts, position } = context;
2055
- const positionClasses = {
2056
- "top-right": "top-4 right-4",
2057
- "top-left": "top-4 left-4",
2058
- "bottom-right": "bottom-4 right-4",
2059
- "bottom-left": "bottom-4 left-4",
2060
- "top-center": "top-4 left-1/2 -translate-x-1/2",
2061
- "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
2062
- };
2063
2194
  return createPortal(
2064
2195
  /* @__PURE__ */ React29.createElement(
2065
2196
  "div",
2066
2197
  {
2067
2198
  className: cx(
2068
2199
  "fixed z-50 flex flex-col gap-2 pointer-events-none",
2069
- positionClasses[position]
2200
+ POSITION_CLASSES[position]
2070
2201
  )
2071
2202
  },
2072
2203
  toasts.map((toast) => /* @__PURE__ */ React29.createElement(Toast, { key: toast.id, ...toast }))
@@ -2097,7 +2228,7 @@ var Toast = ({
2097
2228
  action
2098
2229
  }) => {
2099
2230
  const context = useContext2(ToastContext);
2100
- useEffect(() => {
2231
+ useEffect2(() => {
2101
2232
  if (duration && duration > 0) {
2102
2233
  const timer = setTimeout(() => {
2103
2234
  context?.removeToast(id);
@@ -2129,41 +2260,17 @@ var Toast = ({
2129
2260
  Toast.displayName = "Toast";
2130
2261
 
2131
2262
  // src/components/Modal.tsx
2132
- import React30, { useEffect as useEffect2, useState as useState4 } from "react";
2263
+ import React30, { useEffect as useEffect3, useState as useState5 } from "react";
2133
2264
  import { createPortal as createPortal2 } from "react-dom";
2134
2265
  import { X as X3 } from "lucide-react";
2135
2266
  var Modal = ({ isOpen, onClose, title, children, className }) => {
2136
- const [mounted, setMounted] = useState4(false);
2137
- useEffect2(() => {
2267
+ const [mounted, setMounted] = useState5(false);
2268
+ useEffect3(() => {
2138
2269
  setMounted(true);
2139
2270
  }, []);
2140
- useEffect2(() => {
2141
- if (isOpen) {
2142
- const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
2143
- document.body.style.overflow = "hidden";
2144
- document.body.style.paddingRight = `${scrollbarWidth}px`;
2145
- } else {
2146
- document.body.style.overflow = "unset";
2147
- document.body.style.paddingRight = "0px";
2148
- }
2149
- return () => {
2150
- document.body.style.overflow = "unset";
2151
- document.body.style.paddingRight = "0px";
2152
- };
2153
- }, [isOpen]);
2154
- useEffect2(() => {
2155
- const handleEsc = (e) => {
2156
- if (e.key === "Escape") {
2157
- onClose();
2158
- }
2159
- };
2160
- window.addEventListener("keydown", handleEsc);
2161
- return () => window.removeEventListener("keydown", handleEsc);
2162
- }, [onClose]);
2163
- if (!mounted) {
2164
- return null;
2165
- }
2166
- if (!isOpen) {
2271
+ useScrollLock(isOpen);
2272
+ useEscapeKey(onClose, isOpen);
2273
+ if (!mounted || !isOpen) {
2167
2274
  return null;
2168
2275
  }
2169
2276
  const content = /* @__PURE__ */ React30.createElement(
@@ -2202,7 +2309,7 @@ var Modal = ({ isOpen, onClose, title, children, className }) => {
2202
2309
  Modal.displayName = "Modal";
2203
2310
 
2204
2311
  // src/components/Drawer.tsx
2205
- import React31, { useEffect as useEffect3, useState as useState5 } from "react";
2312
+ import React31, { useEffect as useEffect4, useState as useState6 } from "react";
2206
2313
  import { createPortal as createPortal3 } from "react-dom";
2207
2314
  import { X as X4 } from "lucide-react";
2208
2315
  var SIZE_MAP2 = {
@@ -2237,7 +2344,7 @@ var SIZE_MAP2 = {
2237
2344
  bottom: "h-full"
2238
2345
  }
2239
2346
  };
2240
- var POSITION_CLASSES = {
2347
+ var POSITION_CLASSES2 = {
2241
2348
  left: "left-0 top-0 h-full",
2242
2349
  right: "right-0 top-0 h-full",
2243
2350
  top: "top-0 left-0 w-full",
@@ -2258,33 +2365,12 @@ var Drawer = ({
2258
2365
  children,
2259
2366
  className
2260
2367
  }) => {
2261
- const [mounted, setMounted] = useState5(false);
2262
- useEffect3(() => {
2368
+ const [mounted, setMounted] = useState6(false);
2369
+ useEffect4(() => {
2263
2370
  setMounted(true);
2264
2371
  }, []);
2265
- useEffect3(() => {
2266
- if (isOpen) {
2267
- const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
2268
- document.body.style.overflow = "hidden";
2269
- document.body.style.paddingRight = `${scrollbarWidth}px`;
2270
- } else {
2271
- document.body.style.overflow = "unset";
2272
- document.body.style.paddingRight = "0px";
2273
- }
2274
- return () => {
2275
- document.body.style.overflow = "unset";
2276
- document.body.style.paddingRight = "0px";
2277
- };
2278
- }, [isOpen]);
2279
- useEffect3(() => {
2280
- const handleEsc = (e) => {
2281
- if (e.key === "Escape") {
2282
- onClose();
2283
- }
2284
- };
2285
- window.addEventListener("keydown", handleEsc);
2286
- return () => window.removeEventListener("keydown", handleEsc);
2287
- }, [onClose]);
2372
+ useScrollLock(isOpen);
2373
+ useEscapeKey(onClose, isOpen);
2288
2374
  if (!mounted) {
2289
2375
  return null;
2290
2376
  }
@@ -2315,7 +2401,7 @@ var Drawer = ({
2315
2401
  className: cx(
2316
2402
  "fixed bg-charcoal border-ash shadow-2xl flex flex-col",
2317
2403
  "transition-transform duration-300 ease-out",
2318
- POSITION_CLASSES[position],
2404
+ POSITION_CLASSES2[position],
2319
2405
  SIZE_MAP2[size][position],
2320
2406
  position === "left" && "border-r",
2321
2407
  position === "right" && "border-l",
@@ -2342,8 +2428,8 @@ var Drawer = ({
2342
2428
  Drawer.displayName = "Drawer";
2343
2429
 
2344
2430
  // src/components/Popover.tsx
2345
- import React32, { useCallback as useCallback6, useEffect as useEffect4, useId, useRef as useRef3, useState as useState6 } from "react";
2346
- var POSITION_CLASSES2 = {
2431
+ import React32, { useCallback as useCallback7, useId as useId3, useRef as useRef4, useState as useState7 } from "react";
2432
+ var POSITION_CLASSES3 = {
2347
2433
  top: {
2348
2434
  start: "bottom-full left-0 mb-2",
2349
2435
  center: "bottom-full left-1/2 -translate-x-1/2 mb-2",
@@ -2374,12 +2460,12 @@ var Popover = ({
2374
2460
  onOpenChange,
2375
2461
  closeOnClickOutside = true
2376
2462
  }) => {
2377
- const [internalOpen, setInternalOpen] = useState6(false);
2463
+ const [internalOpen, setInternalOpen] = useState7(false);
2378
2464
  const isControlled = controlledOpen !== void 0;
2379
2465
  const isOpen = isControlled ? controlledOpen : internalOpen;
2380
- const containerRef = useRef3(null);
2381
- const baseId = useId();
2382
- const setIsOpen = useCallback6(
2466
+ const containerRef = useRef4(null);
2467
+ const baseId = useId3();
2468
+ const setIsOpen = useCallback7(
2383
2469
  (newOpen) => {
2384
2470
  if (!isControlled) {
2385
2471
  setInternalOpen(newOpen);
@@ -2388,30 +2474,9 @@ var Popover = ({
2388
2474
  },
2389
2475
  [isControlled, onOpenChange]
2390
2476
  );
2391
- useEffect4(() => {
2392
- if (!isOpen || !closeOnClickOutside) {
2393
- return;
2394
- }
2395
- const handleClickOutside = (e) => {
2396
- if (containerRef.current && !containerRef.current.contains(e.target)) {
2397
- setIsOpen(false);
2398
- }
2399
- };
2400
- document.addEventListener("mousedown", handleClickOutside);
2401
- return () => document.removeEventListener("mousedown", handleClickOutside);
2402
- }, [isOpen, closeOnClickOutside, setIsOpen]);
2403
- useEffect4(() => {
2404
- if (!isOpen) {
2405
- return;
2406
- }
2407
- const handleEscape = (e) => {
2408
- if (e.key === "Escape") {
2409
- setIsOpen(false);
2410
- }
2411
- };
2412
- document.addEventListener("keydown", handleEscape);
2413
- return () => document.removeEventListener("keydown", handleEscape);
2414
- }, [isOpen, setIsOpen]);
2477
+ const close = useCallback7(() => setIsOpen(false), [setIsOpen]);
2478
+ useClickOutside(containerRef, close, isOpen && closeOnClickOutside);
2479
+ useEscapeKey(close, isOpen);
2415
2480
  const handleTriggerClick = () => {
2416
2481
  setIsOpen(!isOpen);
2417
2482
  };
@@ -2432,7 +2497,7 @@ var Popover = ({
2432
2497
  "absolute z-50 min-w-48 p-4",
2433
2498
  "bg-charcoal border border-ash shadow-lg",
2434
2499
  "animate-fade-in",
2435
- POSITION_CLASSES2[position][align]
2500
+ POSITION_CLASSES3[position][align]
2436
2501
  )
2437
2502
  },
2438
2503
  children
@@ -2441,7 +2506,7 @@ var Popover = ({
2441
2506
  Popover.displayName = "Popover";
2442
2507
 
2443
2508
  // src/components/Dialog.tsx
2444
- import React33, { useCallback as useCallback7 } from "react";
2509
+ import React33, { useCallback as useCallback8 } from "react";
2445
2510
  var ConfirmDialog = ({
2446
2511
  title = "Confirm",
2447
2512
  description,
@@ -2454,11 +2519,11 @@ var ConfirmDialog = ({
2454
2519
  isLoading = false,
2455
2520
  ...props
2456
2521
  }) => {
2457
- const handleCancel = useCallback7(() => {
2522
+ const handleCancel = useCallback8(() => {
2458
2523
  onCancel?.();
2459
2524
  onClose();
2460
2525
  }, [onCancel, onClose]);
2461
- const handleConfirm = useCallback7(async () => {
2526
+ const handleConfirm = useCallback8(async () => {
2462
2527
  await onConfirm();
2463
2528
  onClose();
2464
2529
  }, [onConfirm, onClose]);
@@ -2502,11 +2567,11 @@ var PromptDialog = ({
2502
2567
  ...props
2503
2568
  }) => {
2504
2569
  const [value, setValue] = React33.useState(defaultValue);
2505
- const handleCancel = useCallback7(() => {
2570
+ const handleCancel = useCallback8(() => {
2506
2571
  onCancel?.();
2507
2572
  onClose();
2508
2573
  }, [onCancel, onClose]);
2509
- const handleSubmit = useCallback7(
2574
+ const handleSubmit = useCallback8(
2510
2575
  async (e) => {
2511
2576
  e.preventDefault();
2512
2577
  await onSubmit(value);
@@ -2543,7 +2608,7 @@ var PromptDialog = ({
2543
2608
  PromptDialog.displayName = "PromptDialog";
2544
2609
 
2545
2610
  // src/components/Tabs.tsx
2546
- import React34, { createContext as createContext3, useCallback as useCallback8, useContext as useContext3, useId as useId2, useState as useState7 } from "react";
2611
+ import React34, { createContext as createContext3, useCallback as useCallback9, useContext as useContext3, useId as useId4, useState as useState8 } from "react";
2547
2612
  var TabsContext = createContext3(null);
2548
2613
  function useTabsContext() {
2549
2614
  const context = useContext3(TabsContext);
@@ -2554,11 +2619,11 @@ function useTabsContext() {
2554
2619
  }
2555
2620
  var Tabs = React34.forwardRef(
2556
2621
  ({ defaultValue, value, onValueChange, children, className, ...props }, ref) => {
2557
- const [internalValue, setInternalValue] = useState7(defaultValue ?? "");
2622
+ const [internalValue, setInternalValue] = useState8(defaultValue ?? "");
2558
2623
  const isControlled = value !== void 0;
2559
2624
  const activeTab = isControlled ? value : internalValue;
2560
- const baseId = useId2();
2561
- const setActiveTab = useCallback8(
2625
+ const baseId = useId4();
2626
+ const setActiveTab = useCallback9(
2562
2627
  (id) => {
2563
2628
  if (!isControlled) {
2564
2629
  setInternalValue(id);
@@ -2654,7 +2719,7 @@ var TabPanel = React34.forwardRef(
2654
2719
  TabPanel.displayName = "TabPanel";
2655
2720
 
2656
2721
  // src/components/Accordion.tsx
2657
- import React35, { createContext as createContext4, useCallback as useCallback9, useContext as useContext4, useId as useId3, useState as useState8 } from "react";
2722
+ import React35, { createContext as createContext4, useCallback as useCallback10, useContext as useContext4, useId as useId5, useState as useState9 } from "react";
2658
2723
  import { ChevronDown } from "lucide-react";
2659
2724
  var AccordionContext = createContext4(null);
2660
2725
  function useAccordionContext() {
@@ -2666,7 +2731,7 @@ function useAccordionContext() {
2666
2731
  }
2667
2732
  var Accordion = React35.forwardRef(
2668
2733
  ({ type = "single", defaultValue, value, onValueChange, children, className, ...props }, ref) => {
2669
- const [internalValue, setInternalValue] = useState8(() => {
2734
+ const [internalValue, setInternalValue] = useState9(() => {
2670
2735
  if (defaultValue) {
2671
2736
  return new Set(Array.isArray(defaultValue) ? defaultValue : [defaultValue]);
2672
2737
  }
@@ -2674,7 +2739,7 @@ var Accordion = React35.forwardRef(
2674
2739
  });
2675
2740
  const isControlled = value !== void 0;
2676
2741
  const expandedItems = isControlled ? new Set(Array.isArray(value) ? value : [value]) : internalValue;
2677
- const toggleItem = useCallback9(
2742
+ const toggleItem = useCallback10(
2678
2743
  (id) => {
2679
2744
  const newSet = new Set(expandedItems);
2680
2745
  if (newSet.has(id)) {
@@ -2725,7 +2790,7 @@ var AccordionTrigger = React35.forwardRef(
2725
2790
  ({ children, className, ...props }, ref) => {
2726
2791
  const { expandedItems, toggleItem } = useAccordionContext();
2727
2792
  const itemContext = useContext4(AccordionItemContext);
2728
- const baseId = useId3();
2793
+ const baseId = useId5();
2729
2794
  if (!itemContext) {
2730
2795
  throw new Error("AccordionTrigger must be used within an AccordionItem");
2731
2796
  }
@@ -2770,7 +2835,7 @@ var AccordionContent = React35.forwardRef(
2770
2835
  ({ children, className, ...props }, ref) => {
2771
2836
  const { expandedItems } = useAccordionContext();
2772
2837
  const itemContext = useContext4(AccordionItemContext);
2773
- const baseId = useId3();
2838
+ const baseId = useId5();
2774
2839
  if (!itemContext) {
2775
2840
  throw new Error("AccordionContent must be used within an AccordionItem");
2776
2841
  }
@@ -2800,12 +2865,12 @@ AccordionContent.displayName = "AccordionContent";
2800
2865
  // src/components/Menu.tsx
2801
2866
  import React36, {
2802
2867
  createContext as createContext5,
2803
- useCallback as useCallback10,
2868
+ useCallback as useCallback11,
2804
2869
  useContext as useContext5,
2805
2870
  useEffect as useEffect5,
2806
- useId as useId4,
2807
- useRef as useRef4,
2808
- useState as useState9
2871
+ useId as useId6,
2872
+ useRef as useRef5,
2873
+ useState as useState10
2809
2874
  } from "react";
2810
2875
  var MenuContext = createContext5(null);
2811
2876
  function useMenuContext() {
@@ -2816,11 +2881,11 @@ function useMenuContext() {
2816
2881
  return context;
2817
2882
  }
2818
2883
  var Menu = ({ children, open, onOpenChange }) => {
2819
- const [internalOpen, setInternalOpen] = useState9(false);
2884
+ const [internalOpen, setInternalOpen] = useState10(false);
2820
2885
  const isControlled = open !== void 0;
2821
2886
  const isOpen = isControlled ? open : internalOpen;
2822
- const baseId = useId4();
2823
- const setIsOpen = useCallback10(
2887
+ const baseId = useId6();
2888
+ const setIsOpen = useCallback11(
2824
2889
  (newOpen) => {
2825
2890
  if (!isControlled) {
2826
2891
  setInternalOpen(newOpen);
@@ -2872,55 +2937,42 @@ var MenuTrigger = React36.forwardRef(
2872
2937
  }
2873
2938
  );
2874
2939
  MenuTrigger.displayName = "MenuTrigger";
2940
+ var MENU_ALIGN_CLASSES = {
2941
+ start: "left-0",
2942
+ center: "left-1/2 -translate-x-1/2",
2943
+ end: "right-0"
2944
+ };
2945
+ var MENU_SIDE_CLASSES = {
2946
+ top: "bottom-full mb-1",
2947
+ bottom: "top-full mt-1"
2948
+ };
2875
2949
  var MenuContent = React36.forwardRef(
2876
2950
  ({ children, className, align = "start", side = "bottom", ...props }, ref) => {
2877
2951
  const { isOpen, setIsOpen, triggerId, menuId } = useMenuContext();
2878
- const menuRef = useRef4(null);
2952
+ const menuRef = useRef5(null);
2953
+ const close = useCallback11(() => setIsOpen(false), [setIsOpen]);
2954
+ useEscapeKey(close, isOpen);
2879
2955
  useEffect5(() => {
2880
2956
  if (!isOpen) {
2881
2957
  return;
2882
2958
  }
2883
2959
  const handleClickOutside = (e) => {
2960
+ const target = e.target;
2884
2961
  const trigger = document.getElementById(triggerId);
2885
- if (menuRef.current && !menuRef.current.contains(e.target) && trigger && !trigger.contains(e.target)) {
2886
- setIsOpen(false);
2887
- }
2888
- };
2889
- const handleEscape = (e) => {
2890
- if (e.key === "Escape") {
2962
+ if (menuRef.current && !menuRef.current.contains(target) && !trigger?.contains(target)) {
2891
2963
  setIsOpen(false);
2892
2964
  }
2893
2965
  };
2894
2966
  document.addEventListener("mousedown", handleClickOutside);
2895
- document.addEventListener("keydown", handleEscape);
2896
- return () => {
2897
- document.removeEventListener("mousedown", handleClickOutside);
2898
- document.removeEventListener("keydown", handleEscape);
2899
- };
2967
+ return () => document.removeEventListener("mousedown", handleClickOutside);
2900
2968
  }, [isOpen, setIsOpen, triggerId]);
2901
2969
  if (!isOpen) {
2902
2970
  return null;
2903
2971
  }
2904
- const alignmentClasses = {
2905
- start: "left-0",
2906
- center: "left-1/2 -translate-x-1/2",
2907
- end: "right-0"
2908
- };
2909
- const sideClasses = {
2910
- top: "bottom-full mb-1",
2911
- bottom: "top-full mt-1"
2912
- };
2913
2972
  return /* @__PURE__ */ React36.createElement(
2914
2973
  "div",
2915
2974
  {
2916
- ref: (node) => {
2917
- menuRef.current = node;
2918
- if (typeof ref === "function") {
2919
- ref(node);
2920
- } else if (ref) {
2921
- ref.current = node;
2922
- }
2923
- },
2975
+ ref: composeRefs(menuRef, ref),
2924
2976
  id: menuId,
2925
2977
  role: "menu",
2926
2978
  "aria-labelledby": triggerId,
@@ -2928,8 +2980,8 @@ var MenuContent = React36.forwardRef(
2928
2980
  "absolute z-50 min-w-40 py-1",
2929
2981
  "bg-charcoal border border-ash shadow-lg",
2930
2982
  "animate-fade-in",
2931
- alignmentClasses[align],
2932
- sideClasses[side],
2983
+ MENU_ALIGN_CLASSES[align],
2984
+ MENU_SIDE_CLASSES[side],
2933
2985
  className
2934
2986
  ),
2935
2987
  ...props
@@ -3653,12 +3705,19 @@ function SquareLoaderIcon({ className, ...props }) {
3653
3705
  }
3654
3706
 
3655
3707
  // src/components/Message.tsx
3656
- import React55, { useEffect as useEffect6, useRef as useRef5, useState as useState10 } from "react";
3708
+ import React55, { useCallback as useCallback12, useEffect as useEffect6, useRef as useRef6, useState as useState11 } from "react";
3709
+ import { Check as Check3, ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight3, Copy, GitBranch, Pencil, RotateCcw, Send, X as X5 } from "lucide-react";
3657
3710
 
3658
3711
  // src/components/MarkdownContent.tsx
3659
3712
  import React54, { useMemo } from "react";
3660
3713
  import DOMPurify from "dompurify";
3661
3714
  import { marked } from "marked";
3715
+ DOMPurify.addHook("afterSanitizeAttributes", (node) => {
3716
+ if (node.tagName === "A") {
3717
+ node.setAttribute("target", "_blank");
3718
+ node.setAttribute("rel", "noopener noreferrer");
3719
+ }
3720
+ });
3662
3721
  var DEFAULT_SANITIZE_CONFIG = {
3663
3722
  ALLOWED_TAGS: [
3664
3723
  "h1",
@@ -3726,16 +3785,6 @@ var DEFAULT_SANITIZE_CONFIG = {
3726
3785
  ADD_ATTR: ["target", "rel"],
3727
3786
  ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto|tel):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i
3728
3787
  };
3729
- function useDOMPurifySetup() {
3730
- useMemo(() => {
3731
- DOMPurify.addHook("afterSanitizeAttributes", (node) => {
3732
- if (node.tagName === "A") {
3733
- node.setAttribute("target", "_blank");
3734
- node.setAttribute("rel", "noopener noreferrer");
3735
- }
3736
- });
3737
- }, []);
3738
- }
3739
3788
  var CURSOR_BASE_CLASSES = "inline-block bg-current animate-cursor-blink w-0.5 h-cursor translate-y-cursor-offset";
3740
3789
  function injectStreamingCursor(html, cursorClassName) {
3741
3790
  if (!html.trim()) {
@@ -3765,7 +3814,6 @@ function injectStreamingCursor(html, cursorClassName) {
3765
3814
  }
3766
3815
  var MarkdownContent = React54.forwardRef(
3767
3816
  ({ className, content, isMarkdown = true, sanitizeConfig, isStreaming, cursorClassName, ...rest }, ref) => {
3768
- useDOMPurifySetup();
3769
3817
  const sanitizedHtml = useMemo(() => {
3770
3818
  if (!content && !isStreaming) {
3771
3819
  return "";
@@ -3787,7 +3835,7 @@ var MarkdownContent = React54.forwardRef(
3787
3835
  return injectStreamingCursor(sanitized, cursorClassName);
3788
3836
  }
3789
3837
  return sanitized;
3790
- }, [content, sanitizeConfig, isStreaming, cursorClassName]);
3838
+ }, [content, isMarkdown, sanitizeConfig, isStreaming, cursorClassName]);
3791
3839
  return /* @__PURE__ */ React54.createElement(
3792
3840
  "div",
3793
3841
  {
@@ -3802,162 +3850,32 @@ var MarkdownContent = React54.forwardRef(
3802
3850
  MarkdownContent.displayName = "MarkdownContent";
3803
3851
 
3804
3852
  // src/components/Message.tsx
3805
- var variantStyles2 = {
3853
+ var VARIANT_STYLES3 = {
3806
3854
  user: "bg-gold text-obsidian ml-auto",
3807
3855
  assistant: "bg-charcoal border border-ash text-white mr-auto"
3808
3856
  };
3809
- var ActionButton = ({ onClick, label, children, className, disabled }) => /* @__PURE__ */ React55.createElement(
3810
- "button",
3811
- {
3812
- type: "button",
3813
- onClick,
3814
- disabled,
3815
- className: cx(
3816
- "p-1.5 text-silver/60 hover:text-silver transition-colors duration-150",
3817
- "hover:bg-white/5",
3818
- "disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-transparent",
3819
- className
3820
- ),
3821
- "aria-label": label
3822
- },
3823
- children
3824
- );
3825
- var CopyIcon = () => /* @__PURE__ */ React55.createElement(
3826
- "svg",
3827
- {
3828
- xmlns: "http://www.w3.org/2000/svg",
3829
- viewBox: "0 0 24 24",
3830
- fill: "none",
3831
- stroke: "currentColor",
3832
- strokeWidth: "2",
3833
- strokeLinecap: "round",
3834
- strokeLinejoin: "round",
3835
- className: "w-3.5 h-3.5"
3836
- },
3837
- /* @__PURE__ */ React55.createElement("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
3838
- /* @__PURE__ */ React55.createElement("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
3839
- );
3840
- var CheckIcon = () => /* @__PURE__ */ React55.createElement(
3841
- "svg",
3842
- {
3843
- xmlns: "http://www.w3.org/2000/svg",
3844
- viewBox: "0 0 24 24",
3845
- fill: "none",
3846
- stroke: "currentColor",
3847
- strokeWidth: "2",
3848
- strokeLinecap: "round",
3849
- strokeLinejoin: "round",
3850
- className: "w-3.5 h-3.5 text-success"
3851
- },
3852
- /* @__PURE__ */ React55.createElement("polyline", { points: "20 6 9 17 4 12" })
3853
- );
3854
- var PencilIcon = () => /* @__PURE__ */ React55.createElement(
3855
- "svg",
3856
- {
3857
- xmlns: "http://www.w3.org/2000/svg",
3858
- viewBox: "0 0 24 24",
3859
- fill: "none",
3860
- stroke: "currentColor",
3861
- strokeWidth: "2",
3862
- strokeLinecap: "round",
3863
- strokeLinejoin: "round",
3864
- className: "w-3.5 h-3.5"
3865
- },
3866
- /* @__PURE__ */ React55.createElement("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }),
3867
- /* @__PURE__ */ React55.createElement("path", { d: "m15 5 4 4" })
3868
- );
3869
- var RetryIcon = () => /* @__PURE__ */ React55.createElement(
3870
- "svg",
3871
- {
3872
- xmlns: "http://www.w3.org/2000/svg",
3873
- viewBox: "0 0 24 24",
3874
- fill: "none",
3875
- stroke: "currentColor",
3876
- strokeWidth: "2",
3877
- strokeLinecap: "round",
3878
- strokeLinejoin: "round",
3879
- className: "w-3.5 h-3.5"
3880
- },
3881
- /* @__PURE__ */ React55.createElement("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
3882
- /* @__PURE__ */ React55.createElement("path", { d: "M21 3v5h-5" }),
3883
- /* @__PURE__ */ React55.createElement("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
3884
- /* @__PURE__ */ React55.createElement("path", { d: "M8 16H3v5" })
3885
- );
3886
- var ChevronLeftIcon2 = () => /* @__PURE__ */ React55.createElement(
3887
- "svg",
3888
- {
3889
- xmlns: "http://www.w3.org/2000/svg",
3890
- viewBox: "0 0 24 24",
3891
- fill: "none",
3892
- stroke: "currentColor",
3893
- strokeWidth: "2",
3894
- strokeLinecap: "round",
3895
- strokeLinejoin: "round",
3896
- className: "w-3 h-3"
3897
- },
3898
- /* @__PURE__ */ React55.createElement("path", { d: "m15 18-6-6 6-6" })
3899
- );
3900
- var ChevronRightIcon2 = () => /* @__PURE__ */ React55.createElement(
3901
- "svg",
3902
- {
3903
- xmlns: "http://www.w3.org/2000/svg",
3904
- viewBox: "0 0 24 24",
3905
- fill: "none",
3906
- stroke: "currentColor",
3907
- strokeWidth: "2",
3908
- strokeLinecap: "round",
3909
- strokeLinejoin: "round",
3910
- className: "w-3 h-3"
3911
- },
3912
- /* @__PURE__ */ React55.createElement("path", { d: "m9 18 6-6-6-6" })
3857
+ var ACTION_BUTTON_CLASSES = cx(
3858
+ "p-1.5 text-silver/60 hover:text-silver transition-colors duration-150",
3859
+ "hover:bg-white/5",
3860
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-transparent"
3913
3861
  );
3914
- var GitBranchIcon = () => /* @__PURE__ */ React55.createElement(
3915
- "svg",
3916
- {
3917
- xmlns: "http://www.w3.org/2000/svg",
3918
- viewBox: "0 0 24 24",
3919
- fill: "none",
3920
- stroke: "currentColor",
3921
- strokeWidth: "2",
3922
- strokeLinecap: "round",
3923
- strokeLinejoin: "round",
3924
- className: "w-3 h-3 mr-0.5 text-silver/50"
3925
- },
3926
- /* @__PURE__ */ React55.createElement("line", { x1: "6", x2: "6", y1: "3", y2: "15" }),
3927
- /* @__PURE__ */ React55.createElement("circle", { cx: "18", cy: "6", r: "3" }),
3928
- /* @__PURE__ */ React55.createElement("circle", { cx: "6", cy: "18", r: "3" }),
3929
- /* @__PURE__ */ React55.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })
3930
- );
3931
- var XIcon = () => /* @__PURE__ */ React55.createElement(
3932
- "svg",
3933
- {
3934
- xmlns: "http://www.w3.org/2000/svg",
3935
- viewBox: "0 0 24 24",
3936
- fill: "none",
3937
- stroke: "currentColor",
3938
- strokeWidth: "2",
3939
- strokeLinecap: "round",
3940
- strokeLinejoin: "round",
3941
- className: "w-4 h-4"
3942
- },
3943
- /* @__PURE__ */ React55.createElement("path", { d: "M18 6 6 18" }),
3944
- /* @__PURE__ */ React55.createElement("path", { d: "m6 6 12 12" })
3945
- );
3946
- var SendIcon = () => /* @__PURE__ */ React55.createElement(
3947
- "svg",
3948
- {
3949
- xmlns: "http://www.w3.org/2000/svg",
3950
- viewBox: "0 0 24 24",
3951
- fill: "none",
3952
- stroke: "currentColor",
3953
- strokeWidth: "2",
3954
- strokeLinecap: "round",
3955
- strokeLinejoin: "round",
3956
- className: "w-4 h-4"
3957
- },
3958
- /* @__PURE__ */ React55.createElement("path", { d: "m22 2-7 20-4-9-9-4Z" }),
3959
- /* @__PURE__ */ React55.createElement("path", { d: "M22 2 11 13" })
3862
+ var BRANCH_BUTTON_CLASSES = cx(
3863
+ "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
3864
+ "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
3960
3865
  );
3866
+ function ActionButton({ onClick, label, children, disabled }) {
3867
+ return /* @__PURE__ */ React55.createElement(
3868
+ "button",
3869
+ {
3870
+ type: "button",
3871
+ onClick,
3872
+ disabled,
3873
+ className: ACTION_BUTTON_CLASSES,
3874
+ "aria-label": label
3875
+ },
3876
+ children
3877
+ );
3878
+ }
3961
3879
  var Message = React55.forwardRef(
3962
3880
  ({
3963
3881
  variant = "assistant",
@@ -3970,10 +3888,10 @@ var Message = React55.forwardRef(
3970
3888
  ...rest
3971
3889
  }, ref) => {
3972
3890
  const isUser = variant === "user";
3973
- const [copied, setCopied] = useState10(false);
3974
- const [isEditing, setIsEditing] = useState10(false);
3975
- const [editValue, setEditValue] = useState10(typeof content === "string" ? content : "");
3976
- const textareaRef = useRef5(null);
3891
+ const { copied, copy } = useCopyToClipboard();
3892
+ const [isEditing, setIsEditing] = useState11(false);
3893
+ const [editValue, setEditValue] = useState11(typeof content === "string" ? content : "");
3894
+ const textareaRef = useRef6(null);
3977
3895
  const showBranchNav = branchInfo && branchInfo.total > 1;
3978
3896
  const showActions = actions && !hideActions && !isStreaming;
3979
3897
  useEffect6(() => {
@@ -3985,25 +3903,11 @@ var Message = React55.forwardRef(
3985
3903
  textarea.setSelectionRange(textarea.value.length, textarea.value.length);
3986
3904
  }
3987
3905
  }, [isEditing]);
3988
- const handleCopy = async () => {
3989
- if (typeof content !== "string") {
3990
- return;
3991
- }
3992
- try {
3993
- await navigator.clipboard.writeText(content);
3994
- setCopied(true);
3995
- setTimeout(() => setCopied(false), 2e3);
3996
- } catch {
3997
- const textArea = document.createElement("textarea");
3998
- textArea.value = content;
3999
- document.body.appendChild(textArea);
4000
- textArea.select();
4001
- document.execCommand("copy");
4002
- document.body.removeChild(textArea);
4003
- setCopied(true);
4004
- setTimeout(() => setCopied(false), 2e3);
3906
+ const handleCopy = useCallback12(() => {
3907
+ if (typeof content === "string") {
3908
+ void copy(content);
4005
3909
  }
4006
- };
3910
+ }, [copy, content]);
4007
3911
  const handleStartEdit = () => {
4008
3912
  if (typeof content === "string") {
4009
3913
  setEditValue(content);
@@ -4066,7 +3970,7 @@ var Message = React55.forwardRef(
4066
3970
  className: "p-1.5 text-obsidian/60 hover:text-obsidian transition-colors",
4067
3971
  "aria-label": "Cancel edit"
4068
3972
  },
4069
- /* @__PURE__ */ React55.createElement(XIcon, null)
3973
+ /* @__PURE__ */ React55.createElement(X5, { className: "w-4 h-4" })
4070
3974
  ), /* @__PURE__ */ React55.createElement(
4071
3975
  "button",
4072
3976
  {
@@ -4076,13 +3980,13 @@ var Message = React55.forwardRef(
4076
3980
  className: "p-1.5 text-obsidian/60 hover:text-obsidian transition-colors disabled:opacity-30",
4077
3981
  "aria-label": "Submit edit"
4078
3982
  },
4079
- /* @__PURE__ */ React55.createElement(SendIcon, null)
3983
+ /* @__PURE__ */ React55.createElement(Send, { className: "w-4 h-4" })
4080
3984
  )))) : /* @__PURE__ */ React55.createElement(
4081
3985
  "div",
4082
3986
  {
4083
3987
  className: cx(
4084
3988
  "px-3 py-2 w-fit max-w-11/12",
4085
- variantStyles2[variant]
3989
+ VARIANT_STYLES3[variant]
4086
3990
  )
4087
3991
  },
4088
3992
  typeof content === "string" ? /* @__PURE__ */ React55.createElement(
@@ -4104,33 +4008,27 @@ var Message = React55.forwardRef(
4104
4008
  onClick: handleCopy,
4105
4009
  label: copied ? "Copied!" : "Copy message"
4106
4010
  },
4107
- copied ? /* @__PURE__ */ React55.createElement(CheckIcon, null) : /* @__PURE__ */ React55.createElement(CopyIcon, null)
4108
- ), isUser && actions.onEdit && typeof content === "string" && /* @__PURE__ */ React55.createElement(ActionButton, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React55.createElement(PencilIcon, null)), !isUser && actions.onRetry && /* @__PURE__ */ React55.createElement(ActionButton, { onClick: actions.onRetry, label: "Regenerate response" }, /* @__PURE__ */ React55.createElement(RetryIcon, null)), showBranchNav && /* @__PURE__ */ React55.createElement(React55.Fragment, null, /* @__PURE__ */ React55.createElement("div", { className: "w-px h-4 bg-ash/40 mx-1" }), /* @__PURE__ */ React55.createElement("div", { className: "flex items-center gap-0.5 text-silver/70" }, /* @__PURE__ */ React55.createElement(GitBranchIcon, null), /* @__PURE__ */ React55.createElement(
4011
+ copied ? /* @__PURE__ */ React55.createElement(Check3, { className: "w-3.5 h-3.5 text-success" }) : /* @__PURE__ */ React55.createElement(Copy, { className: "w-3.5 h-3.5" })
4012
+ ), isUser && actions.onEdit && typeof content === "string" && /* @__PURE__ */ React55.createElement(ActionButton, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React55.createElement(Pencil, { className: "w-3.5 h-3.5" })), !isUser && actions.onRetry && /* @__PURE__ */ React55.createElement(ActionButton, { onClick: actions.onRetry, label: "Regenerate response" }, /* @__PURE__ */ React55.createElement(RotateCcw, { className: "w-3.5 h-3.5" })), showBranchNav && /* @__PURE__ */ React55.createElement(React55.Fragment, null, /* @__PURE__ */ React55.createElement("div", { className: "w-px h-4 bg-ash/40 mx-1" }), /* @__PURE__ */ React55.createElement("div", { className: "flex items-center gap-0.5 text-silver/70" }, /* @__PURE__ */ React55.createElement(GitBranch, { className: "w-3 h-3 mr-0.5 text-silver/50" }), /* @__PURE__ */ React55.createElement(
4109
4013
  "button",
4110
4014
  {
4111
4015
  type: "button",
4112
4016
  onClick: branchInfo.onPrevious,
4113
4017
  disabled: branchInfo.current <= 1,
4114
- className: cx(
4115
- "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
4116
- "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
4117
- ),
4018
+ className: BRANCH_BUTTON_CLASSES,
4118
4019
  "aria-label": "Previous branch"
4119
4020
  },
4120
- /* @__PURE__ */ React55.createElement(ChevronLeftIcon2, null)
4021
+ /* @__PURE__ */ React55.createElement(ChevronLeft2, { className: "w-3 h-3" })
4121
4022
  ), /* @__PURE__ */ React55.createElement("span", { className: "text-xs tabular-nums min-w-6 text-center" }, branchInfo.current, "/", branchInfo.total), /* @__PURE__ */ React55.createElement(
4122
4023
  "button",
4123
4024
  {
4124
4025
  type: "button",
4125
4026
  onClick: branchInfo.onNext,
4126
4027
  disabled: branchInfo.current >= branchInfo.total,
4127
- className: cx(
4128
- "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
4129
- "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
4130
- ),
4028
+ className: BRANCH_BUTTON_CLASSES,
4131
4029
  "aria-label": "Next branch"
4132
4030
  },
4133
- /* @__PURE__ */ React55.createElement(ChevronRightIcon2, null)
4031
+ /* @__PURE__ */ React55.createElement(ChevronRight3, { className: "w-3 h-3" })
4134
4032
  ))))
4135
4033
  );
4136
4034
  }
@@ -4141,7 +4039,7 @@ Message.displayName = "Message";
4141
4039
  import React56 from "react";
4142
4040
  var StreamingCursor = React56.forwardRef(
4143
4041
  ({ className, variant = "line", ...rest }, ref) => {
4144
- const variantStyles3 = {
4042
+ const variantStyles2 = {
4145
4043
  block: "w-2.5 h-cursor translate-y-cursor-offset",
4146
4044
  line: "w-0.5 h-cursor translate-y-cursor-offset",
4147
4045
  underscore: "w-2.5 h-0.5 self-end mb-0.5"
@@ -4152,7 +4050,7 @@ var StreamingCursor = React56.forwardRef(
4152
4050
  ref,
4153
4051
  className: cx(
4154
4052
  "inline-block bg-current animate-cursor-blink",
4155
- variantStyles3[variant],
4053
+ variantStyles2[variant],
4156
4054
  className
4157
4055
  ),
4158
4056
  "aria-hidden": "true",
@@ -4164,18 +4062,18 @@ var StreamingCursor = React56.forwardRef(
4164
4062
  StreamingCursor.displayName = "StreamingCursor";
4165
4063
 
4166
4064
  // src/components/chat/ChatInterface.tsx
4167
- import React74, { useCallback as useCallback20, useEffect as useEffect16, useMemo as useMemo5, useRef as useRef14, useState as useState21 } from "react";
4065
+ import React76, { useCallback as useCallback22, useEffect as useEffect16, useMemo as useMemo5, useRef as useRef15, useState as useState22 } from "react";
4168
4066
 
4169
4067
  // src/components/chat/ChatView.tsx
4170
- import React58, { useEffect as useEffect9 } from "react";
4068
+ import React60, { useEffect as useEffect9 } from "react";
4171
4069
 
4172
4070
  // src/components/chat/hooks/useScrollAnchor.ts
4173
- import { useCallback as useCallback11, useRef as useRef6 } from "react";
4071
+ import { useCallback as useCallback13, useRef as useRef7 } from "react";
4174
4072
  function useScrollAnchor(options = {}) {
4175
4073
  const { behavior = "smooth", block = "start" } = options;
4176
- const containerRef = useRef6(null);
4177
- const anchorRef = useRef6(null);
4178
- const scrollToAnchor = useCallback11(() => {
4074
+ const containerRef = useRef7(null);
4075
+ const anchorRef = useRef7(null);
4076
+ const scrollToAnchor = useCallback13(() => {
4179
4077
  const el = anchorRef.current;
4180
4078
  if (!el) {
4181
4079
  return;
@@ -4186,7 +4084,7 @@ function useScrollAnchor(options = {}) {
4186
4084
  });
4187
4085
  });
4188
4086
  }, [behavior, block]);
4189
- const scrollToBottom = useCallback11(() => {
4087
+ const scrollToBottom = useCallback13(() => {
4190
4088
  const container = containerRef.current;
4191
4089
  if (!container) {
4192
4090
  return;
@@ -4197,7 +4095,7 @@ function useScrollAnchor(options = {}) {
4197
4095
  container.scrollTop = container.scrollHeight;
4198
4096
  }
4199
4097
  }, [behavior]);
4200
- const isScrolledToBottom = useCallback11(() => {
4098
+ const isScrolledToBottom = useCallback13(() => {
4201
4099
  const container = containerRef.current;
4202
4100
  if (!container) {
4203
4101
  return true;
@@ -4216,15 +4114,15 @@ function useScrollAnchor(options = {}) {
4216
4114
  }
4217
4115
 
4218
4116
  // src/components/chat/hooks/useAdaptiveSpacer.ts
4219
- import { useCallback as useCallback12, useEffect as useEffect7, useRef as useRef7, useState as useState11 } from "react";
4117
+ import { useCallback as useCallback14, useEffect as useEffect7, useRef as useRef8, useState as useState12 } from "react";
4220
4118
  function useAdaptiveSpacer(options = {}) {
4221
4119
  const { minHeight = 0, containerRef: externalContainerRef, anchorRef } = options;
4222
- const internalContainerRef = useRef7(null);
4120
+ const internalContainerRef = useRef8(null);
4223
4121
  const containerRef = externalContainerRef ?? internalContainerRef;
4224
- const contentRef = useRef7(null);
4225
- const spacerRef = useRef7(null);
4226
- const [spacerHeight, setSpacerHeight] = useState11(0);
4227
- const recalculate = useCallback12(() => {
4122
+ const contentRef = useRef8(null);
4123
+ const spacerRef = useRef8(null);
4124
+ const [spacerHeight, setSpacerHeight] = useState12(0);
4125
+ const recalculate = useCallback14(() => {
4228
4126
  const container = containerRef.current;
4229
4127
  const content = contentRef.current;
4230
4128
  if (!container || !content) {
@@ -4283,7 +4181,7 @@ function useAdaptiveSpacer(options = {}) {
4283
4181
  }
4284
4182
 
4285
4183
  // src/components/chat/ThinkingIndicator.tsx
4286
- import React57, { useEffect as useEffect8, useState as useState12 } from "react";
4184
+ import React57, { useEffect as useEffect8, useState as useState13 } from "react";
4287
4185
  var THINKING_PHRASES = [
4288
4186
  "Consulting the ancient tomes...",
4289
4187
  "Parsing the ineffable...",
@@ -4307,22 +4205,29 @@ var ThinkingIndicator = React57.forwardRef(
4307
4205
  className,
4308
4206
  ...rest
4309
4207
  }, ref) => {
4310
- const [currentIndex, setCurrentIndex] = useState12(
4208
+ const [currentIndex, setCurrentIndex] = useState13(
4311
4209
  () => Math.floor(Math.random() * phrases.length)
4312
4210
  );
4313
- const [isTransitioning, setIsTransitioning] = useState12(false);
4211
+ const [isTransitioning, setIsTransitioning] = useState13(false);
4314
4212
  useEffect8(() => {
4315
4213
  if (!isVisible || phrases.length <= 1) {
4316
4214
  return;
4317
4215
  }
4216
+ let fadeTimeout = null;
4318
4217
  const interval = setInterval(() => {
4319
4218
  setIsTransitioning(true);
4320
- setTimeout(() => {
4219
+ fadeTimeout = setTimeout(() => {
4321
4220
  setCurrentIndex((prev) => (prev + 1) % phrases.length);
4322
4221
  setIsTransitioning(false);
4222
+ fadeTimeout = null;
4323
4223
  }, 200);
4324
4224
  }, phraseInterval);
4325
- return () => clearInterval(interval);
4225
+ return () => {
4226
+ clearInterval(interval);
4227
+ if (fadeTimeout !== null) {
4228
+ clearTimeout(fadeTimeout);
4229
+ }
4230
+ };
4326
4231
  }, [isVisible, phrases.length, phraseInterval]);
4327
4232
  if (!isVisible) {
4328
4233
  return null;
@@ -4375,73 +4280,250 @@ var ThinkingIndicator = React57.forwardRef(
4375
4280
  );
4376
4281
  ThinkingIndicator.displayName = "ThinkingIndicator";
4377
4282
 
4378
- // src/components/chat/ChatView.tsx
4379
- var ChatView = React58.forwardRef(
4380
- ({ messages, latestUserMessageIndex, isStreaming, isThinking, onScroll, className, ...rest }, ref) => {
4381
- const { containerRef, anchorRef, scrollToAnchor } = useScrollAnchor({
4382
- behavior: "smooth",
4383
- block: "start"
4384
- });
4385
- const { contentRef, spacerRef, spacerHeight } = useAdaptiveSpacer({
4386
- containerRef,
4387
- anchorRef
4388
- });
4389
- useEffect9(() => {
4390
- if (latestUserMessageIndex !== void 0 && latestUserMessageIndex >= 0) {
4391
- scrollToAnchor();
4392
- }
4393
- }, [latestUserMessageIndex, scrollToAnchor]);
4394
- const latestUserIdx = latestUserMessageIndex ?? messages.reduceRight((found, msg, idx) => {
4395
- if (found === -1 && msg.variant === "user") {
4396
- return idx;
4397
- }
4398
- return found;
4399
- }, -1);
4400
- const showThinking = isThinking && messages.length > 0 && messages[messages.length - 1]?.variant === "user";
4283
+ // src/components/chat/Checkpoint.tsx
4284
+ import React58 from "react";
4285
+ import {
4286
+ ArrowLeft,
4287
+ ChevronLeft as ChevronLeft3,
4288
+ ChevronRight as ChevronRight4,
4289
+ GitBranch as GitBranch2,
4290
+ GitCommitVertical,
4291
+ GitMerge,
4292
+ PencilLine
4293
+ } from "lucide-react";
4294
+ var KIND_ICONS = {
4295
+ task: GitBranch2,
4296
+ submit: GitMerge,
4297
+ rename: PencilLine,
4298
+ init: GitCommitVertical
4299
+ };
4300
+ var KIND_ARIA_LABELS = {
4301
+ task: "Task checkpoint",
4302
+ submit: "Submit checkpoint",
4303
+ rename: "Rename checkpoint",
4304
+ init: "Project head checkpoint"
4305
+ };
4306
+ var Checkpoint = React58.forwardRef(
4307
+ function Checkpoint2({ name, executionKind, status = "completed", isActive, muted, branchInfo, onJumpHere }, ref) {
4308
+ const KindIcon = KIND_ICONS[executionKind];
4309
+ const isFailed = status === "failed";
4310
+ const isCancelled = status === "cancelled";
4311
+ const isInteractive = !isActive && !!onJumpHere;
4312
+ const iconColor = isActive ? "text-gold" : isFailed ? "text-error-muted" : "text-silver/50";
4313
+ const nameClasses = cx(
4314
+ "transition-colors text-xs",
4315
+ isActive ? "text-silver font-medium" : isInteractive ? "text-silver/70 hover:text-white underline decoration-silver/30 underline-offset-4 decoration-dotted hover:decoration-silver/70" : "text-silver/50"
4316
+ );
4401
4317
  return /* @__PURE__ */ React58.createElement(
4402
4318
  "div",
4403
4319
  {
4404
- ref: (node) => {
4405
- ;
4406
- containerRef.current = node;
4407
- if (typeof ref === "function") {
4408
- ref(node);
4409
- } else if (ref) {
4410
- ref.current = node;
4411
- }
4412
- },
4413
- onScroll,
4320
+ ref,
4321
+ role: "group",
4322
+ "aria-label": KIND_ARIA_LABELS[executionKind],
4414
4323
  className: cx(
4415
- "flex flex-col w-full h-full overflow-y-auto scroll-smooth",
4416
- "px-4 py-6 overscroll-contain",
4417
- className
4418
- ),
4419
- ...rest
4324
+ "group/checkpoint flex items-center gap-2 py-1.5 select-none",
4325
+ muted && "opacity-60"
4326
+ )
4420
4327
  },
4421
- /* @__PURE__ */ React58.createElement("div", { ref: contentRef, className: "relative flex flex-col gap-3" }, messages.map(({
4422
- id,
4423
- variant,
4424
- className: messageClassName,
4425
- branchInfo,
4426
- actions,
4427
- isStreaming: nodeIsStreaming,
4428
- ...messageProps
4429
- }, index) => {
4430
- const isAnchor = index === latestUserIdx;
4431
- const isLastMessage = index === messages.length - 1;
4432
- const showStreaming = isLastMessage && isStreaming && variant === "assistant";
4433
- const isMessageStreaming = showStreaming || !!nodeIsStreaming;
4434
- return /* @__PURE__ */ React58.createElement(
4435
- "div",
4436
- {
4437
- key: id ?? `msg-${index}`,
4438
- ref: isAnchor ? anchorRef : void 0,
4439
- className: isAnchor ? "scroll-mt-4" : void 0
4440
- },
4441
- /* @__PURE__ */ React58.createElement(
4442
- Message,
4443
- {
4444
- variant,
4328
+ /* @__PURE__ */ React58.createElement(KindIcon, { className: cx("w-3.5 h-3.5 shrink-0", iconColor), "aria-hidden": "true" }),
4329
+ /* @__PURE__ */ React58.createElement(
4330
+ "button",
4331
+ {
4332
+ type: "button",
4333
+ onClick: isInteractive ? onJumpHere : void 0,
4334
+ disabled: !isInteractive,
4335
+ className: cx(
4336
+ nameClasses,
4337
+ "truncate text-left",
4338
+ !isInteractive && "cursor-default"
4339
+ ),
4340
+ "aria-label": isInteractive ? `Jump to checkpoint ${name}` : name
4341
+ },
4342
+ /* @__PURE__ */ React58.createElement("span", { className: "truncate" }, name),
4343
+ isFailed && /* @__PURE__ */ React58.createElement("span", { className: "ml-1.5 text-error-muted" }, "\xB7 failed"),
4344
+ isCancelled && /* @__PURE__ */ React58.createElement("span", { className: "ml-1.5 text-silver/40" }, "\xB7 cancelled")
4345
+ ),
4346
+ isInteractive && /* @__PURE__ */ React58.createElement(
4347
+ "span",
4348
+ {
4349
+ className: cx(
4350
+ "ml-1 inline-flex items-center gap-1 text-xs text-silver/40",
4351
+ "opacity-0 group-hover/checkpoint:opacity-100 transition-opacity",
4352
+ "pointer-events-none"
4353
+ ),
4354
+ "aria-hidden": "true"
4355
+ },
4356
+ /* @__PURE__ */ React58.createElement(ArrowLeft, { className: "w-3 h-3" }),
4357
+ "Jump here"
4358
+ ),
4359
+ branchInfo && branchInfo.total > 1 && /* @__PURE__ */ React58.createElement(
4360
+ "div",
4361
+ {
4362
+ className: "ml-auto inline-flex items-center gap-0.5 text-silver/70 text-xs",
4363
+ role: "navigation",
4364
+ "aria-label": "Switch sibling checkpoint"
4365
+ },
4366
+ /* @__PURE__ */ React58.createElement(
4367
+ "button",
4368
+ {
4369
+ type: "button",
4370
+ onClick: branchInfo.onPrevious,
4371
+ disabled: branchInfo.current <= 1,
4372
+ className: cx(
4373
+ "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
4374
+ "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
4375
+ ),
4376
+ "aria-label": "Previous sibling checkpoint"
4377
+ },
4378
+ /* @__PURE__ */ React58.createElement(ChevronLeft3, { className: "w-3 h-3" })
4379
+ ),
4380
+ /* @__PURE__ */ React58.createElement("span", { className: "tabular-nums min-w-6 text-center" }, branchInfo.current, "/", branchInfo.total),
4381
+ /* @__PURE__ */ React58.createElement(
4382
+ "button",
4383
+ {
4384
+ type: "button",
4385
+ onClick: branchInfo.onNext,
4386
+ disabled: branchInfo.current >= branchInfo.total,
4387
+ className: cx(
4388
+ "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
4389
+ "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
4390
+ ),
4391
+ "aria-label": "Next sibling checkpoint"
4392
+ },
4393
+ /* @__PURE__ */ React58.createElement(ChevronRight4, { className: "w-3 h-3" })
4394
+ )
4395
+ )
4396
+ );
4397
+ }
4398
+ );
4399
+ Checkpoint.displayName = "Checkpoint";
4400
+
4401
+ // src/components/chat/GreyedDivider.tsx
4402
+ import React59 from "react";
4403
+ import { ArrowDown } from "lucide-react";
4404
+ function pluralize(n, singular, plural) {
4405
+ return `${n} ${n === 1 ? singular : plural}`;
4406
+ }
4407
+ function summarize(messageCount, checkpointCount) {
4408
+ const parts = [];
4409
+ if (messageCount > 0) {
4410
+ parts.push(pluralize(messageCount, "message", "messages"));
4411
+ }
4412
+ if (checkpointCount > 0) {
4413
+ parts.push(pluralize(checkpointCount, "checkpoint", "checkpoints"));
4414
+ }
4415
+ return parts.length > 0 ? parts.join(", ") : "no items";
4416
+ }
4417
+ var GreyedDivider = React59.forwardRef(
4418
+ function GreyedDivider2({ messageCount, checkpointCount, onJumpToLatest }, ref) {
4419
+ if (messageCount === 0 && checkpointCount === 0) {
4420
+ return null;
4421
+ }
4422
+ return /* @__PURE__ */ React59.createElement(
4423
+ "div",
4424
+ {
4425
+ ref,
4426
+ role: "separator",
4427
+ "aria-label": "Start of rewound timeline",
4428
+ className: "flex items-center gap-3 py-2 text-xs text-silver/50 select-none"
4429
+ },
4430
+ /* @__PURE__ */ React59.createElement("div", { className: "flex-1 h-px bg-ash/40", "aria-hidden": "true" }),
4431
+ /* @__PURE__ */ React59.createElement("span", { className: "inline-flex items-center gap-1.5 whitespace-nowrap" }, /* @__PURE__ */ React59.createElement(ArrowDown, { className: "w-3 h-3", "aria-hidden": "true" }), "Later in this conversation \xB7 ", summarize(messageCount, checkpointCount)),
4432
+ /* @__PURE__ */ React59.createElement("div", { className: "flex-1 h-px bg-ash/40", "aria-hidden": "true" }),
4433
+ onJumpToLatest && /* @__PURE__ */ React59.createElement(
4434
+ "button",
4435
+ {
4436
+ type: "button",
4437
+ onClick: onJumpToLatest,
4438
+ className: cx(
4439
+ "shrink-0 transition-colors",
4440
+ "text-silver/60 hover:text-white",
4441
+ "underline decoration-silver/30 underline-offset-4 decoration-dotted hover:decoration-silver/70"
4442
+ )
4443
+ },
4444
+ "Jump to latest \u2192"
4445
+ )
4446
+ );
4447
+ }
4448
+ );
4449
+ GreyedDivider.displayName = "GreyedDivider";
4450
+
4451
+ // src/components/chat/ChatView.tsx
4452
+ var ChatView = React60.forwardRef(
4453
+ function ChatView2({ items, latestUserMessageIndex, isStreaming, isThinking, onScroll, className, ...rest }, ref) {
4454
+ const { containerRef, anchorRef, scrollToAnchor } = useScrollAnchor({
4455
+ behavior: "smooth",
4456
+ block: "start"
4457
+ });
4458
+ const { contentRef, spacerRef, spacerHeight } = useAdaptiveSpacer({
4459
+ containerRef,
4460
+ anchorRef
4461
+ });
4462
+ const latestUserIdx = latestUserMessageIndex ?? items.reduceRight((found, item, idx) => {
4463
+ if (found === -1 && item.kind === "message" && item.variant === "user") {
4464
+ return idx;
4465
+ }
4466
+ return found;
4467
+ }, -1);
4468
+ useEffect9(() => {
4469
+ if (latestUserMessageIndex !== void 0 && latestUserMessageIndex >= 0) {
4470
+ scrollToAnchor();
4471
+ }
4472
+ }, [latestUserMessageIndex, scrollToAnchor]);
4473
+ const lastMessageIdx = items.reduceRight((found, item, idx) => {
4474
+ return found === -1 && item.kind === "message" ? idx : found;
4475
+ }, -1);
4476
+ const lastMessage = lastMessageIdx >= 0 ? items[lastMessageIdx] : null;
4477
+ const showThinking = isThinking && lastMessage?.kind === "message" && lastMessage.variant === "user";
4478
+ return /* @__PURE__ */ React60.createElement(
4479
+ "div",
4480
+ {
4481
+ ref: composeRefs(containerRef, ref),
4482
+ onScroll,
4483
+ className: cx(
4484
+ "flex flex-col w-full h-full overflow-y-auto scroll-smooth",
4485
+ "px-4 py-6 overscroll-contain",
4486
+ className
4487
+ ),
4488
+ ...rest
4489
+ },
4490
+ /* @__PURE__ */ React60.createElement("div", { ref: contentRef, className: "relative flex flex-col gap-3" }, items.map((item, index) => {
4491
+ const isAnchor = index === latestUserIdx;
4492
+ const wrapperRef = isAnchor ? anchorRef : void 0;
4493
+ const wrapperClass = isAnchor ? "scroll-mt-4" : void 0;
4494
+ if (item.kind === "divider") {
4495
+ const { kind: _k2, id: id2, ...dividerProps } = item;
4496
+ return /* @__PURE__ */ React60.createElement("div", { key: id2 }, /* @__PURE__ */ React60.createElement(GreyedDivider, { ...dividerProps }));
4497
+ }
4498
+ if (item.kind === "checkpoint") {
4499
+ const { kind: _k2, id: id2, ...checkpointProps } = item;
4500
+ return /* @__PURE__ */ React60.createElement("div", { key: id2, ref: wrapperRef, className: wrapperClass }, /* @__PURE__ */ React60.createElement(Checkpoint, { ...checkpointProps }));
4501
+ }
4502
+ const {
4503
+ kind: _k,
4504
+ id,
4505
+ variant,
4506
+ muted,
4507
+ className: messageClassName,
4508
+ branchInfo,
4509
+ actions,
4510
+ isStreaming: nodeIsStreaming,
4511
+ ...messageProps
4512
+ } = item;
4513
+ const isLastMessage = index === lastMessageIdx;
4514
+ const showStreaming = isLastMessage && isStreaming && variant === "assistant";
4515
+ const isMessageStreaming = showStreaming || !!nodeIsStreaming;
4516
+ return /* @__PURE__ */ React60.createElement(
4517
+ "div",
4518
+ {
4519
+ key: id,
4520
+ ref: wrapperRef,
4521
+ className: cx(wrapperClass, muted && "opacity-60")
4522
+ },
4523
+ /* @__PURE__ */ React60.createElement(
4524
+ Message,
4525
+ {
4526
+ variant,
4445
4527
  isStreaming: isMessageStreaming,
4446
4528
  className: messageClassName,
4447
4529
  branchInfo,
@@ -4451,8 +4533,8 @@ var ChatView = React58.forwardRef(
4451
4533
  }
4452
4534
  )
4453
4535
  );
4454
- }), showThinking && /* @__PURE__ */ React58.createElement(ThinkingIndicator, { isVisible: true })),
4455
- /* @__PURE__ */ React58.createElement(
4536
+ }), showThinking && /* @__PURE__ */ React60.createElement(ThinkingIndicator, { isVisible: true })),
4537
+ /* @__PURE__ */ React60.createElement(
4456
4538
  "div",
4457
4539
  {
4458
4540
  ref: spacerRef,
@@ -4467,8 +4549,8 @@ var ChatView = React58.forwardRef(
4467
4549
  ChatView.displayName = "ChatView";
4468
4550
 
4469
4551
  // src/components/chat/ChatInput.tsx
4470
- import React59, { useCallback as useCallback13, useEffect as useEffect10, useRef as useRef8, useState as useState13 } from "react";
4471
- import { Paperclip, Send, Square, X as X5 } from "lucide-react";
4552
+ import React61, { useCallback as useCallback15, useEffect as useEffect10, useRef as useRef9, useState as useState14 } from "react";
4553
+ import { Paperclip, Send as Send2, Square, X as X6 } from "lucide-react";
4472
4554
 
4473
4555
  // src/components/chat/types.ts
4474
4556
  function isImageFile(file) {
@@ -4486,155 +4568,14 @@ function revokePreviewUrl(url) {
4486
4568
  }
4487
4569
  }
4488
4570
  function generateId() {
4489
- return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
4490
- }
4491
- function createEmptyTree() {
4492
- return {
4493
- nodes: {},
4494
- rootIds: [],
4495
- activeLeafId: null
4496
- };
4497
- }
4498
- function addMessageToTree(tree, message, parentId = null) {
4499
- const newNodes = { ...tree.nodes };
4500
- const newRootIds = [...tree.rootIds];
4501
- let branchIndex = 0;
4502
- if (parentId && newNodes[parentId]) {
4503
- branchIndex = newNodes[parentId].children.length;
4504
- } else if (!parentId) {
4505
- branchIndex = newRootIds.length;
4506
- }
4507
- newNodes[message.id] = {
4508
- ...message,
4509
- parentId,
4510
- children: [],
4511
- branchIndex,
4512
- createdAt: message.createdAt ?? Date.now()
4513
- };
4514
- if (parentId && newNodes[parentId]) {
4515
- newNodes[parentId] = {
4516
- ...newNodes[parentId],
4517
- children: [...newNodes[parentId].children, message.id]
4518
- };
4519
- } else {
4520
- newRootIds.push(message.id);
4521
- }
4522
- return {
4523
- nodes: newNodes,
4524
- rootIds: newRootIds,
4525
- activeLeafId: message.id
4526
- };
4527
- }
4528
- function getActivePathMessages(tree) {
4529
- if (!tree.activeLeafId) {
4530
- return [];
4531
- }
4532
- const path = [];
4533
- let currentId = tree.activeLeafId;
4534
- while (currentId) {
4535
- const node = tree.nodes[currentId];
4536
- if (!node) {
4537
- break;
4538
- }
4539
- path.unshift(node);
4540
- currentId = node.parentId;
4541
- }
4542
- return path;
4543
- }
4544
- function getSiblingInfo(tree, nodeId) {
4545
- const node = tree.nodes[nodeId];
4546
- if (!node) {
4547
- return { total: 1, current: 1 };
4548
- }
4549
- if (node.parentId) {
4550
- const parent = tree.nodes[node.parentId];
4551
- if (parent) {
4552
- const index = parent.children.indexOf(nodeId);
4553
- return {
4554
- total: parent.children.length,
4555
- current: index + 1
4556
- };
4557
- }
4558
- } else {
4559
- const index = tree.rootIds.indexOf(nodeId);
4560
- return {
4561
- total: tree.rootIds.length,
4562
- current: index + 1
4563
- };
4564
- }
4565
- return { total: 1, current: 1 };
4566
- }
4567
- function switchBranch(tree, nodeId, direction) {
4568
- const node = tree.nodes[nodeId];
4569
- if (!node) {
4570
- return tree;
4571
- }
4572
- let siblings;
4573
- let currentIndex;
4574
- if (node.parentId) {
4575
- const parent = tree.nodes[node.parentId];
4576
- if (!parent) {
4577
- return tree;
4578
- }
4579
- siblings = parent.children;
4580
- currentIndex = siblings.indexOf(nodeId);
4581
- } else {
4582
- siblings = tree.rootIds;
4583
- currentIndex = siblings.indexOf(nodeId);
4584
- }
4585
- if (siblings.length <= 1) {
4586
- return tree;
4587
- }
4588
- const newIndex = direction === "next" ? (currentIndex + 1) % siblings.length : (currentIndex - 1 + siblings.length) % siblings.length;
4589
- let leafId = siblings[newIndex];
4590
- let currentNode = tree.nodes[leafId];
4591
- while (currentNode && currentNode.children.length > 0) {
4592
- leafId = currentNode.children[0];
4593
- currentNode = tree.nodes[leafId];
4594
- }
4595
- return {
4596
- ...tree,
4597
- activeLeafId: leafId
4598
- };
4599
- }
4600
- function updateNodeContent(tree, nodeId, content, isStreaming) {
4601
- const node = tree.nodes[nodeId];
4602
- if (!node) {
4603
- return tree;
4604
- }
4605
- return {
4606
- ...tree,
4607
- nodes: {
4608
- ...tree.nodes,
4609
- [nodeId]: {
4610
- ...node,
4611
- content,
4612
- isStreaming: isStreaming ?? node.isStreaming
4613
- }
4614
- }
4615
- };
4616
- }
4617
- function messagesToTree(messages) {
4618
- let tree = createEmptyTree();
4619
- for (const msg of messages) {
4620
- const parentId = tree.activeLeafId;
4621
- tree = addMessageToTree(tree, {
4622
- id: msg.id,
4623
- role: msg.role,
4624
- content: msg.content,
4625
- parentId,
4626
- isStreaming: msg.isStreaming
4627
- }, parentId);
4571
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
4572
+ return crypto.randomUUID();
4628
4573
  }
4629
- return tree;
4630
- }
4631
- function isBranchPoint(tree, nodeId) {
4632
- const node = tree.nodes[nodeId];
4633
- return node ? node.children.length > 1 : false;
4574
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
4634
4575
  }
4635
4576
 
4636
4577
  // src/components/chat/ChatInput.tsx
4637
- var ChatInput = React59.forwardRef(
4578
+ var ChatInput = React61.forwardRef(
4638
4579
  ({
4639
4580
  position = "bottom",
4640
4581
  placeholder = "Send a message...",
@@ -4656,13 +4597,13 @@ var ChatInput = React59.forwardRef(
4656
4597
  className,
4657
4598
  ...rest
4658
4599
  }, ref) => {
4659
- const [value, setValue] = useState13(initialInputValue);
4660
- const [localAttachments, setLocalAttachments] = useState13([]);
4661
- const [isDragOver, setIsDragOver] = useState13(false);
4662
- const textareaRef = useRef8(null);
4663
- const fileInputRef = useRef8(null);
4600
+ const [value, setValue] = useState14(initialInputValue);
4601
+ const [localAttachments, setLocalAttachments] = useState14([]);
4602
+ const [isDragOver, setIsDragOver] = useState14(false);
4603
+ const textareaRef = useRef9(null);
4604
+ const fileInputRef = useRef9(null);
4664
4605
  const attachments = controlledAttachments ?? localAttachments;
4665
- const setAttachments = useCallback13(
4606
+ const setAttachments = useCallback15(
4666
4607
  (newAttachments) => {
4667
4608
  if (onAttachmentsChange) {
4668
4609
  if (typeof newAttachments === "function") {
@@ -4676,7 +4617,7 @@ var ChatInput = React59.forwardRef(
4676
4617
  },
4677
4618
  [attachments, onAttachmentsChange]
4678
4619
  );
4679
- const handleSubmit = useCallback13(() => {
4620
+ const handleSubmit = useCallback15(() => {
4680
4621
  const trimmed = value.trim();
4681
4622
  if (!trimmed || disabled || isStreaming) {
4682
4623
  return;
@@ -4688,7 +4629,7 @@ var ChatInput = React59.forwardRef(
4688
4629
  textareaRef.current.style.height = "auto";
4689
4630
  }
4690
4631
  }, [value, disabled, isStreaming, onSubmit, attachments, setAttachments]);
4691
- const handleKeyDown = useCallback13(
4632
+ const handleKeyDown = useCallback15(
4692
4633
  (e) => {
4693
4634
  if (e.key === "Enter" && !e.shiftKey) {
4694
4635
  e.preventDefault();
@@ -4697,7 +4638,7 @@ var ChatInput = React59.forwardRef(
4697
4638
  },
4698
4639
  [handleSubmit]
4699
4640
  );
4700
- const handleChange = useCallback13((e) => {
4641
+ const handleChange = useCallback15((e) => {
4701
4642
  setValue(e.target.value);
4702
4643
  onInputChange?.(e.target.value);
4703
4644
  const textarea = e.target;
@@ -4709,7 +4650,7 @@ var ChatInput = React59.forwardRef(
4709
4650
  textareaRef.current.focus();
4710
4651
  }
4711
4652
  }, [disabled, isStreaming, autoFocus]);
4712
- const addFiles = useCallback13(
4653
+ const addFiles = useCallback15(
4713
4654
  (files) => {
4714
4655
  const newAttachments = Array.from(files).map((file) => ({
4715
4656
  id: generateId(),
@@ -4721,7 +4662,7 @@ var ChatInput = React59.forwardRef(
4721
4662
  },
4722
4663
  [setAttachments]
4723
4664
  );
4724
- const handleFileSelect = useCallback13(
4665
+ const handleFileSelect = useCallback15(
4725
4666
  (e) => {
4726
4667
  const files = e.target.files;
4727
4668
  if (files && files.length > 0) {
@@ -4731,7 +4672,7 @@ var ChatInput = React59.forwardRef(
4731
4672
  },
4732
4673
  [addFiles]
4733
4674
  );
4734
- const handleRemoveAttachment = useCallback13(
4675
+ const handleRemoveAttachment = useCallback15(
4735
4676
  (id) => {
4736
4677
  const attachment = attachments.find((a) => a.id === id);
4737
4678
  if (attachment && onAttachmentRemove) {
@@ -4747,23 +4688,23 @@ var ChatInput = React59.forwardRef(
4747
4688
  },
4748
4689
  [attachments, onAttachmentRemove, setAttachments]
4749
4690
  );
4750
- const handleDragEnter = useCallback13((e) => {
4691
+ const handleDragEnter = useCallback15((e) => {
4751
4692
  e.preventDefault();
4752
4693
  e.stopPropagation();
4753
4694
  setIsDragOver(true);
4754
4695
  }, []);
4755
- const handleDragLeave = useCallback13((e) => {
4696
+ const handleDragLeave = useCallback15((e) => {
4756
4697
  e.preventDefault();
4757
4698
  e.stopPropagation();
4758
4699
  if (!e.currentTarget.contains(e.relatedTarget)) {
4759
4700
  setIsDragOver(false);
4760
4701
  }
4761
4702
  }, []);
4762
- const handleDragOver = useCallback13((e) => {
4703
+ const handleDragOver = useCallback15((e) => {
4763
4704
  e.preventDefault();
4764
4705
  e.stopPropagation();
4765
4706
  }, []);
4766
- const handleDrop = useCallback13(
4707
+ const handleDrop = useCallback15(
4767
4708
  (e) => {
4768
4709
  e.preventDefault();
4769
4710
  e.stopPropagation();
@@ -4779,7 +4720,7 @@ var ChatInput = React59.forwardRef(
4779
4720
  const hasAttachments = attachments.length > 0;
4780
4721
  const isUploading = attachments.some((a) => a.status === "uploading");
4781
4722
  const canSubmit = value.trim() && !disabled && !isStreaming && !isUploading;
4782
- return /* @__PURE__ */ React59.createElement(
4723
+ return /* @__PURE__ */ React61.createElement(
4783
4724
  "div",
4784
4725
  {
4785
4726
  ref,
@@ -4791,12 +4732,12 @@ var ChatInput = React59.forwardRef(
4791
4732
  ),
4792
4733
  ...rest
4793
4734
  },
4794
- isCentered && helperText && /* @__PURE__ */ React59.createElement("p", { className: "text-silver text-sm mb-4 text-center" }, helperText),
4795
- notice && /* @__PURE__ */ React59.createElement("div", { className: cx(
4735
+ isCentered && helperText && /* @__PURE__ */ React61.createElement("p", { className: "text-silver text-sm mb-4 text-center" }, helperText),
4736
+ notice && /* @__PURE__ */ React61.createElement("div", { className: cx(
4796
4737
  "w-full flex items-start gap-2 px-3 py-2 mb-1 text-xs",
4797
4738
  isCentered && "max-w-lg",
4798
4739
  notice.variant === "warning" ? "bg-gold/5 border border-gold/20 text-gold/80" : "bg-error/10 border border-error/30 text-error"
4799
- ) }, /* @__PURE__ */ React59.createElement("span", { className: "flex-1" }, notice.content), (notice.dismissible ?? notice.variant === "warning") && notice.onDismiss && /* @__PURE__ */ React59.createElement(
4740
+ ) }, /* @__PURE__ */ React61.createElement("span", { className: "flex-1" }, notice.content), (notice.dismissible ?? notice.variant === "warning") && notice.onDismiss && /* @__PURE__ */ React61.createElement(
4800
4741
  "button",
4801
4742
  {
4802
4743
  type: "button",
@@ -4807,9 +4748,9 @@ var ChatInput = React59.forwardRef(
4807
4748
  notice.variant === "warning" ? "text-gold" : "text-error"
4808
4749
  )
4809
4750
  },
4810
- /* @__PURE__ */ React59.createElement(X5, { className: "w-3 h-3" })
4751
+ /* @__PURE__ */ React61.createElement(X6, { className: "w-3 h-3" })
4811
4752
  )),
4812
- /* @__PURE__ */ React59.createElement(
4753
+ /* @__PURE__ */ React61.createElement(
4813
4754
  "div",
4814
4755
  {
4815
4756
  className: cx(
@@ -4824,7 +4765,7 @@ var ChatInput = React59.forwardRef(
4824
4765
  onDragOver: showAttachmentButton ? handleDragOver : void 0,
4825
4766
  onDrop: showAttachmentButton ? handleDrop : void 0
4826
4767
  },
4827
- hasAttachments && /* @__PURE__ */ React59.createElement("div", { className: "px-3 pt-3 pb-1" }, /* @__PURE__ */ React59.createElement(
4768
+ hasAttachments && /* @__PURE__ */ React61.createElement("div", { className: "px-3 pt-3 pb-1" }, /* @__PURE__ */ React61.createElement(
4828
4769
  AttachmentPreview,
4829
4770
  {
4830
4771
  attachments,
@@ -4832,14 +4773,14 @@ var ChatInput = React59.forwardRef(
4832
4773
  removable: !isStreaming
4833
4774
  }
4834
4775
  )),
4835
- isDragOver && /* @__PURE__ */ React59.createElement(
4776
+ isDragOver && /* @__PURE__ */ React61.createElement(
4836
4777
  "div",
4837
4778
  {
4838
4779
  className: "absolute inset-0 bg-gold/10 flex items-center justify-center z-10 pointer-events-none"
4839
4780
  },
4840
- /* @__PURE__ */ React59.createElement("span", { className: "text-gold text-sm font-medium" }, "Drop files here")
4781
+ /* @__PURE__ */ React61.createElement("span", { className: "text-gold text-sm font-medium" }, "Drop files here")
4841
4782
  ),
4842
- /* @__PURE__ */ React59.createElement("div", { className: "flex items-end" }, showAttachmentButton && /* @__PURE__ */ React59.createElement(React59.Fragment, null, /* @__PURE__ */ React59.createElement(
4783
+ /* @__PURE__ */ React61.createElement("div", { className: "flex items-end" }, showAttachmentButton && /* @__PURE__ */ React61.createElement(React61.Fragment, null, /* @__PURE__ */ React61.createElement(
4843
4784
  "button",
4844
4785
  {
4845
4786
  type: "button",
@@ -4851,8 +4792,8 @@ var ChatInput = React59.forwardRef(
4851
4792
  ),
4852
4793
  "aria-label": "Attach file"
4853
4794
  },
4854
- /* @__PURE__ */ React59.createElement(Paperclip, { className: "w-5 h-5" })
4855
- ), /* @__PURE__ */ React59.createElement(
4795
+ /* @__PURE__ */ React61.createElement(Paperclip, { className: "w-5 h-5" })
4796
+ ), /* @__PURE__ */ React61.createElement(
4856
4797
  "input",
4857
4798
  {
4858
4799
  ref: fileInputRef,
@@ -4863,7 +4804,7 @@ var ChatInput = React59.forwardRef(
4863
4804
  className: "hidden",
4864
4805
  "aria-hidden": "true"
4865
4806
  }
4866
- )), /* @__PURE__ */ React59.createElement(
4807
+ )), /* @__PURE__ */ React61.createElement(
4867
4808
  "textarea",
4868
4809
  {
4869
4810
  ref: textareaRef,
@@ -4881,7 +4822,7 @@ var ChatInput = React59.forwardRef(
4881
4822
  ),
4882
4823
  style: { maxHeight: 200 }
4883
4824
  }
4884
- ), isStreaming ? /* @__PURE__ */ React59.createElement(
4825
+ ), isStreaming ? /* @__PURE__ */ React61.createElement(
4885
4826
  "button",
4886
4827
  {
4887
4828
  type: "button",
@@ -4892,8 +4833,8 @@ var ChatInput = React59.forwardRef(
4892
4833
  ),
4893
4834
  "aria-label": "Stop generation"
4894
4835
  },
4895
- /* @__PURE__ */ React59.createElement(Square, { className: "w-5 h-5 fill-current" })
4896
- ) : /* @__PURE__ */ React59.createElement(
4836
+ /* @__PURE__ */ React61.createElement(Square, { className: "w-5 h-5 fill-current" })
4837
+ ) : /* @__PURE__ */ React61.createElement(
4897
4838
  "button",
4898
4839
  {
4899
4840
  type: "button",
@@ -4906,7 +4847,7 @@ var ChatInput = React59.forwardRef(
4906
4847
  ),
4907
4848
  "aria-label": "Send message"
4908
4849
  },
4909
- /* @__PURE__ */ React59.createElement(Send, { className: "w-5 h-5" })
4850
+ /* @__PURE__ */ React61.createElement(Send2, { className: "w-5 h-5" })
4910
4851
  ))
4911
4852
  )
4912
4853
  );
@@ -4915,13 +4856,14 @@ var ChatInput = React59.forwardRef(
4915
4856
  ChatInput.displayName = "ChatInput";
4916
4857
 
4917
4858
  // src/components/chat/ArtifactsPanel.tsx
4918
- import React69, { useCallback as useCallback15, useEffect as useEffect12, useRef as useRef10, useState as useState16 } from "react";
4859
+ import React71, { useCallback as useCallback17, useEffect as useEffect12, useRef as useRef11, useState as useState17 } from "react";
4860
+ import { Image } from "lucide-react";
4919
4861
 
4920
4862
  // src/components/ArtifactCard.tsx
4921
- import React66 from "react";
4863
+ import React68 from "react";
4922
4864
 
4923
4865
  // src/components/ImageCard.tsx
4924
- import React60 from "react";
4866
+ import React62 from "react";
4925
4867
  var ASPECT_RATIO_PRESETS = {
4926
4868
  landscape: "3 / 2",
4927
4869
  portrait: "2 / 3",
@@ -4933,7 +4875,7 @@ function resolveAspectRatio(ratio) {
4933
4875
  }
4934
4876
  return ratio.replace("/", " / ");
4935
4877
  }
4936
- var ImageCard = React60.forwardRef(
4878
+ var ImageCard = React62.forwardRef(
4937
4879
  ({
4938
4880
  src,
4939
4881
  alt = "",
@@ -4949,7 +4891,7 @@ var ImageCard = React60.forwardRef(
4949
4891
  loading,
4950
4892
  ...props
4951
4893
  }, ref) => {
4952
- return /* @__PURE__ */ React60.createElement(
4894
+ return /* @__PURE__ */ React62.createElement(
4953
4895
  Card,
4954
4896
  {
4955
4897
  ref,
@@ -4957,13 +4899,13 @@ var ImageCard = React60.forwardRef(
4957
4899
  loading,
4958
4900
  ...props
4959
4901
  },
4960
- /* @__PURE__ */ React60.createElement(
4902
+ /* @__PURE__ */ React62.createElement(
4961
4903
  Card.Media,
4962
4904
  {
4963
4905
  className: mediaClassName,
4964
4906
  style: { aspectRatio: resolveAspectRatio(aspectRatio) }
4965
4907
  },
4966
- /* @__PURE__ */ React60.createElement(React60.Fragment, null, src && /* @__PURE__ */ React60.createElement(
4908
+ /* @__PURE__ */ React62.createElement(React62.Fragment, null, src && /* @__PURE__ */ React62.createElement(
4967
4909
  "img",
4968
4910
  {
4969
4911
  src,
@@ -4973,7 +4915,7 @@ var ImageCard = React60.forwardRef(
4973
4915
  objectFit === "cover" ? "object-cover" : "object-contain"
4974
4916
  )
4975
4917
  }
4976
- ), overlay && /* @__PURE__ */ React60.createElement(
4918
+ ), overlay && /* @__PURE__ */ React62.createElement(
4977
4919
  "div",
4978
4920
  {
4979
4921
  className: "absolute inset-0 bg-obsidian/80 opacity-0 group-hover:opacity-100 transition-opacity duration-200 flex items-center justify-center"
@@ -4981,7 +4923,7 @@ var ImageCard = React60.forwardRef(
4981
4923
  overlay
4982
4924
  ))
4983
4925
  ),
4984
- /* @__PURE__ */ React60.createElement(
4926
+ /* @__PURE__ */ React62.createElement(
4985
4927
  Card.Header,
4986
4928
  {
4987
4929
  title,
@@ -4989,14 +4931,14 @@ var ImageCard = React60.forwardRef(
4989
4931
  className: contentClassName
4990
4932
  }
4991
4933
  ),
4992
- children && /* @__PURE__ */ React60.createElement(Card.Body, { className: contentClassName }, children)
4934
+ children && /* @__PURE__ */ React62.createElement(Card.Body, { className: contentClassName }, children)
4993
4935
  );
4994
4936
  }
4995
4937
  );
4996
4938
  ImageCard.displayName = "ImageCard";
4997
4939
 
4998
4940
  // src/components/VideoCard.tsx
4999
- import React61 from "react";
4941
+ import React63 from "react";
5000
4942
  import ReactPlayer from "react-player";
5001
4943
  var ASPECT_RATIO_PRESETS2 = {
5002
4944
  video: "16 / 9",
@@ -5009,7 +4951,7 @@ function resolveAspectRatio2(ratio) {
5009
4951
  }
5010
4952
  return ratio.replace("/", " / ");
5011
4953
  }
5012
- var VideoCard = React61.forwardRef(
4954
+ var VideoCard = React63.forwardRef(
5013
4955
  ({
5014
4956
  src,
5015
4957
  title,
@@ -5029,7 +4971,7 @@ var VideoCard = React61.forwardRef(
5029
4971
  loading,
5030
4972
  ...props
5031
4973
  }, ref) => {
5032
- return /* @__PURE__ */ React61.createElement(
4974
+ return /* @__PURE__ */ React63.createElement(
5033
4975
  Card,
5034
4976
  {
5035
4977
  ref,
@@ -5037,13 +4979,13 @@ var VideoCard = React61.forwardRef(
5037
4979
  loading,
5038
4980
  ...props
5039
4981
  },
5040
- /* @__PURE__ */ React61.createElement(
4982
+ /* @__PURE__ */ React63.createElement(
5041
4983
  Card.Media,
5042
4984
  {
5043
4985
  className: mediaClassName,
5044
4986
  style: { aspectRatio: resolveAspectRatio2(aspectRatio) }
5045
4987
  },
5046
- src && /* @__PURE__ */ React61.createElement(
4988
+ src && /* @__PURE__ */ React63.createElement(
5047
4989
  ReactPlayer,
5048
4990
  {
5049
4991
  src,
@@ -5060,7 +5002,7 @@ var VideoCard = React61.forwardRef(
5060
5002
  }
5061
5003
  )
5062
5004
  ),
5063
- /* @__PURE__ */ React61.createElement(
5005
+ /* @__PURE__ */ React63.createElement(
5064
5006
  Card.Header,
5065
5007
  {
5066
5008
  title,
@@ -5068,17 +5010,17 @@ var VideoCard = React61.forwardRef(
5068
5010
  className: contentClassName
5069
5011
  }
5070
5012
  ),
5071
- children && /* @__PURE__ */ React61.createElement(Card.Body, { className: contentClassName }, children)
5013
+ children && /* @__PURE__ */ React63.createElement(Card.Body, { className: contentClassName }, children)
5072
5014
  );
5073
5015
  }
5074
5016
  );
5075
5017
  VideoCard.displayName = "VideoCard";
5076
5018
 
5077
5019
  // src/components/AudioCard.tsx
5078
- import React62 from "react";
5020
+ import React64 from "react";
5079
5021
  import ReactPlayer2 from "react-player";
5080
5022
  import { Music } from "lucide-react";
5081
- var AudioCard = React62.forwardRef(
5023
+ var AudioCard = React64.forwardRef(
5082
5024
  ({
5083
5025
  src,
5084
5026
  title,
@@ -5097,7 +5039,7 @@ var AudioCard = React62.forwardRef(
5097
5039
  loading,
5098
5040
  ...props
5099
5041
  }, ref) => {
5100
- return /* @__PURE__ */ React62.createElement(
5042
+ return /* @__PURE__ */ React64.createElement(
5101
5043
  Card,
5102
5044
  {
5103
5045
  ref,
@@ -5105,10 +5047,10 @@ var AudioCard = React62.forwardRef(
5105
5047
  loading,
5106
5048
  ...props
5107
5049
  },
5108
- /* @__PURE__ */ React62.createElement(Card.Media, { className: cx(
5050
+ /* @__PURE__ */ React64.createElement(Card.Media, { className: cx(
5109
5051
  "bg-obsidian py-8 flex flex-col items-center justify-center",
5110
5052
  mediaClassName
5111
- ) }, /* @__PURE__ */ React62.createElement("div", { className: "mb-4 text-gold" }, /* @__PURE__ */ React62.createElement(Music, { size: 48 })), src && /* @__PURE__ */ React62.createElement("div", { className: "w-full px-4" }, /* @__PURE__ */ React62.createElement(
5053
+ ) }, /* @__PURE__ */ React64.createElement("div", { className: "mb-4 text-gold" }, /* @__PURE__ */ React64.createElement(Music, { size: 48 })), src && /* @__PURE__ */ React64.createElement("div", { className: "w-full px-4" }, /* @__PURE__ */ React64.createElement(
5112
5054
  ReactPlayer2,
5113
5055
  {
5114
5056
  src,
@@ -5119,19 +5061,11 @@ var AudioCard = React62.forwardRef(
5119
5061
  loop,
5120
5062
  width: "100%",
5121
5063
  height,
5122
- style: { backgroundColor: "transparent" },
5123
- config: {
5124
- file: {
5125
- forceAudio: true,
5126
- attributes: {
5127
- style: { width: "100%", height }
5128
- }
5129
- }
5130
- },
5064
+ style: { backgroundColor: "transparent", width: "100%", height },
5131
5065
  ...playerProps
5132
5066
  }
5133
5067
  ))),
5134
- /* @__PURE__ */ React62.createElement(
5068
+ /* @__PURE__ */ React64.createElement(
5135
5069
  Card.Header,
5136
5070
  {
5137
5071
  title,
@@ -5139,16 +5073,16 @@ var AudioCard = React62.forwardRef(
5139
5073
  className: contentClassName
5140
5074
  }
5141
5075
  ),
5142
- children && /* @__PURE__ */ React62.createElement(Card.Body, { className: contentClassName }, children)
5076
+ children && /* @__PURE__ */ React64.createElement(Card.Body, { className: contentClassName }, children)
5143
5077
  );
5144
5078
  }
5145
5079
  );
5146
5080
  AudioCard.displayName = "AudioCard";
5147
5081
 
5148
5082
  // src/components/PdfCard.tsx
5149
- import React63 from "react";
5083
+ import React65 from "react";
5150
5084
  import { FileText as FileText2 } from "lucide-react";
5151
- var PdfCard = React63.forwardRef(
5085
+ var PdfCard = React65.forwardRef(
5152
5086
  ({
5153
5087
  src,
5154
5088
  title,
@@ -5161,7 +5095,7 @@ var PdfCard = React63.forwardRef(
5161
5095
  loading,
5162
5096
  ...props
5163
5097
  }, ref) => {
5164
- return /* @__PURE__ */ React63.createElement(
5098
+ return /* @__PURE__ */ React65.createElement(
5165
5099
  Card,
5166
5100
  {
5167
5101
  ref,
@@ -5169,13 +5103,13 @@ var PdfCard = React63.forwardRef(
5169
5103
  loading,
5170
5104
  ...props
5171
5105
  },
5172
- /* @__PURE__ */ React63.createElement(
5106
+ /* @__PURE__ */ React65.createElement(
5173
5107
  Card.Media,
5174
5108
  {
5175
5109
  className: cx("bg-obsidian", mediaClassName),
5176
5110
  style: { height }
5177
5111
  },
5178
- src && /* @__PURE__ */ React63.createElement(
5112
+ src && /* @__PURE__ */ React65.createElement(
5179
5113
  "iframe",
5180
5114
  {
5181
5115
  src: `${src}#view=FitH`,
@@ -5184,23 +5118,23 @@ var PdfCard = React63.forwardRef(
5184
5118
  }
5185
5119
  )
5186
5120
  ),
5187
- /* @__PURE__ */ React63.createElement(
5121
+ /* @__PURE__ */ React65.createElement(
5188
5122
  Card.Header,
5189
5123
  {
5190
5124
  title,
5191
5125
  subtitle,
5192
5126
  className: contentClassName,
5193
- action: /* @__PURE__ */ React63.createElement("div", { className: "p-2 bg-ash/20 text-gold shrink-0" }, /* @__PURE__ */ React63.createElement(FileText2, { size: 20 }))
5127
+ action: /* @__PURE__ */ React65.createElement("div", { className: "p-2 bg-ash/20 text-gold shrink-0" }, /* @__PURE__ */ React65.createElement(FileText2, { size: 20 }))
5194
5128
  }
5195
5129
  ),
5196
- children && /* @__PURE__ */ React63.createElement(Card.Body, { className: contentClassName }, children)
5130
+ children && /* @__PURE__ */ React65.createElement(Card.Body, { className: contentClassName }, children)
5197
5131
  );
5198
5132
  }
5199
5133
  );
5200
5134
  PdfCard.displayName = "PdfCard";
5201
5135
 
5202
5136
  // src/components/ScriptCard.tsx
5203
- import React64 from "react";
5137
+ import React66 from "react";
5204
5138
  var SCRIPT_ELEMENT_TYPES = {
5205
5139
  SCENE_HEADING: "scene-heading",
5206
5140
  ACTION: "action",
@@ -5214,28 +5148,28 @@ var SCRIPT_ELEMENT_TYPES = {
5214
5148
  function ScriptElementRenderer({ element }) {
5215
5149
  switch (element.type) {
5216
5150
  case "scene-heading":
5217
- return /* @__PURE__ */ React64.createElement("p", { className: "mt-4 mb-2 font-bold uppercase text-gold text-xs tracking-wide" }, element.content);
5151
+ return /* @__PURE__ */ React66.createElement("p", { className: "mt-4 mb-2 font-bold uppercase text-gold text-xs tracking-wide" }, element.content);
5218
5152
  case "action":
5219
- return /* @__PURE__ */ React64.createElement("p", { className: "my-2 text-silver text-xs leading-relaxed" }, element.content);
5153
+ return /* @__PURE__ */ React66.createElement("p", { className: "my-2 text-silver text-xs leading-relaxed" }, element.content);
5220
5154
  case "character":
5221
- return /* @__PURE__ */ React64.createElement("p", { className: "mt-4 mb-0.5 ml-8 font-bold text-white text-xs uppercase tracking-wide" }, element.content);
5155
+ return /* @__PURE__ */ React66.createElement("p", { className: "mt-4 mb-0.5 ml-8 font-bold text-white text-xs uppercase tracking-wide" }, element.content);
5222
5156
  case "parenthetical":
5223
- return /* @__PURE__ */ React64.createElement("p", { className: "ml-6 text-silver/70 text-xs italic" }, "(", element.content, ")");
5157
+ return /* @__PURE__ */ React66.createElement("p", { className: "ml-6 text-silver/70 text-xs italic" }, "(", element.content, ")");
5224
5158
  case "dialogue":
5225
- return /* @__PURE__ */ React64.createElement("p", { className: "ml-4 mr-8 text-silver text-xs leading-relaxed" }, element.content);
5159
+ return /* @__PURE__ */ React66.createElement("p", { className: "ml-4 mr-8 text-silver text-xs leading-relaxed" }, element.content);
5226
5160
  case "transition":
5227
- return /* @__PURE__ */ React64.createElement("p", { className: "mt-4 mb-2 text-right font-bold uppercase text-gold/80 text-xs tracking-wide" }, element.content);
5161
+ return /* @__PURE__ */ React66.createElement("p", { className: "mt-4 mb-2 text-right font-bold uppercase text-gold/80 text-xs tracking-wide" }, element.content);
5228
5162
  case "title":
5229
- return /* @__PURE__ */ React64.createElement("p", { className: "mt-6 mb-2 text-center font-bold text-gold text-sm" }, element.content);
5163
+ return /* @__PURE__ */ React66.createElement("p", { className: "mt-6 mb-2 text-center font-bold text-gold text-sm" }, element.content);
5230
5164
  case "subtitle":
5231
- return /* @__PURE__ */ React64.createElement("p", { className: "text-center italic text-gold/70 text-xs" }, element.content);
5165
+ return /* @__PURE__ */ React66.createElement("p", { className: "text-center italic text-gold/70 text-xs" }, element.content);
5232
5166
  default:
5233
5167
  return null;
5234
5168
  }
5235
5169
  }
5236
- var ScriptCard = React64.forwardRef(
5170
+ var ScriptCard = React66.forwardRef(
5237
5171
  ({ title, subtitle, elements, maxHeight = "16rem", className, style, loading, ...rest }, ref) => {
5238
- return /* @__PURE__ */ React64.createElement(
5172
+ return /* @__PURE__ */ React66.createElement(
5239
5173
  Card,
5240
5174
  {
5241
5175
  ref,
@@ -5243,20 +5177,20 @@ var ScriptCard = React64.forwardRef(
5243
5177
  loading,
5244
5178
  ...rest
5245
5179
  },
5246
- /* @__PURE__ */ React64.createElement(
5180
+ /* @__PURE__ */ React66.createElement(
5247
5181
  Card.Header,
5248
5182
  {
5249
5183
  title,
5250
5184
  subtitle
5251
5185
  }
5252
5186
  ),
5253
- /* @__PURE__ */ React64.createElement(
5187
+ /* @__PURE__ */ React66.createElement(
5254
5188
  Card.Body,
5255
5189
  {
5256
5190
  className: "font-mono overflow-y-auto",
5257
5191
  style: { maxHeight, ...style }
5258
5192
  },
5259
- elements.map((element, index) => /* @__PURE__ */ React64.createElement(ScriptElementRenderer, { key: index, element }))
5193
+ elements.map((element, index) => /* @__PURE__ */ React66.createElement(ScriptElementRenderer, { key: index, element }))
5260
5194
  )
5261
5195
  );
5262
5196
  }
@@ -5264,8 +5198,8 @@ var ScriptCard = React64.forwardRef(
5264
5198
  ScriptCard.displayName = "ScriptCard";
5265
5199
 
5266
5200
  // src/components/TextCard.tsx
5267
- import React65 from "react";
5268
- var TextCard = React65.forwardRef(
5201
+ import React67 from "react";
5202
+ var TextCard = React67.forwardRef(
5269
5203
  ({
5270
5204
  content,
5271
5205
  title,
@@ -5277,7 +5211,7 @@ var TextCard = React65.forwardRef(
5277
5211
  loading,
5278
5212
  ...props
5279
5213
  }, ref) => {
5280
- return /* @__PURE__ */ React65.createElement(
5214
+ return /* @__PURE__ */ React67.createElement(
5281
5215
  Card,
5282
5216
  {
5283
5217
  ref,
@@ -5285,20 +5219,20 @@ var TextCard = React65.forwardRef(
5285
5219
  loading,
5286
5220
  ...props
5287
5221
  },
5288
- /* @__PURE__ */ React65.createElement(
5222
+ /* @__PURE__ */ React67.createElement(
5289
5223
  Card.Header,
5290
5224
  {
5291
5225
  title,
5292
5226
  subtitle
5293
5227
  }
5294
5228
  ),
5295
- /* @__PURE__ */ React65.createElement(
5229
+ /* @__PURE__ */ React67.createElement(
5296
5230
  Card.Body,
5297
5231
  {
5298
5232
  className: cx("overflow-y-auto", contentClassName),
5299
5233
  style: { maxHeight }
5300
5234
  },
5301
- /* @__PURE__ */ React65.createElement(
5235
+ /* @__PURE__ */ React67.createElement(
5302
5236
  MarkdownContent,
5303
5237
  {
5304
5238
  content,
@@ -5336,7 +5270,7 @@ var ARTIFACT_TYPES = {
5336
5270
  SCRIPT: "SCRIPT",
5337
5271
  PDF: "PDF"
5338
5272
  };
5339
- var ArtifactCard = React66.forwardRef(
5273
+ var ArtifactCard = React68.forwardRef(
5340
5274
  ({ artifact, onExpand, loading, className, ...props }, ref) => {
5341
5275
  const derivedLoading = deriveCardSlotLoading(artifact);
5342
5276
  const commonProps = {
@@ -5354,7 +5288,7 @@ var ArtifactCard = React66.forwardRef(
5354
5288
  const renderContent = () => {
5355
5289
  switch (artifact.type) {
5356
5290
  case "IMAGE":
5357
- return /* @__PURE__ */ React66.createElement(
5291
+ return /* @__PURE__ */ React68.createElement(
5358
5292
  ImageCard,
5359
5293
  {
5360
5294
  ...commonProps,
@@ -5364,7 +5298,7 @@ var ArtifactCard = React66.forwardRef(
5364
5298
  }
5365
5299
  );
5366
5300
  case "VIDEO":
5367
- return /* @__PURE__ */ React66.createElement(
5301
+ return /* @__PURE__ */ React68.createElement(
5368
5302
  VideoCard,
5369
5303
  {
5370
5304
  ...commonProps,
@@ -5374,7 +5308,7 @@ var ArtifactCard = React66.forwardRef(
5374
5308
  }
5375
5309
  );
5376
5310
  case "AUDIO":
5377
- return /* @__PURE__ */ React66.createElement(
5311
+ return /* @__PURE__ */ React68.createElement(
5378
5312
  AudioCard,
5379
5313
  {
5380
5314
  ...commonProps,
@@ -5383,7 +5317,7 @@ var ArtifactCard = React66.forwardRef(
5383
5317
  }
5384
5318
  );
5385
5319
  case "PDF":
5386
- return /* @__PURE__ */ React66.createElement(
5320
+ return /* @__PURE__ */ React68.createElement(
5387
5321
  PdfCard,
5388
5322
  {
5389
5323
  ...commonProps,
@@ -5391,7 +5325,7 @@ var ArtifactCard = React66.forwardRef(
5391
5325
  }
5392
5326
  );
5393
5327
  case "SCRIPT":
5394
- return /* @__PURE__ */ React66.createElement(
5328
+ return /* @__PURE__ */ React68.createElement(
5395
5329
  ScriptCard,
5396
5330
  {
5397
5331
  ...commonProps,
@@ -5400,7 +5334,7 @@ var ArtifactCard = React66.forwardRef(
5400
5334
  }
5401
5335
  );
5402
5336
  case "TEXT":
5403
- return /* @__PURE__ */ React66.createElement(
5337
+ return /* @__PURE__ */ React68.createElement(
5404
5338
  TextCard,
5405
5339
  {
5406
5340
  ...commonProps,
@@ -5411,12 +5345,14 @@ var ArtifactCard = React66.forwardRef(
5411
5345
  )
5412
5346
  }
5413
5347
  );
5414
- default:
5415
- return null;
5348
+ default: {
5349
+ const _exhaustive = artifact.type;
5350
+ return _exhaustive;
5351
+ }
5416
5352
  }
5417
5353
  };
5418
5354
  const isCardExpandable = !!onExpand && (artifact.type === "IMAGE" || artifact.type === "PDF" || artifact.type === "SCRIPT" || artifact.type === "TEXT");
5419
- return /* @__PURE__ */ React66.createElement(
5355
+ return /* @__PURE__ */ React68.createElement(
5420
5356
  "div",
5421
5357
  {
5422
5358
  ref,
@@ -5429,7 +5365,7 @@ var ArtifactCard = React66.forwardRef(
5429
5365
  onClick: isCardExpandable ? handleExpand : void 0,
5430
5366
  ...props
5431
5367
  },
5432
- onExpand && /* @__PURE__ */ React66.createElement(
5368
+ onExpand && /* @__PURE__ */ React68.createElement(
5433
5369
  "button",
5434
5370
  {
5435
5371
  onClick: handleExpand,
@@ -5440,7 +5376,7 @@ var ArtifactCard = React66.forwardRef(
5440
5376
  ),
5441
5377
  "aria-label": "Expand artifact"
5442
5378
  },
5443
- /* @__PURE__ */ React66.createElement(ExpandIcon, { className: "w-4 h-4" })
5379
+ /* @__PURE__ */ React68.createElement(ExpandIcon, { className: "w-4 h-4" })
5444
5380
  ),
5445
5381
  renderContent()
5446
5382
  );
@@ -5449,16 +5385,16 @@ var ArtifactCard = React66.forwardRef(
5449
5385
  ArtifactCard.displayName = "ArtifactCard";
5450
5386
 
5451
5387
  // src/components/ArtifactGroup.tsx
5452
- import React67, { useEffect as useEffect11, useRef as useRef9, useState as useState14 } from "react";
5388
+ import React69, { useEffect as useEffect11, useRef as useRef10, useState as useState15 } from "react";
5453
5389
  var LAYER_OFFSET = "8px";
5454
5390
  var LAYER_OFFSET_2X = "16px";
5455
- var ArtifactGroup = React67.forwardRef(
5391
+ var ArtifactGroup = React69.forwardRef(
5456
5392
  ({ node, onClick, className, ...props }, ref) => {
5457
5393
  const children = node.children;
5458
5394
  const count = children.length;
5459
5395
  const frontChild = children[0];
5460
- const prevCountRef = useRef9(count);
5461
- const [badgePing, setBadgePing] = useState14(false);
5396
+ const prevCountRef = useRef10(count);
5397
+ const [badgePing, setBadgePing] = useState15(false);
5462
5398
  useEffect11(() => {
5463
5399
  if (count !== prevCountRef.current) {
5464
5400
  prevCountRef.current = count;
@@ -5474,21 +5410,21 @@ var ArtifactGroup = React67.forwardRef(
5474
5410
  };
5475
5411
  const renderFrontContent = () => {
5476
5412
  if (!frontChild) {
5477
- return /* @__PURE__ */ React67.createElement("div", { className: "w-full aspect-video bg-graphite border border-ash/40 flex items-center justify-center" }, /* @__PURE__ */ React67.createElement("span", { className: "text-silver text-sm" }, "Empty group"));
5413
+ return /* @__PURE__ */ React69.createElement("div", { className: "w-full aspect-video bg-graphite border border-ash/40 flex items-center justify-center" }, /* @__PURE__ */ React69.createElement("span", { className: "text-silver text-sm" }, "Empty group"));
5478
5414
  }
5479
5415
  if (frontChild.type === "ARTIFACT" && frontChild.artifact) {
5480
- return /* @__PURE__ */ React67.createElement(ArtifactCard, { artifact: frontChild.artifact, className: "w-full" });
5416
+ return /* @__PURE__ */ React69.createElement(ArtifactCard, { artifact: frontChild.artifact, className: "w-full" });
5481
5417
  }
5482
- return /* @__PURE__ */ React67.createElement(
5418
+ return /* @__PURE__ */ React69.createElement(
5483
5419
  "div",
5484
5420
  {
5485
5421
  className: "w-full aspect-video bg-graphite border border-gold/30 flex flex-col items-center justify-center gap-2 p-4"
5486
5422
  },
5487
- /* @__PURE__ */ React67.createElement("span", { className: "text-sm text-silver uppercase tracking-wider" }, frontChild.type === "GROUP" ? "Group" : "Variants"),
5488
- /* @__PURE__ */ React67.createElement("span", { className: "text-white font-semibold" }, frontChild.label)
5423
+ /* @__PURE__ */ React69.createElement("span", { className: "text-sm text-silver uppercase tracking-wider" }, frontChild.type === "GROUP" ? "Group" : "Variants"),
5424
+ /* @__PURE__ */ React69.createElement("span", { className: "text-white font-semibold" }, frontChild.label)
5489
5425
  );
5490
5426
  };
5491
- return /* @__PURE__ */ React67.createElement(
5427
+ return /* @__PURE__ */ React69.createElement(
5492
5428
  "div",
5493
5429
  {
5494
5430
  ref,
@@ -5508,21 +5444,21 @@ var ArtifactGroup = React67.forwardRef(
5508
5444
  "aria-label": `${node.label} \u2014 ${count} items`,
5509
5445
  ...props
5510
5446
  },
5511
- /* @__PURE__ */ React67.createElement(Card, { noPadding: true, className: "p-5" }, /* @__PURE__ */ React67.createElement("h3", { className: "text-lg font-semibold text-white m-0 mb-4" }, node.label), /* @__PURE__ */ React67.createElement("div", { style: { paddingRight: LAYER_OFFSET_2X, paddingBottom: LAYER_OFFSET_2X } }, /* @__PURE__ */ React67.createElement("div", { className: "relative" }, /* @__PURE__ */ React67.createElement(
5447
+ /* @__PURE__ */ React69.createElement(Card, { noPadding: true, className: "p-5" }, /* @__PURE__ */ React69.createElement("h3", { className: "text-lg font-semibold text-white m-0 mb-4" }, node.label), /* @__PURE__ */ React69.createElement("div", { style: { paddingRight: LAYER_OFFSET_2X, paddingBottom: LAYER_OFFSET_2X } }, /* @__PURE__ */ React69.createElement("div", { className: "relative" }, /* @__PURE__ */ React69.createElement(
5512
5448
  "div",
5513
5449
  {
5514
5450
  className: "absolute inset-0 bg-charcoal border border-ash/30 pointer-events-none",
5515
5451
  style: { transform: `translate(${LAYER_OFFSET_2X}, ${LAYER_OFFSET_2X})` },
5516
5452
  "aria-hidden": "true"
5517
5453
  }
5518
- ), /* @__PURE__ */ React67.createElement(
5454
+ ), /* @__PURE__ */ React69.createElement(
5519
5455
  "div",
5520
5456
  {
5521
5457
  className: "absolute inset-0 bg-charcoal border border-ash/40 pointer-events-none",
5522
5458
  style: { transform: `translate(${LAYER_OFFSET}, ${LAYER_OFFSET})` },
5523
5459
  "aria-hidden": "true"
5524
5460
  }
5525
- ), /* @__PURE__ */ React67.createElement("div", { className: "relative transition-transform duration-200 group-hover:-translate-y-0.5" }, renderFrontContent()), /* @__PURE__ */ React67.createElement(
5461
+ ), /* @__PURE__ */ React69.createElement("div", { className: "relative transition-transform duration-200 group-hover:-translate-y-0.5" }, renderFrontContent()), /* @__PURE__ */ React69.createElement(
5526
5462
  "div",
5527
5463
  {
5528
5464
  className: "absolute -top-2 -right-2 z-10 min-w-6 h-6 px-1.5 flex items-center justify-center bg-gold text-obsidian text-xs font-bold",
@@ -5536,13 +5472,13 @@ var ArtifactGroup = React67.forwardRef(
5536
5472
  ArtifactGroup.displayName = "ArtifactGroup";
5537
5473
 
5538
5474
  // src/components/ArtifactVariantStack.tsx
5539
- import React68 from "react";
5540
- var ArtifactVariantStack = React68.forwardRef(
5475
+ import React70 from "react";
5476
+ var ArtifactVariantStack = React70.forwardRef(
5541
5477
  ({ node, onExpandArtifact, onGroupClick, className, ...props }, ref) => {
5542
5478
  const children = node.children;
5543
5479
  const renderChild = (child) => {
5544
5480
  if (child.type === "ARTIFACT" && child.artifact) {
5545
- return /* @__PURE__ */ React68.createElement("div", { key: child.id, className: "flex-1 min-w-0" }, /* @__PURE__ */ React68.createElement(
5481
+ return /* @__PURE__ */ React70.createElement("div", { key: child.id, className: "flex-1 min-w-0" }, /* @__PURE__ */ React70.createElement(
5546
5482
  ArtifactCard,
5547
5483
  {
5548
5484
  artifact: child.artifact,
@@ -5552,18 +5488,18 @@ var ArtifactVariantStack = React68.forwardRef(
5552
5488
  ));
5553
5489
  }
5554
5490
  if (child.type === "GROUP") {
5555
- return /* @__PURE__ */ React68.createElement("div", { key: child.id, className: "flex-1 min-w-0" }, /* @__PURE__ */ React68.createElement(ArtifactGroup, { node: child, onClick: onGroupClick }));
5491
+ return /* @__PURE__ */ React70.createElement("div", { key: child.id, className: "flex-1 min-w-0" }, /* @__PURE__ */ React70.createElement(ArtifactGroup, { node: child, onClick: onGroupClick }));
5556
5492
  }
5557
- return /* @__PURE__ */ React68.createElement("div", { key: child.id, className: "flex-1 min-w-0" }, /* @__PURE__ */ React68.createElement(
5493
+ return /* @__PURE__ */ React70.createElement("div", { key: child.id, className: "flex-1 min-w-0" }, /* @__PURE__ */ React70.createElement(
5558
5494
  "div",
5559
5495
  {
5560
5496
  className: "aspect-video bg-graphite border border-gold/30 flex flex-col items-center justify-center gap-2 p-4"
5561
5497
  },
5562
- /* @__PURE__ */ React68.createElement("span", { className: "text-xs text-silver uppercase tracking-wider" }, "Variants"),
5563
- /* @__PURE__ */ React68.createElement("span", { className: "text-sm text-white font-semibold truncate max-w-full" }, child.label)
5498
+ /* @__PURE__ */ React70.createElement("span", { className: "text-xs text-silver uppercase tracking-wider" }, "Variants"),
5499
+ /* @__PURE__ */ React70.createElement("span", { className: "text-sm text-white font-semibold truncate max-w-full" }, child.label)
5564
5500
  ));
5565
5501
  };
5566
- return /* @__PURE__ */ React68.createElement(
5502
+ return /* @__PURE__ */ React70.createElement(
5567
5503
  Card,
5568
5504
  {
5569
5505
  ref,
@@ -5571,17 +5507,17 @@ var ArtifactVariantStack = React68.forwardRef(
5571
5507
  className: cx("w-full p-5", className),
5572
5508
  ...props
5573
5509
  },
5574
- /* @__PURE__ */ React68.createElement("h3", { className: "text-lg font-semibold text-white m-0 mb-4" }, node.label),
5575
- /* @__PURE__ */ React68.createElement("div", { className: "flex gap-3" }, children.map(renderChild))
5510
+ /* @__PURE__ */ React70.createElement("h3", { className: "text-lg font-semibold text-white m-0 mb-4" }, node.label),
5511
+ /* @__PURE__ */ React70.createElement("div", { className: "flex gap-3" }, children.map(renderChild))
5576
5512
  );
5577
5513
  }
5578
5514
  );
5579
5515
  ArtifactVariantStack.displayName = "ArtifactVariantStack";
5580
5516
 
5581
5517
  // src/components/chat/hooks/useArtifactTreeNavigation.ts
5582
- import { useCallback as useCallback14, useMemo as useMemo2, useState as useState15 } from "react";
5518
+ import { useCallback as useCallback16, useMemo as useMemo2, useState as useState16 } from "react";
5583
5519
  function useArtifactTreeNavigation(rootNodes) {
5584
- const [stack, setStack] = useState15([]);
5520
+ const [stack, setStack] = useState16([]);
5585
5521
  const currentNodes = useMemo2(() => {
5586
5522
  if (stack.length === 0) return rootNodes;
5587
5523
  return stack[stack.length - 1].children;
@@ -5594,13 +5530,13 @@ function useArtifactTreeNavigation(rootNodes) {
5594
5530
  return entries;
5595
5531
  }, [stack]);
5596
5532
  const isAtRoot = stack.length === 0;
5597
- const navigateInto = useCallback14((node) => {
5533
+ const navigateInto = useCallback16((node) => {
5598
5534
  setStack((prev) => [...prev, node]);
5599
5535
  }, []);
5600
- const navigateTo = useCallback14((index) => {
5536
+ const navigateTo = useCallback16((index) => {
5601
5537
  setStack((prev) => prev.slice(0, index));
5602
5538
  }, []);
5603
- const navigateBack = useCallback14(() => {
5539
+ const navigateBack = useCallback16(() => {
5604
5540
  setStack((prev) => prev.slice(0, -1));
5605
5541
  }, []);
5606
5542
  return {
@@ -5619,55 +5555,47 @@ function ArtifactModal({
5619
5555
  artifact,
5620
5556
  onClose
5621
5557
  }) {
5622
- useEffect12(() => {
5623
- const handleKeyDown = (e) => {
5624
- if (e.key === "Escape") {
5625
- onClose();
5626
- }
5627
- };
5628
- document.addEventListener("keydown", handleKeyDown);
5629
- return () => document.removeEventListener("keydown", handleKeyDown);
5630
- }, [onClose]);
5631
- const handleBackdropClick = useCallback15((e) => {
5558
+ useEscapeKey(onClose);
5559
+ const handleBackdropClick = useCallback17((e) => {
5632
5560
  if (e.target === e.currentTarget) {
5633
5561
  onClose();
5634
5562
  }
5635
5563
  }, [onClose]);
5636
- return /* @__PURE__ */ React69.createElement(
5564
+ return /* @__PURE__ */ React71.createElement(
5637
5565
  "div",
5638
5566
  {
5639
5567
  className: "fixed inset-0 z-50 flex items-center justify-center bg-void/90 backdrop-blur-sm animate-fade-in",
5640
5568
  onClick: handleBackdropClick
5641
5569
  },
5642
- /* @__PURE__ */ React69.createElement(
5570
+ /* @__PURE__ */ React71.createElement(
5643
5571
  "div",
5644
5572
  {
5645
5573
  className: "relative w-11/12 h-5/6 max-w-6xl bg-charcoal border border-ash/40 flex flex-col overflow-hidden"
5646
5574
  },
5647
- /* @__PURE__ */ React69.createElement(
5575
+ /* @__PURE__ */ React71.createElement(
5648
5576
  "div",
5649
5577
  {
5650
5578
  className: "flex items-center justify-between p-4 border-b border-ash/40 shrink-0"
5651
5579
  },
5652
- /* @__PURE__ */ React69.createElement("div", null, artifact.title && /* @__PURE__ */ React69.createElement("h3", { className: "text-sm font-semibold text-white" }, artifact.title), artifact.subtitle && /* @__PURE__ */ React69.createElement("p", { className: "text-xs text-silver" }, artifact.subtitle)),
5653
- /* @__PURE__ */ React69.createElement(
5580
+ /* @__PURE__ */ React71.createElement("div", null, artifact.title && /* @__PURE__ */ React71.createElement("h3", { className: "text-sm font-semibold text-white" }, artifact.title), artifact.subtitle && /* @__PURE__ */ React71.createElement("p", { className: "text-xs text-silver" }, artifact.subtitle)),
5581
+ /* @__PURE__ */ React71.createElement(
5654
5582
  "button",
5655
5583
  {
5656
5584
  onClick: onClose,
5657
5585
  className: "p-2 text-silver hover:text-white hover:bg-ash/20 transition-colors",
5658
5586
  "aria-label": "Close modal"
5659
5587
  },
5660
- /* @__PURE__ */ React69.createElement(CloseIcon, { className: "w-5 h-5" })
5588
+ /* @__PURE__ */ React71.createElement(CloseIcon, { className: "w-5 h-5" })
5661
5589
  )
5662
5590
  ),
5663
- /* @__PURE__ */ React69.createElement("div", { className: "flex-1 overflow-auto p-4" }, artifact.type === "IMAGE" && /* @__PURE__ */ React69.createElement(
5591
+ /* @__PURE__ */ React71.createElement("div", { className: "flex-1 overflow-auto p-4" }, artifact.type === "IMAGE" && /* @__PURE__ */ React71.createElement(
5664
5592
  "img",
5665
5593
  {
5666
5594
  src: artifact.url,
5667
5595
  alt: artifact.alt || "Artifact image",
5668
5596
  className: "max-w-full max-h-full object-contain mx-auto"
5669
5597
  }
5670
- ), artifact.type === "VIDEO" && /* @__PURE__ */ React69.createElement(
5598
+ ), artifact.type === "VIDEO" && /* @__PURE__ */ React71.createElement(
5671
5599
  VideoCard,
5672
5600
  {
5673
5601
  src: artifact.url || "",
@@ -5675,20 +5603,20 @@ function ArtifactModal({
5675
5603
  controls: true,
5676
5604
  className: "max-w-full max-h-full mx-auto"
5677
5605
  }
5678
- ), artifact.type === "AUDIO" && /* @__PURE__ */ React69.createElement(
5606
+ ), artifact.type === "AUDIO" && /* @__PURE__ */ React71.createElement(
5679
5607
  AudioCard,
5680
5608
  {
5681
5609
  src: artifact.url || "",
5682
5610
  controls: true,
5683
5611
  className: "max-w-xl mx-auto"
5684
5612
  }
5685
- ), artifact.type === "PDF" && /* @__PURE__ */ React69.createElement(
5613
+ ), artifact.type === "PDF" && /* @__PURE__ */ React71.createElement(
5686
5614
  PdfCard,
5687
5615
  {
5688
5616
  src: artifact.url || "",
5689
5617
  className: "h-full border-0"
5690
5618
  }
5691
- ), artifact.type === "TEXT" && /* @__PURE__ */ React69.createElement(
5619
+ ), artifact.type === "TEXT" && /* @__PURE__ */ React71.createElement(
5692
5620
  MarkdownContent,
5693
5621
  {
5694
5622
  content: artifact.inlineContent || "",
@@ -5698,7 +5626,7 @@ function ArtifactModal({
5698
5626
  artifact.mimeType === "text/plain" && "whitespace-pre-wrap"
5699
5627
  )
5700
5628
  }
5701
- ), artifact.type === "SCRIPT" && artifact.scriptElements && /* @__PURE__ */ React69.createElement(
5629
+ ), artifact.type === "SCRIPT" && artifact.scriptElements && /* @__PURE__ */ React71.createElement(
5702
5630
  ScriptCard,
5703
5631
  {
5704
5632
  elements: artifact.scriptElements,
@@ -5716,7 +5644,7 @@ function NodeRenderer({
5716
5644
  onGroupClick
5717
5645
  }) {
5718
5646
  if (node.type === "ARTIFACT" && node.artifact) {
5719
- return /* @__PURE__ */ React69.createElement(
5647
+ return /* @__PURE__ */ React71.createElement(
5720
5648
  ArtifactCard,
5721
5649
  {
5722
5650
  artifact: node.artifact,
@@ -5726,10 +5654,10 @@ function NodeRenderer({
5726
5654
  );
5727
5655
  }
5728
5656
  if (node.type === "GROUP") {
5729
- return /* @__PURE__ */ React69.createElement(ArtifactGroup, { node, onClick: onGroupClick });
5657
+ return /* @__PURE__ */ React71.createElement(ArtifactGroup, { node, onClick: onGroupClick });
5730
5658
  }
5731
5659
  if (node.type === "VARIANT_SET") {
5732
- return /* @__PURE__ */ React69.createElement(
5660
+ return /* @__PURE__ */ React71.createElement(
5733
5661
  ArtifactVariantStack,
5734
5662
  {
5735
5663
  node,
@@ -5740,32 +5668,32 @@ function NodeRenderer({
5740
5668
  }
5741
5669
  return null;
5742
5670
  }
5743
- var ArtifactsPanel = React69.forwardRef(
5671
+ var ArtifactsPanel = React71.forwardRef(
5744
5672
  ({
5745
5673
  nodes,
5746
5674
  loading,
5747
5675
  className,
5748
5676
  ...rest
5749
5677
  }, ref) => {
5750
- const [expandedArtifact, setExpandedArtifact] = useState16(null);
5751
- const [zoomIndex, setZoomIndex] = useState16(ZOOM_LEVELS.length - 1);
5678
+ const [expandedArtifact, setExpandedArtifact] = useState17(null);
5679
+ const [zoomIndex, setZoomIndex] = useState17(ZOOM_LEVELS.length - 1);
5752
5680
  const treeNav = useArtifactTreeNavigation(nodes || []);
5753
5681
  const hasNodes = !!nodes && nodes.length > 0;
5754
- const handleExpandArtifact = useCallback15((artifact) => {
5682
+ const handleExpandArtifact = useCallback17((artifact) => {
5755
5683
  setExpandedArtifact(artifact);
5756
5684
  }, []);
5757
- const handleGroupClick = useCallback15((node) => {
5685
+ const handleGroupClick = useCallback17((node) => {
5758
5686
  treeNav.navigateInto(node);
5759
5687
  }, [treeNav]);
5760
- const zoomIn = useCallback15(() => {
5688
+ const zoomIn = useCallback17(() => {
5761
5689
  setZoomIndex((prev) => Math.min(prev + 1, ZOOM_LEVELS.length - 1));
5762
5690
  }, []);
5763
- const zoomOut = useCallback15(() => {
5691
+ const zoomOut = useCallback17(() => {
5764
5692
  setZoomIndex((prev) => Math.max(prev - 1, 0));
5765
5693
  }, []);
5766
5694
  const currentZoom = ZOOM_LEVELS[zoomIndex];
5767
- const contentRef = useRef10(null);
5768
- const [contentHeight, setContentHeight] = useState16(void 0);
5695
+ const contentRef = useRef11(null);
5696
+ const [contentHeight, setContentHeight] = useState17(void 0);
5769
5697
  useEffect12(() => {
5770
5698
  const el = contentRef.current;
5771
5699
  if (!el) return;
@@ -5775,7 +5703,7 @@ var ArtifactsPanel = React69.forwardRef(
5775
5703
  observer.observe(el);
5776
5704
  return () => observer.disconnect();
5777
5705
  }, []);
5778
- return /* @__PURE__ */ React69.createElement(React69.Fragment, null, /* @__PURE__ */ React69.createElement(
5706
+ return /* @__PURE__ */ React71.createElement(React71.Fragment, null, /* @__PURE__ */ React71.createElement(
5779
5707
  "div",
5780
5708
  {
5781
5709
  ref,
@@ -5786,19 +5714,19 @@ var ArtifactsPanel = React69.forwardRef(
5786
5714
  ),
5787
5715
  ...rest
5788
5716
  },
5789
- /* @__PURE__ */ React69.createElement(
5717
+ /* @__PURE__ */ React71.createElement(
5790
5718
  "div",
5791
5719
  {
5792
5720
  className: "flex items-center justify-between p-4 border-b border-ash/40 shrink-0"
5793
5721
  },
5794
- /* @__PURE__ */ React69.createElement("h3", { className: "text-sm font-semibold text-white" }, "Artifacts"),
5795
- hasNodes && /* @__PURE__ */ React69.createElement(
5722
+ /* @__PURE__ */ React71.createElement("h3", { className: "text-sm font-semibold text-white" }, "Artifacts"),
5723
+ hasNodes && /* @__PURE__ */ React71.createElement(
5796
5724
  "div",
5797
5725
  {
5798
5726
  className: "flex items-center gap-0.5",
5799
5727
  "data-testid": "zoom-controls"
5800
5728
  },
5801
- /* @__PURE__ */ React69.createElement(
5729
+ /* @__PURE__ */ React71.createElement(
5802
5730
  "button",
5803
5731
  {
5804
5732
  onClick: zoomOut,
@@ -5812,8 +5740,8 @@ var ArtifactsPanel = React69.forwardRef(
5812
5740
  },
5813
5741
  "\u2212"
5814
5742
  ),
5815
- /* @__PURE__ */ React69.createElement("span", { className: "text-xs text-silver w-8 text-center tabular-nums", "data-testid": "zoom-level" }, Math.round(currentZoom * 100), "%"),
5816
- /* @__PURE__ */ React69.createElement(
5743
+ /* @__PURE__ */ React71.createElement("span", { className: "text-xs text-silver w-8 text-center tabular-nums", "data-testid": "zoom-level" }, Math.round(currentZoom * 100), "%"),
5744
+ /* @__PURE__ */ React71.createElement(
5817
5745
  "button",
5818
5746
  {
5819
5747
  onClick: zoomIn,
@@ -5829,7 +5757,7 @@ var ArtifactsPanel = React69.forwardRef(
5829
5757
  )
5830
5758
  )
5831
5759
  ),
5832
- hasNodes && !treeNav.isAtRoot && /* @__PURE__ */ React69.createElement(
5760
+ hasNodes && !treeNav.isAtRoot && /* @__PURE__ */ React71.createElement(
5833
5761
  "nav",
5834
5762
  {
5835
5763
  className: "flex items-center gap-1 px-4 py-2 border-b border-ash/40 shrink-0 overflow-x-auto text-xs",
@@ -5838,7 +5766,7 @@ var ArtifactsPanel = React69.forwardRef(
5838
5766
  },
5839
5767
  treeNav.breadcrumbs.map((crumb, i) => {
5840
5768
  const isLast = i === treeNav.breadcrumbs.length - 1;
5841
- return /* @__PURE__ */ React69.createElement("span", { key: i, className: "flex items-center gap-1 shrink-0" }, i > 0 && /* @__PURE__ */ React69.createElement(ChevronRightIcon, { className: "w-3 h-3 text-silver/50", "aria-hidden": true }), isLast ? /* @__PURE__ */ React69.createElement("span", { className: "text-gold font-medium" }, crumb.label) : /* @__PURE__ */ React69.createElement(
5769
+ return /* @__PURE__ */ React71.createElement("span", { key: i, className: "flex items-center gap-1 shrink-0" }, i > 0 && /* @__PURE__ */ React71.createElement(ChevronRightIcon, { className: "w-3 h-3 text-silver/50", "aria-hidden": true }), isLast ? /* @__PURE__ */ React71.createElement("span", { className: "text-gold font-medium" }, crumb.label) : /* @__PURE__ */ React71.createElement(
5842
5770
  "button",
5843
5771
  {
5844
5772
  onClick: () => treeNav.navigateTo(i),
@@ -5848,18 +5776,18 @@ var ArtifactsPanel = React69.forwardRef(
5848
5776
  ));
5849
5777
  })
5850
5778
  ),
5851
- /* @__PURE__ */ React69.createElement(
5779
+ /* @__PURE__ */ React71.createElement(
5852
5780
  "div",
5853
5781
  {
5854
5782
  className: "flex-1 overflow-auto relative",
5855
5783
  "data-testid": "artifacts-scroll-area"
5856
5784
  },
5857
- /* @__PURE__ */ React69.createElement(
5785
+ /* @__PURE__ */ React71.createElement(
5858
5786
  "div",
5859
5787
  {
5860
5788
  style: currentZoom !== 1 && contentHeight !== void 0 ? { height: contentHeight * currentZoom } : void 0
5861
5789
  },
5862
- /* @__PURE__ */ React69.createElement(
5790
+ /* @__PURE__ */ React71.createElement(
5863
5791
  "div",
5864
5792
  {
5865
5793
  ref: contentRef,
@@ -5870,7 +5798,7 @@ var ArtifactsPanel = React69.forwardRef(
5870
5798
  transformOrigin: "top center"
5871
5799
  } : void 0
5872
5800
  },
5873
- treeNav.currentNodes.length === 0 ? /* @__PURE__ */ React69.createElement("p", { className: "text-xs text-silver/60 text-center py-8" }, hasNodes ? "Empty group" : "No artifacts to display") : treeNav.currentNodes.map((node) => /* @__PURE__ */ React69.createElement(
5801
+ treeNav.currentNodes.length === 0 ? /* @__PURE__ */ React71.createElement("p", { className: "text-xs text-silver/60 text-center py-8" }, hasNodes ? "Empty group" : "No artifacts to display") : treeNav.currentNodes.map((node) => /* @__PURE__ */ React71.createElement(
5874
5802
  NodeRenderer,
5875
5803
  {
5876
5804
  key: node.id,
@@ -5883,7 +5811,7 @@ var ArtifactsPanel = React69.forwardRef(
5883
5811
  )
5884
5812
  )
5885
5813
  )
5886
- ), expandedArtifact && /* @__PURE__ */ React69.createElement(
5814
+ ), expandedArtifact && /* @__PURE__ */ React71.createElement(
5887
5815
  ArtifactModal,
5888
5816
  {
5889
5817
  artifact: expandedArtifact,
@@ -5893,8 +5821,8 @@ var ArtifactsPanel = React69.forwardRef(
5893
5821
  }
5894
5822
  );
5895
5823
  ArtifactsPanel.displayName = "ArtifactsPanel";
5896
- var ArtifactsPanelToggle = React69.forwardRef(({ artifactCount = 0, onExpand, className, ...rest }, ref) => {
5897
- return /* @__PURE__ */ React69.createElement(
5824
+ var ArtifactsPanelToggle = React71.forwardRef(({ artifactCount = 0, onExpand, className, ...rest }, ref) => {
5825
+ return /* @__PURE__ */ React71.createElement(
5898
5826
  "button",
5899
5827
  {
5900
5828
  ref,
@@ -5911,24 +5839,8 @@ var ArtifactsPanelToggle = React69.forwardRef(({ artifactCount = 0, onExpand, cl
5911
5839
  "aria-label": "Expand artifacts panel",
5912
5840
  ...rest
5913
5841
  },
5914
- /* @__PURE__ */ React69.createElement(
5915
- "svg",
5916
- {
5917
- xmlns: "http://www.w3.org/2000/svg",
5918
- viewBox: "0 0 20 20",
5919
- fill: "currentColor",
5920
- className: "w-5 h-5"
5921
- },
5922
- /* @__PURE__ */ React69.createElement(
5923
- "path",
5924
- {
5925
- fillRule: "evenodd",
5926
- d: "M2 4.5A1.5 1.5 0 013.5 3h13A1.5 1.5 0 0118 4.5v11a1.5 1.5 0 01-1.5 1.5h-13A1.5 1.5 0 012 15.5v-11zM4 5v1h1V5H4zm2 0v1h1V5H6zm7 0v1h1V5h-1zm2 0v1h1V5h-1zM4 14v1h1v-1H4zm2 0v1h1v-1H6zm7 0v1h1v-1h-1zm2 0v1h1v-1h-1zM8 8.118a.5.5 0 01.757-.429l4 2.382a.5.5 0 010 .858l-4 2.382A.5.5 0 018 12.882V8.118z",
5927
- clipRule: "evenodd"
5928
- }
5929
- )
5930
- ),
5931
- artifactCount > 0 && /* @__PURE__ */ React69.createElement(
5842
+ /* @__PURE__ */ React71.createElement(Image, { className: "w-5 h-5", "aria-hidden": true }),
5843
+ artifactCount > 0 && /* @__PURE__ */ React71.createElement(
5932
5844
  "span",
5933
5845
  {
5934
5846
  className: "absolute -top-1 -right-1 w-4 h-4 bg-gold text-obsidian text-xs font-medium flex items-center justify-center"
@@ -5940,7 +5852,8 @@ var ArtifactsPanelToggle = React69.forwardRef(({ artifactCount = 0, onExpand, cl
5940
5852
  ArtifactsPanelToggle.displayName = "ArtifactsPanelToggle";
5941
5853
 
5942
5854
  // src/components/chat/HistoryPanel.tsx
5943
- import React70, { useCallback as useCallback16, useEffect as useEffect13, useMemo as useMemo3, useRef as useRef11, useState as useState17 } from "react";
5855
+ import React72, { useCallback as useCallback18, useEffect as useEffect13, useMemo as useMemo3, useRef as useRef12, useState as useState18 } from "react";
5856
+ import { ChevronDown as ChevronDown2, Pencil as Pencil2 } from "lucide-react";
5944
5857
  function parseTimestamp(ts) {
5945
5858
  if (ts == null) {
5946
5859
  return null;
@@ -5976,66 +5889,18 @@ function groupConversations(conversations) {
5976
5889
  { key: "older", label: "Older", conversations: olderList }
5977
5890
  ].filter((g) => g.conversations.length > 0);
5978
5891
  }
5979
- function ChevronDownIcon({ className }) {
5980
- return /* @__PURE__ */ React70.createElement(
5981
- "svg",
5982
- {
5983
- xmlns: "http://www.w3.org/2000/svg",
5984
- viewBox: "0 0 20 20",
5985
- fill: "currentColor",
5986
- className,
5987
- "aria-hidden": "true"
5988
- },
5989
- /* @__PURE__ */ React70.createElement(
5990
- "path",
5991
- {
5992
- fillRule: "evenodd",
5993
- d: "M5.23 7.21a.75.75 0 011.06.02L10 11.06l3.71-3.83a.75.75 0 111.08 1.04l-4.25 4.39a.75.75 0 01-1.08 0L5.21 8.27a.75.75 0 01.02-1.06z",
5994
- clipRule: "evenodd"
5995
- }
5996
- )
5997
- );
5998
- }
5999
- function PencilIcon2({ className }) {
6000
- return /* @__PURE__ */ React70.createElement(
6001
- "svg",
6002
- {
6003
- xmlns: "http://www.w3.org/2000/svg",
6004
- viewBox: "0 0 20 20",
6005
- fill: "currentColor",
6006
- className,
6007
- "aria-hidden": "true"
6008
- },
6009
- /* @__PURE__ */ React70.createElement(
6010
- "path",
6011
- {
6012
- d: "M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z"
6013
- }
6014
- )
6015
- );
6016
- }
6017
5892
  function ProjectFilter({
6018
5893
  projects,
6019
5894
  value,
6020
5895
  onChange,
6021
5896
  className
6022
5897
  }) {
6023
- const [open, setOpen] = useState17(false);
6024
- const ref = useRef11(null);
6025
- useEffect13(() => {
6026
- if (!open) {
6027
- return;
6028
- }
6029
- const handler = (e) => {
6030
- if (ref.current && !ref.current.contains(e.target)) {
6031
- setOpen(false);
6032
- }
6033
- };
6034
- document.addEventListener("mousedown", handler);
6035
- return () => document.removeEventListener("mousedown", handler);
6036
- }, [open]);
5898
+ const [open, setOpen] = useState18(false);
5899
+ const ref = useRef12(null);
5900
+ const closeFilter = useCallback18(() => setOpen(false), []);
5901
+ useClickOutside(ref, closeFilter, open);
6037
5902
  const label = value ?? "All projects";
6038
- return /* @__PURE__ */ React70.createElement("div", { className: cx("relative min-w-0", className), ref }, /* @__PURE__ */ React70.createElement(
5903
+ return /* @__PURE__ */ React72.createElement("div", { className: cx("relative min-w-0", className), ref }, /* @__PURE__ */ React72.createElement(
6039
5904
  "button",
6040
5905
  {
6041
5906
  type: "button",
@@ -6051,9 +5916,9 @@ function ProjectFilter({
6051
5916
  "transition-colors duration-150 min-w-0"
6052
5917
  )
6053
5918
  },
6054
- /* @__PURE__ */ React70.createElement("span", { className: "truncate" }, label),
6055
- /* @__PURE__ */ React70.createElement(ChevronDownIcon, { className: "w-3 h-3 shrink-0" })
6056
- ), open && /* @__PURE__ */ React70.createElement(
5919
+ /* @__PURE__ */ React72.createElement("span", { className: "truncate" }, label),
5920
+ /* @__PURE__ */ React72.createElement(ChevronDown2, { className: "w-3 h-3 shrink-0", "aria-hidden": true })
5921
+ ), open && /* @__PURE__ */ React72.createElement(
6057
5922
  "div",
6058
5923
  {
6059
5924
  role: "listbox",
@@ -6063,7 +5928,7 @@ function ProjectFilter({
6063
5928
  "max-h-60 overflow-y-auto"
6064
5929
  )
6065
5930
  },
6066
- /* @__PURE__ */ React70.createElement(
5931
+ /* @__PURE__ */ React72.createElement(
6067
5932
  "button",
6068
5933
  {
6069
5934
  type: "button",
@@ -6081,7 +5946,7 @@ function ProjectFilter({
6081
5946
  },
6082
5947
  "All projects"
6083
5948
  ),
6084
- projects.map((p) => /* @__PURE__ */ React70.createElement(
5949
+ projects.map((p) => /* @__PURE__ */ React72.createElement(
6085
5950
  "button",
6086
5951
  {
6087
5952
  key: p,
@@ -6107,33 +5972,33 @@ function ConversationRow({
6107
5972
  onSelect,
6108
5973
  onRename
6109
5974
  }) {
6110
- const [isEditing, setIsEditing] = useState17(false);
6111
- const [draft, setDraft] = useState17(conversation.title);
6112
- const inputRef = useRef11(null);
5975
+ const [isEditing, setIsEditing] = useState18(false);
5976
+ const [draft, setDraft] = useState18(conversation.title);
5977
+ const inputRef = useRef12(null);
6113
5978
  useEffect13(() => {
6114
5979
  if (isEditing && inputRef.current) {
6115
5980
  inputRef.current.focus();
6116
5981
  inputRef.current.select();
6117
5982
  }
6118
5983
  }, [isEditing]);
6119
- const startEdit = useCallback16((e) => {
5984
+ const startEdit = useCallback18((e) => {
6120
5985
  e.stopPropagation();
6121
5986
  setDraft(conversation.title);
6122
5987
  setIsEditing(true);
6123
5988
  }, [conversation.title]);
6124
- const commit = useCallback16(() => {
5989
+ const commit = useCallback18(() => {
6125
5990
  const trimmed = draft.trim();
6126
5991
  if (trimmed && trimmed !== conversation.title) {
6127
5992
  onRename?.(conversation.id, trimmed);
6128
5993
  }
6129
5994
  setIsEditing(false);
6130
5995
  }, [draft, conversation.id, conversation.title, onRename]);
6131
- const cancel = useCallback16(() => {
5996
+ const cancel = useCallback18(() => {
6132
5997
  setDraft(conversation.title);
6133
5998
  setIsEditing(false);
6134
5999
  }, [conversation.title]);
6135
6000
  if (isEditing) {
6136
- return /* @__PURE__ */ React70.createElement(
6001
+ return /* @__PURE__ */ React72.createElement(
6137
6002
  "div",
6138
6003
  {
6139
6004
  className: cx(
@@ -6141,7 +6006,7 @@ function ConversationRow({
6141
6006
  conversation.isActive ? "bg-ash/40" : "bg-ash/20"
6142
6007
  )
6143
6008
  },
6144
- /* @__PURE__ */ React70.createElement(
6009
+ /* @__PURE__ */ React72.createElement(
6145
6010
  "input",
6146
6011
  {
6147
6012
  ref: inputRef,
@@ -6166,10 +6031,10 @@ function ConversationRow({
6166
6031
  "aria-label": "Conversation title"
6167
6032
  }
6168
6033
  ),
6169
- conversation.project && /* @__PURE__ */ React70.createElement("p", { className: "text-xs text-silver/60 truncate mt-1" }, conversation.project)
6034
+ conversation.project && /* @__PURE__ */ React72.createElement("p", { className: "text-xs text-silver/60 truncate mt-1" }, conversation.project)
6170
6035
  );
6171
6036
  }
6172
- return /* @__PURE__ */ React70.createElement("div", { className: "relative group" }, /* @__PURE__ */ React70.createElement(
6037
+ return /* @__PURE__ */ React72.createElement("div", { className: "relative group" }, /* @__PURE__ */ React72.createElement(
6173
6038
  "button",
6174
6039
  {
6175
6040
  onClick: () => onSelect?.(conversation.id),
@@ -6179,7 +6044,7 @@ function ConversationRow({
6179
6044
  conversation.isActive ? "bg-ash/40 text-white" : "text-silver hover:bg-ash/20 hover:text-white"
6180
6045
  )
6181
6046
  },
6182
- /* @__PURE__ */ React70.createElement(
6047
+ /* @__PURE__ */ React72.createElement(
6183
6048
  "p",
6184
6049
  {
6185
6050
  className: cx(
@@ -6189,8 +6054,8 @@ function ConversationRow({
6189
6054
  },
6190
6055
  conversation.title
6191
6056
  ),
6192
- conversation.project && /* @__PURE__ */ React70.createElement("p", { className: "text-xs text-silver/60 truncate mt-0.5" }, conversation.project)
6193
- ), onRename && /* @__PURE__ */ React70.createElement(
6057
+ conversation.project && /* @__PURE__ */ React72.createElement("p", { className: "text-xs text-silver/60 truncate mt-0.5" }, conversation.project)
6058
+ ), onRename && /* @__PURE__ */ React72.createElement(
6194
6059
  "button",
6195
6060
  {
6196
6061
  type: "button",
@@ -6203,7 +6068,7 @@ function ConversationRow({
6203
6068
  "transition-opacity duration-150"
6204
6069
  )
6205
6070
  },
6206
- /* @__PURE__ */ React70.createElement(PencilIcon2, { className: "w-3.5 h-3.5" })
6071
+ /* @__PURE__ */ React72.createElement(Pencil2, { className: "w-3.5 h-3.5", "aria-hidden": true })
6207
6072
  ));
6208
6073
  }
6209
6074
  function HistoryPanel({
@@ -6212,7 +6077,7 @@ function HistoryPanel({
6212
6077
  onNewChat,
6213
6078
  onRenameConversation
6214
6079
  }) {
6215
- const [projectFilter, setProjectFilter] = useState17(null);
6080
+ const [projectFilter, setProjectFilter] = useState18(null);
6216
6081
  const projects = useMemo3(() => {
6217
6082
  const set = /* @__PURE__ */ new Set();
6218
6083
  for (const c of conversations) {
@@ -6238,7 +6103,7 @@ function HistoryPanel({
6238
6103
  [filteredConversations]
6239
6104
  );
6240
6105
  const hasFilter = projects.length > 0;
6241
- return /* @__PURE__ */ React70.createElement("div", { className: "h-full flex flex-col" }, /* @__PURE__ */ React70.createElement("div", { className: "px-4 py-3 border-b border-ash/40 shrink-0 flex items-center gap-2" }, /* @__PURE__ */ React70.createElement("h3", { className: "text-xs font-medium text-white shrink-0" }, "History"), (hasFilter || onNewChat) && /* @__PURE__ */ React70.createElement("div", { className: "flex items-center gap-2 flex-1 min-w-0" }, hasFilter && /* @__PURE__ */ React70.createElement(React70.Fragment, null, /* @__PURE__ */ React70.createElement("div", { className: "w-px h-3 bg-ash/40 shrink-0 mx-1" }), /* @__PURE__ */ React70.createElement(
6106
+ return /* @__PURE__ */ React72.createElement("div", { className: "h-full flex flex-col" }, /* @__PURE__ */ React72.createElement("div", { className: "px-4 py-3 border-b border-ash/40 shrink-0 flex items-center gap-2" }, /* @__PURE__ */ React72.createElement("h3", { className: "text-xs font-medium text-white shrink-0" }, "History"), (hasFilter || onNewChat) && /* @__PURE__ */ React72.createElement("div", { className: "flex items-center gap-2 flex-1 min-w-0" }, hasFilter && /* @__PURE__ */ React72.createElement(React72.Fragment, null, /* @__PURE__ */ React72.createElement("div", { className: "w-px h-3 bg-ash/40 shrink-0 mx-1" }), /* @__PURE__ */ React72.createElement(
6242
6107
  ProjectFilter,
6243
6108
  {
6244
6109
  projects,
@@ -6246,7 +6111,7 @@ function HistoryPanel({
6246
6111
  onChange: setProjectFilter,
6247
6112
  className: "flex-1"
6248
6113
  }
6249
- )), onNewChat && /* @__PURE__ */ React70.createElement(React70.Fragment, null, /* @__PURE__ */ React70.createElement("div", { className: "w-px h-3 bg-ash/40 shrink-0 mx-1" }), /* @__PURE__ */ React70.createElement(
6114
+ )), onNewChat && /* @__PURE__ */ React72.createElement(React72.Fragment, null, /* @__PURE__ */ React72.createElement("div", { className: "w-px h-3 bg-ash/40 shrink-0 mx-1" }), /* @__PURE__ */ React72.createElement(
6250
6115
  "button",
6251
6116
  {
6252
6117
  onClick: onNewChat,
@@ -6258,15 +6123,15 @@ function HistoryPanel({
6258
6123
  "transition-colors duration-200"
6259
6124
  )
6260
6125
  },
6261
- /* @__PURE__ */ React70.createElement(PlusIcon, { className: "w-4 h-4" }),
6262
- /* @__PURE__ */ React70.createElement("span", { className: "truncate" }, "New Chat")
6263
- )))), /* @__PURE__ */ React70.createElement("div", { className: "flex-1 overflow-y-auto py-2" }, conversations.length === 0 ? /* @__PURE__ */ React70.createElement("p", { className: "px-4 py-2 text-xs text-silver/60" }, "No conversations yet") : groups.length === 0 ? /* @__PURE__ */ React70.createElement("p", { className: "px-4 py-2 text-xs text-silver/60" }, "No conversations match this filter") : /* @__PURE__ */ React70.createElement("div", null, groups.map((group, index) => /* @__PURE__ */ React70.createElement("section", { key: group.key, className: cx(index > 0 && "mt-3") }, /* @__PURE__ */ React70.createElement("div", { className: "flex items-center gap-2 px-3 pb-2" }, /* @__PURE__ */ React70.createElement(
6126
+ /* @__PURE__ */ React72.createElement(PlusIcon, { className: "w-4 h-4" }),
6127
+ /* @__PURE__ */ React72.createElement("span", { className: "truncate" }, "New Chat")
6128
+ )))), /* @__PURE__ */ React72.createElement("div", { className: "flex-1 overflow-y-auto py-2" }, conversations.length === 0 ? /* @__PURE__ */ React72.createElement("p", { className: "px-4 py-2 text-xs text-silver/60" }, "No conversations yet") : groups.length === 0 ? /* @__PURE__ */ React72.createElement("p", { className: "px-4 py-2 text-xs text-silver/60" }, "No conversations match this filter") : /* @__PURE__ */ React72.createElement("div", null, groups.map((group, index) => /* @__PURE__ */ React72.createElement("section", { key: group.key, className: cx(index > 0 && "mt-3") }, /* @__PURE__ */ React72.createElement("div", { className: "flex items-center gap-2 px-3 pb-2" }, /* @__PURE__ */ React72.createElement(
6264
6129
  "span",
6265
6130
  {
6266
6131
  className: "text-xs font-medium uppercase tracking-wider text-gold/70"
6267
6132
  },
6268
6133
  group.label
6269
- ), /* @__PURE__ */ React70.createElement("div", { className: "flex-1 h-px bg-gold/20" })), /* @__PURE__ */ React70.createElement("div", { className: "space-y-1 px-2" }, group.conversations.map((conversation) => /* @__PURE__ */ React70.createElement(
6134
+ ), /* @__PURE__ */ React72.createElement("div", { className: "flex-1 h-px bg-gold/20" })), /* @__PURE__ */ React72.createElement("div", { className: "space-y-1 px-2" }, group.conversations.map((conversation) => /* @__PURE__ */ React72.createElement(
6270
6135
  ConversationRow,
6271
6136
  {
6272
6137
  key: conversation.id,
@@ -6278,7 +6143,7 @@ function HistoryPanel({
6278
6143
  }
6279
6144
 
6280
6145
  // src/components/chat/TodosList.tsx
6281
- import React71, { useCallback as useCallback17, useMemo as useMemo4, useState as useState18 } from "react";
6146
+ import React73, { useCallback as useCallback19, useMemo as useMemo4, useState as useState19 } from "react";
6282
6147
  import { Loader2 as Loader22, Square as Square2 } from "lucide-react";
6283
6148
  var TASK_STATUSES = {
6284
6149
  PENDING: "pending",
@@ -6290,16 +6155,16 @@ var TASK_STATUSES = {
6290
6155
  function TaskIcon({ status }) {
6291
6156
  switch (status) {
6292
6157
  case "done":
6293
- return /* @__PURE__ */ React71.createElement(CheckSquareIcon, null);
6158
+ return /* @__PURE__ */ React73.createElement(CheckSquareIcon, null);
6294
6159
  case "in_progress":
6295
- return /* @__PURE__ */ React71.createElement(SquareLoaderIcon, null);
6160
+ return /* @__PURE__ */ React73.createElement(SquareLoaderIcon, null);
6296
6161
  case "cancelled":
6297
- return /* @__PURE__ */ React71.createElement(CrossSquareIcon, { variant: "cancelled" });
6162
+ return /* @__PURE__ */ React73.createElement(CrossSquareIcon, { variant: "cancelled" });
6298
6163
  case "failed":
6299
- return /* @__PURE__ */ React71.createElement(CrossSquareIcon, { variant: "failed" });
6164
+ return /* @__PURE__ */ React73.createElement(CrossSquareIcon, { variant: "failed" });
6300
6165
  case "pending":
6301
6166
  default:
6302
- return /* @__PURE__ */ React71.createElement(EmptySquareIcon, null);
6167
+ return /* @__PURE__ */ React73.createElement(EmptySquareIcon, null);
6303
6168
  }
6304
6169
  }
6305
6170
  function sortTasks(tasks) {
@@ -6319,14 +6184,14 @@ function TaskItem({ task, depth = 0 }) {
6319
6184
  const isSubtle = task.status === "cancelled" || task.status === "failed";
6320
6185
  const showSubtasks = task.subtasks && task.subtasks.length > 0;
6321
6186
  const sortedSubtasks = showSubtasks ? sortTasks(task.subtasks) : [];
6322
- return /* @__PURE__ */ React71.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ React71.createElement(
6187
+ return /* @__PURE__ */ React73.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ React73.createElement(
6323
6188
  "div",
6324
6189
  {
6325
6190
  className: "flex items-center gap-2 py-1",
6326
6191
  style: { paddingLeft: `${depth * 1.5}rem` }
6327
6192
  },
6328
- /* @__PURE__ */ React71.createElement(TaskIcon, { status: task.status }),
6329
- /* @__PURE__ */ React71.createElement(
6193
+ /* @__PURE__ */ React73.createElement(TaskIcon, { status: task.status }),
6194
+ /* @__PURE__ */ React73.createElement(
6330
6195
  "span",
6331
6196
  {
6332
6197
  className: cx(
@@ -6338,10 +6203,10 @@ function TaskItem({ task, depth = 0 }) {
6338
6203
  )
6339
6204
  },
6340
6205
  task.label,
6341
- task.status === "cancelled" && /* @__PURE__ */ React71.createElement("span", { className: "text-silver/40 ml-1" }, "(cancelled)"),
6342
- task.status === "failed" && /* @__PURE__ */ React71.createElement("span", { className: "text-error/60 ml-1" }, "(failed)")
6206
+ task.status === "cancelled" && /* @__PURE__ */ React73.createElement("span", { className: "text-silver/40 ml-1" }, "(cancelled)"),
6207
+ task.status === "failed" && /* @__PURE__ */ React73.createElement("span", { className: "text-error/60 ml-1" }, "(failed)")
6343
6208
  )
6344
- ), showSubtasks && /* @__PURE__ */ React71.createElement("div", { className: "flex flex-col" }, sortedSubtasks.map((subtask) => /* @__PURE__ */ React71.createElement(TaskItem, { key: subtask.id, task: subtask, depth: depth + 1 }))));
6209
+ ), showSubtasks && /* @__PURE__ */ React73.createElement("div", { className: "flex flex-col" }, sortedSubtasks.map((subtask) => /* @__PURE__ */ React73.createElement(TaskItem, { key: subtask.id, task: subtask, depth: depth + 1 }))));
6345
6210
  }
6346
6211
  function hasInProgressTask(tasks) {
6347
6212
  return tasks.some((t) => {
@@ -6354,11 +6219,11 @@ function hasInProgressTask(tasks) {
6354
6219
  return false;
6355
6220
  });
6356
6221
  }
6357
- var TodosList = React71.forwardRef(
6222
+ var TodosList = React73.forwardRef(
6358
6223
  ({ tasks, title = "Tasks", onStopAllTasks, className, ...rest }, ref) => {
6359
6224
  const sortedTasks = useMemo4(() => sortTasks(tasks), [tasks]);
6360
- const [isStopping, setIsStopping] = useState18(false);
6361
- const handleStopClick = useCallback17(async () => {
6225
+ const [isStopping, setIsStopping] = useState19(false);
6226
+ const handleStopClick = useCallback19(async () => {
6362
6227
  if (!onStopAllTasks || isStopping) {
6363
6228
  return;
6364
6229
  }
@@ -6379,7 +6244,7 @@ var TodosList = React71.forwardRef(
6379
6244
  if (tasks.length === 0) {
6380
6245
  return null;
6381
6246
  }
6382
- return /* @__PURE__ */ React71.createElement(
6247
+ return /* @__PURE__ */ React73.createElement(
6383
6248
  "div",
6384
6249
  {
6385
6250
  ref,
@@ -6390,16 +6255,16 @@ var TodosList = React71.forwardRef(
6390
6255
  ),
6391
6256
  ...rest
6392
6257
  },
6393
- /* @__PURE__ */ React71.createElement(
6258
+ /* @__PURE__ */ React73.createElement(
6394
6259
  "div",
6395
6260
  {
6396
6261
  className: "flex items-center justify-between px-4 py-2 border-b border-ash/40 flex-shrink-0"
6397
6262
  },
6398
- /* @__PURE__ */ React71.createElement("h4", { className: "text-xs font-medium text-white" }, title),
6399
- /* @__PURE__ */ React71.createElement("span", { className: "text-xs text-silver/60" }, countCompleted(tasks), "/", countTotal(tasks))
6263
+ /* @__PURE__ */ React73.createElement("h4", { className: "text-xs font-medium text-white" }, title),
6264
+ /* @__PURE__ */ React73.createElement("span", { className: "text-xs text-silver/60" }, countCompleted(tasks), "/", countTotal(tasks))
6400
6265
  ),
6401
- /* @__PURE__ */ React71.createElement("div", { className: "flex-1 overflow-y-auto px-4 py-2" }, sortedTasks.map((task) => /* @__PURE__ */ React71.createElement(TaskItem, { key: task.id, task }))),
6402
- showStopButton && /* @__PURE__ */ React71.createElement("div", { className: "px-4 py-2 border-t border-ash/40 flex-shrink-0" }, /* @__PURE__ */ React71.createElement(
6266
+ /* @__PURE__ */ React73.createElement("div", { className: "flex-1 overflow-y-auto px-4 py-2" }, sortedTasks.map((task) => /* @__PURE__ */ React73.createElement(TaskItem, { key: task.id, task }))),
6267
+ showStopButton && /* @__PURE__ */ React73.createElement("div", { className: "px-4 py-2 border-t border-ash/40 flex-shrink-0" }, /* @__PURE__ */ React73.createElement(
6403
6268
  "button",
6404
6269
  {
6405
6270
  type: "button",
@@ -6416,7 +6281,7 @@ var TodosList = React71.forwardRef(
6416
6281
  isStopping ? "cursor-not-allowed opacity-70" : "hover:bg-error/20"
6417
6282
  )
6418
6283
  },
6419
- isStopping ? /* @__PURE__ */ React71.createElement(React71.Fragment, null, /* @__PURE__ */ React71.createElement(Loader22, { className: "w-3 h-3 animate-spin" }), "Stopping tasks") : /* @__PURE__ */ React71.createElement(React71.Fragment, null, /* @__PURE__ */ React71.createElement(Square2, { className: "w-3 h-3 fill-current" }), "Stop All Tasks")
6284
+ isStopping ? /* @__PURE__ */ React73.createElement(React73.Fragment, null, /* @__PURE__ */ React73.createElement(Loader22, { className: "w-3 h-3 animate-spin" }), "Stopping tasks") : /* @__PURE__ */ React73.createElement(React73.Fragment, null, /* @__PURE__ */ React73.createElement(Square2, { className: "w-3 h-3 fill-current" }), "Stop All Tasks")
6420
6285
  ))
6421
6286
  );
6422
6287
  }
@@ -6436,8 +6301,8 @@ function areAllTasksSettled(tasks) {
6436
6301
  }
6437
6302
 
6438
6303
  // src/components/chat/ToolSidebar.tsx
6439
- import React72 from "react";
6440
- var ToolSidebar = React72.forwardRef(
6304
+ import React74 from "react";
6305
+ var ToolSidebar = React74.forwardRef(
6441
6306
  ({ tools, activeTools, onToggleTool, side, className, ...rest }, ref) => {
6442
6307
  const topTools = tools.filter((t) => t.group === `top-${side}`);
6443
6308
  const bottomTools = tools.filter((t) => t.group === `bottom-${side}`);
@@ -6448,7 +6313,7 @@ var ToolSidebar = React72.forwardRef(
6448
6313
  };
6449
6314
  const renderButton = (tool) => {
6450
6315
  const active = isActive(tool.id);
6451
- return /* @__PURE__ */ React72.createElement(
6316
+ return /* @__PURE__ */ React74.createElement(
6452
6317
  "button",
6453
6318
  {
6454
6319
  key: tool.id,
@@ -6460,10 +6325,10 @@ var ToolSidebar = React72.forwardRef(
6460
6325
  "aria-label": tool.label,
6461
6326
  "aria-pressed": active
6462
6327
  },
6463
- /* @__PURE__ */ React72.createElement("span", { className: "w-4 h-4 block" }, tool.icon)
6328
+ /* @__PURE__ */ React74.createElement("span", { className: "w-4 h-4 block" }, tool.icon)
6464
6329
  );
6465
6330
  };
6466
- return /* @__PURE__ */ React72.createElement(
6331
+ return /* @__PURE__ */ React74.createElement(
6467
6332
  "div",
6468
6333
  {
6469
6334
  ref,
@@ -6474,17 +6339,17 @@ var ToolSidebar = React72.forwardRef(
6474
6339
  ),
6475
6340
  ...rest
6476
6341
  },
6477
- /* @__PURE__ */ React72.createElement("div", { className: "flex flex-col items-center gap-1" }, topTools.map(renderButton)),
6478
- /* @__PURE__ */ React72.createElement("div", { className: "flex-1 flex items-center justify-center" }, /* @__PURE__ */ React72.createElement("div", { className: "w-5 border-t border-ash/30" })),
6479
- /* @__PURE__ */ React72.createElement("div", { className: "flex flex-col items-center gap-1" }, bottomTools.map(renderButton))
6342
+ /* @__PURE__ */ React74.createElement("div", { className: "flex flex-col items-center gap-1" }, topTools.map(renderButton)),
6343
+ /* @__PURE__ */ React74.createElement("div", { className: "flex-1 flex items-center justify-center" }, /* @__PURE__ */ React74.createElement("div", { className: "w-5 border-t border-ash/30" })),
6344
+ /* @__PURE__ */ React74.createElement("div", { className: "flex flex-col items-center gap-1" }, bottomTools.map(renderButton))
6480
6345
  );
6481
6346
  }
6482
6347
  );
6483
6348
  ToolSidebar.displayName = "ToolSidebar";
6484
6349
 
6485
6350
  // src/components/chat/ToolPanelContainer.tsx
6486
- import React73, { useCallback as useCallback18, useEffect as useEffect14, useRef as useRef12, useState as useState19 } from "react";
6487
- var ToolPanelContainer = React73.forwardRef(
6351
+ import React75, { useCallback as useCallback20, useEffect as useEffect14, useRef as useRef13, useState as useState20 } from "react";
6352
+ var ToolPanelContainer = React75.forwardRef(
6488
6353
  ({
6489
6354
  topContent,
6490
6355
  bottomContent,
@@ -6495,21 +6360,21 @@ var ToolPanelContainer = React73.forwardRef(
6495
6360
  initialTopPercent = 60,
6496
6361
  ...rest
6497
6362
  }, ref) => {
6498
- const [topPercent, setTopPercent] = useState19(initialTopPercent);
6499
- const [isResizingHeight, setIsResizingHeight] = useState19(false);
6500
- const containerRef = useRef12(null);
6501
- const lastY = useRef12(null);
6363
+ const [topPercent, setTopPercent] = useState20(initialTopPercent);
6364
+ const [isResizingHeight, setIsResizingHeight] = useState20(false);
6365
+ const containerRef = useRef13(null);
6366
+ const lastY = useRef13(null);
6502
6367
  const hasBoth = topContent !== null && bottomContent !== null;
6503
- const startHeightResize = useCallback18((e) => {
6368
+ const startHeightResize = useCallback20((e) => {
6504
6369
  e.preventDefault();
6505
6370
  setIsResizingHeight(true);
6506
6371
  lastY.current = e.clientY;
6507
6372
  }, []);
6508
- const stopHeightResize = useCallback18(() => {
6373
+ const stopHeightResize = useCallback20(() => {
6509
6374
  setIsResizingHeight(false);
6510
6375
  lastY.current = null;
6511
6376
  }, []);
6512
- const resizeHeight = useCallback18(
6377
+ const resizeHeight = useCallback20(
6513
6378
  (e) => {
6514
6379
  if (!isResizingHeight || lastY.current === null || !containerRef.current) {
6515
6380
  return;
@@ -6547,17 +6412,10 @@ var ToolPanelContainer = React73.forwardRef(
6547
6412
  document.body.style.userSelect = "";
6548
6413
  };
6549
6414
  }, [isResizingHeight, resizeHeight, stopHeightResize]);
6550
- return /* @__PURE__ */ React73.createElement(
6415
+ return /* @__PURE__ */ React75.createElement(
6551
6416
  "div",
6552
6417
  {
6553
- ref: (node) => {
6554
- containerRef.current = node;
6555
- if (typeof ref === "function") {
6556
- ref(node);
6557
- } else if (ref) {
6558
- ref.current = node;
6559
- }
6560
- },
6418
+ ref: composeRefs(containerRef, ref),
6561
6419
  className: cx(
6562
6420
  "h-full bg-charcoal/50 flex flex-col relative shrink-0",
6563
6421
  side === "left" ? "border-r border-ash/40" : "border-l border-ash/40",
@@ -6566,7 +6424,7 @@ var ToolPanelContainer = React73.forwardRef(
6566
6424
  style: width ? { width } : void 0,
6567
6425
  ...rest
6568
6426
  },
6569
- /* @__PURE__ */ React73.createElement(
6427
+ /* @__PURE__ */ React75.createElement(
6570
6428
  "div",
6571
6429
  {
6572
6430
  onMouseDown: onResizeStart,
@@ -6577,7 +6435,7 @@ var ToolPanelContainer = React73.forwardRef(
6577
6435
  )
6578
6436
  }
6579
6437
  ),
6580
- topContent !== null && /* @__PURE__ */ React73.createElement(
6438
+ topContent !== null && /* @__PURE__ */ React75.createElement(
6581
6439
  "div",
6582
6440
  {
6583
6441
  className: "min-h-0 overflow-hidden flex flex-col",
@@ -6585,7 +6443,7 @@ var ToolPanelContainer = React73.forwardRef(
6585
6443
  },
6586
6444
  topContent
6587
6445
  ),
6588
- hasBoth && /* @__PURE__ */ React73.createElement(
6446
+ hasBoth && /* @__PURE__ */ React75.createElement(
6589
6447
  "div",
6590
6448
  {
6591
6449
  onMouseDown: startHeightResize,
@@ -6597,7 +6455,7 @@ var ToolPanelContainer = React73.forwardRef(
6597
6455
  )
6598
6456
  }
6599
6457
  ),
6600
- bottomContent !== null && /* @__PURE__ */ React73.createElement(
6458
+ bottomContent !== null && /* @__PURE__ */ React75.createElement(
6601
6459
  "div",
6602
6460
  {
6603
6461
  className: "min-h-0 overflow-hidden flex flex-col",
@@ -6611,26 +6469,26 @@ var ToolPanelContainer = React73.forwardRef(
6611
6469
  ToolPanelContainer.displayName = "ToolPanelContainer";
6612
6470
 
6613
6471
  // src/components/chat/hooks/useResizable.ts
6614
- import { useCallback as useCallback19, useEffect as useEffect15, useRef as useRef13, useState as useState20 } from "react";
6472
+ import { useCallback as useCallback21, useEffect as useEffect15, useRef as useRef14, useState as useState21 } from "react";
6615
6473
  function useResizable({
6616
6474
  initialWidthPercent,
6617
6475
  minWidthPercent,
6618
6476
  maxWidthPercent,
6619
6477
  direction
6620
6478
  }) {
6621
- const [widthPercent, setWidthPercent] = useState20(initialWidthPercent);
6622
- const [isResizing, setIsResizing] = useState20(false);
6623
- const lastX = useRef13(null);
6624
- const startResizing = useCallback19((e) => {
6479
+ const [widthPercent, setWidthPercent] = useState21(initialWidthPercent);
6480
+ const [isResizing, setIsResizing] = useState21(false);
6481
+ const lastX = useRef14(null);
6482
+ const startResizing = useCallback21((e) => {
6625
6483
  e.preventDefault();
6626
6484
  setIsResizing(true);
6627
6485
  lastX.current = e.clientX;
6628
6486
  }, []);
6629
- const stopResizing = useCallback19(() => {
6487
+ const stopResizing = useCallback21(() => {
6630
6488
  setIsResizing(false);
6631
6489
  lastX.current = null;
6632
6490
  }, []);
6633
- const resize = useCallback19(
6491
+ const resize = useCallback21(
6634
6492
  (e) => {
6635
6493
  if (!isResizing || lastX.current === null) {
6636
6494
  return;
@@ -6669,8 +6527,150 @@ function useResizable({
6669
6527
  return { width, widthPercent, isResizing, startResizing };
6670
6528
  }
6671
6529
 
6530
+ // src/components/chat/tree.ts
6531
+ function createEmptyTree() {
6532
+ return { nodes: {}, rootIds: [], activeLeafId: null, lastLeafId: null };
6533
+ }
6534
+ function addNodeToTree(tree, node, parentId = null) {
6535
+ const newNodes = { ...tree.nodes };
6536
+ const newRootIds = [...tree.rootIds];
6537
+ const branchIndex = parentId ? newNodes[parentId]?.children.length ?? 0 : newRootIds.length;
6538
+ newNodes[node.id] = {
6539
+ ...node,
6540
+ parentId,
6541
+ children: [],
6542
+ branchIndex,
6543
+ createdAt: node.createdAt ?? Date.now()
6544
+ };
6545
+ if (parentId && newNodes[parentId]) {
6546
+ newNodes[parentId] = {
6547
+ ...newNodes[parentId],
6548
+ children: [...newNodes[parentId].children, node.id]
6549
+ };
6550
+ } else {
6551
+ newRootIds.push(node.id);
6552
+ }
6553
+ return {
6554
+ nodes: newNodes,
6555
+ rootIds: newRootIds,
6556
+ activeLeafId: node.id,
6557
+ lastLeafId: node.id
6558
+ };
6559
+ }
6560
+ function getActivePath(tree) {
6561
+ return walkUp(tree, tree.activeLeafId).reverse();
6562
+ }
6563
+ function findAncestor(tree, fromId, predicate) {
6564
+ let id = fromId;
6565
+ while (id) {
6566
+ const node = tree.nodes[id];
6567
+ if (!node) return null;
6568
+ if (predicate(node)) return node;
6569
+ id = node.parentId;
6570
+ }
6571
+ return null;
6572
+ }
6573
+ function getSiblingInfo(tree, nodeId) {
6574
+ const siblings = siblingsOf(tree, nodeId);
6575
+ const index = siblings.indexOf(nodeId);
6576
+ if (index < 0) return { total: 1, current: 1 };
6577
+ return { total: siblings.length, current: index + 1 };
6578
+ }
6579
+ function isBranchPoint(tree, nodeId) {
6580
+ return (tree.nodes[nodeId]?.children.length ?? 0) > 1;
6581
+ }
6582
+ function switchBranch(tree, nodeId, direction) {
6583
+ const siblings = siblingsOf(tree, nodeId);
6584
+ if (siblings.length <= 1) return tree;
6585
+ const currentIndex = siblings.indexOf(nodeId);
6586
+ const newIndex = direction === "next" ? (currentIndex + 1) % siblings.length : (currentIndex - 1 + siblings.length) % siblings.length;
6587
+ const leafId = deepestLeafOf(tree, siblings[newIndex]);
6588
+ return { ...tree, activeLeafId: leafId, lastLeafId: leafId };
6589
+ }
6590
+ function setActiveLeaf(tree, leafId) {
6591
+ if (!leafId || !tree.nodes[leafId]) {
6592
+ return { ...tree, activeLeafId: leafId, lastLeafId: leafId };
6593
+ }
6594
+ const lastLeafId = tree.lastLeafId && isAncestor(tree, leafId, tree.lastLeafId) ? tree.lastLeafId : leafId;
6595
+ return { ...tree, activeLeafId: leafId, lastLeafId };
6596
+ }
6597
+ function getGreyedFuture(tree) {
6598
+ const { activeLeafId, lastLeafId } = tree;
6599
+ if (!activeLeafId || !lastLeafId || activeLeafId === lastLeafId) return [];
6600
+ const path = [];
6601
+ let id = lastLeafId;
6602
+ while (id && id !== activeLeafId) {
6603
+ const node = tree.nodes[id];
6604
+ if (!node) return [];
6605
+ path.unshift(node);
6606
+ id = node.parentId;
6607
+ }
6608
+ return id === activeLeafId ? path : [];
6609
+ }
6610
+ function messagesToTree(messages) {
6611
+ let tree = createEmptyTree();
6612
+ for (const msg of messages) {
6613
+ const parentId = tree.activeLeafId;
6614
+ tree = addNodeToTree(
6615
+ tree,
6616
+ { ...msg, kind: "message", parentId },
6617
+ parentId
6618
+ );
6619
+ }
6620
+ return tree;
6621
+ }
6622
+ function updateMessageContent(tree, nodeId, content, isStreaming) {
6623
+ const node = tree.nodes[nodeId];
6624
+ if (!node || node.kind !== "message") return tree;
6625
+ const updated = {
6626
+ ...node,
6627
+ content,
6628
+ isStreaming: isStreaming ?? node.isStreaming
6629
+ };
6630
+ return {
6631
+ ...tree,
6632
+ nodes: {
6633
+ ...tree.nodes,
6634
+ [nodeId]: updated
6635
+ }
6636
+ };
6637
+ }
6638
+ function walkUp(tree, fromId) {
6639
+ const out = [];
6640
+ let id = fromId;
6641
+ while (id) {
6642
+ const node = tree.nodes[id];
6643
+ if (!node) break;
6644
+ out.push(node);
6645
+ id = node.parentId;
6646
+ }
6647
+ return out;
6648
+ }
6649
+ function siblingsOf(tree, nodeId) {
6650
+ const node = tree.nodes[nodeId];
6651
+ if (!node) return [];
6652
+ return node.parentId ? tree.nodes[node.parentId]?.children ?? [] : tree.rootIds;
6653
+ }
6654
+ function deepestLeafOf(tree, nodeId) {
6655
+ let id = nodeId;
6656
+ let node = tree.nodes[id];
6657
+ while (node && node.children.length > 0) {
6658
+ id = node.children[node.children.length - 1];
6659
+ node = tree.nodes[id];
6660
+ }
6661
+ return id;
6662
+ }
6663
+ function isAncestor(tree, ancestorId, descendantId) {
6664
+ let id = descendantId;
6665
+ while (id) {
6666
+ if (id === ancestorId) return true;
6667
+ id = tree.nodes[id]?.parentId ?? null;
6668
+ }
6669
+ return false;
6670
+ }
6671
+
6672
6672
  // src/components/chat/ChatInterface.tsx
6673
- var ChatInterface = React74.forwardRef(
6673
+ var ChatInterface = React76.forwardRef(
6674
6674
  ({
6675
6675
  messages = [],
6676
6676
  conversationTree,
@@ -6679,6 +6679,8 @@ var ChatInterface = React74.forwardRef(
6679
6679
  onMessageSubmit,
6680
6680
  onEditMessage,
6681
6681
  onRetryMessage,
6682
+ onJumpToCheckpoint,
6683
+ onJumpToLatest,
6682
6684
  onStop,
6683
6685
  onSelectConversation,
6684
6686
  onNewChat,
@@ -6707,15 +6709,15 @@ var ChatInterface = React74.forwardRef(
6707
6709
  className,
6708
6710
  ...rest
6709
6711
  }, ref) => {
6710
- const prevArtifactNodesRef = useRef14([]);
6711
- const prevTasksRef = useRef14([]);
6712
- const [internalTools, setInternalTools] = useState21({
6712
+ const prevArtifactNodesRef = useRef15([]);
6713
+ const prevTasksRef = useRef15([]);
6714
+ const [internalTools, setInternalTools] = useState22({
6713
6715
  "top-left": "history",
6714
6716
  "bottom-left": null,
6715
6717
  "top-right": null,
6716
6718
  "bottom-right": null
6717
6719
  });
6718
- const dismissedToolsRef = useRef14(/* @__PURE__ */ new Set());
6720
+ const dismissedToolsRef = useRef15(/* @__PURE__ */ new Set());
6719
6721
  const isPanelControlled = isArtifactsPanelOpen !== void 0;
6720
6722
  const activeTools = useMemo5(() => {
6721
6723
  if (isPanelControlled) {
@@ -6749,11 +6751,11 @@ var ChatInterface = React74.forwardRef(
6749
6751
  const allSettled = tasks.length === 0 || areAllTasksSettled(tasks);
6750
6752
  const allToolDefinitions = useMemo5(() => {
6751
6753
  const builtIn = [
6752
- { id: "history", icon: /* @__PURE__ */ React74.createElement(ChatBubbleIcon, null), label: "History", group: "top-left" },
6753
- { id: "artifacts", icon: /* @__PURE__ */ React74.createElement(MediaIcon, null), label: "Artifacts", group: "top-right" },
6754
+ { id: "history", icon: /* @__PURE__ */ React76.createElement(ChatBubbleIcon, null), label: "History", group: "top-left" },
6755
+ { id: "artifacts", icon: /* @__PURE__ */ React76.createElement(MediaIcon, null), label: "Artifacts", group: "top-right" },
6754
6756
  {
6755
6757
  id: "todos",
6756
- icon: allSettled ? /* @__PURE__ */ React74.createElement(CheckSquareIcon, null) : /* @__PURE__ */ React74.createElement(SquareLoaderIcon, null),
6758
+ icon: allSettled ? /* @__PURE__ */ React76.createElement(CheckSquareIcon, null) : /* @__PURE__ */ React76.createElement(SquareLoaderIcon, null),
6757
6759
  label: "Tasks",
6758
6760
  group: "bottom-right"
6759
6761
  }
@@ -6761,7 +6763,7 @@ var ChatInterface = React74.forwardRef(
6761
6763
  const external = externalTools.map(({ content: _content, ...def }) => def);
6762
6764
  return [...builtIn, ...external];
6763
6765
  }, [allSettled, externalTools]);
6764
- const toggleTool = useCallback20((toolId) => {
6766
+ const toggleTool = useCallback22((toolId) => {
6765
6767
  const toolDef = allToolDefinitions.find((t) => t.id === toolId);
6766
6768
  if (!toolDef) {
6767
6769
  return;
@@ -6791,20 +6793,24 @@ var ChatInterface = React74.forwardRef(
6791
6793
  });
6792
6794
  }, [allToolDefinitions, isPanelControlled, activeTools, onArtifactsPanelOpenChange]);
6793
6795
  const isTreeMode = !!conversationTree;
6794
- const effectiveMessages = useMemo5(() => {
6795
- if (isTreeMode && conversationTree) {
6796
- return getActivePathMessages(conversationTree);
6797
- }
6798
- return messages || [];
6799
- }, [isTreeMode, conversationTree, messages]);
6800
- const latestUserMessageIndex = useMemo5(() => {
6801
- for (let i = effectiveMessages.length - 1; i >= 0; i--) {
6802
- if (effectiveMessages[i].role === "user") {
6803
- return i;
6804
- }
6805
- }
6806
- return -1;
6807
- }, [effectiveMessages]);
6796
+ const tree = isTreeMode ? conversationTree : null;
6797
+ const activePath = useMemo5(() => {
6798
+ if (tree) return getActivePath(tree);
6799
+ return (messages || []).map((m) => ({ ...m, children: [], branchIndex: 0 }));
6800
+ }, [tree, messages]);
6801
+ const greyedFuture = useMemo5(
6802
+ () => tree ? getGreyedFuture(tree) : [],
6803
+ [tree]
6804
+ );
6805
+ const activeCheckpointId = useMemo5(() => {
6806
+ if (!tree) return null;
6807
+ const found = findAncestor(
6808
+ tree,
6809
+ tree.activeLeafId,
6810
+ (n) => n.kind === "checkpoint"
6811
+ );
6812
+ return found?.id ?? null;
6813
+ }, [tree]);
6808
6814
  useEffect16(() => {
6809
6815
  const nodes = artifactNodes || [];
6810
6816
  const prevNodes = prevArtifactNodesRef.current;
@@ -6830,66 +6836,115 @@ var ChatInterface = React74.forwardRef(
6830
6836
  prevArtifactNodesRef.current = nodes;
6831
6837
  prevTasksRef.current = tasks;
6832
6838
  }, [artifactNodes, tasks, isPanelControlled]);
6833
- const handleBranchSwitch = useCallback20(
6839
+ const handleBranchSwitch = useCallback22(
6834
6840
  (nodeId, direction) => {
6835
- if (!isTreeMode || !conversationTree || !onTreeChange) {
6841
+ if (!tree || !onTreeChange) {
6836
6842
  return;
6837
6843
  }
6838
- const newTree = switchBranch(conversationTree, nodeId, direction);
6839
- onTreeChange(newTree);
6844
+ onTreeChange(switchBranch(tree, nodeId, direction));
6840
6845
  },
6841
- [isTreeMode, conversationTree, onTreeChange]
6846
+ [tree, onTreeChange]
6842
6847
  );
6843
- const displayMessages = useMemo5(() => {
6844
- return effectiveMessages.map((msg) => {
6845
- let branchInfo = void 0;
6846
- if (isTreeMode && conversationTree) {
6847
- const siblingInfo = getSiblingInfo(conversationTree, msg.id);
6848
- if (siblingInfo.total > 1) {
6849
- branchInfo = {
6850
- current: siblingInfo.current,
6851
- total: siblingInfo.total,
6852
- onPrevious: () => handleBranchSwitch(msg.id, "prev"),
6853
- onNext: () => handleBranchSwitch(msg.id, "next")
6854
- };
6855
- }
6848
+ const handleJumpToCheckpoint = useCallback22((checkpointId) => {
6849
+ if (!tree) return;
6850
+ if (onJumpToCheckpoint) {
6851
+ onJumpToCheckpoint(checkpointId);
6852
+ return;
6853
+ }
6854
+ if (onTreeChange) {
6855
+ onTreeChange(setActiveLeaf(tree, checkpointId));
6856
+ }
6857
+ }, [tree, onTreeChange, onJumpToCheckpoint]);
6858
+ const handleJumpToLatest = useCallback22(() => {
6859
+ if (!tree) return;
6860
+ if (onJumpToLatest) {
6861
+ onJumpToLatest();
6862
+ return;
6863
+ }
6864
+ if (onTreeChange && tree.lastLeafId) {
6865
+ onTreeChange(setActiveLeaf(tree, tree.lastLeafId));
6866
+ }
6867
+ }, [tree, onTreeChange, onJumpToLatest]);
6868
+ const buildItem = useCallback22(
6869
+ (node, opts) => {
6870
+ const branchInfo = tree && getSiblingInfo(tree, node.id).total > 1 ? {
6871
+ ...getSiblingInfo(tree, node.id),
6872
+ onPrevious: () => handleBranchSwitch(node.id, "prev"),
6873
+ onNext: () => handleBranchSwitch(node.id, "next")
6874
+ } : void 0;
6875
+ if (node.kind === "checkpoint") {
6876
+ return {
6877
+ kind: "checkpoint",
6878
+ id: node.id,
6879
+ name: node.name,
6880
+ executionKind: node.executionKind,
6881
+ status: node.status,
6882
+ isActive: node.id === activeCheckpointId && !opts.muted,
6883
+ muted: opts.muted,
6884
+ branchInfo,
6885
+ onJumpHere: () => handleJumpToCheckpoint(node.id)
6886
+ };
6856
6887
  }
6857
6888
  const actions = enableMessageActions ? {
6858
6889
  showCopy: true,
6859
- onEdit: msg.role === "user" && onEditMessage ? (newContent) => onEditMessage(msg.id, newContent) : void 0,
6860
- onRetry: msg.role === "assistant" && onRetryMessage ? () => onRetryMessage(msg.id) : void 0
6890
+ onEdit: node.role === "user" && onEditMessage ? (newContent) => onEditMessage(node.id, newContent) : void 0,
6891
+ onRetry: node.role === "assistant" && onRetryMessage ? () => onRetryMessage(node.id) : void 0
6861
6892
  } : void 0;
6862
- const {
6863
- role,
6864
- parentId,
6865
- children,
6866
- branchIndex,
6867
- createdAt,
6868
- ...rest2
6869
- } = msg;
6870
6893
  return {
6871
- ...rest2,
6872
- variant: role,
6894
+ kind: "message",
6895
+ id: node.id,
6896
+ variant: node.role,
6897
+ content: node.content,
6898
+ isStreaming: node.isStreaming,
6899
+ muted: opts.muted,
6873
6900
  branchInfo,
6874
6901
  actions
6875
6902
  };
6876
- });
6877
- }, [
6878
- effectiveMessages,
6879
- isTreeMode,
6880
- conversationTree,
6881
- enableMessageActions,
6882
- onEditMessage,
6883
- onRetryMessage,
6884
- handleBranchSwitch
6885
- ]);
6886
- const handleSubmit = useCallback20(
6903
+ },
6904
+ [
6905
+ tree,
6906
+ activeCheckpointId,
6907
+ enableMessageActions,
6908
+ onEditMessage,
6909
+ onRetryMessage,
6910
+ handleBranchSwitch,
6911
+ handleJumpToCheckpoint
6912
+ ]
6913
+ );
6914
+ const displayItems = useMemo5(() => {
6915
+ const items = activePath.map((n) => buildItem(n, { muted: false }));
6916
+ if (greyedFuture.length > 0) {
6917
+ const messageCount = greyedFuture.filter((n) => n.kind === "message").length;
6918
+ const checkpointCount = greyedFuture.filter((n) => n.kind === "checkpoint").length;
6919
+ items.push({
6920
+ kind: "divider",
6921
+ id: "__greyed_divider__",
6922
+ messageCount,
6923
+ checkpointCount,
6924
+ onJumpToLatest: handleJumpToLatest
6925
+ });
6926
+ for (const n of greyedFuture) {
6927
+ items.push(buildItem(n, { muted: true }));
6928
+ }
6929
+ }
6930
+ return items;
6931
+ }, [activePath, greyedFuture, buildItem, handleJumpToLatest]);
6932
+ const latestUserMessageIndex = useMemo5(() => {
6933
+ for (let i = displayItems.length - 1; i >= 0; i--) {
6934
+ const item = displayItems[i];
6935
+ if (item.kind === "message" && item.variant === "user" && !item.muted) {
6936
+ return i;
6937
+ }
6938
+ }
6939
+ return -1;
6940
+ }, [displayItems]);
6941
+ const handleSubmit = useCallback22(
6887
6942
  (message, attachments) => {
6888
6943
  onMessageSubmit?.(message, attachments);
6889
6944
  },
6890
6945
  [onMessageSubmit]
6891
6946
  );
6892
- const isEmpty = effectiveMessages.length === 0;
6947
+ const isEmpty = displayItems.length === 0;
6893
6948
  const leftToolDefs = useMemo5(
6894
6949
  () => allToolDefinitions.filter((t) => t.group === "top-left" || t.group === "bottom-left"),
6895
6950
  [allToolDefinitions]
@@ -6908,7 +6963,7 @@ var ChatInterface = React74.forwardRef(
6908
6963
  }
6909
6964
  switch (toolId) {
6910
6965
  case "history":
6911
- return /* @__PURE__ */ React74.createElement(
6966
+ return /* @__PURE__ */ React76.createElement(
6912
6967
  HistoryPanel,
6913
6968
  {
6914
6969
  conversations,
@@ -6918,7 +6973,7 @@ var ChatInterface = React74.forwardRef(
6918
6973
  }
6919
6974
  );
6920
6975
  case "artifacts":
6921
- return /* @__PURE__ */ React74.createElement(
6976
+ return /* @__PURE__ */ React76.createElement(
6922
6977
  ArtifactsPanel,
6923
6978
  {
6924
6979
  nodes: artifactNodes,
@@ -6926,7 +6981,7 @@ var ChatInterface = React74.forwardRef(
6926
6981
  }
6927
6982
  );
6928
6983
  case "todos":
6929
- return tasks.length > 0 ? /* @__PURE__ */ React74.createElement(
6984
+ return tasks.length > 0 ? /* @__PURE__ */ React76.createElement(
6930
6985
  TodosList,
6931
6986
  {
6932
6987
  tasks,
@@ -6934,21 +6989,21 @@ var ChatInterface = React74.forwardRef(
6934
6989
  onStopAllTasks,
6935
6990
  className: "h-full"
6936
6991
  }
6937
- ) : /* @__PURE__ */ React74.createElement("div", { className: "h-full flex flex-col" }, /* @__PURE__ */ React74.createElement("div", { className: "flex items-center p-4 border-b border-ash/40 shrink-0" }, /* @__PURE__ */ React74.createElement("h3", { className: "text-xs font-medium text-white" }, "Tasks")), /* @__PURE__ */ React74.createElement("div", { className: "flex-1 flex items-center justify-center" }, /* @__PURE__ */ React74.createElement("p", { className: "text-xs text-silver/60" }, "No tasks")));
6992
+ ) : /* @__PURE__ */ React76.createElement("div", { className: "h-full flex flex-col" }, /* @__PURE__ */ React76.createElement("div", { className: "flex items-center p-4 border-b border-ash/40 shrink-0" }, /* @__PURE__ */ React76.createElement("h3", { className: "text-xs font-medium text-white" }, "Tasks")), /* @__PURE__ */ React76.createElement("div", { className: "flex-1 flex items-center justify-center" }, /* @__PURE__ */ React76.createElement("p", { className: "text-xs text-silver/60" }, "No tasks")));
6938
6993
  default: {
6939
6994
  const externalTool = externalTools.find((t) => t.id === toolId);
6940
6995
  return externalTool?.content ?? null;
6941
6996
  }
6942
6997
  }
6943
6998
  };
6944
- return /* @__PURE__ */ React74.createElement(
6999
+ return /* @__PURE__ */ React76.createElement(
6945
7000
  "div",
6946
7001
  {
6947
7002
  ref,
6948
7003
  className: cx("flex h-full w-full bg-obsidian overflow-hidden", className),
6949
7004
  ...rest
6950
7005
  },
6951
- hasLeftTools && /* @__PURE__ */ React74.createElement(
7006
+ hasLeftTools && /* @__PURE__ */ React76.createElement(
6952
7007
  ToolSidebar,
6953
7008
  {
6954
7009
  tools: leftToolDefs,
@@ -6957,7 +7012,7 @@ var ChatInterface = React74.forwardRef(
6957
7012
  side: "left"
6958
7013
  }
6959
7014
  ),
6960
- isLeftPanelOpen && /* @__PURE__ */ React74.createElement(
7015
+ isLeftPanelOpen && /* @__PURE__ */ React76.createElement(
6961
7016
  ToolPanelContainer,
6962
7017
  {
6963
7018
  topContent: renderToolContent(activeTools["top-left"]),
@@ -6968,28 +7023,28 @@ var ChatInterface = React74.forwardRef(
6968
7023
  initialTopPercent: 30
6969
7024
  }
6970
7025
  ),
6971
- /* @__PURE__ */ React74.createElement("div", { className: "flex-1 flex flex-col min-w-0 relative" }, /* @__PURE__ */ React74.createElement("div", { className: cx(
7026
+ /* @__PURE__ */ React76.createElement("div", { className: "flex-1 flex flex-col min-w-0 relative" }, /* @__PURE__ */ React76.createElement("div", { className: cx(
6972
7027
  "flex-1 flex flex-col min-h-0 relative",
6973
7028
  isEmpty ? "justify-center" : "justify-start"
6974
- ) }, /* @__PURE__ */ React74.createElement("div", { className: cx(
7029
+ ) }, /* @__PURE__ */ React76.createElement("div", { className: cx(
6975
7030
  "transition-all duration-500 ease-in-out",
6976
7031
  isEmpty ? "flex-1" : "flex-zero"
6977
- ) }), /* @__PURE__ */ React74.createElement("div", { className: cx(
7032
+ ) }), /* @__PURE__ */ React76.createElement("div", { className: cx(
6978
7033
  "transition-all duration-500 ease-in-out overflow-hidden flex flex-col",
6979
7034
  isEmpty ? "flex-zero opacity-0" : "flex-1 opacity-100"
6980
- ) }, /* @__PURE__ */ React74.createElement(
7035
+ ) }, /* @__PURE__ */ React76.createElement(
6981
7036
  ChatView,
6982
7037
  {
6983
- messages: displayMessages,
7038
+ items: displayItems,
6984
7039
  latestUserMessageIndex,
6985
7040
  isStreaming,
6986
7041
  isThinking,
6987
7042
  className: "flex-1"
6988
7043
  }
6989
- )), /* @__PURE__ */ React74.createElement("div", { className: cx(
7044
+ )), /* @__PURE__ */ React76.createElement("div", { className: cx(
6990
7045
  "transition-all duration-500 ease-in-out z-10 w-full flex flex-col items-center",
6991
7046
  isEmpty ? "p-4" : "shrink-0 p-4 border-t border-ash/40 bg-obsidian"
6992
- ) }, isEmpty && /* @__PURE__ */ React74.createElement("div", { className: "mb-8 text-center animate-fade-in duration-500" }, emptyState ? emptyState : /* @__PURE__ */ React74.createElement("h1", { className: "text-4xl md:text-5xl font-heading text-gold mb-2 tracking-tight" }, "Welcome!")), /* @__PURE__ */ React74.createElement(
7047
+ ) }, isEmpty && /* @__PURE__ */ React76.createElement("div", { className: "mb-8 text-center animate-fade-in duration-500" }, emptyState ? emptyState : /* @__PURE__ */ React76.createElement("h1", { className: "text-4xl md:text-5xl font-heading text-gold mb-2 tracking-tight" }, "Welcome!")), /* @__PURE__ */ React76.createElement(
6993
7048
  ChatInput,
6994
7049
  {
6995
7050
  position: isEmpty ? "centered" : "bottom",
@@ -7008,11 +7063,11 @@ var ChatInterface = React74.forwardRef(
7008
7063
  initialInputValue,
7009
7064
  autoFocus
7010
7065
  }
7011
- )), /* @__PURE__ */ React74.createElement("div", { className: cx(
7066
+ )), /* @__PURE__ */ React76.createElement("div", { className: cx(
7012
7067
  "transition-all duration-500 ease-in-out",
7013
7068
  isEmpty ? "flex-1" : "flex-zero"
7014
7069
  ) }))),
7015
- isRightPanelOpen && /* @__PURE__ */ React74.createElement(
7070
+ isRightPanelOpen && /* @__PURE__ */ React76.createElement(
7016
7071
  ToolPanelContainer,
7017
7072
  {
7018
7073
  topContent: renderToolContent(activeTools["top-right"]),
@@ -7023,7 +7078,7 @@ var ChatInterface = React74.forwardRef(
7023
7078
  initialTopPercent: 70
7024
7079
  }
7025
7080
  ),
7026
- hasRightTools && /* @__PURE__ */ React74.createElement(
7081
+ hasRightTools && /* @__PURE__ */ React76.createElement(
7027
7082
  ToolSidebar,
7028
7083
  {
7029
7084
  tools: rightToolDefs,
@@ -7038,9 +7093,9 @@ var ChatInterface = React74.forwardRef(
7038
7093
  ChatInterface.displayName = "ChatInterface";
7039
7094
 
7040
7095
  // src/components/chat/MessageActions.tsx
7041
- import React75, { useCallback as useCallback21, useState as useState22 } from "react";
7042
- import { Check as Check3, Copy, Pencil, RotateCcw, Send as Send2, X as X6 } from "lucide-react";
7043
- var ActionButton2 = ({ onClick, label, children, className, disabled }) => /* @__PURE__ */ React75.createElement(
7096
+ import React77, { useCallback as useCallback23, useState as useState23 } from "react";
7097
+ import { Check as Check4, Copy as Copy2, Pencil as Pencil3, RotateCcw as RotateCcw2, Send as Send3, X as X7 } from "lucide-react";
7098
+ var ActionButton2 = ({ onClick, label, children, className, disabled }) => /* @__PURE__ */ React77.createElement(
7044
7099
  "button",
7045
7100
  {
7046
7101
  type: "button",
@@ -7056,7 +7111,7 @@ var ActionButton2 = ({ onClick, label, children, className, disabled }) => /* @_
7056
7111
  },
7057
7112
  children
7058
7113
  );
7059
- var MessageActions = React75.forwardRef(
7114
+ var MessageActions = React77.forwardRef(
7060
7115
  ({
7061
7116
  variant,
7062
7117
  content,
@@ -7068,12 +7123,12 @@ var MessageActions = React75.forwardRef(
7068
7123
  className,
7069
7124
  ...rest
7070
7125
  }, ref) => {
7071
- const [localIsEditing, setLocalIsEditing] = useState22(false);
7072
- const [localEditValue, setLocalEditValue] = useState22(content);
7073
- const [copied, setCopied] = useState22(false);
7126
+ const [localIsEditing, setLocalIsEditing] = useState23(false);
7127
+ const [localEditValue, setLocalEditValue] = useState23(content);
7128
+ const { copied, copy } = useCopyToClipboard();
7074
7129
  const isEditing = controlledIsEditing ?? localIsEditing;
7075
7130
  const editValue = controlledEditValue ?? localEditValue;
7076
- const setIsEditing = useCallback21(
7131
+ const setIsEditing = useCallback23(
7077
7132
  (value) => {
7078
7133
  if (onEditingChange) {
7079
7134
  onEditingChange(value);
@@ -7083,41 +7138,28 @@ var MessageActions = React75.forwardRef(
7083
7138
  },
7084
7139
  [onEditingChange]
7085
7140
  );
7086
- const setEditValue = useCallback21((value) => {
7141
+ const setEditValue = useCallback23((value) => {
7087
7142
  setLocalEditValue(value);
7088
7143
  }, []);
7089
- const handleCopy = useCallback21(async () => {
7090
- try {
7091
- await navigator.clipboard.writeText(content);
7092
- setCopied(true);
7093
- setTimeout(() => setCopied(false), 2e3);
7094
- } catch {
7095
- const textArea = document.createElement("textarea");
7096
- textArea.value = content;
7097
- document.body.appendChild(textArea);
7098
- textArea.select();
7099
- document.execCommand("copy");
7100
- document.body.removeChild(textArea);
7101
- setCopied(true);
7102
- setTimeout(() => setCopied(false), 2e3);
7103
- }
7104
- }, [content]);
7105
- const handleStartEdit = useCallback21(() => {
7144
+ const handleCopy = useCallback23(() => {
7145
+ void copy(content);
7146
+ }, [copy, content]);
7147
+ const handleStartEdit = useCallback23(() => {
7106
7148
  setLocalEditValue(content);
7107
7149
  setIsEditing(true);
7108
7150
  }, [content, setIsEditing]);
7109
- const handleCancelEdit = useCallback21(() => {
7151
+ const handleCancelEdit = useCallback23(() => {
7110
7152
  setIsEditing(false);
7111
7153
  setLocalEditValue(content);
7112
7154
  }, [content, setIsEditing]);
7113
- const handleSubmitEdit = useCallback21(() => {
7155
+ const handleSubmitEdit = useCallback23(() => {
7114
7156
  const trimmed = editValue.trim();
7115
7157
  if (trimmed && trimmed !== content) {
7116
7158
  onEdit?.(trimmed);
7117
7159
  }
7118
7160
  setIsEditing(false);
7119
7161
  }, [editValue, content, onEdit, setIsEditing]);
7120
- const handleEditKeyDown = useCallback21(
7162
+ const handleEditKeyDown = useCallback23(
7121
7163
  (e) => {
7122
7164
  if (e.key === "Enter" && !e.shiftKey) {
7123
7165
  e.preventDefault();
@@ -7130,19 +7172,19 @@ var MessageActions = React75.forwardRef(
7130
7172
  );
7131
7173
  const isUser = variant === "user";
7132
7174
  if (isUser && isEditing) {
7133
- return /* @__PURE__ */ React75.createElement(
7175
+ return /* @__PURE__ */ React77.createElement(
7134
7176
  "div",
7135
7177
  {
7136
7178
  ref,
7137
7179
  className: cx("mt-2", className),
7138
7180
  ...rest
7139
7181
  },
7140
- /* @__PURE__ */ React75.createElement(
7182
+ /* @__PURE__ */ React77.createElement(
7141
7183
  "div",
7142
7184
  {
7143
7185
  className: "relative bg-charcoal border border-ash/60 focus-within:border-gold/60 focus-within:ring-1 focus-within:ring-gold/20"
7144
7186
  },
7145
- /* @__PURE__ */ React75.createElement(
7187
+ /* @__PURE__ */ React77.createElement(
7146
7188
  "textarea",
7147
7189
  {
7148
7190
  value: editValue,
@@ -7153,15 +7195,15 @@ var MessageActions = React75.forwardRef(
7153
7195
  rows: 2
7154
7196
  }
7155
7197
  ),
7156
- /* @__PURE__ */ React75.createElement("div", { className: "absolute right-2 bottom-2 flex gap-1" }, /* @__PURE__ */ React75.createElement(
7198
+ /* @__PURE__ */ React77.createElement("div", { className: "absolute right-2 bottom-2 flex gap-1" }, /* @__PURE__ */ React77.createElement(
7157
7199
  ActionButton2,
7158
7200
  {
7159
7201
  onClick: handleCancelEdit,
7160
7202
  label: "Cancel edit",
7161
7203
  className: "text-silver/60 hover:text-error"
7162
7204
  },
7163
- /* @__PURE__ */ React75.createElement(X6, { className: "w-4 h-4" })
7164
- ), /* @__PURE__ */ React75.createElement(
7205
+ /* @__PURE__ */ React77.createElement(X7, { className: "w-4 h-4" })
7206
+ ), /* @__PURE__ */ React77.createElement(
7165
7207
  ActionButton2,
7166
7208
  {
7167
7209
  onClick: handleSubmitEdit,
@@ -7169,13 +7211,13 @@ var MessageActions = React75.forwardRef(
7169
7211
  className: "text-silver/60 hover:text-gold",
7170
7212
  disabled: !editValue.trim() || editValue.trim() === content
7171
7213
  },
7172
- /* @__PURE__ */ React75.createElement(Send2, { className: "w-4 h-4" })
7214
+ /* @__PURE__ */ React77.createElement(Send3, { className: "w-4 h-4" })
7173
7215
  ))
7174
7216
  ),
7175
- /* @__PURE__ */ React75.createElement("p", { className: "text-xs text-silver/50 mt-1" }, "Press Enter to submit, Esc to cancel. This will create a new branch.")
7217
+ /* @__PURE__ */ React77.createElement("p", { className: "text-xs text-silver/50 mt-1" }, "Press Enter to submit, Esc to cancel. This will create a new branch.")
7176
7218
  );
7177
7219
  }
7178
- return /* @__PURE__ */ React75.createElement(
7220
+ return /* @__PURE__ */ React77.createElement(
7179
7221
  "div",
7180
7222
  {
7181
7223
  ref,
@@ -7186,18 +7228,18 @@ var MessageActions = React75.forwardRef(
7186
7228
  ),
7187
7229
  ...rest
7188
7230
  },
7189
- /* @__PURE__ */ React75.createElement(ActionButton2, { onClick: handleCopy, label: copied ? "Copied!" : "Copy message" }, copied ? /* @__PURE__ */ React75.createElement(Check3, { className: "w-3.5 h-3.5 text-success" }) : /* @__PURE__ */ React75.createElement(Copy, { className: "w-3.5 h-3.5" })),
7190
- isUser && onEdit && /* @__PURE__ */ React75.createElement(ActionButton2, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React75.createElement(Pencil, { className: "w-3.5 h-3.5" })),
7191
- !isUser && onRetry && /* @__PURE__ */ React75.createElement(ActionButton2, { onClick: onRetry, label: "Regenerate response" }, /* @__PURE__ */ React75.createElement(RotateCcw, { className: "w-3.5 h-3.5" }))
7231
+ /* @__PURE__ */ React77.createElement(ActionButton2, { onClick: handleCopy, label: copied ? "Copied!" : "Copy message" }, copied ? /* @__PURE__ */ React77.createElement(Check4, { className: "w-3.5 h-3.5 text-success" }) : /* @__PURE__ */ React77.createElement(Copy2, { className: "w-3.5 h-3.5" })),
7232
+ isUser && onEdit && /* @__PURE__ */ React77.createElement(ActionButton2, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React77.createElement(Pencil3, { className: "w-3.5 h-3.5" })),
7233
+ !isUser && onRetry && /* @__PURE__ */ React77.createElement(ActionButton2, { onClick: onRetry, label: "Regenerate response" }, /* @__PURE__ */ React77.createElement(RotateCcw2, { className: "w-3.5 h-3.5" }))
7192
7234
  );
7193
7235
  }
7194
7236
  );
7195
7237
  MessageActions.displayName = "MessageActions";
7196
7238
 
7197
7239
  // src/components/chat/BranchNavigator.tsx
7198
- import React76 from "react";
7199
- import { ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight3, GitBranch } from "lucide-react";
7200
- var BranchNavigator = React76.forwardRef(
7240
+ import React78 from "react";
7241
+ import { ChevronLeft as ChevronLeft4, ChevronRight as ChevronRight5, GitBranch as GitBranch3 } from "lucide-react";
7242
+ var BranchNavigator = React78.forwardRef(
7201
7243
  ({
7202
7244
  current,
7203
7245
  total,
@@ -7216,7 +7258,7 @@ var BranchNavigator = React76.forwardRef(
7216
7258
  const buttonSize = size === "sm" ? "p-0.5" : "p-1";
7217
7259
  const iconSize = size === "sm" ? "w-3 h-3" : "w-4 h-4";
7218
7260
  const textSize = size === "sm" ? "text-xs" : "text-sm";
7219
- return /* @__PURE__ */ React76.createElement(
7261
+ return /* @__PURE__ */ React78.createElement(
7220
7262
  "div",
7221
7263
  {
7222
7264
  ref,
@@ -7228,8 +7270,8 @@ var BranchNavigator = React76.forwardRef(
7228
7270
  "aria-label": "Branch navigation",
7229
7271
  ...rest
7230
7272
  },
7231
- showIcon && /* @__PURE__ */ React76.createElement(GitBranch, { className: cx(iconSize, "mr-0.5 text-silver/50"), "aria-hidden": "true" }),
7232
- /* @__PURE__ */ React76.createElement(
7273
+ showIcon && /* @__PURE__ */ React78.createElement(GitBranch3, { className: cx(iconSize, "mr-0.5 text-silver/50"), "aria-hidden": "true" }),
7274
+ /* @__PURE__ */ React78.createElement(
7233
7275
  "button",
7234
7276
  {
7235
7277
  type: "button",
@@ -7242,10 +7284,10 @@ var BranchNavigator = React76.forwardRef(
7242
7284
  ),
7243
7285
  "aria-label": "Previous branch"
7244
7286
  },
7245
- /* @__PURE__ */ React76.createElement(ChevronLeft2, { className: iconSize })
7287
+ /* @__PURE__ */ React78.createElement(ChevronLeft4, { className: iconSize })
7246
7288
  ),
7247
- /* @__PURE__ */ React76.createElement("span", { className: cx(textSize, "tabular-nums min-w-6 text-center") }, current, "/", total),
7248
- /* @__PURE__ */ React76.createElement(
7289
+ /* @__PURE__ */ React78.createElement("span", { className: cx(textSize, "tabular-nums min-w-6 text-center") }, current, "/", total),
7290
+ /* @__PURE__ */ React78.createElement(
7249
7291
  "button",
7250
7292
  {
7251
7293
  type: "button",
@@ -7258,7 +7300,7 @@ var BranchNavigator = React76.forwardRef(
7258
7300
  ),
7259
7301
  "aria-label": "Next branch"
7260
7302
  },
7261
- /* @__PURE__ */ React76.createElement(ChevronRight3, { className: iconSize })
7303
+ /* @__PURE__ */ React78.createElement(ChevronRight5, { className: iconSize })
7262
7304
  )
7263
7305
  );
7264
7306
  }
@@ -7266,16 +7308,16 @@ var BranchNavigator = React76.forwardRef(
7266
7308
  BranchNavigator.displayName = "BranchNavigator";
7267
7309
 
7268
7310
  // src/components/BrandIcon.tsx
7269
- import React77 from "react";
7311
+ import React79 from "react";
7270
7312
  var sizeMap2 = {
7271
7313
  sm: "h-8 w-8 text-sm",
7272
7314
  md: "h-12 w-12 text-base",
7273
7315
  lg: "h-16 w-16 text-lg"
7274
7316
  };
7275
- var BrandIcon = React77.forwardRef(
7317
+ var BrandIcon = React79.forwardRef(
7276
7318
  ({ size = "md", variant = "solid", children, className, ...rest }, ref) => {
7277
7319
  const variantClasses = variant === "solid" ? "bg-gold text-obsidian border-2 border-gold" : "bg-transparent text-gold border-2 border-gold";
7278
- return /* @__PURE__ */ React77.createElement(
7320
+ return /* @__PURE__ */ React79.createElement(
7279
7321
  "div",
7280
7322
  {
7281
7323
  ref,
@@ -7294,17 +7336,17 @@ var BrandIcon = React77.forwardRef(
7294
7336
  BrandIcon.displayName = "BrandIcon";
7295
7337
 
7296
7338
  // src/components/ColorSwatch.tsx
7297
- import React78 from "react";
7298
- var ColorSwatch = React78.forwardRef(
7339
+ import React80 from "react";
7340
+ var ColorSwatch = React80.forwardRef(
7299
7341
  ({ color, label, className, ...rest }, ref) => {
7300
- return /* @__PURE__ */ React78.createElement(
7342
+ return /* @__PURE__ */ React80.createElement(
7301
7343
  "div",
7302
7344
  {
7303
7345
  ref,
7304
7346
  className: cx("flex flex-col items-center gap-2", className),
7305
7347
  ...rest
7306
7348
  },
7307
- /* @__PURE__ */ React78.createElement(
7349
+ /* @__PURE__ */ React80.createElement(
7308
7350
  "div",
7309
7351
  {
7310
7352
  className: "h-16 w-16 border-2 border-ash rounded-none shadow-sm",
@@ -7312,22 +7354,22 @@ var ColorSwatch = React78.forwardRef(
7312
7354
  "aria-label": label || color
7313
7355
  }
7314
7356
  ),
7315
- label && /* @__PURE__ */ React78.createElement("span", { className: "text-xs text-silver font-medium" }, label)
7357
+ label && /* @__PURE__ */ React80.createElement("span", { className: "text-xs text-silver font-medium" }, label)
7316
7358
  );
7317
7359
  }
7318
7360
  );
7319
7361
  ColorSwatch.displayName = "ColorSwatch";
7320
7362
 
7321
7363
  // src/components/SectionHeading.tsx
7322
- import React79 from "react";
7364
+ import React81 from "react";
7323
7365
  var levelStyles = {
7324
7366
  h2: "text-2xl mb-4",
7325
7367
  h3: "text-xl mb-3"
7326
7368
  };
7327
- var SectionHeading = React79.forwardRef(
7369
+ var SectionHeading = React81.forwardRef(
7328
7370
  ({ level = "h2", children, className, ...rest }, ref) => {
7329
7371
  const Component = level;
7330
- return /* @__PURE__ */ React79.createElement(
7372
+ return /* @__PURE__ */ React81.createElement(
7331
7373
  Component,
7332
7374
  {
7333
7375
  ref,
@@ -7383,6 +7425,7 @@ export {
7383
7425
  ChatView,
7384
7426
  CheckSquareIcon,
7385
7427
  Checkbox,
7428
+ Checkpoint,
7386
7429
  ChevronLeftIcon,
7387
7430
  ChevronRightIcon,
7388
7431
  CloseIcon,
@@ -7396,6 +7439,7 @@ export {
7396
7439
  EmptySquareIcon,
7397
7440
  ExpandIcon,
7398
7441
  FileChip,
7442
+ GreyedDivider,
7399
7443
  HelperText,
7400
7444
  HistoryIcon,
7401
7445
  HistoryPanel,
@@ -7473,19 +7517,22 @@ export {
7473
7517
  ToolSidebar,
7474
7518
  Tooltip,
7475
7519
  VideoCard,
7476
- addMessageToTree,
7520
+ addNodeToTree,
7477
7521
  areAllTasksSettled,
7478
7522
  createEmptyTree,
7479
7523
  createPreviewUrl,
7524
+ findAncestor,
7480
7525
  generateId,
7481
- getActivePathMessages,
7526
+ getActivePath,
7527
+ getGreyedFuture,
7482
7528
  getSiblingInfo,
7483
7529
  isBranchPoint,
7484
7530
  isImageFile,
7485
7531
  messagesToTree,
7486
7532
  revokePreviewUrl,
7533
+ setActiveLeaf,
7487
7534
  switchBranch,
7488
- updateNodeContent,
7535
+ updateMessageContent,
7489
7536
  useArtifactTreeNavigation,
7490
7537
  useResizable,
7491
7538
  useScrollAnchor,