@lukeashford/aurelius 4.2.0 → 4.3.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.js CHANGED
@@ -1487,42 +1487,84 @@ function getFileIcon(type) {
1487
1487
  }
1488
1488
  return import_lucide_react2.File;
1489
1489
  }
1490
- var statusStyles = {
1490
+ var statusBorderClass = {
1491
1491
  pending: "border-silver/30",
1492
1492
  uploading: "border-gold/50",
1493
- complete: "border-success/50",
1494
- error: "border-error/50"
1493
+ uploaded: "border-info/50",
1494
+ analyzing: "border-info/50",
1495
+ analyzed: "border-success/50",
1496
+ upload_failed: "border-error/50",
1497
+ analysis_failed: "border-error/50"
1495
1498
  };
1499
+ var statusHoverLabel = {
1500
+ pending: null,
1501
+ uploading: "Uploading...",
1502
+ uploaded: "Upload complete. Analyzing...",
1503
+ analyzing: "Upload complete. Analyzing...",
1504
+ analyzed: null,
1505
+ upload_failed: "Upload failed. Remove and try again.",
1506
+ analysis_failed: "Analysis failed. Provide a description in your next message."
1507
+ };
1508
+ function isErrorStatus(status) {
1509
+ return status === "upload_failed" || status === "analysis_failed";
1510
+ }
1496
1511
  var FileChip = import_react16.default.forwardRef(
1497
1512
  ({
1498
1513
  name,
1499
1514
  size,
1500
1515
  type,
1501
- status = "complete",
1516
+ status = "analyzed",
1502
1517
  previewUrl,
1503
1518
  onRemove,
1504
1519
  removable = true,
1505
1520
  error,
1521
+ artifactId,
1522
+ onOpen,
1506
1523
  className,
1524
+ title,
1507
1525
  ...rest
1508
1526
  }, ref) => {
1509
1527
  const Icon = getFileIcon(type);
1510
1528
  const isImage = type?.startsWith("image/");
1511
1529
  const showPreview = isImage && previewUrl;
1530
+ const clickable = !!(artifactId && onOpen);
1531
+ const hoverLabel = statusHoverLabel[status];
1532
+ const tooltip = title ?? hoverLabel ?? name;
1533
+ const showError = isErrorStatus(status);
1534
+ const handleClick = () => {
1535
+ if (clickable) {
1536
+ onOpen(artifactId);
1537
+ }
1538
+ };
1539
+ const handleKeyDown = (e) => {
1540
+ if (!clickable) {
1541
+ return;
1542
+ }
1543
+ if (e.key === "Enter" || e.key === " ") {
1544
+ e.preventDefault();
1545
+ onOpen(artifactId);
1546
+ }
1547
+ };
1512
1548
  return /* @__PURE__ */ import_react16.default.createElement(
1513
1549
  "div",
1514
1550
  {
1551
+ ...rest,
1515
1552
  ref,
1516
1553
  className: cx(
1517
1554
  "group relative inline-flex items-center gap-2 px-2 py-1.5",
1518
1555
  "bg-charcoal border text-sm text-white",
1519
1556
  "transition-colors duration-150",
1520
- statusStyles[status],
1521
- status === "error" && "bg-error/10",
1557
+ statusBorderClass[status],
1558
+ showError && "bg-error/10",
1559
+ clickable && "cursor-pointer hover:bg-graphite",
1522
1560
  className
1523
1561
  ),
1524
- role: "listitem",
1525
- ...rest
1562
+ role: clickable ? "button" : "listitem",
1563
+ tabIndex: clickable ? 0 : void 0,
1564
+ onClick: clickable ? handleClick : void 0,
1565
+ onKeyDown: clickable ? handleKeyDown : void 0,
1566
+ title: tooltip,
1567
+ "aria-label": hoverLabel ? `${name}: ${hoverLabel}` : name
1526
1568
  },
1527
1569
  showPreview ? /* @__PURE__ */ import_react16.default.createElement("div", { className: "w-8 h-8 flex-shrink-0 overflow-hidden bg-slate" }, /* @__PURE__ */ import_react16.default.createElement(
1528
1570
  "img",
@@ -1533,10 +1575,11 @@ var FileChip = import_react16.default.forwardRef(
1533
1575
  }
1534
1576
  )) : /* @__PURE__ */ import_react16.default.createElement(Icon, { className: cx(
1535
1577
  "w-4 h-4 flex-shrink-0",
1536
- status === "error" ? "text-error" : "text-silver"
1578
+ showError ? "text-error" : "text-silver"
1537
1579
  ) }),
1538
- /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex flex-col min-w-0 flex-1" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "truncate max-w-40", title: name }, name), size !== void 0 && status !== "error" && /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-xs text-silver/60" }, formatBytes(size)), status === "error" && error && /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-xs text-error truncate", title: error }, error)),
1580
+ /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex flex-col min-w-0 flex-1" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "truncate max-w-40", title: name }, name), size !== void 0 && !showError && /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-xs text-silver/60" }, formatBytes(size)), showError && error && /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-xs text-error truncate", title: error }, error)),
1539
1581
  status === "uploading" && /* @__PURE__ */ import_react16.default.createElement(import_lucide_react2.Loader2, { className: "w-3.5 h-3.5 text-gold animate-spin flex-shrink-0" }),
1582
+ (status === "uploaded" || status === "analyzing") && /* @__PURE__ */ import_react16.default.createElement(import_lucide_react2.Loader2, { className: "w-3.5 h-3.5 text-info animate-spin flex-shrink-0" }),
1540
1583
  status === "pending" && /* @__PURE__ */ import_react16.default.createElement("div", { className: "w-2 h-2 rounded-full bg-silver/50 flex-shrink-0" }),
1541
1584
  removable && onRemove && /* @__PURE__ */ import_react16.default.createElement(
1542
1585
  "button",
@@ -1569,6 +1612,7 @@ var AttachmentPreview = import_react17.default.forwardRef(
1569
1612
  onRemove,
1570
1613
  removable = true,
1571
1614
  maxVisible,
1615
+ onOpen,
1572
1616
  className,
1573
1617
  ...rest
1574
1618
  }, ref) => {
@@ -1597,7 +1641,9 @@ var AttachmentPreview = import_react17.default.forwardRef(
1597
1641
  previewUrl: attachment.previewUrl,
1598
1642
  error: attachment.error,
1599
1643
  removable,
1600
- onRemove: onRemove ? () => onRemove(attachment.id) : void 0
1644
+ onRemove: onRemove ? () => onRemove(attachment.id) : void 0,
1645
+ artifactId: attachment.artifactId,
1646
+ onOpen
1601
1647
  }
1602
1648
  )),
1603
1649
  hiddenCount > 0 && /* @__PURE__ */ import_react17.default.createElement(
@@ -4049,6 +4095,8 @@ var Message = import_react56.default.forwardRef(
4049
4095
  branchInfo,
4050
4096
  actions,
4051
4097
  hideActions,
4098
+ attachments,
4099
+ onAttachmentOpen,
4052
4100
  ...rest
4053
4101
  }, ref) => {
4054
4102
  const isUser = variant === "user";
@@ -4116,6 +4164,14 @@ var Message = import_react56.default.forwardRef(
4116
4164
  ),
4117
4165
  ...rest
4118
4166
  },
4167
+ attachments && attachments.length > 0 && /* @__PURE__ */ import_react56.default.createElement("div", { className: cx("mb-1.5", isUser ? "self-end" : "self-start") }, /* @__PURE__ */ import_react56.default.createElement(
4168
+ AttachmentPreview,
4169
+ {
4170
+ attachments,
4171
+ removable: false,
4172
+ onOpen: onAttachmentOpen
4173
+ }
4174
+ )),
4119
4175
  isUser && isEditing ? /* @__PURE__ */ import_react56.default.createElement("div", { className: "w-full max-w-11/12" }, /* @__PURE__ */ import_react56.default.createElement("div", { className: "relative bg-gold" }, /* @__PURE__ */ import_react56.default.createElement(
4120
4176
  "textarea",
4121
4177
  {
@@ -4366,6 +4422,7 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4366
4422
  isVisible = true,
4367
4423
  phraseInterval = 2500,
4368
4424
  phrases = THINKING_PHRASES,
4425
+ manualLabel,
4369
4426
  className,
4370
4427
  ...rest
4371
4428
  }, ref) => {
@@ -4373,8 +4430,9 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4373
4430
  () => Math.floor(Math.random() * phrases.length)
4374
4431
  );
4375
4432
  const [isTransitioning, setIsTransitioning] = (0, import_react60.useState)(false);
4433
+ const isManual = manualLabel !== void 0;
4376
4434
  (0, import_react60.useEffect)(() => {
4377
- if (!isVisible || phrases.length <= 1) {
4435
+ if (!isVisible || isManual || phrases.length <= 1) {
4378
4436
  return;
4379
4437
  }
4380
4438
  let fadeTimeout = null;
@@ -4392,7 +4450,7 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4392
4450
  clearTimeout(fadeTimeout);
4393
4451
  }
4394
4452
  };
4395
- }, [isVisible, phrases.length, phraseInterval]);
4453
+ }, [isVisible, isManual, phrases.length, phraseInterval]);
4396
4454
  if (!isVisible) {
4397
4455
  return null;
4398
4456
  }
@@ -4429,7 +4487,7 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4429
4487
  style: { animationDelay: "300ms" }
4430
4488
  }
4431
4489
  )),
