@lukeashford/aurelius 4.1.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(
@@ -3871,12 +3917,14 @@ var import_lucide_react11 = require("lucide-react");
3871
3917
  var import_react55 = __toESM(require("react"));
3872
3918
  var import_dompurify = __toESM(require("dompurify"));
3873
3919
  var import_marked = require("marked");
3874
- import_dompurify.default.addHook("afterSanitizeAttributes", (node) => {
3875
- if (node.tagName === "A") {
3876
- node.setAttribute("target", "_blank");
3877
- node.setAttribute("rel", "noopener noreferrer");
3878
- }
3879
- });
3920
+ if (typeof window !== "undefined" && typeof import_dompurify.default.addHook === "function") {
3921
+ import_dompurify.default.addHook("afterSanitizeAttributes", (node) => {
3922
+ if (node.tagName === "A") {
3923
+ node.setAttribute("target", "_blank");
3924
+ node.setAttribute("rel", "noopener noreferrer");
3925
+ }
3926
+ });
3927
+ }
3880
3928
  var DEFAULT_SANITIZE_CONFIG = {
3881
3929
  ALLOWED_TAGS: [
3882
3930
  "h1",
@@ -3953,6 +4001,9 @@ function injectStreamingCursor(html, cursorClassName) {
3953
4001
  CURSOR_BASE_CLASSES,
3954
4002
  cursorClassName
3955
4003
  )}" aria-hidden="true"></span>`;
4004
+ if (typeof DOMParser === "undefined") {
4005
+ return html + cursorHtml;
4006
+ }
3956
4007
  const parser = new DOMParser();
3957
4008
  const doc = parser.parseFromString(`<div>${html}</div>`, "text/html");
3958
4009
  const container = doc.body.firstChild;
@@ -3989,7 +4040,7 @@ var MarkdownContent = import_react55.default.forwardRef(
3989
4040
  } else {
3990
4041
  htmlContent = content;
3991
4042
  }
3992
- const sanitized = htmlContent ? import_dompurify.default.sanitize(htmlContent, config) : "";
4043
+ const sanitized = htmlContent && typeof import_dompurify.default.sanitize === "function" ? import_dompurify.default.sanitize(htmlContent, config) : htmlContent || "";
3993
4044
  if (isStreaming) {
3994
4045
  return injectStreamingCursor(sanitized, cursorClassName);
3995
4046
  }
@@ -4044,6 +4095,8 @@ var Message = import_react56.default.forwardRef(
4044
4095
  branchInfo,
4045
4096
  actions,
4046
4097
  hideActions,
4098
+ attachments,
4099
+ onAttachmentOpen,
4047
4100
  ...rest
4048
4101
  }, ref) => {
4049
4102
  const isUser = variant === "user";
@@ -4111,6 +4164,14 @@ var Message = import_react56.default.forwardRef(
4111
4164
  ),
4112
4165
  ...rest
4113
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
+ )),
4114
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(
4115
4176
  "textarea",
4116
4177
  {
@@ -4361,6 +4422,7 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4361
4422
  isVisible = true,
4362
4423
  phraseInterval = 2500,
4363
4424
  phrases = THINKING_PHRASES,
4425
+ manualLabel,
4364
4426
  className,
4365
4427
  ...rest
4366
4428
  }, ref) => {
@@ -4368,8 +4430,9 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4368
4430
  () => Math.floor(Math.random() * phrases.length)
4369
4431
  );
4370
4432
  const [isTransitioning, setIsTransitioning] = (0, import_react60.useState)(false);
4433
+ const isManual = manualLabel !== void 0;
4371
4434
  (0, import_react60.useEffect)(() => {
4372
- if (!isVisible || phrases.length <= 1) {
4435
+ if (!isVisible || isManual || phrases.length <= 1) {
4373
4436
  return;
4374
4437
  }
4375
4438
  let fadeTimeout = null;
@@ -4387,7 +4450,7 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4387
4450
  clearTimeout(fadeTimeout);
4388
4451
  }
4389
4452
  };
4390
- }, [isVisible, phrases.length, phraseInterval]);
4453
+ }, [isVisible, isManual, phrases.length, phraseInterval]);
4391
4454
  if (!isVisible) {
4392
4455
  return null;
4393
4456
  }
@@ -4424,7 +4487,7 @@ var ThinkingIndicator = import_react60.default.forwardRef(
4424
4487
  style: { animationDelay: "300ms" }
4425
4488
  }
4426
4489
  )),
