@lukeashford/aurelius 4.2.0 → 4.4.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,91 @@ 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: "Analyzing",
1503
+ analyzing: "Analyzing",
1504
+ analyzed: null,
1505
+ upload_failed: "Upload failed",
1506
+ analysis_failed: "Couldn't process this file"
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;
1512
- return /* @__PURE__ */ import_react16.default.createElement(
1530
+ const clickable = !!(artifactId && onOpen);
1531
+ const hoverLabel = statusHoverLabel[status];
1532
+ const tooltipContent = isErrorStatus(status) ? error ?? hoverLabel ?? null : hoverLabel;
1533
+ const [hovered, setHovered] = (0, import_react16.useState)(false);
1534
+ const [focused, setFocused] = (0, import_react16.useState)(false);
1535
+ const showError = isErrorStatus(status);
1536
+ const handleClick = () => {
1537
+ if (clickable) {
1538
+ onOpen(artifactId);
1539
+ }
1540
+ };
1541
+ const handleKeyDown = (e) => {
1542
+ if (!clickable) {
1543
+ return;
1544
+ }
1545
+ if (e.key === "Enter" || e.key === " ") {
1546
+ e.preventDefault();
1547
+ onOpen(artifactId);
1548
+ }
1549
+ };
1550
+ const tooltipOpen = tooltipContent !== null && (hovered || focused);
1551
+ const chip = /* @__PURE__ */ import_react16.default.createElement(
1513
1552
  "div",
1514
1553
  {
1554
+ ...rest,
1515
1555
  ref,
1516
1556
  className: cx(
1517
1557
  "group relative inline-flex items-center gap-2 px-2 py-1.5",
1518
1558
  "bg-charcoal border text-sm text-white",
1519
1559
  "transition-colors duration-150",
1520
- statusStyles[status],
1521
- status === "error" && "bg-error/10",
1560
+ statusBorderClass[status],
1561
+ showError && "bg-error/10",
1562
+ clickable && "cursor-pointer hover:bg-graphite",
1522
1563
  className
1523
1564
  ),
1524
- role: "listitem",
1525
- ...rest
1565
+ role: clickable ? "button" : "listitem",
1566
+ tabIndex: clickable ? 0 : void 0,
1567
+ onClick: clickable ? handleClick : void 0,
1568
+ onKeyDown: clickable ? handleKeyDown : void 0,
1569
+ onMouseEnter: () => setHovered(true),
1570
+ onMouseLeave: () => setHovered(false),
1571
+ onFocus: () => setFocused(true),
1572
+ onBlur: () => setFocused(false),
1573
+ title,
1574
+ "aria-label": hoverLabel ? `${name}: ${hoverLabel}` : name
1526
1575
  },
1527
1576
  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
1577
  "img",
@@ -1533,10 +1582,11 @@ var FileChip = import_react16.default.forwardRef(
1533
1582
  }
1534
1583
  )) : /* @__PURE__ */ import_react16.default.createElement(Icon, { className: cx(
1535
1584
  "w-4 h-4 flex-shrink-0",
1536
- status === "error" ? "text-error" : "text-silver"
1585
+ showError ? "text-error" : "text-silver"
1537
1586
  ) }),
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)),
1587
+ /* @__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
1588
  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" }),
1589
+ (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
1590
  status === "pending" && /* @__PURE__ */ import_react16.default.createElement("div", { className: "w-2 h-2 rounded-full bg-silver/50 flex-shrink-0" }),
1541
1591
  removable && onRemove && /* @__PURE__ */ import_react16.default.createElement(
1542
1592
  "button",
@@ -1557,6 +1607,10 @@ var FileChip = import_react16.default.forwardRef(
1557
1607
  /* @__PURE__ */ import_react16.default.createElement(import_lucide_react2.X, { className: "w-3.5 h-3.5" })
1558
1608
  )
1559
1609
  );
1610
+ if (tooltipContent === null) {
1611
+ return chip;
1612
+ }
1613
+ return /* @__PURE__ */ import_react16.default.createElement(Tooltip, { content: tooltipContent, open: tooltipOpen, side: "top" }, chip);
1560
1614
  }
1561
1615
  );
1562
1616
  FileChip.displayName = "FileChip";
@@ -1569,6 +1623,7 @@ var AttachmentPreview = import_react17.default.forwardRef(
1569
1623
  onRemove,
1570
1624
  removable = true,
1571
1625
  maxVisible,
1626
+ onOpen,
1572
1627
  className,
1573
1628
  ...rest
1574
1629
  }, ref) => {
@@ -1597,7 +1652,9 @@ var AttachmentPreview = import_react17.default.forwardRef(
1597
1652
  previewUrl: attachment.previewUrl,
1598
1653
  error: attachment.error,
1599
1654
  removable,
1600
- onRemove: onRemove ? () => onRemove(attachment.id) : void 0
1655
+ onRemove: onRemove ? () => onRemove(attachment.id) : void 0,
1656
+ artifactId: attachment.artifactId,
1657
+ onOpen
1601
1658
  }
1602
1659
  )),
1603
1660
  hiddenCount > 0 && /* @__PURE__ */ import_react17.default.createElement(
@@ -4049,6 +4106,8 @@ var Message = import_react56.default.forwardRef(
4049
4106
  branchInfo,
4050
4107
  actions,
4051
4108
  hideActions,
4109
+ attachments,
4110
+ onAttachmentOpen,
4052
4111
  ...rest
4053
4112
  }, ref) => {
4054
4113
  const isUser = variant === "user";
@@ -4116,6 +4175,14 @@ var Message = import_react56.default.forwardRef(
4116
4175
  ),
4117
4176
  ...rest
4118
4177
  },
4178
+ 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(
4179
+ AttachmentPreview,
4180
+ {
4181
+ attachments,
4182
+ removable: false,
4183
+ onOpen: onAttachmentOpen
4184
+ }
4185
+ )),
4119
4186
  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
4187
  "textarea",
4121
4188
  {
@@ -4366,6 +4433,7 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4366
4433
  isVisible = true,
4367
4434
  phraseInterval = 2500,
4368
4435
  phrases = THINKING_PHRASES,
4436
+ manualLabel,
4369
4437
  className,
4370
4438
  ...rest
4371
4439
  }, ref) => {
@@ -4373,8 +4441,9 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4373
4441
  () => Math.floor(Math.random() * phrases.length)
4374
4442
  );
4375
4443
  const [isTransitioning, setIsTransitioning] = (0, import_react60.useState)(false);
4444
+ const isManual = manualLabel !== void 0;
4376
4445
  (0, import_react60.useEffect)(() => {
4377
- if (!isVisible || phrases.length <= 1) {
4446
+ if (!isVisible || isManual || phrases.length <= 1) {
4378
4447
  return;
4379
4448
  }
4380
4449
  let fadeTimeout = null;
@@ -4392,7 +4461,7 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4392
4461
  clearTimeout(fadeTimeout);
4393
4462
  }
4394
4463
  };
4395
- }, [isVisible, phrases.length, phraseInterval]);
4464
+ }, [isVisible, isManual, phrases.length, phraseInterval]);
4396
4465
  if (!isVisible) {
4397
4466
  return null;
4398
4467
  }
@@ -4429,7 +4498,7 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4429
4498
  style: { animationDelay: "300ms" }
4430
4499
  }
4431
4500
  )),