4432
- /* @__PURE__ */ import_react60.default.createElement(
4490
+ isManual ? /* @__PURE__ */ import_react60.default.createElement("span", { className: "text-sm italic" }, manualLabel) : /* @__PURE__ */ import_react60.default.createElement(
4433
4491
  "span",
4434
4492
  {
4435
4493
  className: cx(
@@ -4451,13 +4509,15 @@ var KIND_ICONS = {
4451
4509
  task: import_lucide_react12.GitBranch,
4452
4510
  submit: import_lucide_react12.GitMerge,
4453
4511
  rename: import_lucide_react12.PencilLine,
4454
- init: import_lucide_react12.GitCommitVertical
4512
+ init: import_lucide_react12.GitCommitVertical,
4513
+ ingest: import_lucide_react12.Upload
4455
4514
  };
4456
4515
  var KIND_ARIA_LABELS = {
4457
4516
  task: "Task checkpoint",
4458
4517
  submit: "Submit checkpoint",
4459
4518
  rename: "Rename checkpoint",
4460
- init: "Project head checkpoint"
4519
+ init: "Project head checkpoint",
4520
+ ingest: "Upload batch checkpoint"
4461
4521
  };
4462
4522
  var Checkpoint = import_react61.default.forwardRef(
4463
4523
  function Checkpoint2({ name, executionKind, status = "completed", isActive, muted, branchInfo, onJumpHere }, ref) {
@@ -4606,7 +4666,16 @@ GreyedDivider.displayName = "GreyedDivider";
4606
4666
 
4607
4667
  // src/components/chat/ChatView.tsx
4608
4668
  var ChatView = import_react63.default.forwardRef(
4609
- function ChatView2({ items, latestUserMessageIndex, isStreaming, isThinking, onScroll, className, ...rest }, ref) {
4669
+ function ChatView2({
4670
+ items,
4671
+ latestUserMessageIndex,
4672
+ isStreaming,
4673
+ isThinking,
4674
+ thinkingLabel,
4675
+ onScroll,
4676
+ className,
4677
+ ...rest
4678
+ }, ref) {
4610
4679
  const { containerRef, anchorRef, scrollToAnchor } = useScrollAnchor({
4611
4680
  behavior: "smooth",
4612
4681
  block: "start"
@@ -4689,7 +4758,7 @@ var ChatView = import_react63.default.forwardRef(
4689
4758
  }
4690
4759
  )
4691
4760
  );
4692
- }), showThinking && /* @__PURE__ */ import_react63.default.createElement(ThinkingIndicator, { isVisible: true })),
4761
+ }), showThinking && /* @__PURE__ */ import_react63.default.createElement(ThinkingIndicator, { isVisible: true, manualLabel: thinkingLabel })),
4693
4762
  /* @__PURE__ */ import_react63.default.createElement(
4694
4763
  "div",
4695
4764
  {
@@ -4874,8 +4943,8 @@ var ChatInput = import_react64.default.forwardRef(
4874
4943
  );
4875
4944
  const isCentered = position === "centered";
4876
4945
  const hasAttachments = attachments.length > 0;
4877
- const isUploading = attachments.some((a) => a.status === "uploading");
4878
- const canSubmit = value.trim() && !disabled && !isStreaming && !isUploading;
4946
+ const isUploadIncomplete = attachments.some((a) => a.status === "pending" || a.status === "uploading" || a.status === "upload_failed");
4947
+ const canSubmit = value.trim() && !disabled && !isStreaming && !isUploadIncomplete;
4879
4948
  return /* @__PURE__ */ import_react64.default.createElement(
4880
4949
  "div",
4881
4950
  {
@@ -5012,7 +5081,7 @@ var ChatInput = import_react64.default.forwardRef(
5012
5081
  ChatInput.displayName = "ChatInput";
5013
5082
 
5014
5083
  // src/components/chat/ArtifactsPanel.tsx
5015
- var import_react75 = __toESM(require("react"));
5084
+ var import_react76 = __toESM(require("react"));
5016
5085
  var import_lucide_react17 = require("lucide-react");
5017
5086
 
5018
5087
  // src/components/ArtifactCard.tsx
@@ -5670,15 +5739,74 @@ var ArtifactVariantStack = import_react73.default.forwardRef(
5670
5739
  );
5671
5740
  ArtifactVariantStack.displayName = "ArtifactVariantStack";
5672
5741
 
5673
- // src/components/chat/hooks/useArtifactTreeNavigation.ts
5742
+ // src/components/chat/hooks/useResizable.ts
5674
5743
  var import_react74 = require("react");
5744
+ function useResizable({
5745
+ initialWidthPercent,
5746
+ minWidthPercent,
5747
+ maxWidthPercent,
5748
+ direction
5749
+ }) {
5750
+ const [widthPercent, setWidthPercent] = (0, import_react74.useState)(initialWidthPercent);
5751
+ const [isResizing, setIsResizing] = (0, import_react74.useState)(false);
5752
+ const lastX = (0, import_react74.useRef)(null);
5753
+ const startResizing = (0, import_react74.useCallback)((e) => {
5754
+ e.preventDefault();
5755
+ setIsResizing(true);
5756
+ lastX.current = e.clientX;
5757
+ }, []);
5758
+ const stopResizing = (0, import_react74.useCallback)(() => {
5759
+ setIsResizing(false);
5760
+ lastX.current = null;
5761
+ }, []);
5762
+ const resize = (0, import_react74.useCallback)(
5763
+ (e) => {
5764
+ if (!isResizing || lastX.current === null) {
5765
+ return;
5766
+ }
5767
+ const deltaX = e.clientX - lastX.current;
5768
+ const factor = direction === "right" ? 1 : -1;
5769
+ const deltaPercent = deltaX / window.innerWidth * 100;
5770
+ setWidthPercent((prevPercent) => {
5771
+ const newPercent = prevPercent + deltaPercent * factor;
5772
+ return Math.min(Math.max(newPercent, minWidthPercent), maxWidthPercent);
5773
+ });
5774
+ lastX.current = e.clientX;
5775
+ },
5776
+ [isResizing, direction, minWidthPercent, maxWidthPercent]
5777
+ );
5778
+ (0, import_react74.useEffect)(() => {
5779
+ if (isResizing) {
5780
+ window.addEventListener("mousemove", resize);
5781
+ window.addEventListener("mouseup", stopResizing);
5782
+ document.body.style.cursor = "col-resize";
5783
+ document.body.style.userSelect = "none";
5784
+ } else {
5785
+ window.removeEventListener("mousemove", resize);
5786
+ window.removeEventListener("mouseup", stopResizing);
5787
+ document.body.style.cursor = "";
5788
+ document.body.style.userSelect = "";
5789
+ }
5790
+ return () => {
5791
+ window.removeEventListener("mousemove", resize);
5792
+ window.removeEventListener("mouseup", stopResizing);
5793
+ document.body.style.cursor = "";
5794
+ document.body.style.userSelect = "";
5795
+ };
5796
+ }, [isResizing, resize, stopResizing]);
5797
+ const width = `${widthPercent}vw`;
5798
+ return { width, widthPercent, isResizing, startResizing };
5799
+ }
5800
+
5801
+ // src/components/chat/hooks/useArtifactTreeNavigation.ts
5802
+ var import_react75 = require("react");
5675
5803
  function useArtifactTreeNavigation(rootNodes) {
5676
- const [stack, setStack] = (0, import_react74.useState)([]);
5677
- const currentNodes = (0, import_react74.useMemo)(() => {
5804
+ const [stack, setStack] = (0, import_react75.useState)([]);
5805
+ const currentNodes = (0, import_react75.useMemo)(() => {
5678
5806
  if (stack.length === 0) return rootNodes;
5679
5807
  return stack[stack.length - 1].children;
5680
5808
  }, [rootNodes, stack]);
5681
- const breadcrumbs = (0, import_react74.useMemo)(() => {
5809
+ const breadcrumbs = (0, import_react75.useMemo)(() => {
5682
5810
  const entries = [{ label: "Project", node: null }];
5683
5811
  for (const node of stack) {
5684
5812
  entries.push({ label: node.label, node });
@@ -5686,13 +5814,13 @@ function useArtifactTreeNavigation(rootNodes) {
5686
5814
  return entries;
5687
5815
  }, [stack]);
5688
5816
  const isAtRoot = stack.length === 0;
5689
- const navigateInto = (0, import_react74.useCallback)((node) => {
5817
+ const navigateInto = (0, import_react75.useCallback)((node) => {
5690
5818
  setStack((prev) => [...prev, node]);
5691
5819
  }, []);
5692
- const navigateTo = (0, import_react74.useCallback)((index) => {
5820
+ const navigateTo = (0, import_react75.useCallback)((index) => {
5693
5821
  setStack((prev) => prev.slice(0, index));
5694
5822
  }, []);
5695
- const navigateBack = (0, import_react74.useCallback)(() => {
5823
+ const navigateBack = (0, import_react75.useCallback)(() => {
5696
5824
  setStack((prev) => prev.slice(0, -1));
5697
5825
  }, []);
5698
5826
  return {
@@ -5712,46 +5840,46 @@ function ArtifactModal({
5712
5840
  onClose
5713
5841
  }) {
5714
5842
  useEscapeKey(onClose);
5715
- const handleBackdropClick = (0, import_react75.useCallback)((e) => {
5843
+ const handleBackdropClick = (0, import_react76.useCallback)((e) => {
5716
5844
  if (e.target === e.currentTarget) {
5717
5845
  onClose();
5718
5846
  }
5719
5847
  }, [onClose]);
5720
- return /* @__PURE__ */ import_react75.default.createElement(
5848
+ return /* @__PURE__ */ import_react76.default.createElement(
5721
5849
  "div",
5722
5850
  {
5723
5851
  className: "fixed inset-0 z-50 flex items-center justify-center bg-void/90 backdrop-blur-sm animate-fade-in",
5724
5852
  onClick: handleBackdropClick
5725
5853
  },
5726
- /* @__PURE__ */ import_react75.default.createElement(
5854
+ /* @__PURE__ */ import_react76.default.createElement(
5727
5855
  "div",
5728
5856
  {
5729
5857
  className: "relative w-11/12 h-5/6 max-w-6xl bg-charcoal border border-ash/40 flex flex-col overflow-hidden"
5730
5858
  },
5731
- /* @__PURE__ */ import_react75.default.createElement(
5859
+ /* @__PURE__ */ import_react76.default.createElement(
5732
5860
  "div",
5733
5861
  {
5734
5862
  className: "flex items-center justify-between p-4 border-b border-ash/40 shrink-0"
5735
5863
  },
5736
- /* @__PURE__ */ import_react75.default.createElement("div", null, artifact.title && /* @__PURE__ */ import_react75.default.createElement("h3", { className: "text-sm font-semibold text-white" }, artifact.title), artifact.subtitle && /* @__PURE__ */ import_react75.default.createElement("p", { className: "text-xs text-silver" }, artifact.subtitle)),
5737
- /* @__PURE__ */ import_react75.default.createElement(
5864
+ /* @__PURE__ */ import_react76.default.createElement("div", null, artifact.title && /* @__PURE__ */ import_react76.default.createElement("h3", { className: "text-sm font-semibold text-white" }, artifact.title), artifact.subtitle && /* @__PURE__ */ import_react76.default.createElement("p", { className: "text-xs text-silver" }, artifact.subtitle)),
5865
+ /* @__PURE__ */ import_react76.default.createElement(
5738
5866
  "button",
5739
5867
  {
5740
5868
  onClick: onClose,
5741
5869
  className: "p-2 text-silver hover:text-white hover:bg-ash/20 transition-colors",
5742
5870
  "aria-label": "Close modal"
5743
5871
  },
5744
- /* @__PURE__ */ import_react75.default.createElement(CloseIcon, { className: "w-5 h-5" })
5872
+ /* @__PURE__ */ import_react76.default.createElement(CloseIcon, { className: "w-5 h-5" })
5745
5873
  )
5746
5874
  ),
5747
- /* @__PURE__ */ import_react75.default.createElement("div", { className: "flex-1 overflow-auto p-4" }, artifact.type === "IMAGE" && /* @__PURE__ */ import_react75.default.createElement(
5875
+ /* @__PURE__ */ import_react76.default.createElement("div", { className: "flex-1 overflow-auto p-4" }, artifact.type === "IMAGE" && /* @__PURE__ */ import_react76.default.createElement(
5748
5876
  "img",
5749
5877
  {
5750
5878
  src: artifact.url,
5751
5879
  alt: artifact.alt || "Artifact image",
5752
5880
  className: "max-w-full max-h-full object-contain mx-auto"
5753
5881
  }
5754
- ), artifact.type === "VIDEO" && /* @__PURE__ */ import_react75.default.createElement(
5882
+ ), artifact.type === "VIDEO" && /* @__PURE__ */ import_react76.default.createElement(
5755
5883
  VideoCard,
5756
5884
  {
5757
5885
  src: artifact.url || "",
@@ -5759,20 +5887,20 @@ function ArtifactModal({
5759
5887
  controls: true,
5760
5888
  className: "max-w-full max-h-full mx-auto"
5761
5889
  }
5762
- ), artifact.type === "AUDIO" && /* @__PURE__ */ import_react75.default.createElement(
5890
+ ), artifact.type === "AUDIO" && /* @__PURE__ */ import_react76.default.createElement(
5763
5891
  AudioCard,
5764
5892
  {
5765
5893
  src: artifact.url || "",
5766
5894
  controls: true,
5767
5895
  className: "max-w-xl mx-auto"
5768
5896
  }
5769
- ), artifact.type === "PDF" && /* @__PURE__ */ import_react75.default.createElement(
5897
+ ), artifact.type === "PDF" && /* @__PURE__ */ import_react76.default.createElement(
5770
5898
  PdfCard,
5771
5899
  {
5772
5900
  src: artifact.url || "",
5773
5901
  className: "h-full border-0"
5774
5902
  }
5775
- ), artifact.type === "TEXT" && /* @__PURE__ */ import_react75.default.createElement(
5903
+ ), artifact.type === "TEXT" && /* @__PURE__ */ import_react76.default.createElement(
5776
5904
  MarkdownContent,
5777
5905
  {
5778
5906
  content: artifact.inlineContent || "",
@@ -5782,7 +5910,7 @@ function ArtifactModal({
5782
5910
  artifact.mimeType === "text/plain" && "whitespace-pre-wrap"
5783
5911
  )
5784
5912
  }
5785
- ), artifact.type === "SCRIPT" && artifact.scriptElements && /* @__PURE__ */ import_react75.default.createElement(
5913
+ ), artifact.type === "SCRIPT" && artifact.scriptElements && /* @__PURE__ */ import_react76.default.createElement(
5786
5914
  ScriptCard,
5787
5915
  {
5788
5916
  elements: artifact.scriptElements,
@@ -5793,6 +5921,20 @@ function ArtifactModal({
5793
5921
  )
5794
5922
  );
5795
5923
  }
5924
+ function findArtifactInNodes(nodes, artifactId) {
5925
+ for (const node of nodes) {
5926
+ if (node.type === "ARTIFACT" && node.artifact?.id === artifactId) {
5927
+ return node.artifact;
5928
+ }
5929
+ if (node.children && node.children.length > 0) {
5930
+ const found = findArtifactInNodes(node.children, artifactId);
5931
+ if (found) {
5932
+ return found;
5933
+ }
5934
+ }
5935
+ }
5936
+ return null;
5937
+ }
5796
5938
  function NodeRenderer({
5797
5939
  node,
5798
5940
  loading,
@@ -5800,7 +5942,7 @@ function NodeRenderer({
5800
5942
  onGroupClick
5801
5943
  }) {
5802
5944
  if (node.type === "ARTIFACT" && node.artifact) {
5803
- return /* @__PURE__ */ import_react75.default.createElement(
5945
+ return /* @__PURE__ */ import_react76.default.createElement(
5804
5946
  ArtifactCard,
5805
5947
  {
5806
5948
  artifact: node.artifact,
@@ -5810,10 +5952,10 @@ function NodeRenderer({
5810
5952
  );
5811
5953
  }
5812
5954
  if (node.type === "GROUP") {
5813
- return /* @__PURE__ */ import_react75.default.createElement(ArtifactGroup, { node, onClick: onGroupClick });
5955
+ return /* @__PURE__ */ import_react76.default.createElement(ArtifactGroup, { node, onClick: onGroupClick });
5814
5956
  }
5815
5957
  if (node.type === "VARIANT_SET") {
5816
- return /* @__PURE__ */ import_react75.default.createElement(
5958
+ return /* @__PURE__ */ import_react76.default.createElement(
5817
5959
  ArtifactVariantStack,
5818
5960
  {
5819
5961
  node,
@@ -5824,42 +5966,59 @@ function NodeRenderer({
5824
5966
  }
5825
5967
  return null;
5826
5968
  }
5827
- var ArtifactsPanel = import_react75.default.forwardRef(
5969
+ var ArtifactsPanel = import_react76.default.forwardRef(
5828
5970
  ({
5829
5971
  nodes,
5830
5972
  loading,
5973
+ openArtifactId,
5974
+ onArtifactClosed,
5831
5975
  className,
5832
5976
  ...rest
5833
5977
  }, ref) => {
5834
- const [expandedArtifact, setExpandedArtifact] = (0, import_react75.useState)(null);
5835
- const [zoomIndex, setZoomIndex] = (0, import_react75.useState)(ZOOM_LEVELS.length - 1);
5978
+ const [expandedArtifact, setExpandedArtifact] = (0, import_react76.useState)(null);
5979
+ const [zoomIndex, setZoomIndex] = (0, import_react76.useState)(ZOOM_LEVELS.length - 1);
5836
5980
  const treeNav = useArtifactTreeNavigation(nodes || []);
5837
5981
  const hasNodes = !!nodes && nodes.length > 0;
5838
- const handleExpandArtifact = (0, import_react75.useCallback)((artifact) => {
5982
+ const handleExpandArtifact = (0, import_react76.useCallback)((artifact) => {
5839
5983
  setExpandedArtifact(artifact);
5840
5984
  }, []);
5841
- const handleGroupClick = (0, import_react75.useCallback)((node) => {
5985
+ const handleGroupClick = (0, import_react76.useCallback)((node) => {
5842
5986
  treeNav.navigateInto(node);
5843
5987
  }, [treeNav]);
5844
- const zoomIn = (0, import_react75.useCallback)(() => {
5988
+ (0, import_react76.useEffect)(() => {
5989
+ if (!openArtifactId || !nodes) {
5990
+ return;
5991
+ }
5992
+ const found = findArtifactInNodes(nodes, openArtifactId);
5993
+ if (found) {
5994
+ setExpandedArtifact(found);
5995
+ }
5996
+ }, [openArtifactId, nodes]);
5997
+ const handleModalClose = (0, import_react76.useCallback)(() => {
5998
+ setExpandedArtifact(null);
5999
+ onArtifactClosed?.();
6000
+ }, [onArtifactClosed]);
6001
+ const zoomIn = (0, import_react76.useCallback)(() => {
5845
6002
  setZoomIndex((prev) => Math.min(prev + 1, ZOOM_LEVELS.length - 1));
5846
6003
  }, []);
5847
- const zoomOut = (0, import_react75.useCallback)(() => {
6004
+ const zoomOut = (0, import_react76.useCallback)(() => {
5848
6005
  setZoomIndex((prev) => Math.max(prev - 1, 0));
5849
6006
  }, []);
5850
6007
  const currentZoom = ZOOM_LEVELS[zoomIndex];
5851
- const contentRef = (0, import_react75.useRef)(null);
5852
- const [contentHeight, setContentHeight] = (0, import_react75.useState)(void 0);
5853
- (0, import_react75.useEffect)(() => {
6008
+ const contentRef = (0, import_react76.useRef)(null);
6009
+ const [contentHeight, setContentHeight] = (0, import_react76.useState)(void 0);
6010
+ (0, import_react76.useEffect)(() => {
5854
6011
  const el = contentRef.current;
5855
- if (!el) return;
6012
+ if (!el) {
6013
+ return;
6014
+ }
5856
6015
  const observer = new ResizeObserver(([entry]) => {
5857
6016
  setContentHeight(entry.contentRect.height);
5858
6017
  });
5859
6018
  observer.observe(el);
5860
6019
  return () => observer.disconnect();
5861
6020
  }, []);
5862
- return /* @__PURE__ */ import_react75.default.createElement(import_react75.default.Fragment, null, /* @__PURE__ */ import_react75.default.createElement(
6021
+ return /* @__PURE__ */ import_react76.default.createElement(import_react76.default.Fragment, null, /* @__PURE__ */ import_react76.default.createElement(
5863
6022
  "div",
5864
6023
  {
5865
6024
  ref,
@@ -5870,19 +6029,19 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5870
6029
  ),
5871
6030
  ...rest
5872
6031
  },
5873
- /* @__PURE__ */ import_react75.default.createElement(
6032
+ /* @__PURE__ */ import_react76.default.createElement(
5874
6033
  "div",
5875
6034
  {
5876
6035
  className: "flex items-center justify-between p-4 border-b border-ash/40 shrink-0"
5877
6036
  },
5878
- /* @__PURE__ */ import_react75.default.createElement("h3", { className: "text-sm font-semibold text-white" }, "Artifacts"),
5879
- hasNodes && /* @__PURE__ */ import_react75.default.createElement(
6037
+ /* @__PURE__ */ import_react76.default.createElement("h3", { className: "text-sm font-semibold text-white" }, "Artifacts"),
6038
+ hasNodes && /* @__PURE__ */ import_react76.default.createElement(
5880
6039
  "div",
5881
6040
  {
5882
6041
  className: "flex items-center gap-0.5",
5883
6042
  "data-testid": "zoom-controls"
5884
6043
  },
5885
- /* @__PURE__ */ import_react75.default.createElement(
6044
+ /* @__PURE__ */ import_react76.default.createElement(
5886
6045
  "button",
5887
6046
  {
5888
6047
  onClick: zoomOut,
@@ -5896,8 +6055,16 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5896
6055
  },
5897
6056
  "\u2212"
5898
6057
  ),
5899
- /* @__PURE__ */ import_react75.default.createElement("span", { className: "text-xs text-silver w-8 text-center tabular-nums", "data-testid": "zoom-level" }, Math.round(currentZoom * 100), "%"),
5900
- /* @__PURE__ */ import_react75.default.createElement(
6058
+ /* @__PURE__ */ import_react76.default.createElement(
6059
+ "span",
6060
+ {
6061
+ className: "text-xs text-silver w-8 text-center tabular-nums",
6062
+ "data-testid": "zoom-level"
6063
+ },
6064
+ Math.round(currentZoom * 100),
6065
+ "%"
6066
+ ),
6067
+ /* @__PURE__ */ import_react76.default.createElement(
5901
6068
  "button",
5902
6069
  {
5903
6070
  onClick: zoomIn,
@@ -5913,7 +6080,7 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5913
6080
  )
5914
6081
  )
5915
6082
  ),
5916
- hasNodes && !treeNav.isAtRoot && /* @__PURE__ */ import_react75.default.createElement(
6083
+ hasNodes && !treeNav.isAtRoot && /* @__PURE__ */ import_react76.default.createElement(
5917
6084
  "nav",
5918
6085
  {
5919
6086
  className: "flex items-center gap-1 px-4 py-2 border-b border-ash/40 shrink-0 overflow-x-auto text-xs",
@@ -5922,7 +6089,7 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5922
6089
  },
5923
6090
  treeNav.breadcrumbs.map((crumb, i) => {
5924
6091
  const isLast = i === treeNav.breadcrumbs.length - 1;
5925
- return /* @__PURE__ */ import_react75.default.createElement("span", { key: i, className: "flex items-center gap-1 shrink-0" }, i > 0 && /* @__PURE__ */ import_react75.default.createElement(ChevronRightIcon, { className: "w-3 h-3 text-silver/50", "aria-hidden": true }), isLast ? /* @__PURE__ */ import_react75.default.createElement("span", { className: "text-gold font-medium" }, crumb.label) : /* @__PURE__ */ import_react75.default.createElement(
6092
+ return /* @__PURE__ */ import_react76.default.createElement("span", { key: i, className: "flex items-center gap-1 shrink-0" }, i > 0 && /* @__PURE__ */ import_react76.default.createElement(ChevronRightIcon, { className: "w-3 h-3 text-silver/50", "aria-hidden": true }), isLast ? /* @__PURE__ */ import_react76.default.createElement("span", { className: "text-gold font-medium" }, crumb.label) : /* @__PURE__ */ import_react76.default.createElement(
5926
6093
  "button",
5927
6094
  {
5928
6095
  onClick: () => treeNav.navigateTo(i),
@@ -5932,18 +6099,18 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5932
6099
  ));
5933
6100
  })
5934
6101
  ),
5935
- /* @__PURE__ */ import_react75.default.createElement(
6102
+ /* @__PURE__ */ import_react76.default.createElement(
5936
6103
  "div",
5937
6104
  {
5938
6105
  className: "flex-1 overflow-auto relative",
5939
6106
  "data-testid": "artifacts-scroll-area"
5940
6107
  },
5941
- /* @__PURE__ */ import_react75.default.createElement(
6108
+ /* @__PURE__ */ import_react76.default.createElement(
5942
6109
  "div",
5943
6110
  {
5944
6111
  style: currentZoom !== 1 && contentHeight !== void 0 ? { height: contentHeight * currentZoom } : void 0
5945
6112
  },
5946
- /* @__PURE__ */ import_react75.default.createElement(
6113
+ /* @__PURE__ */ import_react76.default.createElement(
5947
6114
  "div",
5948
6115
  {
5949
6116
  ref: contentRef,
@@ -5954,7 +6121,7 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5954
6121
  transformOrigin: "top center"
5955
6122
  } : void 0
5956
6123
  },
5957
- treeNav.currentNodes.length === 0 ? /* @__PURE__ */ import_react75.default.createElement("p", { className: "text-xs text-silver/60 text-center py-8" }, hasNodes ? "Empty group" : "No artifacts to display") : treeNav.currentNodes.map((node) => /* @__PURE__ */ import_react75.default.createElement(
6124
+ treeNav.currentNodes.length === 0 ? /* @__PURE__ */ import_react76.default.createElement("p", { className: "text-xs text-silver/60 text-center py-8" }, hasNodes ? "Empty group" : "No artifacts to display") : treeNav.currentNodes.map((node) => /* @__PURE__ */ import_react76.default.createElement(
5958
6125
  NodeRenderer,
5959
6126
  {
5960
6127
  key: node.id,
@@ -5967,18 +6134,18 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5967
6134
  )
5968
6135
  )
5969
6136
  )
5970
- ), expandedArtifact && /* @__PURE__ */ import_react75.default.createElement(
6137
+ ), expandedArtifact && /* @__PURE__ */ import_react76.default.createElement(
5971
6138
  ArtifactModal,
5972
6139
  {
5973
6140
  artifact: expandedArtifact,
5974
- onClose: () => setExpandedArtifact(null)
6141
+ onClose: handleModalClose
5975
6142
  }
5976
6143
  ));
5977
6144
  }
5978
6145
  );
5979
6146
  ArtifactsPanel.displayName = "ArtifactsPanel";
5980
- var ArtifactsPanelToggle = import_react75.default.forwardRef(({ artifactCount = 0, onExpand, className, ...rest }, ref) => {
5981
- return /* @__PURE__ */ import_react75.default.createElement(
6147
+ var ArtifactsPanelToggle = import_react76.default.forwardRef(({ artifactCount = 0, onExpand, className, ...rest }, ref) => {
6148
+ return /* @__PURE__ */ import_react76.default.createElement(
5982
6149
  "button",
5983
6150
  {
5984
6151
  ref,
@@ -5995,8 +6162,8 @@ var ArtifactsPanelToggle = import_react75.default.forwardRef(({ artifactCount =
5995
6162
  "aria-label": "Expand artifacts panel",
5996
6163
  ...rest
5997
6164
  },
5998
- /* @__PURE__ */ import_react75.default.createElement(import_lucide_react17.Image, { className: "w-5 h-5", "aria-hidden": true }),
5999
- artifactCount > 0 && /* @__PURE__ */ import_react75.default.createElement(
6165
+ /* @__PURE__ */ import_react76.default.createElement(import_lucide_react17.Image, { className: "w-5 h-5", "aria-hidden": true }),
6166
+ artifactCount > 0 && /* @__PURE__ */ import_react76.default.createElement(
6000
6167
  "span",
6001
6168
  {
6002
6169
  className: "absolute -top-1 -right-1 w-4 h-4 bg-gold text-obsidian text-xs font-medium flex items-center justify-center"
@@ -6008,7 +6175,7 @@ var ArtifactsPanelToggle = import_react75.default.forwardRef(({ artifactCount =
6008
6175
  ArtifactsPanelToggle.displayName = "ArtifactsPanelToggle";
6009
6176
 
6010
6177
  // src/components/chat/HistoryPanel.tsx
6011
- var import_react76 = __toESM(require("react"));
6178
+ var import_react77 = __toESM(require("react"));
6012
6179
  var import_lucide_react18 = require("lucide-react");
6013
6180
  function parseTimestamp(ts) {
6014
6181
  if (ts == null) {
@@ -6051,12 +6218,12 @@ function ProjectFilter({
6051
6218
  onChange,
6052
6219
  className
6053
6220
  }) {
6054
- const [open, setOpen] = (0, import_react76.useState)(false);
6055
- const ref = (0, import_react76.useRef)(null);
6056
- const closeFilter = (0, import_react76.useCallback)(() => setOpen(false), []);
6221
+ const [open, setOpen] = (0, import_react77.useState)(false);
6222
+ const ref = (0, import_react77.useRef)(null);
6223
+ const closeFilter = (0, import_react77.useCallback)(() => setOpen(false), []);
6057
6224
  useClickOutside(ref, closeFilter, open);
6058
6225
  const label = value ?? "All projects";
6059
- return /* @__PURE__ */ import_react76.default.createElement("div", { className: cx("relative min-w-0", className), ref }, /* @__PURE__ */ import_react76.default.createElement(
6226
+ return /* @__PURE__ */ import_react77.default.createElement("div", { className: cx("relative min-w-0", className), ref }, /* @__PURE__ */ import_react77.default.createElement(
6060
6227
  "button",
6061
6228
  {
6062
6229
  type: "button",
@@ -6072,9 +6239,9 @@ function ProjectFilter({
6072
6239
  "transition-colors duration-150 min-w-0"
6073
6240
  )
6074
6241
  },
6075
- /* @__PURE__ */ import_react76.default.createElement("span", { className: "truncate" }, label),
6076
- /* @__PURE__ */ import_react76.default.createElement(import_lucide_react18.ChevronDown, { className: "w-3 h-3 shrink-0", "aria-hidden": true })
6077
- ), open && /* @__PURE__ */ import_react76.default.createElement(
6242
+ /* @__PURE__ */ import_react77.default.createElement("span", { className: "truncate" }, label),
6243
+ /* @__PURE__ */ import_react77.default.createElement(import_lucide_react18.ChevronDown, { className: "w-3 h-3 shrink-0", "aria-hidden": true })
6244
+ ), open && /* @__PURE__ */ import_react77.default.createElement(
6078
6245
  "div",
6079
6246
  {
6080
6247
  role: "listbox",
@@ -6084,7 +6251,7 @@ function ProjectFilter({
6084
6251
  "max-h-60 overflow-y-auto"
6085
6252
  )
6086
6253
  },
6087
- /* @__PURE__ */ import_react76.default.createElement(
6254
+ /* @__PURE__ */ import_react77.default.createElement(
6088
6255
  "button",
6089
6256
  {
6090
6257
  type: "button",
@@ -6102,7 +6269,7 @@ function ProjectFilter({
6102
6269
  },
6103
6270
  "All projects"
6104
6271
  ),
6105
- projects.map((p) => /* @__PURE__ */ import_react76.default.createElement(
6272
+ projects.map((p) => /* @__PURE__ */ import_react77.default.createElement(
6106
6273
  "button",
6107
6274
  {
6108
6275
  key: p,
@@ -6128,33 +6295,33 @@ function ConversationRow({
6128
6295
  onSelect,
6129
6296
  onRename
6130
6297
  }) {
6131
- const [isEditing, setIsEditing] = (0, import_react76.useState)(false);
6132
- const [draft, setDraft] = (0, import_react76.useState)(conversation.title);
6133
- const inputRef = (0, import_react76.useRef)(null);
6134
- (0, import_react76.useEffect)(() => {
6298
+ const [isEditing, setIsEditing] = (0, import_react77.useState)(false);
6299
+ const [draft, setDraft] = (0, import_react77.useState)(conversation.title);
6300
+ const inputRef = (0, import_react77.useRef)(null);
6301
+ (0, import_react77.useEffect)(() => {
6135
6302
  if (isEditing && inputRef.current) {
6136
6303
  inputRef.current.focus();
6137
6304
  inputRef.current.select();
6138
6305
  }
6139
6306
  }, [isEditing]);
6140
- const startEdit = (0, import_react76.useCallback)((e) => {
6307
+ const startEdit = (0, import_react77.useCallback)((e) => {
6141
6308
  e.stopPropagation();
6142
6309
  setDraft(conversation.title);
6143
6310
  setIsEditing(true);
6144
6311
  }, [conversation.title]);
6145
- const commit = (0, import_react76.useCallback)(() => {
6312
+ const commit = (0, import_react77.useCallback)(() => {
6146
6313
  const trimmed = draft.trim();
6147
6314
  if (trimmed && trimmed !== conversation.title) {
6148
6315
  onRename?.(conversation.id, trimmed);
6149
6316
  }
6150
6317
  setIsEditing(false);
6151
6318
  }, [draft, conversation.id, conversation.title, onRename]);
6152
- const cancel = (0, import_react76.useCallback)(() => {
6319
+ const cancel = (0, import_react77.useCallback)(() => {
6153
6320
  setDraft(conversation.title);
6154
6321
  setIsEditing(false);
6155
6322
  }, [conversation.title]);
6156
6323
  if (isEditing) {
6157
- return /* @__PURE__ */ import_react76.default.createElement(
6324
+ return /* @__PURE__ */ import_react77.default.createElement(
6158
6325
  "div",
6159
6326
  {
6160
6327
  className: cx(
@@ -6162,7 +6329,7 @@ function ConversationRow({
6162
6329
  conversation.isActive ? "bg-ash/40" : "bg-ash/20"
6163
6330
  )
6164
6331
  },
6165
- /* @__PURE__ */ import_react76.default.createElement(
6332
+ /* @__PURE__ */ import_react77.default.createElement(
6166
6333
  "input",
6167
6334
  {
6168
6335
  ref: inputRef,
@@ -6187,10 +6354,10 @@ function ConversationRow({
6187
6354
  "aria-label": "Conversation title"
6188
6355
  }
6189
6356
  ),
6190
- conversation.project && /* @__PURE__ */ import_react76.default.createElement("p", { className: "text-xs text-silver/60 truncate mt-1" }, conversation.project)
6357
+ conversation.project && /* @__PURE__ */ import_react77.default.createElement("p", { className: "text-xs text-silver/60 truncate mt-1" }, conversation.project)
6191
6358
  );
6192
6359
  }
6193
- return /* @__PURE__ */ import_react76.default.createElement("div", { className: "relative group" }, /* @__PURE__ */ import_react76.default.createElement(
6360
+ return /* @__PURE__ */ import_react77.default.createElement("div", { className: "relative group" }, /* @__PURE__ */ import_react77.default.createElement(
6194
6361
  "button",
6195
6362
  {
6196
6363
  onClick: () => onSelect?.(conversation.id),
@@ -6200,7 +6367,7 @@ function ConversationRow({
6200
6367
  conversation.isActive ? "bg-ash/40 text-white" : "text-silver hover:bg-ash/20 hover:text-white"
6201
6368
  )
6202
6369
  },
6203
- /* @__PURE__ */ import_react76.default.createElement(
6370
+ /* @__PURE__ */ import_react77.default.createElement(
6204
6371
  "p",
6205
6372
  {
6206
6373
  className: cx(
@@ -6210,8 +6377,8 @@ function ConversationRow({
6210
6377
  },
6211
6378
  conversation.title
6212
6379
  ),
6213
- conversation.project && /* @__PURE__ */ import_react76.default.createElement("p", { className: "text-xs text-silver/60 truncate mt-0.5" }, conversation.project)
6214
- ), onRename && /* @__PURE__ */ import_react76.default.createElement(
6380
+ conversation.project && /* @__PURE__ */ import_react77.default.createElement("p", { className: "text-xs text-silver/60 truncate mt-0.5" }, conversation.project)
6381
+ ), onRename && /* @__PURE__ */ import_react77.default.createElement(
6215
6382
  "button",
6216
6383
  {
6217
6384
  type: "button",
@@ -6224,7 +6391,7 @@ function ConversationRow({
6224
6391
  "transition-opacity duration-150"
6225
6392
  )
6226
6393
  },
6227
- /* @__PURE__ */ import_react76.default.createElement(import_lucide_react18.Pencil, { className: "w-3.5 h-3.5", "aria-hidden": true })
6394
+ /* @__PURE__ */ import_react77.default.createElement(import_lucide_react18.Pencil, { className: "w-3.5 h-3.5", "aria-hidden": true })
6228
6395
  ));
6229
6396
  }
6230
6397
  function HistoryPanel({
@@ -6233,8 +6400,8 @@ function HistoryPanel({
6233
6400
  onNewChat,
6234
6401
  onRenameConversation
6235
6402
  }) {
6236
- const [projectFilter, setProjectFilter] = (0, import_react76.useState)(null);
6237
- const projects = (0, import_react76.useMemo)(() => {
6403
+ const [projectFilter, setProjectFilter] = (0, import_react77.useState)(null);
6404
+ const projects = (0, import_react77.useMemo)(() => {
6238
6405
  const set = /* @__PURE__ */ new Set();
6239
6406
  for (const c of conversations) {
6240
6407
  if (c.project) {
@@ -6243,23 +6410,23 @@ function HistoryPanel({
6243
6410
  }
6244
6411
  return Array.from(set).sort((a, b) => a.localeCompare(b));
6245
6412
  }, [conversations]);
6246
- (0, import_react76.useEffect)(() => {
6413
+ (0, import_react77.useEffect)(() => {
6247
6414
  if (projectFilter && !projects.includes(projectFilter)) {
6248
6415
  setProjectFilter(null);
6249
6416
  }
6250
6417
  }, [projects, projectFilter]);
6251
- const filteredConversations = (0, import_react76.useMemo)(() => {
6418
+ const filteredConversations = (0, import_react77.useMemo)(() => {
6252
6419
  if (!projectFilter) {
6253
6420
  return conversations;
6254
6421
  }
6255
6422
  return conversations.filter((c) => c.project === projectFilter);
6256
6423
  }, [conversations, projectFilter]);
6257
- const groups = (0, import_react76.useMemo)(
6424
+ const groups = (0, import_react77.useMemo)(
6258
6425
  () => groupConversations(filteredConversations),
6259
6426
  [filteredConversations]
6260
6427
  );
6261
6428
  const hasFilter = projects.length > 0;
6262
- return /* @__PURE__ */ import_react76.default.createElement("div", { className: "h-full flex flex-col" }, /* @__PURE__ */ import_react76.default.createElement("div", { className: "px-4 py-3 border-b border-ash/40 shrink-0 flex items-center gap-2" }, /* @__PURE__ */ import_react76.default.createElement("h3", { className: "text-xs font-medium text-white shrink-0" }, "History"), (hasFilter || onNewChat) && /* @__PURE__ */ import_react76.default.createElement("div", { className: "flex items-center gap-2 flex-1 min-w-0" }, hasFilter && /* @__PURE__ */ import_react76.default.createElement(import_react76.default.Fragment, null, /* @__PURE__ */ import_react76.default.createElement("div", { className: "w-px h-3 bg-ash/40 shrink-0 mx-1" }), /* @__PURE__ */ import_react76.default.createElement(
6429
+ return /* @__PURE__ */ import_react77.default.createElement("div", { className: "h-full flex flex-col" }, /* @__PURE__ */ import_react77.default.createElement("div", { className: "px-4 py-3 border-b border-ash/40 shrink-0 flex items-center gap-2" }, /* @__PURE__ */ import_react77.default.createElement("h3", { className: "text-xs font-medium text-white shrink-0" }, "History"), (hasFilter || onNewChat) && /* @__PURE__ */ import_react77.default.createElement("div", { className: "flex items-center gap-2 flex-1 min-w-0" }, hasFilter && /* @__PURE__ */ import_react77.default.createElement(import_react77.default.Fragment, null, /* @__PURE__ */ import_react77.default.createElement("div", { className: "w-px h-3 bg-ash/40 shrink-0 mx-1" }), /* @__PURE__ */ import_react77.default.createElement(
6263
6430
  ProjectFilter,
6264
6431
  {
6265
6432
  projects,
@@ -6267,7 +6434,7 @@ function HistoryPanel({
6267
6434
  onChange: setProjectFilter,
6268
6435
  className: "flex-1"
6269
6436
  }
6270
- )), onNewChat && /* @__PURE__ */ import_react76.default.createElement(import_react76.default.Fragment, null, /* @__PURE__ */ import_react76.default.createElement("div", { className: "w-px h-3 bg-ash/40 shrink-0 mx-1" }), /* @__PURE__ */ import_react76.default.createElement(
6437
+ )), onNewChat && /* @__PURE__ */ import_react77.default.createElement(import_react77.default.Fragment, null, /* @__PURE__ */ import_react77.default.createElement("div", { className: "w-px h-3 bg-ash/40 shrink-0 mx-1" }), /* @__PURE__ */ import_react77.default.createElement(
6271
6438
  "button",
6272
6439
  {
6273
6440
  onClick: onNewChat,
@@ -6279,15 +6446,15 @@ function HistoryPanel({
6279
6446
  "transition-colors duration-200"
6280
6447
  )
6281
6448
  },
6282
- /* @__PURE__ */ import_react76.default.createElement(PlusIcon, { className: "w-4 h-4" }),
6283
- /* @__PURE__ */ import_react76.default.createElement("span", { className: "truncate" }, "New Chat")
6284
- )))), /* @__PURE__ */ import_react76.default.createElement("div", { className: "flex-1 overflow-y-auto py-2" }, conversations.length === 0 ? /* @__PURE__ */ import_react76.default.createElement("p", { className: "px-4 py-2 text-xs text-silver/60" }, "No conversations yet") : groups.length === 0 ? /* @__PURE__ */ import_react76.default.createElement("p", { className: "px-4 py-2 text-xs text-silver/60" }, "No conversations match this filter") : /* @__PURE__ */ import_react76.default.createElement("div", null, groups.map((group, index) => /* @__PURE__ */ import_react76.default.createElement("section", { key: group.key, className: cx(index > 0 && "mt-3") }, /* @__PURE__ */ import_react76.default.createElement("div", { className: "flex items-center gap-2 px-3 pb-2" }, /* @__PURE__ */ import_react76.default.createElement(
6449
+ /* @__PURE__ */ import_react77.default.createElement(PlusIcon, { className: "w-4 h-4" }),
6450
+ /* @__PURE__ */ import_react77.default.createElement("span", { className: "truncate" }, "New Chat")
6451
+ )))), /* @__PURE__ */ import_react77.default.createElement("div", { className: "flex-1 overflow-y-auto py-2" }, conversations.length === 0 ? /* @__PURE__ */ import_react77.default.createElement("p", { className: "px-4 py-2 text-xs text-silver/60" }, "No conversations yet") : groups.length === 0 ? /* @__PURE__ */ import_react77.default.createElement("p", { className: "px-4 py-2 text-xs text-silver/60" }, "No conversations match this filter") : /* @__PURE__ */ import_react77.default.createElement("div", null, groups.map((group, index) => /* @__PURE__ */ import_react77.default.createElement("section", { key: group.key, className: cx(index > 0 && "mt-3") }, /* @__PURE__ */ import_react77.default.createElement("div", { className: "flex items-center gap-2 px-3 pb-2" }, /* @__PURE__ */ import_react77.default.createElement(
6285
6452
  "span",
6286
6453
  {
6287
6454
  className: "text-xs font-medium uppercase tracking-wider text-gold/70"
6288
6455
  },
6289
6456
  group.label
6290
- ), /* @__PURE__ */ import_react76.default.createElement("div", { className: "flex-1 h-px bg-gold/20" })), /* @__PURE__ */ import_react76.default.createElement("div", { className: "space-y-1 px-2" }, group.conversations.map((conversation) => /* @__PURE__ */ import_react76.default.createElement(
6457
+ ), /* @__PURE__ */ import_react77.default.createElement("div", { className: "flex-1 h-px bg-gold/20" })), /* @__PURE__ */ import_react77.default.createElement("div", { className: "space-y-1 px-2" }, group.conversations.map((conversation) => /* @__PURE__ */ import_react77.default.createElement(
6291
6458
  ConversationRow,
6292
6459
  {
6293
6460
  key: conversation.id,
@@ -6299,7 +6466,7 @@ function HistoryPanel({
6299
6466
  }
6300
6467
 
6301
6468
  // src/components/chat/TodosList.tsx
6302
- var import_react77 = __toESM(require("react"));
6469
+ var import_react78 = __toESM(require("react"));
6303
6470
  var import_lucide_react19 = require("lucide-react");
6304
6471
  var TASK_STATUSES = {
6305
6472
  PENDING: "pending",
@@ -6311,16 +6478,16 @@ var TASK_STATUSES = {
6311
6478
  function TaskIcon({ status }) {
6312
6479
  switch (status) {
6313
6480
  case "done":
6314
- return /* @__PURE__ */ import_react77.default.createElement(CheckSquareIcon, null);
6481
+ return /* @__PURE__ */ import_react78.default.createElement(CheckSquareIcon, null);
6315
6482
  case "in_progress":
6316
- return /* @__PURE__ */ import_react77.default.createElement(SquareLoaderIcon, null);
6483
+ return /* @__PURE__ */ import_react78.default.createElement(SquareLoaderIcon, null);
6317
6484
  case "cancelled":
6318
- return /* @__PURE__ */ import_react77.default.createElement(CrossSquareIcon, { variant: "cancelled" });
6485
+ return /* @__PURE__ */ import_react78.default.createElement(CrossSquareIcon, { variant: "cancelled" });
6319
6486
  case "failed":
6320
- return /* @__PURE__ */ import_react77.default.createElement(CrossSquareIcon, { variant: "failed" });
6487
+ return /* @__PURE__ */ import_react78.default.createElement(CrossSquareIcon, { variant: "failed" });
6321
6488
  case "pending":
6322
6489
  default:
6323
- return /* @__PURE__ */ import_react77.default.createElement(EmptySquareIcon, null);
6490
+ return /* @__PURE__ */ import_react78.default.createElement(EmptySquareIcon, null);
6324
6491
  }
6325
6492
  }
6326
6493
  function sortTasks(tasks) {
@@ -6340,14 +6507,14 @@ function TaskItem({ task, depth = 0 }) {
6340
6507
  const isSubtle = task.status === "cancelled" || task.status === "failed";
6341
6508
  const showSubtasks = task.subtasks && task.subtasks.length > 0;
6342
6509
  const sortedSubtasks = showSubtasks ? sortTasks(task.subtasks) : [];
6343
- return /* @__PURE__ */ import_react77.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ import_react77.default.createElement(
6510
+ return /* @__PURE__ */ import_react78.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ import_react78.default.createElement(
6344
6511
  "div",
6345
6512
  {
6346
6513
  className: "flex items-center gap-2 py-1",
6347
6514
  style: { paddingLeft: `${depth * 1.5}rem` }
6348
6515
  },
6349
- /* @__PURE__ */ import_react77.default.createElement(TaskIcon, { status: task.status }),
6350
- /* @__PURE__ */ import_react77.default.createElement(
6516
+ /* @__PURE__ */ import_react78.default.createElement(TaskIcon, { status: task.status }),
6517
+ /* @__PURE__ */ import_react78.default.createElement(
6351
6518
  "span",
6352
6519
  {
6353
6520
  className: cx(
@@ -6359,10 +6526,10 @@ function TaskItem({ task, depth = 0 }) {
6359
6526
  )
6360
6527
  },
6361
6528
  task.label,
6362
- task.status === "cancelled" && /* @__PURE__ */ import_react77.default.createElement("span", { className: "text-silver/40 ml-1" }, "(cancelled)"),
6363
- task.status === "failed" && /* @__PURE__ */ import_react77.default.createElement("span", { className: "text-error/60 ml-1" }, "(failed)")
6529
+ task.status === "cancelled" && /* @__PURE__ */ import_react78.default.createElement("span", { className: "text-silver/40 ml-1" }, "(cancelled)"),
6530
+ task.status === "failed" && /* @__PURE__ */ import_react78.default.createElement("span", { className: "text-error/60 ml-1" }, "(failed)")
6364
6531
  )
6365
- ), showSubtasks && /* @__PURE__ */ import_react77.default.createElement("div", { className: "flex flex-col" }, sortedSubtasks.map((subtask) => /* @__PURE__ */ import_react77.default.createElement(TaskItem, { key: subtask.id, task: subtask, depth: depth + 1 }))));
6532
+ ), showSubtasks && /* @__PURE__ */ import_react78.default.createElement("div", { className: "flex flex-col" }, sortedSubtasks.map((subtask) => /* @__PURE__ */ import_react78.default.createElement(TaskItem, { key: subtask.id, task: subtask, depth: depth + 1 }))));
6366
6533
  }
6367
6534
  function hasInProgressTask(tasks) {
6368
6535
  return tasks.some((t) => {
@@ -6375,11 +6542,11 @@ function hasInProgressTask(tasks) {
6375
6542
  return false;
6376
6543
  });
6377
6544
  }
6378
- var TodosList = import_react77.default.forwardRef(
6545
+ var TodosList = import_react78.default.forwardRef(
6379
6546
  ({ tasks, title = "Tasks", onStopAllTasks, className, ...rest }, ref) => {
6380
- const sortedTasks = (0, import_react77.useMemo)(() => sortTasks(tasks), [tasks]);
6381
- const [isStopping, setIsStopping] = (0, import_react77.useState)(false);
6382
- const handleStopClick = (0, import_react77.useCallback)(async () => {
6547
+ const sortedTasks = (0, import_react78.useMemo)(() => sortTasks(tasks), [tasks]);
6548
+ const [isStopping, setIsStopping] = (0, import_react78.useState)(false);
6549
+ const handleStopClick = (0, import_react78.useCallback)(async () => {
6383
6550
  if (!onStopAllTasks || isStopping) {
6384
6551
  return;
6385
6552
  }
@@ -6400,7 +6567,7 @@ var TodosList = import_react77.default.forwardRef(
6400
6567
  if (tasks.length === 0) {
6401
6568
  return null;
6402
6569
  }
6403
- return /* @__PURE__ */ import_react77.default.createElement(
6570
+ return /* @__PURE__ */ import_react78.default.createElement(
6404
6571
  "div",
6405
6572
  {
6406
6573
  ref,
@@ -6411,16 +6578,16 @@ var TodosList = import_react77.default.forwardRef(
6411
6578
  ),
6412
6579
  ...rest
6413
6580
  },
6414
- /* @__PURE__ */ import_react77.default.createElement(
6581
+ /* @__PURE__ */ import_react78.default.createElement(
6415
6582
  "div",
6416
6583
  {
6417
6584
  className: "flex items-center justify-between px-4 py-2 border-b border-ash/40 flex-shrink-0"
6418
6585
  },
6419
- /* @__PURE__ */ import_react77.default.createElement("h4", { className: "text-xs font-medium text-white" }, title),
6420
- /* @__PURE__ */ import_react77.default.createElement("span", { className: "text-xs text-silver/60" }, countCompleted(tasks), "/", countTotal(tasks))
6586
+ /* @__PURE__ */ import_react78.default.createElement("h4", { className: "text-xs font-medium text-white" }, title),
6587
+ /* @__PURE__ */ import_react78.default.createElement("span", { className: "text-xs text-silver/60" }, countCompleted(tasks), "/", countTotal(tasks))
6421
6588
  ),
6422
- /* @__PURE__ */ import_react77.default.createElement("div", { className: "flex-1 overflow-y-auto px-4 py-2" }, sortedTasks.map((task) => /* @__PURE__ */ import_react77.default.createElement(TaskItem, { key: task.id, task }))),
6423
- showStopButton && /* @__PURE__ */ import_react77.default.createElement("div", { className: "px-4 py-2 border-t border-ash/40 flex-shrink-0" }, /* @__PURE__ */ import_react77.default.createElement(
6589
+ /* @__PURE__ */ import_react78.default.createElement("div", { className: "flex-1 overflow-y-auto px-4 py-2" }, sortedTasks.map((task) => /* @__PURE__ */ import_react78.default.createElement(TaskItem, { key: task.id, task }))),
6590
+ showStopButton && /* @__PURE__ */ import_react78.default.createElement("div", { className: "px-4 py-2 border-t border-ash/40 flex-shrink-0" }, /* @__PURE__ */ import_react78.default.createElement(
6424
6591
  "button",
6425
6592
  {
6426
6593
  type: "button",
@@ -6437,7 +6604,7 @@ var TodosList = import_react77.default.forwardRef(
6437
6604
  isStopping ? "cursor-not-allowed opacity-70" : "hover:bg-error/20"
6438
6605
  )
6439
6606
  },
6440
- isStopping ? /* @__PURE__ */ import_react77.default.createElement(import_react77.default.Fragment, null, /* @__PURE__ */ import_react77.default.createElement(import_lucide_react19.Loader2, { className: "w-3 h-3 animate-spin" }), "Stopping tasks") : /* @__PURE__ */ import_react77.default.createElement(import_react77.default.Fragment, null, /* @__PURE__ */ import_react77.default.createElement(import_lucide_react19.Square, { className: "w-3 h-3 fill-current" }), "Stop All Tasks")
6607
+ isStopping ? /* @__PURE__ */ import_react78.default.createElement(import_react78.default.Fragment, null, /* @__PURE__ */ import_react78.default.createElement(import_lucide_react19.Loader2, { className: "w-3 h-3 animate-spin" }), "Stopping tasks") : /* @__PURE__ */ import_react78.default.createElement(import_react78.default.Fragment, null, /* @__PURE__ */ import_react78.default.createElement(import_lucide_react19.Square, { className: "w-3 h-3 fill-current" }), "Stop All Tasks")
6441
6608
  ))
6442
6609
  );
6443
6610
  }
@@ -6457,8 +6624,8 @@ function areAllTasksSettled(tasks) {
6457
6624
  }
6458
6625
 
6459
6626
  // src/components/chat/ToolSidebar.tsx
6460
- var import_react78 = __toESM(require("react"));
6461
- var ToolSidebar = import_react78.default.forwardRef(
6627
+ var import_react79 = __toESM(require("react"));
6628
+ var ToolSidebar = import_react79.default.forwardRef(
6462
6629
  ({ tools, activeTools, onToggleTool, side, className, ...rest }, ref) => {
6463
6630
  const topTools = tools.filter((t) => t.group === `top-${side}`);
6464
6631
  const bottomTools = tools.filter((t) => t.group === `bottom-${side}`);
@@ -6469,7 +6636,7 @@ var ToolSidebar = import_react78.default.forwardRef(
6469
6636
  };
6470
6637
  const renderButton = (tool) => {
6471
6638
  const active = isActive(tool.id);
6472
- return /* @__PURE__ */ import_react78.default.createElement(
6639
+ return /* @__PURE__ */ import_react79.default.createElement(
6473
6640
  "button",
6474
6641
  {
6475
6642
  key: tool.id,
@@ -6481,10 +6648,10 @@ var ToolSidebar = import_react78.default.forwardRef(
6481
6648
  "aria-label": tool.label,
6482
6649
  "aria-pressed": active
6483
6650
  },
6484
- /* @__PURE__ */ import_react78.default.createElement("span", { className: "w-4 h-4 block" }, tool.icon)
6651
+ /* @__PURE__ */ import_react79.default.createElement("span", { className: "w-4 h-4 block" }, tool.icon)
6485
6652
  );
6486
6653
  };
6487
- return /* @__PURE__ */ import_react78.default.createElement(
6654
+ return /* @__PURE__ */ import_react79.default.createElement(
6488
6655
  "div",
6489
6656
  {
6490
6657
  ref,
@@ -6495,17 +6662,17 @@ var ToolSidebar = import_react78.default.forwardRef(
6495
6662
  ),
6496
6663
  ...rest
6497
6664
  },
6498
- /* @__PURE__ */ import_react78.default.createElement("div", { className: "flex flex-col items-center gap-1" }, topTools.map(renderButton)),
6499
- /* @__PURE__ */ import_react78.default.createElement("div", { className: "flex-1 flex items-center justify-center" }, /* @__PURE__ */ import_react78.default.createElement("div", { className: "w-5 border-t border-ash/30" })),
6500
- /* @__PURE__ */ import_react78.default.createElement("div", { className: "flex flex-col items-center gap-1" }, bottomTools.map(renderButton))
6665
+ /* @__PURE__ */ import_react79.default.createElement("div", { className: "flex flex-col items-center gap-1" }, topTools.map(renderButton)),
6666
+ /* @__PURE__ */ import_react79.default.createElement("div", { className: "flex-1 flex items-center justify-center" }, /* @__PURE__ */ import_react79.default.createElement("div", { className: "w-5 border-t border-ash/30" })),
6667
+ /* @__PURE__ */ import_react79.default.createElement("div", { className: "flex flex-col items-center gap-1" }, bottomTools.map(renderButton))
6501
6668
  );
6502
6669
  }
6503
6670
  );
6504
6671
  ToolSidebar.displayName = "ToolSidebar";
6505
6672
 
6506
6673
  // src/components/chat/ToolPanelContainer.tsx
6507
- var import_react79 = __toESM(require("react"));
6508
- var ToolPanelContainer = import_react79.default.forwardRef(
6674
+ var import_react80 = __toESM(require("react"));
6675
+ var ToolPanelContainer = import_react80.default.forwardRef(
6509
6676
  ({
6510
6677
  topContent,
6511
6678
  bottomContent,
@@ -6516,21 +6683,21 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6516
6683
  initialTopPercent = 60,
6517
6684
  ...rest
6518
6685
  }, ref) => {
6519
- const [topPercent, setTopPercent] = (0, import_react79.useState)(initialTopPercent);
6520
- const [isResizingHeight, setIsResizingHeight] = (0, import_react79.useState)(false);
6521
- const containerRef = (0, import_react79.useRef)(null);
6522
- const lastY = (0, import_react79.useRef)(null);
6686
+ const [topPercent, setTopPercent] = (0, import_react80.useState)(initialTopPercent);
6687
+ const [isResizingHeight, setIsResizingHeight] = (0, import_react80.useState)(false);
6688
+ const containerRef = (0, import_react80.useRef)(null);
6689
+ const lastY = (0, import_react80.useRef)(null);
6523
6690
  const hasBoth = topContent !== null && bottomContent !== null;
6524
- const startHeightResize = (0, import_react79.useCallback)((e) => {
6691
+ const startHeightResize = (0, import_react80.useCallback)((e) => {
6525
6692
  e.preventDefault();
6526
6693
  setIsResizingHeight(true);
6527
6694
  lastY.current = e.clientY;
6528
6695
  }, []);
6529
- const stopHeightResize = (0, import_react79.useCallback)(() => {
6696
+ const stopHeightResize = (0, import_react80.useCallback)(() => {
6530
6697
  setIsResizingHeight(false);
6531
6698
  lastY.current = null;
6532
6699
  }, []);
6533
- const resizeHeight = (0, import_react79.useCallback)(
6700
+ const resizeHeight = (0, import_react80.useCallback)(
6534
6701
  (e) => {
6535
6702
  if (!isResizingHeight || lastY.current === null || !containerRef.current) {
6536
6703
  return;
@@ -6549,7 +6716,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6549
6716
  },
6550
6717
  [isResizingHeight]
6551
6718
  );
6552
- (0, import_react79.useEffect)(() => {
6719
+ (0, import_react80.useEffect)(() => {
6553
6720
  if (isResizingHeight) {
6554
6721
  window.addEventListener("mousemove", resizeHeight);
6555
6722
  window.addEventListener("mouseup", stopHeightResize);
@@ -6568,7 +6735,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6568
6735
  document.body.style.userSelect = "";
6569
6736
  };
6570
6737
  }, [isResizingHeight, resizeHeight, stopHeightResize]);
6571
- return /* @__PURE__ */ import_react79.default.createElement(
6738
+ return /* @__PURE__ */ import_react80.default.createElement(
6572
6739
  "div",
6573
6740
  {
6574
6741
  ref: composeRefs(containerRef, ref),
@@ -6580,7 +6747,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6580
6747
  style: width ? { width } : void 0,
6581
6748
  ...rest
6582
6749
  },
6583
- /* @__PURE__ */ import_react79.default.createElement(
6750
+ /* @__PURE__ */ import_react80.default.createElement(
6584
6751
  "div",
6585
6752
  {
6586
6753
  onMouseDown: onResizeStart,
@@ -6591,7 +6758,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6591
6758
  )
6592
6759
  }
6593
6760
  ),
6594
- topContent !== null && /* @__PURE__ */ import_react79.default.createElement(
6761
+ topContent !== null && /* @__PURE__ */ import_react80.default.createElement(
6595
6762
  "div",
6596
6763
  {
6597
6764
  className: "min-h-0 overflow-hidden flex flex-col",
@@ -6599,7 +6766,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6599
6766
  },
6600
6767
  topContent
6601
6768
  ),
6602
- hasBoth && /* @__PURE__ */ import_react79.default.createElement(
6769
+ hasBoth && /* @__PURE__ */ import_react80.default.createElement(
6603
6770
  "div",
6604
6771
  {
6605
6772
  onMouseDown: startHeightResize,
@@ -6611,7 +6778,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6611
6778
  )
6612
6779
  }
6613
6780
  ),
6614
- bottomContent !== null && /* @__PURE__ */ import_react79.default.createElement(
6781
+ bottomContent !== null && /* @__PURE__ */ import_react80.default.createElement(
6615
6782
  "div",
6616
6783
  {
6617
6784
  className: "min-h-0 overflow-hidden flex flex-col",
@@ -6624,65 +6791,6 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6624
6791
  );
6625
6792
  ToolPanelContainer.displayName = "ToolPanelContainer";
6626
6793
 
6627
- // src/components/chat/hooks/useResizable.ts
6628
- var import_react80 = require("react");
6629
- function useResizable({
6630
- initialWidthPercent,
6631
- minWidthPercent,
6632
- maxWidthPercent,
6633
- direction
6634
- }) {
6635
- const [widthPercent, setWidthPercent] = (0, import_react80.useState)(initialWidthPercent);
6636
- const [isResizing, setIsResizing] = (0, import_react80.useState)(false);
6637
- const lastX = (0, import_react80.useRef)(null);
6638
- const startResizing = (0, import_react80.useCallback)((e) => {
6639
- e.preventDefault();
6640
- setIsResizing(true);
6641
- lastX.current = e.clientX;
6642
- }, []);
6643
- const stopResizing = (0, import_react80.useCallback)(() => {
6644
- setIsResizing(false);
6645
- lastX.current = null;
6646
- }, []);
6647
- const resize = (0, import_react80.useCallback)(
6648
- (e) => {
6649
- if (!isResizing || lastX.current === null) {
6650
- return;
6651
- }
6652
- const deltaX = e.clientX - lastX.current;
6653
- const factor = direction === "right" ? 1 : -1;
6654
- const deltaPercent = deltaX / window.innerWidth * 100;
6655
- setWidthPercent((prevPercent) => {
6656
- const newPercent = prevPercent + deltaPercent * factor;
6657
- return Math.min(Math.max(newPercent, minWidthPercent), maxWidthPercent);
6658
- });
6659
- lastX.current = e.clientX;
6660
- },
6661
- [isResizing, direction, minWidthPercent, maxWidthPercent]
6662
- );
6663
- (0, import_react80.useEffect)(() => {
6664
- if (isResizing) {
6665
- window.addEventListener("mousemove", resize);
6666
- window.addEventListener("mouseup", stopResizing);
6667
- document.body.style.cursor = "col-resize";
6668
- document.body.style.userSelect = "none";
6669
- } else {
6670
- window.removeEventListener("mousemove", resize);
6671
- window.removeEventListener("mouseup", stopResizing);
6672
- document.body.style.cursor = "";
6673
- document.body.style.userSelect = "";
6674
- }
6675
- return () => {
6676
- window.removeEventListener("mousemove", resize);
6677
- window.removeEventListener("mouseup", stopResizing);
6678
- document.body.style.cursor = "";
6679
- document.body.style.userSelect = "";
6680
- };
6681
- }, [isResizing, resize, stopResizing]);
6682
- const width = `${widthPercent}vw`;
6683
- return { width, widthPercent, isResizing, startResizing };
6684
- }
6685
-
6686
6794
  // src/components/chat/tree.ts
6687
6795
  function createEmptyTree() {
6688
6796
  return { nodes: {}, rootIds: [], activeLeafId: null, lastLeafId: null };
@@ -6843,6 +6951,7 @@ var ChatInterface = import_react81.default.forwardRef(
6843
6951
  onRenameConversation,
6844
6952
  isStreaming = false,
6845
6953
  isThinking = false,
6954
+ thinkingLabel,
6846
6955
  placeholder = "Send a message...",
6847
6956
  emptyStateHelper = "Let's talk.",
6848
6957
  emptyState,
@@ -6851,6 +6960,7 @@ var ChatInterface = import_react81.default.forwardRef(
6851
6960
  attachments: propsAttachments,
6852
6961
  onAttachmentsChange,
6853
6962
  onAttachmentRemove,
6963
+ onAttachmentOpen,
6854
6964
  artifactNodes,
6855
6965
  isArtifactsPanelOpen,
6856
6966
  onArtifactsPanelOpenChange,
@@ -6867,6 +6977,14 @@ var ChatInterface = import_react81.default.forwardRef(
6867
6977
  }, ref) => {
6868
6978
  const prevArtifactNodesRef = (0, import_react81.useRef)([]);
6869
6979
  const prevTasksRef = (0, import_react81.useRef)([]);
6980
+ const [panelOpenArtifactId, setPanelOpenArtifactId] = (0, import_react81.useState)(null);
6981
+ const handleAttachmentOpen = (0, import_react81.useCallback)((artifactId) => {
6982
+ setPanelOpenArtifactId(artifactId);
6983
+ onAttachmentOpen?.(artifactId);
6984
+ }, [onAttachmentOpen]);
6985
+ const handleArtifactPanelClosed = (0, import_react81.useCallback)(() => {
6986
+ setPanelOpenArtifactId(null);
6987
+ }, []);
6870
6988
  const [internalTools, setInternalTools] = (0, import_react81.useState)({
6871
6989
  "top-left": "history",
6872
6990
  "bottom-left": null,
@@ -7054,7 +7172,15 @@ var ChatInterface = import_react81.default.forwardRef(
7054
7172
  isStreaming: node.isStreaming,
7055
7173
  muted: opts.muted,
7056
7174
  branchInfo,
7057
- actions
7175
+ actions,
7176
+ attachments: node.attachments ? node.attachments.map((a) => ({
7177
+ id: a.id,
7178
+ file: { name: a.name, size: a.size ?? 0, type: a.type },
7179
+ previewUrl: a.previewUrl,
7180
+ artifactId: a.artifactId,
7181
+ status: a.status ?? "analyzed"
7182
+ })) : void 0,
7183
+ onAttachmentOpen: handleAttachmentOpen
7058
7184
  };
7059
7185
  },
7060
7186
  [
@@ -7064,7 +7190,8 @@ var ChatInterface = import_react81.default.forwardRef(
7064
7190
  onEditMessage,
7065
7191
  onRetryMessage,
7066
7192
  handleBranchSwitch,
7067
- handleJumpToCheckpoint
7193
+ handleJumpToCheckpoint,
7194
+ handleAttachmentOpen
7068
7195
  ]
7069
7196
  );
7070
7197
  const displayItems = (0, import_react81.useMemo)(() => {
@@ -7133,6 +7260,8 @@ var ChatInterface = import_react81.default.forwardRef(
7133
7260
  ArtifactsPanel,
7134
7261
  {
7135
7262
  nodes: artifactNodes,
7263
+ openArtifactId: panelOpenArtifactId,
7264
+ onArtifactClosed: handleArtifactPanelClosed,
7136
7265
  className: "h-full"
7137
7266
  }
7138
7267
  );
@@ -7195,6 +7324,7 @@ var ChatInterface = import_react81.default.forwardRef(
7195
7324
  latestUserMessageIndex,
7196
7325
  isStreaming,
7197
7326
  isThinking,
7327
+ thinkingLabel,
7198
7328
  className: "flex-1"
7199
7329
  }
7200
7330
  )), /* @__PURE__ */ import_react81.default.createElement("div", { className: cx(