4427
- /* @__PURE__ */ import_react60.default.createElement(
4490
+ isManual ? /* @__PURE__ */ import_react60.default.createElement("span", { className: "text-sm italic" }, manualLabel) : /* @__PURE__ */ import_react60.default.createElement(
4428
4491
  "span",
4429
4492
  {
4430
4493
  className: cx(
@@ -4446,13 +4509,15 @@ var KIND_ICONS = {
4446
4509
  task: import_lucide_react12.GitBranch,
4447
4510
  submit: import_lucide_react12.GitMerge,
4448
4511
  rename: import_lucide_react12.PencilLine,
4449
- init: import_lucide_react12.GitCommitVertical
4512
+ init: import_lucide_react12.GitCommitVertical,
4513
+ ingest: import_lucide_react12.Upload
4450
4514
  };
4451
4515
  var KIND_ARIA_LABELS = {
4452
4516
  task: "Task checkpoint",
4453
4517
  submit: "Submit checkpoint",
4454
4518
  rename: "Rename checkpoint",
4455
- init: "Project head checkpoint"
4519
+ init: "Project head checkpoint",
4520
+ ingest: "Upload batch checkpoint"
4456
4521
  };
4457
4522
  var Checkpoint = import_react61.default.forwardRef(
4458
4523
  function Checkpoint2({ name, executionKind, status = "completed", isActive, muted, branchInfo, onJumpHere }, ref) {
@@ -4601,7 +4666,16 @@ GreyedDivider.displayName = "GreyedDivider";
4601
4666
 
4602
4667
  // src/components/chat/ChatView.tsx
4603
4668
  var ChatView = import_react63.default.forwardRef(
4604
- 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) {
4605
4679
  const { containerRef, anchorRef, scrollToAnchor } = useScrollAnchor({
4606
4680
  behavior: "smooth",
4607
4681
  block: "start"
@@ -4684,7 +4758,7 @@ var ChatView = import_react63.default.forwardRef(
4684
4758
  }
4685
4759
  )
4686
4760
  );
4687
- }), showThinking && /* @__PURE__ */ import_react63.default.createElement(ThinkingIndicator, { isVisible: true })),
4761
+ }), showThinking && /* @__PURE__ */ import_react63.default.createElement(ThinkingIndicator, { isVisible: true, manualLabel: thinkingLabel })),
4688
4762
  /* @__PURE__ */ import_react63.default.createElement(
4689
4763
  "div",
4690
4764
  {
@@ -4869,8 +4943,8 @@ var ChatInput = import_react64.default.forwardRef(
4869
4943
  );
4870
4944
  const isCentered = position === "centered";
4871
4945
  const hasAttachments = attachments.length > 0;
4872
- const isUploading = attachments.some((a) => a.status === "uploading");
4873
- 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;
4874
4948
  return /* @__PURE__ */ import_react64.default.createElement(
4875
4949
  "div",
4876
4950
  {
@@ -5007,7 +5081,7 @@ var ChatInput = import_react64.default.forwardRef(
5007
5081
  ChatInput.displayName = "ChatInput";
5008
5082
 
5009
5083
  // src/components/chat/ArtifactsPanel.tsx
5010
- var import_react75 = __toESM(require("react"));
5084
+ var import_react76 = __toESM(require("react"));
5011
5085
  var import_lucide_react17 = require("lucide-react");
5012
5086
 
5013
5087
  // src/components/ArtifactCard.tsx
@@ -5665,15 +5739,74 @@ var ArtifactVariantStack = import_react73.default.forwardRef(
5665
5739
  );
5666
5740
  ArtifactVariantStack.displayName = "ArtifactVariantStack";
5667
5741
 
5668
- // src/components/chat/hooks/useArtifactTreeNavigation.ts
5742
+ // src/components/chat/hooks/useResizable.ts
5669
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");
5670
5803
  function useArtifactTreeNavigation(rootNodes) {
5671
- const [stack, setStack] = (0, import_react74.useState)([]);
5672
- const currentNodes = (0, import_react74.useMemo)(() => {
5804
+ const [stack, setStack] = (0, import_react75.useState)([]);
5805
+ const currentNodes = (0, import_react75.useMemo)(() => {
5673
5806
  if (stack.length === 0) return rootNodes;
5674
5807
  return stack[stack.length - 1].children;
5675
5808
  }, [rootNodes, stack]);
5676
- const breadcrumbs = (0, import_react74.useMemo)(() => {
5809
+ const breadcrumbs = (0, import_react75.useMemo)(() => {
5677
5810
  const entries = [{ label: "Project", node: null }];
5678
5811
  for (const node of stack) {
5679
5812
  entries.push({ label: node.label, node });
@@ -5681,13 +5814,13 @@ function useArtifactTreeNavigation(rootNodes) {
5681
5814
  return entries;
5682
5815
  }, [stack]);
5683
5816
  const isAtRoot = stack.length === 0;
5684
- const navigateInto = (0, import_react74.useCallback)((node) => {
5817
+ const navigateInto = (0, import_react75.useCallback)((node) => {
5685
5818
  setStack((prev) => [...prev, node]);
5686
5819
  }, []);
5687
- const navigateTo = (0, import_react74.useCallback)((index) => {
5820
+ const navigateTo = (0, import_react75.useCallback)((index) => {
5688
5821
  setStack((prev) => prev.slice(0, index));
5689
5822
  }, []);
5690
- const navigateBack = (0, import_react74.useCallback)(() => {
5823
+ const navigateBack = (0, import_react75.useCallback)(() => {
5691
5824
  setStack((prev) => prev.slice(0, -1));
5692
5825
  }, []);
5693
5826
  return {
@@ -5707,46 +5840,46 @@ function ArtifactModal({
5707
5840
  onClose
5708
5841
  }) {
5709
5842
  useEscapeKey(onClose);
5710
- const handleBackdropClick = (0, import_react75.useCallback)((e) => {
5843
+ const handleBackdropClick = (0, import_react76.useCallback)((e) => {
5711
5844
  if (e.target === e.currentTarget) {
5712
5845
  onClose();
5713
5846
  }
5714
5847
  }, [onClose]);
5715
- return /* @__PURE__ */ import_react75.default.createElement(
5848
+ return /* @__PURE__ */ import_react76.default.createElement(
5716
5849
  "div",
5717
5850
  {
5718
5851
  className: "fixed inset-0 z-50 flex items-center justify-center bg-void/90 backdrop-blur-sm animate-fade-in",
5719
5852
  onClick: handleBackdropClick
5720
5853
  },
5721
- /* @__PURE__ */ import_react75.default.createElement(
5854
+ /* @__PURE__ */ import_react76.default.createElement(
5722
5855
  "div",
5723
5856
  {
5724
5857
  className: "relative w-11/12 h-5/6 max-w-6xl bg-charcoal border border-ash/40 flex flex-col overflow-hidden"
5725
5858
  },
5726
- /* @__PURE__ */ import_react75.default.createElement(
5859
+ /* @__PURE__ */ import_react76.default.createElement(
5727
5860
  "div",
5728
5861
  {
5729
5862
  className: "flex items-center justify-between p-4 border-b border-ash/40 shrink-0"
5730
5863
  },
5731
- /* @__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)),
5732
- /* @__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(
5733
5866
  "button",
5734
5867
  {
5735
5868
  onClick: onClose,
5736
5869
  className: "p-2 text-silver hover:text-white hover:bg-ash/20 transition-colors",
5737
5870
  "aria-label": "Close modal"
5738
5871
  },
5739
- /* @__PURE__ */ import_react75.default.createElement(CloseIcon, { className: "w-5 h-5" })
5872
+ /* @__PURE__ */ import_react76.default.createElement(CloseIcon, { className: "w-5 h-5" })
5740
5873
  )
5741
5874
  ),
5742
- /* @__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(
5743
5876
  "img",
5744
5877
  {
5745
5878
  src: artifact.url,
5746
5879
  alt: artifact.alt || "Artifact image",
5747
5880
  className: "max-w-full max-h-full object-contain mx-auto"
5748
5881
  }
5749
- ), artifact.type === "VIDEO" && /* @__PURE__ */ import_react75.default.createElement(
5882
+ ), artifact.type === "VIDEO" && /* @__PURE__ */ import_react76.default.createElement(
5750
5883
  VideoCard,
5751
5884
  {
5752
5885
  src: artifact.url || "",
@@ -5754,20 +5887,20 @@ function ArtifactModal({
5754
5887
  controls: true,
5755
5888
  className: "max-w-full max-h-full mx-auto"
5756
5889
  }
5757
- ), artifact.type === "AUDIO" && /* @__PURE__ */ import_react75.default.createElement(
5890
+ ), artifact.type === "AUDIO" && /* @__PURE__ */ import_react76.default.createElement(
5758
5891
  AudioCard,
5759
5892
  {
5760
5893
  src: artifact.url || "",
5761
5894
  controls: true,
5762
5895
  className: "max-w-xl mx-auto"
5763
5896
  }
5764
- ), artifact.type === "PDF" && /* @__PURE__ */ import_react75.default.createElement(
5897
+ ), artifact.type === "PDF" && /* @__PURE__ */ import_react76.default.createElement(
5765
5898
  PdfCard,
5766
5899
  {
5767
5900
  src: artifact.url || "",
5768
5901
  className: "h-full border-0"
5769
5902
  }
5770
- ), artifact.type === "TEXT" && /* @__PURE__ */ import_react75.default.createElement(
5903
+ ), artifact.type === "TEXT" && /* @__PURE__ */ import_react76.default.createElement(
5771
5904
  MarkdownContent,
5772
5905
  {
5773
5906
  content: artifact.inlineContent || "",
@@ -5777,7 +5910,7 @@ function ArtifactModal({
5777
5910
  artifact.mimeType === "text/plain" && "whitespace-pre-wrap"
5778
5911
  )
5779
5912
  }
5780
- ), artifact.type === "SCRIPT" && artifact.scriptElements && /* @__PURE__ */ import_react75.default.createElement(
5913
+ ), artifact.type === "SCRIPT" && artifact.scriptElements && /* @__PURE__ */ import_react76.default.createElement(
5781
5914
  ScriptCard,
5782
5915
  {
5783
5916
  elements: artifact.scriptElements,
@@ -5788,6 +5921,20 @@ function ArtifactModal({
5788
5921
  )
5789
5922
  );
5790
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
+ }
5791
5938
  function NodeRenderer({
5792
5939
  node,
5793
5940
  loading,
@@ -5795,7 +5942,7 @@ function NodeRenderer({
5795
5942
  onGroupClick
5796
5943
  }) {
5797
5944
  if (node.type === "ARTIFACT" && node.artifact) {
5798
- return /* @__PURE__ */ import_react75.default.createElement(
5945
+ return /* @__PURE__ */ import_react76.default.createElement(
5799
5946
  ArtifactCard,
5800
5947
  {
5801
5948
  artifact: node.artifact,
@@ -5805,10 +5952,10 @@ function NodeRenderer({
5805
5952
  );
5806
5953
  }
5807
5954
  if (node.type === "GROUP") {
5808
- return /* @__PURE__ */ import_react75.default.createElement(ArtifactGroup, { node, onClick: onGroupClick });
5955
+ return /* @__PURE__ */ import_react76.default.createElement(ArtifactGroup, { node, onClick: onGroupClick });
5809
5956
  }
5810
5957
  if (node.type === "VARIANT_SET") {
5811
- return /* @__PURE__ */ import_react75.default.createElement(
5958
+ return /* @__PURE__ */ import_react76.default.createElement(
5812
5959
  ArtifactVariantStack,
5813
5960
  {
5814
5961
  node,
@@ -5819,42 +5966,59 @@ function NodeRenderer({
5819
5966
  }
5820
5967
  return null;
5821
5968
  }
5822
- var ArtifactsPanel = import_react75.default.forwardRef(
5969
+ var ArtifactsPanel = import_react76.default.forwardRef(
5823
5970
  ({
5824
5971
  nodes,
5825
5972
  loading,
5973
+ openArtifactId,
5974
+ onArtifactClosed,
5826
5975
  className,
5827
5976
  ...rest
5828
5977
  }, ref) => {
5829
- const [expandedArtifact, setExpandedArtifact] = (0, import_react75.useState)(null);
5830
- 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);
5831
5980
  const treeNav = useArtifactTreeNavigation(nodes || []);
5832
5981
  const hasNodes = !!nodes && nodes.length > 0;
5833
- const handleExpandArtifact = (0, import_react75.useCallback)((artifact) => {
5982
+ const handleExpandArtifact = (0, import_react76.useCallback)((artifact) => {
5834
5983
  setExpandedArtifact(artifact);
5835
5984
  }, []);
5836
- const handleGroupClick = (0, import_react75.useCallback)((node) => {
5985
+ const handleGroupClick = (0, import_react76.useCallback)((node) => {
5837
5986
  treeNav.navigateInto(node);
5838
5987
  }, [treeNav]);
5839
- 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)(() => {
5840
6002
  setZoomIndex((prev) => Math.min(prev + 1, ZOOM_LEVELS.length - 1));
5841
6003
  }, []);
5842
- const zoomOut = (0, import_react75.useCallback)(() => {
6004
+ const zoomOut = (0, import_react76.useCallback)(() => {
5843
6005
  setZoomIndex((prev) => Math.max(prev - 1, 0));
5844
6006
  }, []);
5845
6007
  const currentZoom = ZOOM_LEVELS[zoomIndex];
5846
- const contentRef = (0, import_react75.useRef)(null);
5847
- const [contentHeight, setContentHeight] = (0, import_react75.useState)(void 0);
5848
- (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)(() => {
5849
6011
  const el = contentRef.current;
5850
- if (!el) return;
6012
+ if (!el) {
6013
+ return;
6014
+ }
5851
6015
  const observer = new ResizeObserver(([entry]) => {
5852
6016
  setContentHeight(entry.contentRect.height);
5853
6017
  });
5854
6018
  observer.observe(el);
5855
6019
  return () => observer.disconnect();
5856
6020
  }, []);
5857
- 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(
5858
6022
  "div",
5859
6023
  {
5860
6024
  ref,
@@ -5865,19 +6029,19 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5865
6029
  ),
5866
6030
  ...rest
5867
6031
  },
5868
- /* @__PURE__ */ import_react75.default.createElement(
6032
+ /* @__PURE__ */ import_react76.default.createElement(
5869
6033
  "div",
5870
6034
  {
5871
6035
  className: "flex items-center justify-between p-4 border-b border-ash/40 shrink-0"
5872
6036
  },
5873
- /* @__PURE__ */ import_react75.default.createElement("h3", { className: "text-sm font-semibold text-white" }, "Artifacts"),
5874
- 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(
5875
6039
  "div",
5876
6040
  {
5877
6041
  className: "flex items-center gap-0.5",
5878
6042
  "data-testid": "zoom-controls"
5879
6043
  },
5880
- /* @__PURE__ */ import_react75.default.createElement(
6044
+ /* @__PURE__ */ import_react76.default.createElement(
5881
6045
  "button",
5882
6046
  {
5883
6047
  onClick: zoomOut,
@@ -5891,8 +6055,16 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5891
6055
  },
5892
6056
  "\u2212"
5893
6057
  ),
5894
- /* @__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), "%"),
5895
- /* @__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(
5896
6068
  "button",
5897
6069
  {
5898
6070
  onClick: zoomIn,
@@ -5908,7 +6080,7 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5908
6080
  )
5909
6081
  )
5910
6082
  ),
5911
- hasNodes && !treeNav.isAtRoot && /* @__PURE__ */ import_react75.default.createElement(
6083
+ hasNodes && !treeNav.isAtRoot && /* @__PURE__ */ import_react76.default.createElement(
5912
6084
  "nav",
5913
6085
  {
5914
6086
  className: "flex items-center gap-1 px-4 py-2 border-b border-ash/40 shrink-0 overflow-x-auto text-xs",
@@ -5917,7 +6089,7 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5917
6089
  },
5918
6090
  treeNav.breadcrumbs.map((crumb, i) => {
5919
6091
  const isLast = i === treeNav.breadcrumbs.length - 1;
5920
- 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(
5921
6093
  "button",
5922
6094
  {
5923
6095
  onClick: () => treeNav.navigateTo(i),
@@ -5927,18 +6099,18 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5927
6099
  ));
5928
6100
  })
5929
6101
  ),
5930
- /* @__PURE__ */ import_react75.default.createElement(
6102
+ /* @__PURE__ */ import_react76.default.createElement(
5931
6103
  "div",
5932
6104
  {
5933
6105
  className: "flex-1 overflow-auto relative",
5934
6106
  "data-testid": "artifacts-scroll-area"
5935
6107
  },
5936
- /* @__PURE__ */ import_react75.default.createElement(
6108
+ /* @__PURE__ */ import_react76.default.createElement(
5937
6109
  "div",
5938
6110
  {
5939
6111
  style: currentZoom !== 1 && contentHeight !== void 0 ? { height: contentHeight * currentZoom } : void 0
5940
6112
  },
5941
- /* @__PURE__ */ import_react75.default.createElement(
6113
+ /* @__PURE__ */ import_react76.default.createElement(
5942
6114
  "div",
5943
6115
  {
5944
6116
  ref: contentRef,
@@ -5949,7 +6121,7 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5949
6121
  transformOrigin: "top center"
5950
6122
  } : void 0
5951
6123
  },
5952
- 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(
5953
6125
  NodeRenderer,
5954
6126
  {
5955
6127
  key: node.id,
@@ -5962,18 +6134,18 @@ var ArtifactsPanel = import_react75.default.forwardRef(
5962
6134
  )
5963
6135
  )
5964
6136
  )
5965
- ), expandedArtifact && /* @__PURE__ */ import_react75.default.createElement(
6137
+ ), expandedArtifact && /* @__PURE__ */ import_react76.default.createElement(
5966
6138
  ArtifactModal,
5967
6139
  {
5968
6140
  artifact: expandedArtifact,
5969
- onClose: () => setExpandedArtifact(null)
6141
+ onClose: handleModalClose
5970
6142
  }
5971
6143
  ));
5972
6144
  }
5973
6145
  );
5974
6146
  ArtifactsPanel.displayName = "ArtifactsPanel";
5975
- var ArtifactsPanelToggle = import_react75.default.forwardRef(({ artifactCount = 0, onExpand, className, ...rest }, ref) => {
5976
- 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(
5977
6149
  "button",
5978
6150
  {
5979
6151
  ref,
@@ -5990,8 +6162,8 @@ var ArtifactsPanelToggle = import_react75.default.forwardRef(({ artifactCount =
5990
6162
  "aria-label": "Expand artifacts panel",
5991
6163
  ...rest
5992
6164
  },
5993
- /* @__PURE__ */ import_react75.default.createElement(import_lucide_react17.Image, { className: "w-5 h-5", "aria-hidden": true }),
5994
- 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(
5995
6167
  "span",
5996
6168
  {
5997
6169
  className: "absolute -top-1 -right-1 w-4 h-4 bg-gold text-obsidian text-xs font-medium flex items-center justify-center"
@@ -6003,7 +6175,7 @@ var ArtifactsPanelToggle = import_react75.default.forwardRef(({ artifactCount =
6003
6175
  ArtifactsPanelToggle.displayName = "ArtifactsPanelToggle";
6004
6176
 
6005
6177
  // src/components/chat/HistoryPanel.tsx
6006
- var import_react76 = __toESM(require("react"));
6178
+ var import_react77 = __toESM(require("react"));
6007
6179
  var import_lucide_react18 = require("lucide-react");
6008
6180
  function parseTimestamp(ts) {
6009
6181
  if (ts == null) {
@@ -6046,12 +6218,12 @@ function ProjectFilter({
6046
6218
  onChange,
6047
6219
  className
6048
6220
  }) {
6049
- const [open, setOpen] = (0, import_react76.useState)(false);
6050
- const ref = (0, import_react76.useRef)(null);
6051
- 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), []);
6052
6224
  useClickOutside(ref, closeFilter, open);
6053
6225
  const label = value ?? "All projects";
6054
- 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(
6055
6227
  "button",
6056
6228
  {
6057
6229
  type: "button",
@@ -6067,9 +6239,9 @@ function ProjectFilter({
6067
6239
  "transition-colors duration-150 min-w-0"
6068
6240
  )
6069
6241
  },
6070
- /* @__PURE__ */ import_react76.default.createElement("span", { className: "truncate" }, label),
6071
- /* @__PURE__ */ import_react76.default.createElement(import_lucide_react18.ChevronDown, { className: "w-3 h-3 shrink-0", "aria-hidden": true })
6072
- ), 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(
6073
6245
  "div",
6074
6246
  {
6075
6247
  role: "listbox",
@@ -6079,7 +6251,7 @@ function ProjectFilter({
6079
6251
  "max-h-60 overflow-y-auto"
6080
6252
  )
6081
6253
  },
6082
- /* @__PURE__ */ import_react76.default.createElement(
6254
+ /* @__PURE__ */ import_react77.default.createElement(
6083
6255
  "button",
6084
6256
  {
6085
6257
  type: "button",
@@ -6097,7 +6269,7 @@ function ProjectFilter({
6097
6269
  },
6098
6270
  "All projects"
6099
6271
  ),
6100
- projects.map((p) => /* @__PURE__ */ import_react76.default.createElement(
6272
+ projects.map((p) => /* @__PURE__ */ import_react77.default.createElement(
6101
6273
  "button",
6102
6274
  {
6103
6275
  key: p,
@@ -6123,33 +6295,33 @@ function ConversationRow({
6123
6295
  onSelect,
6124
6296
  onRename
6125
6297
  }) {
6126
- const [isEditing, setIsEditing] = (0, import_react76.useState)(false);
6127
- const [draft, setDraft] = (0, import_react76.useState)(conversation.title);
6128
- const inputRef = (0, import_react76.useRef)(null);
6129
- (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)(() => {
6130
6302
  if (isEditing && inputRef.current) {
6131
6303
  inputRef.current.focus();
6132
6304
  inputRef.current.select();
6133
6305
  }
6134
6306
  }, [isEditing]);
6135
- const startEdit = (0, import_react76.useCallback)((e) => {
6307
+ const startEdit = (0, import_react77.useCallback)((e) => {
6136
6308
  e.stopPropagation();
6137
6309
  setDraft(conversation.title);
6138
6310
  setIsEditing(true);
6139
6311
  }, [conversation.title]);
6140
- const commit = (0, import_react76.useCallback)(() => {
6312
+ const commit = (0, import_react77.useCallback)(() => {
6141
6313
  const trimmed = draft.trim();
6142
6314
  if (trimmed && trimmed !== conversation.title) {
6143
6315
  onRename?.(conversation.id, trimmed);
6144
6316
  }
6145
6317
  setIsEditing(false);
6146
6318
  }, [draft, conversation.id, conversation.title, onRename]);
6147
- const cancel = (0, import_react76.useCallback)(() => {
6319
+ const cancel = (0, import_react77.useCallback)(() => {
6148
6320
  setDraft(conversation.title);
6149
6321
  setIsEditing(false);
6150
6322
  }, [conversation.title]);
6151
6323
  if (isEditing) {
6152
- return /* @__PURE__ */ import_react76.default.createElement(
6324
+ return /* @__PURE__ */ import_react77.default.createElement(
6153
6325
  "div",
6154
6326
  {
6155
6327
  className: cx(
@@ -6157,7 +6329,7 @@ function ConversationRow({
6157
6329
  conversation.isActive ? "bg-ash/40" : "bg-ash/20"
6158
6330
  )
6159
6331
  },
6160
- /* @__PURE__ */ import_react76.default.createElement(
6332
+ /* @__PURE__ */ import_react77.default.createElement(
6161
6333
  "input",
6162
6334
  {
6163
6335
  ref: inputRef,
@@ -6182,10 +6354,10 @@ function ConversationRow({
6182
6354
  "aria-label": "Conversation title"
6183
6355
  }
6184
6356
  ),
6185
- 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)
6186
6358
  );
6187
6359
  }
6188
- 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(
6189
6361
  "button",
6190
6362
  {
6191
6363
  onClick: () => onSelect?.(conversation.id),
@@ -6195,7 +6367,7 @@ function ConversationRow({
6195
6367
  conversation.isActive ? "bg-ash/40 text-white" : "text-silver hover:bg-ash/20 hover:text-white"
6196
6368
  )
6197
6369
  },
6198
- /* @__PURE__ */ import_react76.default.createElement(
6370
+ /* @__PURE__ */ import_react77.default.createElement(
6199
6371
  "p",
6200
6372
  {
6201
6373
  className: cx(
@@ -6205,8 +6377,8 @@ function ConversationRow({
6205
6377
  },
6206
6378
  conversation.title
6207
6379
  ),
6208
- conversation.project && /* @__PURE__ */ import_react76.default.createElement("p", { className: "text-xs text-silver/60 truncate mt-0.5" }, conversation.project)
6209
- ), 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(
6210
6382
  "button",
6211
6383
  {
6212
6384
  type: "button",
@@ -6219,7 +6391,7 @@ function ConversationRow({
6219
6391
  "transition-opacity duration-150"
6220
6392
  )
6221
6393
  },
6222
- /* @__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 })
6223
6395
  ));
6224
6396
  }
6225
6397
  function HistoryPanel({
@@ -6228,8 +6400,8 @@ function HistoryPanel({
6228
6400
  onNewChat,
6229
6401
  onRenameConversation
6230
6402
  }) {
6231
- const [projectFilter, setProjectFilter] = (0, import_react76.useState)(null);
6232
- const projects = (0, import_react76.useMemo)(() => {
6403
+ const [projectFilter, setProjectFilter] = (0, import_react77.useState)(null);
6404
+ const projects = (0, import_react77.useMemo)(() => {
6233
6405
  const set = /* @__PURE__ */ new Set();
6234
6406
  for (const c of conversations) {
6235
6407
  if (c.project) {
@@ -6238,23 +6410,23 @@ function HistoryPanel({
6238
6410
  }
6239
6411
  return Array.from(set).sort((a, b) => a.localeCompare(b));
6240
6412
  }, [conversations]);
6241
- (0, import_react76.useEffect)(() => {
6413
+ (0, import_react77.useEffect)(() => {
6242
6414
  if (projectFilter && !projects.includes(projectFilter)) {
6243
6415
  setProjectFilter(null);
6244
6416
  }
6245
6417
  }, [projects, projectFilter]);
6246
- const filteredConversations = (0, import_react76.useMemo)(() => {
6418
+ const filteredConversations = (0, import_react77.useMemo)(() => {
6247
6419
  if (!projectFilter) {
6248
6420
  return conversations;
6249
6421
  }
6250
6422
  return conversations.filter((c) => c.project === projectFilter);
6251
6423
  }, [conversations, projectFilter]);
6252
- const groups = (0, import_react76.useMemo)(
6424
+ const groups = (0, import_react77.useMemo)(
6253
6425
  () => groupConversations(filteredConversations),
6254
6426
  [filteredConversations]
6255
6427
  );
6256
6428
  const hasFilter = projects.length > 0;
6257
- 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(
6258
6430
  ProjectFilter,
6259
6431
  {
6260
6432
  projects,
@@ -6262,7 +6434,7 @@ function HistoryPanel({
6262
6434
  onChange: setProjectFilter,
6263
6435
  className: "flex-1"
6264
6436
  }
6265
- )), 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(
6266
6438
  "button",
6267
6439
  {
6268
6440
  onClick: onNewChat,
@@ -6274,15 +6446,15 @@ function HistoryPanel({
6274
6446
  "transition-colors duration-200"
6275
6447
  )
6276
6448
  },
6277
- /* @__PURE__ */ import_react76.default.createElement(PlusIcon, { className: "w-4 h-4" }),
6278
- /* @__PURE__ */ import_react76.default.createElement("span", { className: "truncate" }, "New Chat")
6279
- )))), /* @__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(
6280
6452
  "span",
6281
6453
  {
6282
6454
  className: "text-xs font-medium uppercase tracking-wider text-gold/70"
6283
6455
  },
6284
6456
  group.label
6285
- ), /* @__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(
6286
6458
  ConversationRow,
6287
6459
  {
6288
6460
  key: conversation.id,
@@ -6294,7 +6466,7 @@ function HistoryPanel({
6294
6466
  }
6295
6467
 
6296
6468
  // src/components/chat/TodosList.tsx
6297
- var import_react77 = __toESM(require("react"));
6469
+ var import_react78 = __toESM(require("react"));
6298
6470
  var import_lucide_react19 = require("lucide-react");
6299
6471
  var TASK_STATUSES = {
6300
6472
  PENDING: "pending",
@@ -6306,16 +6478,16 @@ var TASK_STATUSES = {
6306
6478
  function TaskIcon({ status }) {
6307
6479
  switch (status) {
6308
6480
  case "done":
6309
- return /* @__PURE__ */ import_react77.default.createElement(CheckSquareIcon, null);
6481
+ return /* @__PURE__ */ import_react78.default.createElement(CheckSquareIcon, null);
6310
6482
  case "in_progress":
6311
- return /* @__PURE__ */ import_react77.default.createElement(SquareLoaderIcon, null);
6483
+ return /* @__PURE__ */ import_react78.default.createElement(SquareLoaderIcon, null);
6312
6484
  case "cancelled":
6313
- return /* @__PURE__ */ import_react77.default.createElement(CrossSquareIcon, { variant: "cancelled" });
6485
+ return /* @__PURE__ */ import_react78.default.createElement(CrossSquareIcon, { variant: "cancelled" });
6314
6486
  case "failed":
6315
- return /* @__PURE__ */ import_react77.default.createElement(CrossSquareIcon, { variant: "failed" });
6487
+ return /* @__PURE__ */ import_react78.default.createElement(CrossSquareIcon, { variant: "failed" });
6316
6488
  case "pending":
6317
6489
  default:
6318
- return /* @__PURE__ */ import_react77.default.createElement(EmptySquareIcon, null);
6490
+ return /* @__PURE__ */ import_react78.default.createElement(EmptySquareIcon, null);
6319
6491
  }
6320
6492
  }
6321
6493
  function sortTasks(tasks) {
@@ -6335,14 +6507,14 @@ function TaskItem({ task, depth = 0 }) {
6335
6507
  const isSubtle = task.status === "cancelled" || task.status === "failed";
6336
6508
  const showSubtasks = task.subtasks && task.subtasks.length > 0;
6337
6509
  const sortedSubtasks = showSubtasks ? sortTasks(task.subtasks) : [];
6338
- 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(
6339
6511
  "div",
6340
6512
  {
6341
6513
  className: "flex items-center gap-2 py-1",
6342
6514
  style: { paddingLeft: `${depth * 1.5}rem` }
6343
6515
  },
6344
- /* @__PURE__ */ import_react77.default.createElement(TaskIcon, { status: task.status }),
6345
- /* @__PURE__ */ import_react77.default.createElement(
6516
+ /* @__PURE__ */ import_react78.default.createElement(TaskIcon, { status: task.status }),
6517
+ /* @__PURE__ */ import_react78.default.createElement(
6346
6518
  "span",
6347
6519
  {
6348
6520
  className: cx(
@@ -6354,10 +6526,10 @@ function TaskItem({ task, depth = 0 }) {
6354
6526
  )
6355
6527
  },
6356
6528
  task.label,
6357
- task.status === "cancelled" && /* @__PURE__ */ import_react77.default.createElement("span", { className: "text-silver/40 ml-1" }, "(cancelled)"),
6358
- 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)")
6359
6531
  )
6360
- ), 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 }))));
6361
6533
  }
6362
6534
  function hasInProgressTask(tasks) {
6363
6535
  return tasks.some((t) => {
@@ -6370,11 +6542,11 @@ function hasInProgressTask(tasks) {
6370
6542
  return false;
6371
6543
  });
6372
6544
  }
6373
- var TodosList = import_react77.default.forwardRef(
6545
+ var TodosList = import_react78.default.forwardRef(
6374
6546
  ({ tasks, title = "Tasks", onStopAllTasks, className, ...rest }, ref) => {
6375
- const sortedTasks = (0, import_react77.useMemo)(() => sortTasks(tasks), [tasks]);
6376
- const [isStopping, setIsStopping] = (0, import_react77.useState)(false);
6377
- 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 () => {
6378
6550
  if (!onStopAllTasks || isStopping) {
6379
6551
  return;
6380
6552
  }
@@ -6395,7 +6567,7 @@ var TodosList = import_react77.default.forwardRef(
6395
6567
  if (tasks.length === 0) {
6396
6568
  return null;
6397
6569
  }
6398
- return /* @__PURE__ */ import_react77.default.createElement(
6570
+ return /* @__PURE__ */ import_react78.default.createElement(
6399
6571
  "div",
6400
6572
  {
6401
6573
  ref,
@@ -6406,16 +6578,16 @@ var TodosList = import_react77.default.forwardRef(
6406
6578
  ),
6407
6579
  ...rest
6408
6580
  },
6409
- /* @__PURE__ */ import_react77.default.createElement(
6581
+ /* @__PURE__ */ import_react78.default.createElement(
6410
6582
  "div",
6411
6583
  {
6412
6584
  className: "flex items-center justify-between px-4 py-2 border-b border-ash/40 flex-shrink-0"
6413
6585
  },
6414
- /* @__PURE__ */ import_react77.default.createElement("h4", { className: "text-xs font-medium text-white" }, title),
6415
- /* @__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))
6416
6588
  ),
6417
- /* @__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 }))),
6418
- 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(
6419
6591
  "button",
6420
6592
  {
6421
6593
  type: "button",
@@ -6432,7 +6604,7 @@ var TodosList = import_react77.default.forwardRef(
6432
6604
  isStopping ? "cursor-not-allowed opacity-70" : "hover:bg-error/20"
6433
6605
  )
6434
6606
  },
6435
- 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")
6436
6608
  ))
6437
6609
  );
6438
6610
  }
@@ -6452,8 +6624,8 @@ function areAllTasksSettled(tasks) {
6452
6624
  }
6453
6625
 
6454
6626
  // src/components/chat/ToolSidebar.tsx
6455
- var import_react78 = __toESM(require("react"));
6456
- var ToolSidebar = import_react78.default.forwardRef(
6627
+ var import_react79 = __toESM(require("react"));
6628
+ var ToolSidebar = import_react79.default.forwardRef(
6457
6629
  ({ tools, activeTools, onToggleTool, side, className, ...rest }, ref) => {
6458
6630
  const topTools = tools.filter((t) => t.group === `top-${side}`);
6459
6631
  const bottomTools = tools.filter((t) => t.group === `bottom-${side}`);
@@ -6464,7 +6636,7 @@ var ToolSidebar = import_react78.default.forwardRef(
6464
6636
  };
6465
6637
  const renderButton = (tool) => {
6466
6638
  const active = isActive(tool.id);
6467
- return /* @__PURE__ */ import_react78.default.createElement(
6639
+ return /* @__PURE__ */ import_react79.default.createElement(
6468
6640
  "button",
6469
6641
  {
6470
6642
  key: tool.id,
@@ -6476,10 +6648,10 @@ var ToolSidebar = import_react78.default.forwardRef(
6476
6648
  "aria-label": tool.label,
6477
6649
  "aria-pressed": active
6478
6650
  },
6479
- /* @__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)
6480
6652
  );
6481
6653
  };
6482
- return /* @__PURE__ */ import_react78.default.createElement(
6654
+ return /* @__PURE__ */ import_react79.default.createElement(
6483
6655
  "div",
6484
6656
  {
6485
6657
  ref,
@@ -6490,17 +6662,17 @@ var ToolSidebar = import_react78.default.forwardRef(
6490
6662
  ),
6491
6663
  ...rest
6492
6664
  },
6493
- /* @__PURE__ */ import_react78.default.createElement("div", { className: "flex flex-col items-center gap-1" }, topTools.map(renderButton)),
6494
- /* @__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" })),
6495
- /* @__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))
6496
6668
  );
6497
6669
  }
6498
6670
  );
6499
6671
  ToolSidebar.displayName = "ToolSidebar";
6500
6672
 
6501
6673
  // src/components/chat/ToolPanelContainer.tsx
6502
- var import_react79 = __toESM(require("react"));
6503
- var ToolPanelContainer = import_react79.default.forwardRef(
6674
+ var import_react80 = __toESM(require("react"));
6675
+ var ToolPanelContainer = import_react80.default.forwardRef(
6504
6676
  ({
6505
6677
  topContent,
6506
6678
  bottomContent,
@@ -6511,21 +6683,21 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6511
6683
  initialTopPercent = 60,
6512
6684
  ...rest
6513
6685
  }, ref) => {
6514
- const [topPercent, setTopPercent] = (0, import_react79.useState)(initialTopPercent);
6515
- const [isResizingHeight, setIsResizingHeight] = (0, import_react79.useState)(false);
6516
- const containerRef = (0, import_react79.useRef)(null);
6517
- 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);
6518
6690
  const hasBoth = topContent !== null && bottomContent !== null;
6519
- const startHeightResize = (0, import_react79.useCallback)((e) => {
6691
+ const startHeightResize = (0, import_react80.useCallback)((e) => {
6520
6692
  e.preventDefault();
6521
6693
  setIsResizingHeight(true);
6522
6694
  lastY.current = e.clientY;
6523
6695
  }, []);
6524
- const stopHeightResize = (0, import_react79.useCallback)(() => {
6696
+ const stopHeightResize = (0, import_react80.useCallback)(() => {
6525
6697
  setIsResizingHeight(false);
6526
6698
  lastY.current = null;
6527
6699
  }, []);
6528
- const resizeHeight = (0, import_react79.useCallback)(
6700
+ const resizeHeight = (0, import_react80.useCallback)(
6529
6701
  (e) => {
6530
6702
  if (!isResizingHeight || lastY.current === null || !containerRef.current) {
6531
6703
  return;
@@ -6544,7 +6716,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6544
6716
  },
6545
6717
  [isResizingHeight]
6546
6718
  );
6547
- (0, import_react79.useEffect)(() => {
6719
+ (0, import_react80.useEffect)(() => {
6548
6720
  if (isResizingHeight) {
6549
6721
  window.addEventListener("mousemove", resizeHeight);
6550
6722
  window.addEventListener("mouseup", stopHeightResize);
@@ -6563,7 +6735,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6563
6735
  document.body.style.userSelect = "";
6564
6736
  };
6565
6737
  }, [isResizingHeight, resizeHeight, stopHeightResize]);
6566
- return /* @__PURE__ */ import_react79.default.createElement(
6738
+ return /* @__PURE__ */ import_react80.default.createElement(
6567
6739
  "div",
6568
6740
  {
6569
6741
  ref: composeRefs(containerRef, ref),
@@ -6575,7 +6747,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6575
6747
  style: width ? { width } : void 0,
6576
6748
  ...rest
6577
6749
  },
6578
- /* @__PURE__ */ import_react79.default.createElement(
6750
+ /* @__PURE__ */ import_react80.default.createElement(
6579
6751
  "div",
6580
6752
  {
6581
6753
  onMouseDown: onResizeStart,
@@ -6586,7 +6758,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6586
6758
  )
6587
6759
  }
6588
6760
  ),
6589
- topContent !== null && /* @__PURE__ */ import_react79.default.createElement(
6761
+ topContent !== null && /* @__PURE__ */ import_react80.default.createElement(
6590
6762
  "div",
6591
6763
  {
6592
6764
  className: "min-h-0 overflow-hidden flex flex-col",
@@ -6594,7 +6766,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6594
6766
  },
6595
6767
  topContent
6596
6768
  ),
6597
- hasBoth && /* @__PURE__ */ import_react79.default.createElement(
6769
+ hasBoth && /* @__PURE__ */ import_react80.default.createElement(
6598
6770
  "div",
6599
6771
  {
6600
6772
  onMouseDown: startHeightResize,
@@ -6606,7 +6778,7 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6606
6778
  )
6607
6779
  }
6608
6780
  ),
6609
- bottomContent !== null && /* @__PURE__ */ import_react79.default.createElement(
6781
+ bottomContent !== null && /* @__PURE__ */ import_react80.default.createElement(
6610
6782
  "div",
6611
6783
  {
6612
6784
  className: "min-h-0 overflow-hidden flex flex-col",
@@ -6619,65 +6791,6 @@ var ToolPanelContainer = import_react79.default.forwardRef(
6619
6791
  );
6620
6792
  ToolPanelContainer.displayName = "ToolPanelContainer";
6621
6793
 
6622
- // src/components/chat/hooks/useResizable.ts
6623
- var import_react80 = require("react");
6624
- function useResizable({
6625
- initialWidthPercent,
6626
- minWidthPercent,
6627
- maxWidthPercent,
6628
- direction
6629
- }) {
6630
- const [widthPercent, setWidthPercent] = (0, import_react80.useState)(initialWidthPercent);
6631
- const [isResizing, setIsResizing] = (0, import_react80.useState)(false);
6632
- const lastX = (0, import_react80.useRef)(null);
6633
- const startResizing = (0, import_react80.useCallback)((e) => {
6634
- e.preventDefault();
6635
- setIsResizing(true);
6636
- lastX.current = e.clientX;
6637
- }, []);
6638
- const stopResizing = (0, import_react80.useCallback)(() => {
6639
- setIsResizing(false);
6640
- lastX.current = null;
6641
- }, []);
6642
- const resize = (0, import_react80.useCallback)(
6643
- (e) => {
6644
- if (!isResizing || lastX.current === null) {
6645
- return;
6646
- }
6647
- const deltaX = e.clientX - lastX.current;
6648
- const factor = direction === "right" ? 1 : -1;
6649
- const deltaPercent = deltaX / window.innerWidth * 100;
6650
- setWidthPercent((prevPercent) => {
6651
- const newPercent = prevPercent + deltaPercent * factor;
6652
- return Math.min(Math.max(newPercent, minWidthPercent), maxWidthPercent);
6653
- });
6654
- lastX.current = e.clientX;
6655
- },
6656
- [isResizing, direction, minWidthPercent, maxWidthPercent]
6657
- );
6658
- (0, import_react80.useEffect)(() => {
6659
- if (isResizing) {
6660
- window.addEventListener("mousemove", resize);
6661
- window.addEventListener("mouseup", stopResizing);
6662
- document.body.style.cursor = "col-resize";
6663
- document.body.style.userSelect = "none";
6664
- } else {
6665
- window.removeEventListener("mousemove", resize);
6666
- window.removeEventListener("mouseup", stopResizing);
6667
- document.body.style.cursor = "";
6668
- document.body.style.userSelect = "";
6669
- }
6670
- return () => {
6671
- window.removeEventListener("mousemove", resize);
6672
- window.removeEventListener("mouseup", stopResizing);
6673
- document.body.style.cursor = "";
6674
- document.body.style.userSelect = "";
6675
- };
6676
- }, [isResizing, resize, stopResizing]);
6677
- const width = `${widthPercent}vw`;
6678
- return { width, widthPercent, isResizing, startResizing };
6679
- }
6680
-
6681
6794
  // src/components/chat/tree.ts
6682
6795
  function createEmptyTree() {
6683
6796
  return { nodes: {}, rootIds: [], activeLeafId: null, lastLeafId: null };
@@ -6838,6 +6951,7 @@ var ChatInterface = import_react81.default.forwardRef(
6838
6951
  onRenameConversation,
6839
6952
  isStreaming = false,
6840
6953
  isThinking = false,
6954
+ thinkingLabel,
6841
6955
  placeholder = "Send a message...",
6842
6956
  emptyStateHelper = "Let's talk.",
6843
6957
  emptyState,
@@ -6846,6 +6960,7 @@ var ChatInterface = import_react81.default.forwardRef(
6846
6960
  attachments: propsAttachments,
6847
6961
  onAttachmentsChange,
6848
6962
  onAttachmentRemove,
6963
+ onAttachmentOpen,
6849
6964
  artifactNodes,
6850
6965
  isArtifactsPanelOpen,
6851
6966
  onArtifactsPanelOpenChange,
@@ -6862,6 +6977,14 @@ var ChatInterface = import_react81.default.forwardRef(
6862
6977
  }, ref) => {
6863
6978
  const prevArtifactNodesRef = (0, import_react81.useRef)([]);
6864
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
+ }, []);
6865
6988
  const [internalTools, setInternalTools] = (0, import_react81.useState)({
6866
6989
  "top-left": "history",
6867
6990
  "bottom-left": null,
@@ -7049,7 +7172,15 @@ var ChatInterface = import_react81.default.forwardRef(
7049
7172
  isStreaming: node.isStreaming,
7050
7173
  muted: opts.muted,
7051
7174
  branchInfo,
7052
- 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
7053
7184
  };
7054
7185
  },
7055
7186
  [
@@ -7059,7 +7190,8 @@ var ChatInterface = import_react81.default.forwardRef(
7059
7190
  onEditMessage,
7060
7191
  onRetryMessage,
7061
7192
  handleBranchSwitch,
7062
- handleJumpToCheckpoint
7193
+ handleJumpToCheckpoint,
7194
+ handleAttachmentOpen
7063
7195
  ]
7064
7196
  );
7065
7197
  const displayItems = (0, import_react81.useMemo)(() => {
@@ -7128,6 +7260,8 @@ var ChatInterface = import_react81.default.forwardRef(
7128
7260
  ArtifactsPanel,
7129
7261
  {
7130
7262
  nodes: artifactNodes,
7263
+ openArtifactId: panelOpenArtifactId,
7264
+ onArtifactClosed: handleArtifactPanelClosed,
7131
7265
  className: "h-full"
7132
7266
  }
7133
7267
  );
@@ -7190,6 +7324,7 @@ var ChatInterface = import_react81.default.forwardRef(
7190
7324
  latestUserMessageIndex,
7191
7325
  isStreaming,
7192
7326
  isThinking,
7327
+ thinkingLabel,
7193
7328
  className: "flex-1"
7194
7329
  }
7195
7330
  )), /* @__PURE__ */ import_react81.default.createElement("div", { className: cx(