4432
- /* @__PURE__ */ import_react60.default.createElement(
4501
+ isManual ? /* @__PURE__ */ import_react60.default.createElement("span", { className: "text-sm italic" }, manualLabel) : /* @__PURE__ */ import_react60.default.createElement(
4433
4502
  "span",
4434
4503
  {
4435
4504
  className: cx(
@@ -4451,13 +4520,15 @@ var KIND_ICONS = {
4451
4520
  task: import_lucide_react12.GitBranch,
4452
4521
  submit: import_lucide_react12.GitMerge,
4453
4522
  rename: import_lucide_react12.PencilLine,
4454
- init: import_lucide_react12.GitCommitVertical
4523
+ init: import_lucide_react12.GitCommitVertical,
4524
+ ingest: import_lucide_react12.Upload
4455
4525
  };
4456
4526
  var KIND_ARIA_LABELS = {
4457
4527
  task: "Task checkpoint",
4458
4528
  submit: "Submit checkpoint",
4459
4529
  rename: "Rename checkpoint",
4460
- init: "Project head checkpoint"
4530
+ init: "Project head checkpoint",
4531
+ ingest: "Upload batch checkpoint"
4461
4532
  };
4462
4533
  var Checkpoint = import_react61.default.forwardRef(
4463
4534
  function Checkpoint2({ name, executionKind, status = "completed", isActive, muted, branchInfo, onJumpHere }, ref) {
@@ -4606,7 +4677,16 @@ GreyedDivider.displayName = "GreyedDivider";
4606
4677
 
4607
4678
  // src/components/chat/ChatView.tsx
4608
4679
  var ChatView = import_react63.default.forwardRef(
4609
- function ChatView2({ items, latestUserMessageIndex, isStreaming, isThinking, onScroll, className, ...rest }, ref) {
4680
+ function ChatView2({
4681
+ items,
4682
+ latestUserMessageIndex,
4683
+ isStreaming,
4684
+ isThinking,
4685
+ thinkingLabel,
4686
+ onScroll,
4687
+ className,
4688
+ ...rest
4689
+ }, ref) {
4610
4690
  const { containerRef, anchorRef, scrollToAnchor } = useScrollAnchor({
4611
4691
  behavior: "smooth",
4612
4692
  block: "start"
@@ -4689,7 +4769,7 @@ var ChatView = import_react63.default.forwardRef(
4689
4769
  }
4690
4770
  )
4691
4771
  );
4692
- }), showThinking && /* @__PURE__ */ import_react63.default.createElement(ThinkingIndicator, { isVisible: true })),
4772
+ }), showThinking && /* @__PURE__ */ import_react63.default.createElement(ThinkingIndicator, { isVisible: true, manualLabel: thinkingLabel })),
4693
4773
  /* @__PURE__ */ import_react63.default.createElement(
4694
4774
  "div",
4695
4775
  {
@@ -4874,8 +4954,8 @@ var ChatInput = import_react64.default.forwardRef(
4874
4954
  );
4875
4955
  const isCentered = position === "centered";
4876
4956
  const hasAttachments = attachments.length > 0;
4877
- const isUploading = attachments.some((a) => a.status === "uploading");
4878
- const canSubmit = value.trim() && !disabled && !isStreaming && !isUploading;
4957
+ const isUploadIncomplete = attachments.some((a) => a.status === "pending" || a.status === "uploading" || a.status === "upload_failed");
4958
+ const canSubmit = value.trim() && !disabled && !isStreaming && !isUploadIncomplete;
4879
4959
  return /* @__PURE__ */ import_react64.default.createElement(
4880
4960
  "div",
4881
4961
  {
@@ -5012,7 +5092,7 @@ var ChatInput = import_react64.default.forwardRef(
5012
5092
  ChatInput.displayName = "ChatInput";
5013
5093
 
5014
5094
  // src/components/chat/ArtifactsPanel.tsx
5015
- var import_react75 = __toESM(require("react"));
5095
+ var import_react76 = __toESM(require("react"));
5016
5096
  var import_lucide_react17 = require("lucide-react");
5017
5097
 
5018
5098
  // src/components/ArtifactCard.tsx
@@ -5670,15 +5750,74 @@ var ArtifactVariantStack = import_react73.default.forwardRef(
5670
5750
  );
5671
5751
  ArtifactVariantStack.displayName = "ArtifactVariantStack";
5672
5752
 
5673
- // src/components/chat/hooks/useArtifactTreeNavigation.ts
5753
+ // src/components/chat/hooks/useResizable.ts
5674
5754
  var import_react74 = require("react");
5755
+ function useResizable({
5756
+ initialWidthPercent,
5757
+ minWidthPercent,
5758
+ maxWidthPercent,
5759
+ direction
5760
+ }) {
5761
+ const [widthPercent, setWidthPercent] = (0, import_react74.useState)(initialWidthPercent);
5762
+ const [isResizing, setIsResizing] = (0, import_react74.useState)(false);
5763
+ const lastX = (0, import_react74.useRef)(null);
5764
+ const startResizing = (0, import_react74.useCallback)((e) => {
5765
+ e.preventDefault();
5766
+ setIsResizing(true);
5767
+ lastX.current = e.clientX;
5768
+ }, []);
5769
+ const stopResizing = (0, import_react74.useCallback)(() => {
5770
+ setIsResizing(false);
5771
+ lastX.current = null;
5772
+ }, []);
5773
+ const resize = (0, import_react74.useCallback)(
5774
+ (e) => {
5775
+ if (!isResizing || lastX.current === null) {
5776
+ return;
5777
+ }
5778
+ const deltaX = e.clientX - lastX.current;
5779
+ const factor = direction === "right" ? 1 : -1;
5780
+ const deltaPercent = deltaX / window.innerWidth * 100;
5781
+ setWidthPercent((prevPercent) => {
5782
+ const newPercent = prevPercent + deltaPercent * factor;
5783
+ return Math.min(Math.max(newPercent, minWidthPercent), maxWidthPercent);
5784
+ });
5785
+ lastX.current = e.clientX;
5786
+ },
5787
+ [isResizing, direction, minWidthPercent, maxWidthPercent]
5788
+ );
5789
+ (0, import_react74.useEffect)(() => {
5790
+ if (isResizing) {
5791
+ window.addEventListener("mousemove", resize);
5792
+ window.addEventListener("mouseup", stopResizing);
5793
+ document.body.style.cursor = "col-resize";
5794
+ document.body.style.userSelect = "none";
5795
+ } else {
5796
+ window.removeEventListener("mousemove", resize);
5797
+ window.removeEventListener("mouseup", stopResizing);
5798
+ document.body.style.cursor = "";
5799
+ document.body.style.userSelect = "";
5800
+ }
5801
+ return () => {
5802
+ window.removeEventListener("mousemove", resize);
5803
+ window.removeEventListener("mouseup", stopResizing);
5804
+ document.body.style.cursor = "";
5805
+ document.body.style.userSelect = "";
5806
+ };
5807
+ }, [isResizing, resize, stopResizing]);
5808
+ const width = `${widthPercent}vw`;
5809
+ return { width, widthPercent, isResizing, startResizing };
5810
+ }
5811
+
5812
+ // src/components/chat/hooks/useArtifactTreeNavigation.ts
5813
+ var import_react75 = require("react");
5675
5814
  function useArtifactTreeNavigation(rootNodes) {
5676
- const [stack, setStack] = (0, import_react74.useState)([]);
5677
- const currentNodes = (0, import_react74.useMemo)(() => {
5815
+ const [stack, setStack] = (0, import_react75.useState)([]);
5816
+ const currentNodes = (0, import_react75.useMemo)(() => {
5678
5817
  if (stack.length === 0) return rootNodes;
5679
5818
  return stack[stack.length - 1].children;
5680
5819
  }, [rootNodes, stack]);
5681
- const breadcrumbs = (0, import_react74.useMemo)(() => {
5820
+ const breadcrumbs = (0, import_react75.useMemo)(() => {
5682
5821
  const entries = [{ label: "Project", node: null }];
5683
5822
  for (const node of stack) {
5684
5823
  entries.push({ label: node.label, node });
@@ -5686,13 +5825,13 @@ function useArtifactTreeNavigation(rootNodes) {
5686
5825
  return entries;
5687
5826
  }, [stack]);
5688
5827
  const isAtRoot = stack.length === 0;
5689
- const navigateInto = (0, import_react74.useCallback)((node) => {
5828
+ const navigateInto = (0, import_react75.useCallback)((node) => {
5690
5829
  setStack((prev) => [...prev, node]);
5691
5830
  }, []);
5692
- const navigateTo = (0, import_react74.useCallback)((index) => {
5831
+ const navigateTo = (0, import_react75.useCallback)((index) => {
5693
5832
  setStack((prev) => prev.slice(0, index));
5694
5833
  }, []);
5695
- const navigateBack = (0, import_react74.useCallback)(() => {
5834
+ const navigateBack = (0, import_react75.useCallback)(() => {
5696
5835
  setStack((prev) => prev.slice(0, -1));
5697
5836
  }, []);
5698
5837
  return {
@@ -5712,46 +5851,46 @@ function ArtifactModal({
5712
5851
  onClose
5713
5852
  }) {
5714
5853
  useEscapeKey(onClose);
5715
- const handleBackdropClick = (0, import_react75.useCallback)((e) => {
5854
+ const handleBackdropClick = (0, import_react76.useCallback)((e) => {
5716
5855
  if (e.target === e.currentTarget) {
5717
5856
  onClose();
5718
5857
  }
5719
5858
  }, [onClose]);
5720
- return /* @__PURE__ */ import_react75.default.createElement(
5859
+ return /* @__PURE__ */ import_react76.default.createElement(
5721
5860
  "div",
5722
5861
  {
5723
5862
  className: "fixed inset-0 z-50 flex items-center justify-center bg-void/90 backdrop-blur-sm animate-fade-in",
5724
5863
  onClick: handleBackdropClick
5725
5864
  },
5726
- /* @__PURE__ */ import_react75.default.createElement(
5865
+ /* @__PURE__ */ import_react76.default.createElement(
5727
5866
  "div",
5728
5867
  {
5729
5868
  className: "relative w-11/12 h-5/6 max-w-6xl bg-charcoal border border-ash/40 flex flex-col overflow-hidden"
5730
5869
  },
5731
- /* @__PURE__ */ import_react75.default.createElement(
5870
+ /* @__PURE__ */ import_react76.default.createElement(
5732
5871
  "div",
5733
5872
  {
5734
5873
  className: "flex items-center justify-between p-4 border-b border-ash/40 shrink-0"
5735
5874
  },
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(
5875
+ /* @__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)),
5876
+ /* @__PURE__ */ import_react76.default.createElement(
5738
5877
  "button",
5739
5878
  {
5740
5879
  onClick: onClose,
5741
5880
  className: "p-2 text-silver hover:text-white hover:bg-ash/20 transition-colors",
5742
5881
  "aria-label": "Close modal"
5743
5882
  },
5744
- /* @__PURE__ */ import_react75.default.createElement(CloseIcon, { className: "w-5 h-5" })
5883
+ /* @__PURE__ */ import_react76.default.createElement(CloseIcon, { className: "w-5 h-5" })
5745
5884
  )
5746
5885
  ),
5747
- /* @__PURE__ */ import_react75.default.createElement("div", { className: "flex-1 overflow-auto p-4" }, artifact.type === "IMAGE" && /* @__PURE__ */ import_react75.default.createElement(
5886
+ /* @__PURE__ */ import_react76.default.createElement("div", { className: "flex-1 overflow-auto p-4" }, artifact.type === "IMAGE" && /* @__PURE__ */ import_react76.default.createElement(
5748
5887
  "img",
5749
5888
  {
5750
5889
  src: artifact.url,
5751
5890
  alt: artifact.alt || "Artifact image",
5752
5891
  className: "max-w-full max-h-full object-contain mx-auto"
5753
5892
  }
5754
- ), artifact.type === "VIDEO" && /* @__PURE__ */ import_react75.default.createElement(
5893
+ ), artifact.type === "VIDEO" && /* @__PURE__ */ import_react76.default.createElement(
5755
5894
  VideoCard,
5756
5895
  {
5757
5896
  src: artifact.url || "",
@@ -5759,20 +5898,20 @@ function ArtifactModal({
5759
5898
  controls: true,
5760
5899
  className: "max-w-full max-h-full mx-auto"
5761
5900
  }
5762
- ), artifact.type === "AUDIO" && /* @__PURE__ */ import_react75.default.createElement(
5901
+ ), artifact.type === "AUDIO" && /* @__PURE__ */ import_react76.default.createElement(
5763
5902
  AudioCard,
5764
5903
  {
5765
5904
  src: artifact.url || "",
5766
5905
  controls: true,
5767
5906
  className: "max-w-xl mx-auto"
5768
5907
  }
5769
- ), artifact.type === "PDF" && /* @__PURE__ */ import_react75.default.createElement(
5908
+ ), artifact.type === "PDF" && /* @__PURE__ */ import_react76.default.createElement(
5770
5909
  PdfCard,
5771
5910
  {
5772
5911
  src: artifact.url || "",
5773
5912
  className: "h-full border-0"
5774
5913
  }
5775
- ), artifact.type === "TEXT" && /* @__PURE__ */ import_react75.default.createElement(
5914
+ ), artifact.type === "TEXT" && /* @__PURE__ */ import_react76.default.createElement(
5776
5915
  MarkdownContent,
5777
5916
  {
5778
5917
  content: artifact.inlineContent || "",
@@ -5782,7 +5921,7 @@ function ArtifactModal({
5782
5921
  artifact.mimeType === "text/plain" && "whitespace-pre-wrap"
5783
5922
  )
5784
5923
  }
5785
- ), artifact.type === "SCRIPT" && artifact.scriptElements && /* @__PURE__ */ import_react75.default.createElement(
5924
+ ), artifact.type === "SCRIPT" && artifact.scriptElements && /* @__PURE__ */ import_react76.default.createElement(
5786
5925
  ScriptCard,
5787
5926
  {
5788
5927
  elements: artifact.scriptElements,
@@ -5793,6 +5932,20 @@ function ArtifactModal({
5793
5932
  )
5794
5933
  );
5795
5934
  }
5935
+ function findArtifactInNodes(nodes, artifactId) {
5936
+ for (const node of nodes) {
5937
+ if (node.type === "ARTIFACT" && node.artifact?.id === artifactId) {
5938
+ return node.artifact;
5939
+ }
5940
+ if (node.children && node.children.length > 0) {
5941
+ const found = findArtifactInNodes(node.children, artifactId);
5942
+ if (found) {
5943
+ return found;
5944
+ }
5945
+ }
5946
+ }
5947
+ return null;
5948
+ }
5796
5949
  function NodeRenderer({
5797
5950
  node,
5798
5951
  loading,
@@ -5800,7 +5953,7 @@ function NodeRenderer({
5800
5953
  onGroupClick
5801
5954
  }) {
5802
5955
  if (node.type === "ARTIFACT" && node.artifact) {
5803
- return /* @__PURE__ */ import_react75.default.createElement(
5956
+ return /* @__PURE__ */ import_react76.default.createElement(
5804
5957
  ArtifactCard,
5805
5958
  {
5806
5959
  artifact: node.artifact,
@@ -5810,10 +5963,10 @@ function NodeRenderer({
5810
5963
  );
5811
5964
  }
5812
5965
  if (node.type === "GROUP") {
5813
- return /* @__PURE__ */ import_react75.default.createElement(ArtifactGroup, { node, onClick: onGroupClick });
5966
+ return /* @__PURE__ */ import_react76.default.createElement(ArtifactGroup, { node, onClick: onGroupClick });
5814
5967
  }
5815
5968
  if (node.type === "VARIANT_SET") {
5816
- return /* @__PURE__ */ import_react75.default.createElement(
5969
+ return /* @__PURE__ */ import_react76.default.createElement(
5817
5970
  ArtifactVariantStack,
5818
5971
  {
5819
5972
  node,
@@ -5824,42 +5977,59 @@ function NodeRenderer({
5824
5977
  }
5825
5978
  return null;
5826
5979
  }
5827
- var ArtifactsPanel = import_react75.default.forwardRef(
5980
+ var ArtifactsPanel = import_react76.default.forwardRef(
5828
5981
  ({
5829
5982
  nodes,
5830
5983
  loading,
5984
+ openArtifactId,
5985
+ onArtifactClosed,
5831
5986
  className,
5832
5987
  ...rest
5833
5988
  }, ref) => {
5834
- const [expandedArtifact, setExpandedArtifact] = (0, import_react75.useState)(null);
5835
- const [zoomIndex, setZoomIndex] = (0, import_react75.useState)(ZOOM_LEVELS.length - 1);
5989
+ const [expandedArtifact, setExpandedArtifact] = (0, import_react76.useState)(null);
5990
+ const [zoomIndex, setZoomIndex] = (0, import_react76.useState)(ZOOM_LEVELS.length - 1);
5836
5991
  const treeNav = useArtifactTreeNavigation(nodes || []);
5837
5992
  const hasNodes = !!nodes && nodes.length > 0;
5838
- const handleExpandArtifact = (0, import_react75.useCallback)((artifact) => {
5993
+ const handleExpandArtifact = (0, import_react76.useCallback)((artifact) => {
5839
5994
  setExpandedArtifact(artifact);
5840
5995
  }, []);
5841
- const handleGroupClick = (0, import_react75.useCallback)((node) => {
5996
+ const handleGroupClick = (0, import_react76.useCallback)((node) => {
5842
5997
  treeNav.navigateInto(node);
5843
5998
  }, [treeNav]);
5844
- const zoomIn = (0, import_react75.useCallback)(() => {
5999
+ (0, import_react76.useEffect)(() => {
6000
+ if (!openArtifactId || !nodes) {
6001
+ return;
6002
+ }
6003
+ const found = findArtifactInNodes(nodes, openArtifactId);
6004
+ if (found) {
6005
+ setExpandedArtifact(found);
6006
+ }
6007
+ }, [openArtifactId, nodes]);
6008
+ const handleModalClose = (0, import_react76.useCallback)(() => {
6009
+ setExpandedArtifact(null);
6010
+ onArtifactClosed?.();
6011
+ }, [onArtifactClosed]);
6012
+ const zoomIn = (0, import_react76.useCallback)(() => {
5845
6013
  setZoomIndex((prev) => Math.min(prev + 1, ZOOM_LEVELS.length - 1));
5846
6014
  }, []);
5847
- const zoomOut = (0, import_react75.useCallback)(() => {
6015
+ const zoomOut = (0, import_react76.useCallback)(() => {
5848
6016
  setZoomIndex((prev) => Math.max(prev - 1, 0));
5849
6017
  }, []);
5850
6018
  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)(() => {
6019
+ const contentRef = (0, import_react76.useRef)(null);
6020
+ const [contentHeight, setContentHeight] = (0, import_react76.useState)(void 0);
6021
+ (0, import_react76.useEffect)(() => {
5854
6022
  const el = contentRef.current;
5855
- if (!el) return;
6023
+ if (!el) {
6024
+ return;
6025
+ }
5856
6026
  const observer = new ResizeObserver(([entry]) => {
5857
6027
  setContentHeight(entry.contentRect.height);
5858
6028
  });
5859
6029
  observer.observe(el);
5860
6030
  return () => observer.disconnect();
5861
6031
  }, []);
5862
- return /* @__PURE__ */ import_react75.default.createElement(import_react75.default.Fragment, null, /* @__PURE__ */ import_react75.default.createElement(
6032
+ return /* @__PURE__ */ import_react76.default.createElement(import_react76.default.Fragment, null, /* @__PURE__ */ import_react76.default.createElement(
5863
6033
  "div",
5864
6034
  {
5865
6035
  ref,
@@ -5870,19 +6040,19 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5870
6040
  ),
5871
6041
  ...rest
5872
6042
  },
5873
- /* @__PURE__ */ import_react75.default.createElement(
6043
+ /* @__PURE__ */ import_react76.default.createElement(
5874
6044
  "div",
5875
6045
  {
5876
6046
  className: "flex items-center justify-between p-4 border-b border-ash/40 shrink-0"
5877
6047
  },
5878
- /* @__PURE__ */ import_react75.default.createElement("h3", { className: "text-sm font-semibold text-white" }, "Artifacts"),
5879
- hasNodes && /* @__PURE__ */ import_react75.default.createElement(
6048
+ /* @__PURE__ */ import_react76.default.createElement("h3", { className: "text-sm font-semibold text-white" }, "Artifacts"),
6049
+ hasNodes && /* @__PURE__ */ import_react76.default.createElement(
5880
6050
  "div",
5881
6051
  {
5882
6052
  className: "flex items-center gap-0.5",
5883
6053
  "data-testid": "zoom-controls"
5884
6054
  },
5885
- /* @__PURE__ */ import_react75.default.createElement(
6055
+ /* @__PURE__ */ import_react76.default.createElement(
5886
6056
  "button",
5887
6057
  {
5888
6058
  onClick: zoomOut,
@@ -5896,8 +6066,16 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5896
6066
  },
5897
6067
  "\u2212"
5898
6068
  ),
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(
6069
+ /* @__PURE__ */ import_react76.default.createElement(
6070
+ "span",
6071
+ {
6072
+ className: "text-xs text-silver w-8 text-center tabular-nums",
6073
+ "data-testid": "zoom-level"
6074
+ },
6075
+ Math.round(currentZoom * 100),
6076
+ "%"
6077
+ ),
6078
+ /* @__PURE__ */ import_react76.default.createElement(
5901
6079
  "button",
5902
6080
  {
5903
6081
  onClick: zoomIn,
@@ -5913,7 +6091,7 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5913
6091
  )
5914
6092
  )
5915
6093
  ),
5916
- hasNodes && !treeNav.isAtRoot && /* @__PURE__ */ import_react75.default.createElement(
6094
+ hasNodes && !treeNav.isAtRoot && /* @__PURE__ */ import_react76.default.createElement(
5917
6095
  "nav",
5918
6096
  {
5919
6097
  className: "flex items-center gap-1 px-4 py-2 border-b border-ash/40 shrink-0 overflow-x-auto text-xs",
@@ -5922,7 +6100,7 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5922
6100
  },
5923
6101
  treeNav.breadcrumbs.map((crumb, i) => {
5924
6102
  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(
6103
+ 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
6104
  "button",
5927
6105
  {
5928
6106
  onClick: () => treeNav.navigateTo(i),
@@ -5932,18 +6110,18 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5932
6110
  ));
5933
6111
  })
5934
6112
  ),
5935
- /* @__PURE__ */ import_react75.default.createElement(
6113
+ /* @__PURE__ */ import_react76.default.createElement(
5936
6114
  "div",
5937
6115
  {
5938
6116
  className: "flex-1 overflow-auto relative",
5939
6117
  "data-testid": "artifacts-scroll-area"
5940
6118
  },
5941
- /* @__PURE__ */ import_react75.default.createElement(
6119
+ /* @__PURE__ */ import_react76.default.createElement(
5942
6120
  "div",
5943
6121
  {
5944
6122
  style: currentZoom !== 1 && contentHeight !== void 0 ? { height: contentHeight * currentZoom } : void 0
5945
6123
  },
5946
- /* @__PURE__ */ import_react75.default.createElement(
6124
+ /* @__PURE__ */ import_react76.default.createElement(
5947
6125
  "div",
5948
6126
  {
5949
6127
  ref: contentRef,
@@ -5954,7 +6132,7 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5954
6132
  transformOrigin: "top center"
5955
6133
  } : void 0
5956
6134
  },
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(
6135
+ 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
6136
  NodeRenderer,
5959
6137
  {
5960
6138
  key: node.id,
@@ -5967,18 +6145,18 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5967
6145
  )
5968
6146
  )
5969
6147
  )
5970
- ), expandedArtifact && /* @__PURE__ */ import_react75.default.createElement(
6148
+ ), expandedArtifact && /* @__PURE__ */ import_react76.default.createElement(
5971
6149
  ArtifactModal,
5972
6150
  {
5973
6151
  artifact: expandedArtifact,
5974
- onClose: () => setExpandedArtifact(null)
6152
+ onClose: handleModalClose
5975
6153
  }
5976
6154
  ));
5977
6155
  }
5978
6156
  );
5979
6157
  ArtifactsPanel.displayName = "ArtifactsPanel";
5980
- var ArtifactsPanelToggle = import_react75.default.forwardRef(({ artifactCount = 0, onExpand, className, ...rest }, ref) => {
5981
- return /* @__PURE__ */ import_react75.default.createElement(
6158
+ var ArtifactsPanelToggle = import_react76.default.forwardRef(({ artifactCount = 0, onExpand, className, ...rest }, ref) => {
6159
+ return /* @__PURE__ */ import_react76.default.createElement(
5982
6160
  "button",
5983
6161
  {
5984
6162
  ref,
@@ -5995,8 +6173,8 @@ var ArtifactsPanelToggle = import_react75.default.forwardRef(({ artifactCount =
5995
6173
  "aria-label": "Expand artifacts panel",
5996
6174
  ...rest
5997
6175
  },
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(
6176
+ /* @__PURE__ */ import_react76.default.createElement(import_lucide_react17.Image, { className: "w-5 h-5", "aria-hidden": true }),
6177
+ artifactCount > 0 && /* @__PURE__ */ import_react76.default.createElement(
6000
6178
  "span",
6001
6179
  {
6002
6180
  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 +6186,7 @@ var ArtifactsPanelToggle = import_react75.default.forwardRef(({ artifactCount =
6008
6186
  ArtifactsPanelToggle.displayName = "ArtifactsPanelToggle";
6009
6187
 
6010
6188
  // src/components/chat/HistoryPanel.tsx
6011
- var import_react76 = __toESM(require("react"));
6189
+ var import_react77 = __toESM(require("react"));
6012
6190
  var import_lucide_react18 = require("lucide-react");
6013
6191
  function parseTimestamp(ts) {
6014
6192
  if (ts == null) {
@@ -6051,12 +6229,12 @@ function ProjectFilter({
6051
6229
  onChange,
6052
6230
  className
6053
6231
  }) {
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), []);
6232
+ const [open, setOpen] = (0, import_react77.useState)(false);
6233
+ const ref = (0, import_react77.useRef)(null);
6234
+ const closeFilter = (0, import_react77.useCallback)(() => setOpen(false), []);
6057
6235
  useClickOutside(ref, closeFilter, open);
6058
6236
  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(
6237
+ return /* @__PURE__ */ import_react77.default.createElement("div", { className: cx("relative min-w-0", className), ref }, /* @__PURE__ */ import_react77.default.createElement(
6060
6238
  "button",
6061
6239
  {
6062
6240
  type: "button",
@@ -6072,9 +6250,9 @@ function ProjectFilter({
6072
6250
  "transition-colors duration-150 min-w-0"
6073
6251
  )
6074
6252
  },
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(
6253
+ /* @__PURE__ */ import_react77.default.createElement("span", { className: "truncate" }, label),
6254
+ /* @__PURE__ */ import_react77.default.createElement(import_lucide_react18.ChevronDown, { className: "w-3 h-3 shrink-0", "aria-hidden": true })
6255
+ ), open && /* @__PURE__ */ import_react77.default.createElement(
6078
6256
  "div",
6079
6257
  {
6080
6258
  role: "listbox",
@@ -6084,7 +6262,7 @@ function ProjectFilter({
6084
6262
  "max-h-60 overflow-y-auto"
6085
6263
  )
6086
6264
  },
6087
- /* @__PURE__ */ import_react76.default.createElement(
6265
+ /* @__PURE__ */ import_react77.default.createElement(
6088
6266
  "button",
6089
6267
  {
6090
6268
  type: "button",
@@ -6102,7 +6280,7 @@ function ProjectFilter({
6102
6280
  },
6103
6281
  "All projects"
6104
6282
  ),
6105
- projects.map((p) => /* @__PURE__ */ import_react76.default.createElement(
6283
+ projects.map((p) => /* @__PURE__ */ import_react77.default.createElement(
6106
6284
  "button",
6107
6285
  {
6108
6286
  key: p,
@@ -6128,33 +6306,33 @@ function ConversationRow({
6128
6306
  onSelect,
6129
6307
  onRename
6130
6308
  }) {
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)(() => {
6309
+ const [isEditing, setIsEditing] = (0, import_react77.useState)(false);
6310
+ const [draft, setDraft] = (0, import_react77.useState)(conversation.title);
6311
+ const inputRef = (0, import_react77.useRef)(null);
6312
+ (0, import_react77.useEffect)(() => {
6135
6313
  if (isEditing && inputRef.current) {
6136
6314
  inputRef.current.focus();
6137
6315
  inputRef.current.select();
6138
6316
  }
6139
6317
  }, [isEditing]);
6140
- const startEdit = (0, import_react76.useCallback)((e) => {
6318
+ const startEdit = (0, import_react77.useCallback)((e) => {
6141
6319
  e.stopPropagation();
6142
6320
  setDraft(conversation.title);
6143
6321
  setIsEditing(true);
6144
6322
  }, [conversation.title]);
6145
- const commit = (0, import_react76.useCallback)(() => {
6323
+ const commit = (0, import_react77.useCallback)(() => {
6146
6324
  const trimmed = draft.trim();
6147
6325
  if (trimmed && trimmed !== conversation.title) {
6148
6326
  onRename?.(conversation.id, trimmed);
6149
6327
  }
6150
6328
  setIsEditing(false);
6151
6329
  }, [draft, conversation.id, conversation.title, onRename]);
6152
- const cancel = (0, import_react76.useCallback)(() => {
6330
+ const cancel = (0, import_react77.useCallback)(() => {
6153
6331
  setDraft(conversation.title);
6154
6332
  setIsEditing(false);
6155
6333
  }, [conversation.title]);
6156
6334
  if (isEditing) {
6157
- return /* @__PURE__ */ import_react76.default.createElement(
6335
+ return /* @__PURE__ */ import_react77.default.createElement(
6158
6336
  "div",
6159
6337
  {
6160
6338
  className: cx(
@@ -6162,7 +6340,7 @@ function ConversationRow({
6162
6340
  conversation.isActive ? "bg-ash/40" : "bg-ash/20"
6163
6341
  )
6164
6342
  },
6165
- /* @__PURE__ */ import_react76.default.createElement(
6343
+ /* @__PURE__ */ import_react77.default.createElement(
6166
6344
  "input",
6167
6345
  {
6168
6346
  ref: inputRef,
@@ -6187,10 +6365,10 @@ function ConversationRow({
6187
6365
  "aria-label": "Conversation title"
6188
6366
  }
6189
6367
  ),
6190
- conversation.project && /* @__PURE__ */ import_react76.default.createElement("p", { className: "text-xs text-silver/60 truncate mt-1" }, conversation.project)
6368
+ conversation.project && /* @__PURE__ */ import_react77.default.createElement("p", { className: "text-xs text-silver/60 truncate mt-1" }, conversation.project)
6191
6369
  );
6192
6370
  }
6193
- return /* @__PURE__ */ import_react76.default.createElement("div", { className: "relative group" }, /* @__PURE__ */ import_react76.default.createElement(
6371
+ return /* @__PURE__ */ import_react77.default.createElement("div", { className: "relative group" }, /* @__PURE__ */ import_react77.default.createElement(
6194
6372
  "button",
6195
6373
  {
6196
6374
  onClick: () => onSelect?.(conversation.id),
@@ -6200,7 +6378,7 @@ function ConversationRow({
6200
6378
  conversation.isActive ? "bg-ash/40 text-white" : "text-silver hover:bg-ash/20 hover:text-white"
6201
6379
  )
6202
6380
  },
6203
- /* @__PURE__ */ import_react76.default.createElement(
6381
+ /* @__PURE__ */ import_react77.default.createElement(
6204
6382
  "p",
6205
6383
  {
6206
6384
  className: cx(
@@ -6210,8 +6388,8 @@ function ConversationRow({
6210
6388
  },
6211
6389
  conversation.title
6212
6390
  ),
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(
6391
+ conversation.project && /* @__PURE__ */ import_react77.default.createElement("p", { className: "text-xs text-silver/60 truncate mt-0.5" }, conversation.project)
6392
+ ), onRename && /* @__PURE__ */ import_react77.default.createElement(
6215
6393
  "button",
6216
6394
  {
6217
6395
  type: "button",
@@ -6224,7 +6402,7 @@ function ConversationRow({
6224
6402
  "transition-opacity duration-150"
6225
6403
  )
6226
6404
  },
6227
- /* @__PURE__ */ import_react76.default.createElement(import_lucide_react18.Pencil, { className: "w-3.5 h-3.5", "aria-hidden": true })
6405
+ /* @__PURE__ */ import_react77.default.createElement(import_lucide_react18.Pencil, { className: "w-3.5 h-3.5", "aria-hidden": true })
6228
6406
  ));
6229
6407
  }
6230
6408
  function HistoryPanel({
@@ -6233,8 +6411,8 @@ function HistoryPanel({
6233
6411
  onNewChat,
6234
6412
  onRenameConversation
6235
6413
  }) {
6236
- const [projectFilter, setProjectFilter] = (0, import_react76.useState)(null);
6237
- const projects = (0, import_react76.useMemo)(() => {
6414
+ const [projectFilter, setProjectFilter] = (0, import_react77.useState)(null);
6415
+ const projects = (0, import_react77.useMemo)(() => {
6238
6416
  const set = /* @__PURE__ */ new Set();
6239
6417
  for (const c of conversations) {
6240
6418
  if (c.project) {
@@ -6243,23 +6421,23 @@ function HistoryPanel({
6243
6421
  }
6244
6422
  return Array.from(set).sort((a, b) => a.localeCompare(b));
6245
6423
  }, [conversations]);
6246
- (0, import_react76.useEffect)(() => {
6424
+ (0, import_react77.useEffect)(() => {
6247
6425
  if (projectFilter && !projects.includes(projectFilter)) {
6248
6426
  setProjectFilter(null);
6249
6427
  }
6250
6428
  }, [projects, projectFilter]);
6251
- const filteredConversations = (0, import_react76.useMemo)(() => {
6429
+ const filteredConversations = (0, import_react77.useMemo)(() => {
6252
6430
  if (!projectFilter) {
6253
6431
  return conversations;
6254
6432
  }
6255
6433
  return conversations.filter((c) => c.project === projectFilter);
6256
6434
  }, [conversations, projectFilter]);
6257
- const groups = (0, import_react76.useMemo)(
6435
+ const groups = (0, import_react77.useMemo)(
6258
6436
  () => groupConversations(filteredConversations),
6259
6437
  [filteredConversations]
6260
6438
  );
6261
6439
  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(
6440
+ 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
6441
  ProjectFilter,
6264
6442
  {
6265
6443
  projects,
@@ -6267,7 +6445,7 @@ function HistoryPanel({
6267
6445
  onChange: setProjectFilter,
6268
6446
  className: "flex-1"
6269
6447
  }
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(
6448
+ )), 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
6449
  "button",
6272
6450
  {
6273
6451
  onClick: onNewChat,
@@ -6279,15 +6457,15 @@ function HistoryPanel({
6279
6457
  "transition-colors duration-200"
6280
6458
  )
6281
6459
  },
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(
6460
+ /* @__PURE__ */ import_react77.default.createElement(PlusIcon, { className: "w-4 h-4" }),
6461
+ /* @__PURE__ */ import_react77.default.createElement("span", { className: "truncate" }, "New Chat")
6462
+ )))), /* @__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
6463
  "span",
6286
6464
  {
6287
6465
  className: "text-xs font-medium uppercase tracking-wider text-gold/70"
6288
6466
  },
6289
6467
  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(
6468
+ ), /* @__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
6469
  ConversationRow,
6292
6470
  {
6293
6471
  key: conversation.id,
@@ -6299,7 +6477,7 @@ function HistoryPanel({
6299
6477
  }
6300
6478
 
6301
6479
  // src/components/chat/TodosList.tsx
6302
- var import_react77 = __toESM(require("react"));
6480
+ var import_react78 = __toESM(require("react"));
6303
6481
  var import_lucide_react19 = require("lucide-react");
6304
6482
  var TASK_STATUSES = {
6305
6483
  PENDING: "pending",
@@ -6311,16 +6489,16 @@ var TASK_STATUSES = {
6311
6489
  function TaskIcon({ status }) {
6312
6490
  switch (status) {
6313
6491
  case "done":
6314
- return /* @__PURE__ */ import_react77.default.createElement(CheckSquareIcon, null);
6492
+ return /* @__PURE__ */ import_react78.default.createElement(CheckSquareIcon, null);
6315
6493
  case "in_progress":
6316
- return /* @__PURE__ */ import_react77.default.createElement(SquareLoaderIcon, null);
6494
+ return /* @__PURE__ */ import_react78.default.createElement(SquareLoaderIcon, null);
6317
6495
  case "cancelled":
6318
- return /* @__PURE__ */ import_react77.default.createElement(CrossSquareIcon, { variant: "cancelled" });
6496
+ return /* @__PURE__ */ import_react78.default.createElement(CrossSquareIcon, { variant: "cancelled" });
6319
6497
  case "failed":
6320
- return /* @__PURE__ */ import_react77.default.createElement(CrossSquareIcon, { variant: "failed" });
6498
+ return /* @__PURE__ */ import_react78.default.createElement(CrossSquareIcon, { variant: "failed" });
6321
6499
  case "pending":
6322
6500
  default:
6323
- return /* @__PURE__ */ import_react77.default.createElement(EmptySquareIcon, null);
6501
+ return /* @__PURE__ */ import_react78.default.createElement(EmptySquareIcon, null);
6324
6502
  }
6325
6503
  }
6326
6504
  function sortTasks(tasks) {
@@ -6340,14 +6518,14 @@ function TaskItem({ task, depth = 0 }) {
6340
6518
  const isSubtle = task.status === "cancelled" || task.status === "failed";
6341
6519
  const showSubtasks = task.subtasks && task.subtasks.length > 0;
6342
6520
  const sortedSubtasks = showSubtasks ? sortTasks(task.subtasks) : [];
6343
- return /* @__PURE__ */ import_react77.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ import_react77.default.createElement(
6521
+ return /* @__PURE__ */ import_react78.default.createElement("div", { className: "flex flex-col" }, /* @__PURE__ */ import_react78.default.createElement(
6344
6522
  "div",
6345
6523
  {
6346
6524
  className: "flex items-center gap-2 py-1",
6347
6525
  style: { paddingLeft: `${depth * 1.5}rem` }
6348
6526
  },
6349
- /* @__PURE__ */ import_react77.default.createElement(TaskIcon, { status: task.status }),
6350
- /* @__PURE__ */ import_react77.default.createElement(
6527
+ /* @__PURE__ */ import_react78.default.createElement(TaskIcon, { status: task.status }),
6528
+ /* @__PURE__ */ import_react78.default.createElement(
6351
6529
  "span",
6352
6530
  {
6353
6531
  className: cx(
@@ -6359,10 +6537,10 @@ function TaskItem({ task, depth = 0 }) {
6359
6537
  )
6360
6538
  },
6361
6539
  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)")
6540
+ task.status === "cancelled" && /* @__PURE__ */ import_react78.default.createElement("span", { className: "text-silver/40 ml-1" }, "(cancelled)"),
6541
+ task.status === "failed" && /* @__PURE__ */ import_react78.default.createElement("span", { className: "text-error/60 ml-1" }, "(failed)")
6364
6542
  )
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 }))));
6543
+ ), 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
6544
  }
6367
6545
  function hasInProgressTask(tasks) {
6368
6546
  return tasks.some((t) => {
@@ -6375,11 +6553,11 @@ function hasInProgressTask(tasks) {
6375
6553
  return false;
6376
6554
  });
6377
6555
  }
6378
- var TodosList = import_react77.default.forwardRef(
6556
+ var TodosList = import_react78.default.forwardRef(
6379
6557
  ({ 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 () => {
6558
+ const sortedTasks = (0, import_react78.useMemo)(() => sortTasks(tasks), [tasks]);
6559
+ const [isStopping, setIsStopping] = (0, import_react78.useState)(false);
6560
+ const handleStopClick = (0, import_react78.useCallback)(async () => {
6383
6561
  if (!onStopAllTasks || isStopping) {
6384
6562
  return;
6385
6563
  }
@@ -6400,7 +6578,7 @@ var TodosList = import_react77.default.forwardRef(
6400
6578
  if (tasks.length === 0) {
6401
6579
  return null;
6402
6580
  }
6403
- return /* @__PURE__ */ import_react77.default.createElement(
6581
+ return /* @__PURE__ */ import_react78.default.createElement(
6404
6582
  "div",
6405
6583
  {
6406
6584
  ref,
@@ -6411,16 +6589,16 @@ var TodosList = import_react77.default.forwardRef(
6411
6589
  ),
6412
6590
  ...rest
6413
6591
  },
6414
- /* @__PURE__ */ import_react77.default.createElement(
6592
+ /* @__PURE__ */ import_react78.default.createElement(
6415
6593
  "div",
6416
6594
  {
6417
6595
  className: "flex items-center justify-between px-4 py-2 border-b border-ash/40 flex-shrink-0"
6418
6596
  },
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))
6597
+ /* @__PURE__ */ import_react78.default.createElement("h4", { className: "text-xs font-medium text-white" }, title),
6598
+ /* @__PURE__ */ import_react78.default.createElement("span", { className: "text-xs text-silver/60" }, countCompleted(tasks), "/", countTotal(tasks))
6421
6599
  ),
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(
6600
+ /* @__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 }))),
6601
+ 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
6602
  "button",
6425
6603
  {
6426
6604
  type: "button",
@@ -6437,7 +6615,7 @@ var TodosList = import_react77.default.forwardRef(
6437
6615
  isStopping ? "cursor-not-allowed opacity-70" : "hover:bg-error/20"
6438
6616
  )
6439
6617
  },
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")
6618
+ 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
6619
  ))
6442
6620
  );
6443
6621
  }
@@ -6457,8 +6635,8 @@ function areAllTasksSettled(tasks) {
6457
6635
  }
6458
6636
 
6459
6637
  // src/components/chat/ToolSidebar.tsx
6460
- var import_react78 = __toESM(require("react"));
6461
- var ToolSidebar = import_react78.default.forwardRef(
6638
+ var import_react79 = __toESM(require("react"));
6639
+ var ToolSidebar = import_react79.default.forwardRef(
6462
6640
  ({ tools, activeTools, onToggleTool, side, className, ...rest }, ref) => {
6463
6641
  const topTools = tools.filter((t) => t.group === `top-${side}`);
6464
6642
  const bottomTools = tools.filter((t) => t.group === `bottom-${side}`);
@@ -6469,7 +6647,7 @@ var ToolSidebar = import_react78.default.forwardRef(
6469
6647
  };
6470
6648
  const renderButton = (tool) => {
6471
6649
  const active = isActive(tool.id);
6472
- return /* @__PURE__ */ import_react78.default.createElement(
6650
+ return /* @__PURE__ */ import_react79.default.createElement(
6473
6651
  "button",
6474
6652
  {
6475
6653
  key: tool.id,
@@ -6481,10 +6659,10 @@ var ToolSidebar = import_react78.default.forwardRef(
6481
6659
  "aria-label": tool.label,
6482
6660
  "aria-pressed": active
6483
6661
  },
6484
- /* @__PURE__ */ import_react78.default.createElement("span", { className: "w-4 h-4 block" }, tool.icon)
6662
+ /* @__PURE__ */ import_react79.default.createElement("span", { className: "w-4 h-4 block" }, tool.icon)
6485
6663
  );
6486
6664
  };
6487
- return /* @__PURE__ */ import_react78.default.createElement(
6665
+ return /* @__PURE__ */ import_react79.default.createElement(
6488
6666
  "div",
6489
6667
  {
6490
6668
  ref,
@@ -6495,17 +6673,17 @@ var ToolSidebar = import_react78.default.forwardRef(
6495
6673
  ),
6496
6674
  ...rest
6497
6675
  },
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))
6676
+ /* @__PURE__ */ import_react79.default.createElement("div", { className: "flex flex-col items-center gap-1" }, topTools.map(renderButton)),
6677
+ /* @__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" })),
6678
+ /* @__PURE__ */ import_react79.default.createElement("div", { className: "flex flex-col items-center gap-1" }, bottomTools.map(renderButton))
6501
6679
  );
6502
6680
  }
6503
6681
  );
6504
6682
  ToolSidebar.displayName = "ToolSidebar";
6505
6683
 
6506
6684
  // src/components/chat/ToolPanelContainer.tsx
6507
- var import_react79 = __toESM(require("react"));
6508
- var ToolPanelContainer = import_react79.default.forwardRef(
6685
+ var import_react80 = __toESM(require("react"));
6686
+ var ToolPanelContainer = import_react80.default.forwardRef(
6509
6687
  ({
6510
6688
  topContent,
6511
6689
  bottomContent,
@@ -6516,21 +6694,21 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6516
6694
  initialTopPercent = 60,
6517
6695
  ...rest
6518
6696
  }, 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);
6697
+ const [topPercent, setTopPercent] = (0, import_react80.useState)(initialTopPercent);
6698
+ const [isResizingHeight, setIsResizingHeight] = (0, import_react80.useState)(false);
6699
+ const containerRef = (0, import_react80.useRef)(null);
6700
+ const lastY = (0, import_react80.useRef)(null);
6523
6701
  const hasBoth = topContent !== null && bottomContent !== null;
6524
- const startHeightResize = (0, import_react79.useCallback)((e) => {
6702
+ const startHeightResize = (0, import_react80.useCallback)((e) => {
6525
6703
  e.preventDefault();
6526
6704
  setIsResizingHeight(true);
6527
6705
  lastY.current = e.clientY;
6528
6706
  }, []);
6529
- const stopHeightResize = (0, import_react79.useCallback)(() => {
6707
+ const stopHeightResize = (0, import_react80.useCallback)(() => {
6530
6708
  setIsResizingHeight(false);
6531
6709
  lastY.current = null;
6532
6710
  }, []);
6533
- const resizeHeight = (0, import_react79.useCallback)(
6711
+ const resizeHeight = (0, import_react80.useCallback)(
6534
6712
  (e) => {
6535
6713
  if (!isResizingHeight || lastY.current === null || !containerRef.current) {
6536
6714
  return;
@@ -6549,7 +6727,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6549
6727
  },
6550
6728
  [isResizingHeight]
6551
6729
  );
6552
- (0, import_react79.useEffect)(() => {
6730
+ (0, import_react80.useEffect)(() => {
6553
6731
  if (isResizingHeight) {
6554
6732
  window.addEventListener("mousemove", resizeHeight);
6555
6733
  window.addEventListener("mouseup", stopHeightResize);
@@ -6568,7 +6746,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6568
6746
  document.body.style.userSelect = "";
6569
6747
  };
6570
6748
  }, [isResizingHeight, resizeHeight, stopHeightResize]);
6571
- return /* @__PURE__ */ import_react79.default.createElement(
6749
+ return /* @__PURE__ */ import_react80.default.createElement(
6572
6750
  "div",
6573
6751
  {
6574
6752
  ref: composeRefs(containerRef, ref),
@@ -6580,7 +6758,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6580
6758
  style: width ? { width } : void 0,
6581
6759
  ...rest
6582
6760
  },
6583
- /* @__PURE__ */ import_react79.default.createElement(
6761
+ /* @__PURE__ */ import_react80.default.createElement(
6584
6762
  "div",
6585
6763
  {
6586
6764
  onMouseDown: onResizeStart,
@@ -6591,7 +6769,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6591
6769
  )
6592
6770
  }
6593
6771
  ),
6594
- topContent !== null && /* @__PURE__ */ import_react79.default.createElement(
6772
+ topContent !== null && /* @__PURE__ */ import_react80.default.createElement(
6595
6773
  "div",
6596
6774
  {
6597
6775
  className: "min-h-0 overflow-hidden flex flex-col",
@@ -6599,7 +6777,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6599
6777
  },
6600
6778
  topContent
6601
6779
  ),
6602
- hasBoth && /* @__PURE__ */ import_react79.default.createElement(
6780
+ hasBoth && /* @__PURE__ */ import_react80.default.createElement(
6603
6781
  "div",
6604
6782
  {
6605
6783
  onMouseDown: startHeightResize,
@@ -6611,7 +6789,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6611
6789
  )
6612
6790
  }
6613
6791
  ),
6614
- bottomContent !== null && /* @__PURE__ */ import_react79.default.createElement(
6792
+ bottomContent !== null && /* @__PURE__ */ import_react80.default.createElement(
6615
6793
  "div",
6616
6794
  {
6617
6795
  className: "min-h-0 overflow-hidden flex flex-col",
@@ -6624,65 +6802,6 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6624
6802
  );
6625
6803
  ToolPanelContainer.displayName = "ToolPanelContainer";
6626
6804
 
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
6805
  // src/components/chat/tree.ts
6687
6806
  function createEmptyTree() {
6688
6807
  return { nodes: {}, rootIds: [], activeLeafId: null, lastLeafId: null };
@@ -6843,6 +6962,7 @@ var ChatInterface = import_react81.default.forwardRef(
6843
6962
  onRenameConversation,
6844
6963
  isStreaming = false,
6845
6964
  isThinking = false,
6965
+ thinkingLabel,
6846
6966
  placeholder = "Send a message...",
6847
6967
  emptyStateHelper = "Let's talk.",
6848
6968
  emptyState,
@@ -6851,6 +6971,7 @@ var ChatInterface = import_react81.default.forwardRef(
6851
6971
  attachments: propsAttachments,
6852
6972
  onAttachmentsChange,
6853
6973
  onAttachmentRemove,
6974
+ onAttachmentOpen,
6854
6975
  artifactNodes,
6855
6976
  isArtifactsPanelOpen,
6856
6977
  onArtifactsPanelOpenChange,
@@ -6867,6 +6988,14 @@ var ChatInterface = import_react81.default.forwardRef(
6867
6988
  }, ref) => {
6868
6989
  const prevArtifactNodesRef = (0, import_react81.useRef)([]);
6869
6990
  const prevTasksRef = (0, import_react81.useRef)([]);
6991
+ const [panelOpenArtifactId, setPanelOpenArtifactId] = (0, import_react81.useState)(null);
6992
+ const handleAttachmentOpen = (0, import_react81.useCallback)((artifactId) => {
6993
+ setPanelOpenArtifactId(artifactId);
6994
+ onAttachmentOpen?.(artifactId);
6995
+ }, [onAttachmentOpen]);
6996
+ const handleArtifactPanelClosed = (0, import_react81.useCallback)(() => {
6997
+ setPanelOpenArtifactId(null);
6998
+ }, []);
6870
6999
  const [internalTools, setInternalTools] = (0, import_react81.useState)({
6871
7000
  "top-left": "history",
6872
7001
  "bottom-left": null,
@@ -7054,7 +7183,15 @@ var ChatInterface = import_react81.default.forwardRef(
7054
7183
  isStreaming: node.isStreaming,
7055
7184
  muted: opts.muted,
7056
7185
  branchInfo,
7057
- actions
7186
+ actions,
7187
+ attachments: node.attachments ? node.attachments.map((a) => ({
7188
+ id: a.id,
7189
+ file: { name: a.name, size: a.size ?? 0, type: a.type },
7190
+ previewUrl: a.previewUrl,
7191
+ artifactId: a.artifactId,
7192
+ status: a.status ?? "analyzed"
7193
+ })) : void 0,
7194
+ onAttachmentOpen: handleAttachmentOpen
7058
7195
  };
7059
7196
  },
7060
7197
  [
@@ -7064,7 +7201,8 @@ var ChatInterface = import_react81.default.forwardRef(
7064
7201
  onEditMessage,
7065
7202
  onRetryMessage,
7066
7203
  handleBranchSwitch,
7067
- handleJumpToCheckpoint
7204
+ handleJumpToCheckpoint,
7205
+ handleAttachmentOpen
7068
7206
  ]
7069
7207
  );
7070
7208
  const displayItems = (0, import_react81.useMemo)(() => {
@@ -7133,6 +7271,8 @@ var ChatInterface = import_react81.default.forwardRef(
7133
7271
  ArtifactsPanel,
7134
7272
  {
7135
7273
  nodes: artifactNodes,
7274
+ openArtifactId: panelOpenArtifactId,
7275
+ onArtifactClosed: handleArtifactPanelClosed,
7136
7276
  className: "h-full"
7137
7277
  }
7138
7278
  );
@@ -7195,6 +7335,7 @@ var ChatInterface = import_react81.default.forwardRef(
7195
7335
  latestUserMessageIndex,
7196
7336
  isStreaming,
7197
7337
  isThinking,
7338
+ thinkingLabel,
7198
7339
  className: "flex-1"
7199
7340
  }
7200
7341
  )), /* @__PURE__ */ import_react81.default.createElement("div", { className: cx(