@tutti-os/agent-gui 0.0.38 → 0.0.39

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.
Files changed (47) hide show
  1. package/dist/{AgentMessageMarkdown-Cq-7DSV2.d.ts → AgentMessageMarkdown-BVeh06AJ.d.ts} +4 -0
  2. package/dist/agent-conversation/index.d.ts +1 -1
  3. package/dist/agent-conversation/index.js +5 -5
  4. package/dist/agent-message-center/index.js +223 -14
  5. package/dist/agent-message-center/index.js.map +1 -1
  6. package/dist/app/renderer/agentactivity.css +67 -0
  7. package/dist/{chunk-7F4M55U3.js → chunk-3AXEEQMV.js} +24 -7
  8. package/dist/chunk-3AXEEQMV.js.map +1 -0
  9. package/dist/{chunk-L7FBT3VR.js → chunk-46IYJEZX.js} +98 -5
  10. package/dist/chunk-46IYJEZX.js.map +1 -0
  11. package/dist/{chunk-44YASHVW.js → chunk-5HQDW73P.js} +433 -143
  12. package/dist/chunk-5HQDW73P.js.map +1 -0
  13. package/dist/{chunk-2ADVHCST.js → chunk-B2JKDZSR.js} +1 -1
  14. package/dist/{chunk-2ADVHCST.js.map → chunk-B2JKDZSR.js.map} +1 -1
  15. package/dist/{chunk-MKSRP5XS.js → chunk-C7ZZZXKB.js} +5 -5
  16. package/dist/{chunk-XROBPALT.js → chunk-RE3AHBX6.js} +2 -2
  17. package/dist/{chunk-JL2WNRYC.js → chunk-WJPEKD3F.js} +17 -1
  18. package/dist/chunk-WJPEKD3F.js.map +1 -0
  19. package/dist/{chunk-NCS7X3XY.js → chunk-XL2EKJTQ.js} +15 -3
  20. package/dist/chunk-XL2EKJTQ.js.map +1 -0
  21. package/dist/{chunk-WHWZZYBV.js → chunk-Y2DQJPTL.js} +2 -2
  22. package/dist/{chunk-SS5YEVAI.js → chunk-Y5SE2XMU.js} +2 -2
  23. package/dist/{chunk-MUZMBEFO.js → chunk-ZWJBG2JM.js} +21 -2
  24. package/dist/chunk-ZWJBG2JM.js.map +1 -0
  25. package/dist/context-mention-palette/index.js +6 -6
  26. package/dist/i18n/index.d.ts +16 -0
  27. package/dist/i18n/index.js +1 -1
  28. package/dist/index.d.ts +2 -2
  29. package/dist/index.js +2077 -961
  30. package/dist/index.js.map +1 -1
  31. package/dist/workbench/contribution.js +2 -2
  32. package/dist/workbench/index.d.ts +2 -1
  33. package/dist/workbench/index.js +2 -2
  34. package/dist/workbench/state.d.ts +6 -0
  35. package/dist/workbench/state.js +1 -1
  36. package/dist/workspace-agent-generated-files.js +2 -2
  37. package/package.json +13 -12
  38. package/dist/chunk-44YASHVW.js.map +0 -1
  39. package/dist/chunk-7F4M55U3.js.map +0 -1
  40. package/dist/chunk-JL2WNRYC.js.map +0 -1
  41. package/dist/chunk-L7FBT3VR.js.map +0 -1
  42. package/dist/chunk-MUZMBEFO.js.map +0 -1
  43. package/dist/chunk-NCS7X3XY.js.map +0 -1
  44. /package/dist/{chunk-MKSRP5XS.js.map → chunk-C7ZZZXKB.js.map} +0 -0
  45. /package/dist/{chunk-XROBPALT.js.map → chunk-RE3AHBX6.js.map} +0 -0
  46. /package/dist/{chunk-WHWZZYBV.js.map → chunk-Y2DQJPTL.js.map} +0 -0
  47. /package/dist/{chunk-SS5YEVAI.js.map → chunk-Y5SE2XMU.js.map} +0 -0
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  getOptionalAgentHostApi,
3
3
  useOptionalAgentHostApi
4
- } from "./chunk-2ADVHCST.js";
4
+ } from "./chunk-B2JKDZSR.js";
5
5
  import {
6
+ translate,
6
7
  useTranslation
7
- } from "./chunk-JL2WNRYC.js";
8
+ } from "./chunk-WJPEKD3F.js";
8
9
  import {
9
10
  resolveAgentWorkspaceFileVisualKind
10
11
  } from "./chunk-PJP5BUU6.js";
@@ -187,18 +188,24 @@ function arrayValue(value) {
187
188
  import {
188
189
  createContext,
189
190
  startTransition as startTransition2,
190
- useCallback,
191
- useEffect as useEffect2,
191
+ useCallback as useCallback3,
192
+ useEffect as useEffect3,
192
193
  useContext,
193
194
  memo,
194
- useMemo,
195
- useState as useState2
195
+ useMemo as useMemo2,
196
+ useState as useState4
196
197
  } from "react";
197
198
 
198
199
  // app/renderer/components/ZoomableImage.tsx
199
200
  import {
200
- cloneElement
201
+ cloneElement,
202
+ isValidElement,
203
+ useCallback as useCallback2,
204
+ useEffect,
205
+ useMemo,
206
+ useState as useState2
201
207
  } from "react";
208
+ import { CopyIcon, DownloadIcon } from "lucide-react";
202
209
  import Zoom from "react-medium-image-zoom";
203
210
 
204
211
  // app/renderer/lib/utils.ts
@@ -208,44 +215,315 @@ function cn(...inputs) {
208
215
  return twMerge(clsx(inputs));
209
216
  }
210
217
 
218
+ // shared/agentConversation/components/ConversationImageContextMenu.tsx
219
+ import {
220
+ useCallback,
221
+ useRef,
222
+ useState
223
+ } from "react";
224
+
225
+ // app/renderer/components/ui/context-menu.tsx
226
+ import {
227
+ ContextMenu,
228
+ ContextMenuContent,
229
+ ContextMenuItem,
230
+ ContextMenuTrigger
231
+ } from "@tutti-os/ui-system";
232
+
233
+ // shared/agentConversation/lib/copyImageToClipboard.ts
234
+ async function imageSrcToPngBlob(src) {
235
+ const response = await fetch(src);
236
+ const blob = await response.blob();
237
+ if (blob.type === "image/png") {
238
+ return blob;
239
+ }
240
+ const bitmap = await createImageBitmap(blob);
241
+ const canvas = document.createElement("canvas");
242
+ canvas.width = bitmap.width;
243
+ canvas.height = bitmap.height;
244
+ const ctx = canvas.getContext("2d");
245
+ if (!ctx) {
246
+ return null;
247
+ }
248
+ ctx.drawImage(bitmap, 0, 0);
249
+ return await new Promise(
250
+ (resolve) => canvas.toBlob((result) => resolve(result), "image/png")
251
+ );
252
+ }
253
+ async function blobToBase64(blob) {
254
+ return new Promise((resolve, reject) => {
255
+ const reader = new FileReader();
256
+ reader.onerror = () => reject(reader.error ?? new Error("read failed"));
257
+ reader.onload = () => {
258
+ const result = typeof reader.result === "string" ? reader.result : "";
259
+ resolve(result.includes(",") ? result.split(",").pop() ?? "" : result);
260
+ };
261
+ reader.readAsDataURL(blob);
262
+ });
263
+ }
264
+ async function copyImageWithWebClipboard(blob) {
265
+ if (typeof navigator === "undefined" || typeof navigator.clipboard?.write !== "function" || typeof ClipboardItem === "undefined") {
266
+ return false;
267
+ }
268
+ try {
269
+ await navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]);
270
+ return true;
271
+ } catch {
272
+ return false;
273
+ }
274
+ }
275
+ async function copyImageToClipboard(src, hostClipboard) {
276
+ try {
277
+ const blob = await imageSrcToPngBlob(src);
278
+ if (!blob) {
279
+ return false;
280
+ }
281
+ if (hostClipboard?.writeImage) {
282
+ try {
283
+ await hostClipboard.writeImage({
284
+ data: await blobToBase64(blob),
285
+ mimeType: "image/png"
286
+ });
287
+ return true;
288
+ } catch {
289
+ }
290
+ }
291
+ return copyImageWithWebClipboard(blob);
292
+ } catch {
293
+ return false;
294
+ }
295
+ }
296
+
297
+ // shared/agentConversation/components/ConversationImageContextMenu.tsx
298
+ import { jsx, jsxs } from "react/jsx-runtime";
299
+ function ConversationImageContextMenu({
300
+ src,
301
+ children,
302
+ asChild = false,
303
+ contentStyle
304
+ }) {
305
+ const agentHostApi = useOptionalAgentHostApi();
306
+ const copyStartedRef = useRef(false);
307
+ const [menuResetKey, setMenuResetKey] = useState(0);
308
+ const copyAndClose = useCallback(() => {
309
+ if (copyStartedRef.current) {
310
+ return;
311
+ }
312
+ copyStartedRef.current = true;
313
+ setMenuResetKey((key) => key + 1);
314
+ void copyImageToClipboard(src, agentHostApi?.clipboard).finally(() => {
315
+ copyStartedRef.current = false;
316
+ });
317
+ }, [agentHostApi?.clipboard, src]);
318
+ return /* @__PURE__ */ jsxs(ContextMenu, { children: [
319
+ /* @__PURE__ */ jsx(ContextMenuTrigger, { asChild, children }),
320
+ /* @__PURE__ */ jsx(ContextMenuContent, { style: contentStyle, children: /* @__PURE__ */ jsx(
321
+ ContextMenuItem,
322
+ {
323
+ onClick: copyAndClose,
324
+ onPointerDown: (event) => {
325
+ if (event.button !== 0) {
326
+ return;
327
+ }
328
+ event.preventDefault();
329
+ copyAndClose();
330
+ },
331
+ onSelect: copyAndClose,
332
+ children: translate("agentHost.agentGui.copyImage")
333
+ }
334
+ ) })
335
+ ] }, menuResetKey);
336
+ }
337
+
211
338
  // app/renderer/components/ZoomableImage.tsx
212
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
339
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
213
340
  function ZoomableImage({
214
341
  className,
342
+ downloadName,
343
+ onContextMenu,
344
+ src,
215
345
  wrapElement = "div",
216
346
  ...props
217
347
  }) {
218
348
  const { t } = useTranslation();
349
+ const actionSource = typeof src === "string" && src.trim() ? src.trim() : null;
350
+ const hasImageActions = Boolean(actionSource && downloadName !== void 0);
351
+ const resolvedDownloadName = useMemo(
352
+ () => resolveImageDownloadName(downloadName, actionSource),
353
+ [actionSource, downloadName]
354
+ );
355
+ const [contextMenuPosition, setContextMenuPosition] = useState2(null);
356
+ const closeContextMenu = useCallback2(() => {
357
+ setContextMenuPosition(null);
358
+ }, []);
359
+ useEffect(() => {
360
+ if (!contextMenuPosition) {
361
+ return;
362
+ }
363
+ document.addEventListener("click", closeContextMenu);
364
+ document.addEventListener("scroll", closeContextMenu, true);
365
+ return () => {
366
+ document.removeEventListener("click", closeContextMenu);
367
+ document.removeEventListener("scroll", closeContextMenu, true);
368
+ };
369
+ }, [closeContextMenu, contextMenuPosition]);
370
+ const handleContextMenu = useCallback2(
371
+ (event) => {
372
+ onContextMenu?.(event);
373
+ if (event.defaultPrevented || !actionSource || !hasImageActions) {
374
+ return;
375
+ }
376
+ event.preventDefault();
377
+ setContextMenuPosition({ x: event.clientX, y: event.clientY });
378
+ },
379
+ [actionSource, hasImageActions, onContextMenu]
380
+ );
381
+ const handleCopyImage = useCallback2(async () => {
382
+ if (!actionSource) {
383
+ return;
384
+ }
385
+ closeContextMenu();
386
+ await copyImageToClipboard(actionSource);
387
+ }, [actionSource, closeContextMenu]);
388
+ const handleCopyImageAction = useCallback2(() => {
389
+ void handleCopyImage().catch(() => void 0);
390
+ }, [handleCopyImage]);
391
+ const handleDownloadImage = useCallback2(() => {
392
+ if (!actionSource) {
393
+ return;
394
+ }
395
+ closeContextMenu();
396
+ downloadImage(actionSource, resolvedDownloadName);
397
+ }, [actionSource, closeContextMenu, resolvedDownloadName]);
398
+ const actionButtons = hasImageActions ? /* @__PURE__ */ jsx2(
399
+ ImageActionButtons,
400
+ {
401
+ copyLabel: t("common.copyImage"),
402
+ downloadLabel: t("common.downloadImage"),
403
+ onCopy: handleCopyImageAction,
404
+ onDownload: handleDownloadImage
405
+ }
406
+ ) : null;
219
407
  const renderZoomContent = ({
220
408
  buttonUnzoom,
221
409
  img
222
- }) => /* @__PURE__ */ jsxs(Fragment, { children: [
223
- img,
224
- cloneElement(buttonUnzoom, {
225
- className: cn(
226
- buttonUnzoom.props.className,
227
- "nodrag tsh-desktop-no-drag"
228
- )
229
- })
230
- ] });
231
- return /* @__PURE__ */ jsx(
232
- Zoom,
233
- {
234
- a11yNameButtonZoom: t("common.expandImage"),
235
- a11yNameButtonUnzoom: t("common.minimizeImage"),
236
- classDialog: "tsh-zoom-dialog nodrag tsh-desktop-no-drag",
237
- wrapElement,
238
- zoomMargin: 24,
239
- ZoomContent: renderZoomContent,
240
- children: /* @__PURE__ */ jsx(
241
- "img",
410
+ }) => {
411
+ const zoomSrc = isValidElement(img) && typeof img.props.src === "string" ? img.props.src : null;
412
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
413
+ !actionButtons && img && zoomSrc ? /* @__PURE__ */ jsx2(
414
+ ConversationImageContextMenu,
242
415
  {
243
- ...props,
244
- className: cn("nodrag tsh-desktop-no-drag cursor-zoom-in", className)
416
+ src: zoomSrc,
417
+ asChild: true,
418
+ contentStyle: { zIndex: "var(--z-dialog-popover)" },
419
+ children: img
245
420
  }
246
- )
247
- }
248
- );
421
+ ) : img,
422
+ actionButtons ? /* @__PURE__ */ jsx2("div", { className: "tsh-zoom-dialog__image-actions nodrag tsh-desktop-no-drag", children: actionButtons }) : null,
423
+ cloneElement(buttonUnzoom, {
424
+ className: cn(
425
+ buttonUnzoom.props.className,
426
+ "nodrag tsh-desktop-no-drag"
427
+ )
428
+ })
429
+ ] });
430
+ };
431
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
432
+ /* @__PURE__ */ jsx2(
433
+ Zoom,
434
+ {
435
+ a11yNameButtonZoom: t("common.expandImage"),
436
+ a11yNameButtonUnzoom: t("common.minimizeImage"),
437
+ classDialog: "tsh-zoom-dialog nodrag tsh-desktop-no-drag",
438
+ wrapElement,
439
+ zoomMargin: 24,
440
+ ZoomContent: renderZoomContent,
441
+ children: /* @__PURE__ */ jsx2(
442
+ "img",
443
+ {
444
+ ...props,
445
+ src,
446
+ onContextMenu: hasImageActions ? handleContextMenu : onContextMenu,
447
+ className: cn("nodrag tsh-desktop-no-drag cursor-zoom-in", className)
448
+ }
449
+ )
450
+ }
451
+ ),
452
+ contextMenuPosition && actionButtons ? /* @__PURE__ */ jsx2(
453
+ "div",
454
+ {
455
+ className: "tsh-image-context-menu nodrag tsh-desktop-no-drag",
456
+ style: {
457
+ left: contextMenuPosition.x,
458
+ top: contextMenuPosition.y
459
+ },
460
+ role: "menu",
461
+ onClick: (event) => event.stopPropagation(),
462
+ children: /* @__PURE__ */ jsx2(
463
+ ImageActionButtons,
464
+ {
465
+ copyLabel: t("common.copyImage"),
466
+ downloadLabel: t("common.downloadImage"),
467
+ itemRole: "menuitem",
468
+ onCopy: handleCopyImageAction,
469
+ onDownload: handleDownloadImage
470
+ }
471
+ )
472
+ }
473
+ ) : null
474
+ ] });
475
+ }
476
+ function ImageActionButtons({
477
+ copyLabel,
478
+ downloadLabel,
479
+ itemRole,
480
+ onCopy,
481
+ onDownload
482
+ }) {
483
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
484
+ /* @__PURE__ */ jsxs2("button", { type: "button", role: itemRole, title: copyLabel, onClick: onCopy, children: [
485
+ /* @__PURE__ */ jsx2(CopyIcon, { "aria-hidden": "true", className: "size-4" }),
486
+ /* @__PURE__ */ jsx2("span", { children: copyLabel })
487
+ ] }),
488
+ /* @__PURE__ */ jsxs2(
489
+ "button",
490
+ {
491
+ type: "button",
492
+ role: itemRole,
493
+ title: downloadLabel,
494
+ onClick: onDownload,
495
+ children: [
496
+ /* @__PURE__ */ jsx2(DownloadIcon, { "aria-hidden": "true", className: "size-4" }),
497
+ /* @__PURE__ */ jsx2("span", { children: downloadLabel })
498
+ ]
499
+ }
500
+ )
501
+ ] });
502
+ }
503
+ function downloadImage(src, name) {
504
+ const link = document.createElement("a");
505
+ link.href = src;
506
+ link.download = name;
507
+ link.rel = "noopener";
508
+ document.body.append(link);
509
+ link.click();
510
+ link.remove();
511
+ }
512
+ function resolveImageDownloadName(name, src) {
513
+ const trimmedName = name?.trim();
514
+ if (trimmedName) {
515
+ return trimmedName;
516
+ }
517
+ const srcName = src ? decodeURIComponentSafe(src.split(/[?#]/, 1)[0] ?? "") : "";
518
+ const lastSegment = srcName.split(/[\\/]/).pop()?.trim();
519
+ return lastSegment || "image.png";
520
+ }
521
+ function decodeURIComponentSafe(value) {
522
+ try {
523
+ return decodeURIComponent(value);
524
+ } catch {
525
+ return value;
526
+ }
249
527
  }
250
528
 
251
529
  // shared/AgentMessageMarkdown.tsx
@@ -828,9 +1106,9 @@ function countChar(value, char) {
828
1106
  // shared/useStreamingVisibleText.ts
829
1107
  import {
830
1108
  startTransition,
831
- useEffect,
832
- useRef,
833
- useState
1109
+ useEffect as useEffect2,
1110
+ useRef as useRef2,
1111
+ useState as useState3
834
1112
  } from "react";
835
1113
  var DEFAULT_FRAME_MS = 24;
836
1114
  var DEFAULT_MAX_CHARS_PER_SECOND = 6e3;
@@ -842,20 +1120,20 @@ function useStreamingVisibleText(sourceText, options) {
842
1120
  maxCharsPerSecond = DEFAULT_MAX_CHARS_PER_SECOND,
843
1121
  trailingFlushChars = DEFAULT_TRAILING_FLUSH_CHARS
844
1122
  } = options;
845
- const [visibleText, setVisibleText] = useState(sourceText);
846
- const sourceRef = useRef(sourceText);
847
- const visibleRef = useRef(visibleText);
848
- const timerRef = useRef(null);
849
- useEffect(() => {
1123
+ const [visibleText, setVisibleText] = useState3(sourceText);
1124
+ const sourceRef = useRef2(sourceText);
1125
+ const visibleRef = useRef2(visibleText);
1126
+ const timerRef = useRef2(null);
1127
+ useEffect2(() => {
850
1128
  visibleRef.current = visibleText;
851
1129
  }, [visibleText]);
852
- useEffect(
1130
+ useEffect2(
853
1131
  () => () => {
854
1132
  clearStreamingVisibleTextTimer(timerRef);
855
1133
  },
856
1134
  []
857
1135
  );
858
- useEffect(() => {
1136
+ useEffect2(() => {
859
1137
  sourceRef.current = sourceText;
860
1138
  if (!enabled) {
861
1139
  clearStreamingVisibleTextTimer(timerRef);
@@ -940,7 +1218,7 @@ function clearStreamingVisibleTextTimer(timerRef) {
940
1218
  }
941
1219
 
942
1220
  // shared/AgentMessageMarkdown.tsx
943
- import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1221
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
944
1222
  var COLLAPSED_LINE_LIMIT = 8;
945
1223
  var APPROX_CHARS_PER_LINE = 34;
946
1224
  var DEFERRED_LONG_MARKDOWN_CHAR_THRESHOLD = 4096;
@@ -1003,7 +1281,7 @@ function AgentMessageMarkdown({
1003
1281
  maxCharsPerSecond: STREAMING_MARKDOWN_MAX_CHARS_PER_SECOND,
1004
1282
  trailingFlushChars: STREAMING_MARKDOWN_TAIL_FLUSH_CHARS
1005
1283
  });
1006
- const stabilizedContent = useMemo(
1284
+ const stabilizedContent = useMemo2(
1007
1285
  () => stabilizeStreamingMarkdownTail(visibleContent, {
1008
1286
  streaming
1009
1287
  }).content,
@@ -1012,16 +1290,16 @@ function AgentMessageMarkdown({
1012
1290
  const workspaceRoot = workspaceLinkContext?.workspaceRoot ?? null;
1013
1291
  const basePath = workspaceLinkContext?.basePath ?? null;
1014
1292
  const workspaceLinkSource = workspaceLinkContext?.source ?? null;
1015
- const [isExpanded, setIsExpanded] = useState2(false);
1293
+ const [isExpanded, setIsExpanded] = useState4(false);
1016
1294
  const resolvedExpandLabel = expandLabel ?? t("agentHost.workspaceAgentMessageExpand");
1017
1295
  const shouldCollapse = collapsible && isLikelyLongerThanLineLimit(stabilizedContent);
1018
1296
  const isCollapsed = shouldCollapse && !isExpanded;
1019
1297
  const ContainerTag = inline ? "span" : "div";
1020
- const contentSignature = useMemo(
1298
+ const contentSignature = useMemo2(
1021
1299
  () => hashMarkdownProfilerContent(stabilizedContent),
1022
1300
  [stabilizedContent]
1023
1301
  );
1024
- const normalizedContent = useMemo(
1302
+ const normalizedContent = useMemo2(
1025
1303
  () => linkBareLocalAbsolutePaths(
1026
1304
  normalizeMentionMarkdownLinks(
1027
1305
  normalizePlainIssueMentionTitle ? normalizePlainIssueMentionTitleContent(
@@ -1037,7 +1315,7 @@ function AgentMessageMarkdown({
1037
1315
  contentSignature,
1038
1316
  shouldDeferMarkdownRender
1039
1317
  );
1040
- const handleLinkClick = useCallback(
1318
+ const handleLinkClick = useCallback3(
1041
1319
  (href) => {
1042
1320
  if (workspaceLinkSource && onLinkAction && workspaceRoot) {
1043
1321
  const action = resolveWorkspaceLinkAction({
@@ -1055,7 +1333,7 @@ function AgentMessageMarkdown({
1055
1333
  },
1056
1334
  [basePath, onLinkAction, onLinkClick, workspaceLinkSource, workspaceRoot]
1057
1335
  );
1058
- const handleAnchorClickCapture = useCallback(
1336
+ const handleAnchorClickCapture = useCallback3(
1059
1337
  (event) => {
1060
1338
  const href = resolveMarkdownAnchorHref(event.target);
1061
1339
  if (!href) {
@@ -1067,9 +1345,9 @@ function AgentMessageMarkdown({
1067
1345
  },
1068
1346
  [handleLinkClick]
1069
1347
  );
1070
- const markdownComponents = useMemo(
1348
+ const markdownComponents = useMemo2(
1071
1349
  () => ({
1072
- a: (props) => /* @__PURE__ */ jsx2(
1350
+ a: (props) => /* @__PURE__ */ jsx3(
1073
1351
  MarkdownLink,
1074
1352
  {
1075
1353
  ...props,
@@ -1078,22 +1356,22 @@ function AgentMessageMarkdown({
1078
1356
  previewMode
1079
1357
  }
1080
1358
  ),
1081
- code: (props) => /* @__PURE__ */ jsx2(MarkdownCode, { ...props, onLinkClick: handleLinkClick }),
1082
- img: (props) => /* @__PURE__ */ jsx2(MarkdownMedia, { ...props, enableZoom: enableImageZoom }),
1083
- p: (props) => /* @__PURE__ */ jsx2(MarkdownParagraph, { ...props, inline }),
1359
+ code: (props) => /* @__PURE__ */ jsx3(MarkdownCode, { ...props, onLinkClick: handleLinkClick }),
1360
+ img: (props) => /* @__PURE__ */ jsx3(MarkdownMedia, { ...props, enableZoom: enableImageZoom }),
1361
+ p: (props) => /* @__PURE__ */ jsx3(MarkdownParagraph, { ...props, inline }),
1084
1362
  ul: MarkdownUnorderedList,
1085
1363
  ol: MarkdownOrderedList,
1086
1364
  li: MarkdownListItem
1087
1365
  }),
1088
1366
  [enableImageZoom, handleLinkClick, inline, previewMode, workspaceAppIcons]
1089
1367
  );
1090
- return /* @__PURE__ */ jsxs2(
1368
+ return /* @__PURE__ */ jsxs3(
1091
1369
  ContainerTag,
1092
1370
  {
1093
1371
  className: "flex w-full min-w-0 flex-col items-start gap-1",
1094
1372
  "data-workspace-agent-markdown-shell": "true",
1095
1373
  children: [
1096
- /* @__PURE__ */ jsx2(
1374
+ /* @__PURE__ */ jsx3(
1097
1375
  ContainerTag,
1098
1376
  {
1099
1377
  className: cn(
@@ -1124,13 +1402,13 @@ function AgentMessageMarkdown({
1124
1402
  "data-agent-mention-only": isMentionOnly ? "true" : void 0,
1125
1403
  "data-collapsed": isCollapsed ? "true" : "false",
1126
1404
  onClickCapture: handleAnchorClickCapture,
1127
- children: markdownRenderReady ? streaming ? /* @__PURE__ */ jsx2(
1405
+ children: markdownRenderReady ? streaming ? /* @__PURE__ */ jsx3(
1128
1406
  StreamingMarkdownBlocks,
1129
1407
  {
1130
1408
  content: normalizedContent,
1131
1409
  components: markdownComponents
1132
1410
  }
1133
- ) : /* @__PURE__ */ jsx2(
1411
+ ) : /* @__PURE__ */ jsx3(
1134
1412
  ReactMarkdown,
1135
1413
  {
1136
1414
  remarkPlugins: [remarkGfm],
@@ -1139,7 +1417,7 @@ function AgentMessageMarkdown({
1139
1417
  components: markdownComponents,
1140
1418
  children: normalizedContent
1141
1419
  }
1142
- ) : /* @__PURE__ */ jsx2(
1420
+ ) : /* @__PURE__ */ jsx3(
1143
1421
  "div",
1144
1422
  {
1145
1423
  className: "whitespace-pre-wrap [overflow-wrap:anywhere]",
@@ -1149,7 +1427,7 @@ function AgentMessageMarkdown({
1149
1427
  )
1150
1428
  }
1151
1429
  ),
1152
- shouldCollapse && !isExpanded ? /* @__PURE__ */ jsx2(
1430
+ shouldCollapse && !isExpanded ? /* @__PURE__ */ jsx3(
1153
1431
  "button",
1154
1432
  {
1155
1433
  type: "button",
@@ -1166,11 +1444,11 @@ function StreamingMarkdownBlocks({
1166
1444
  content,
1167
1445
  components
1168
1446
  }) {
1169
- const blocks = useMemo(
1447
+ const blocks = useMemo2(
1170
1448
  () => splitStreamingMarkdownBlocks(content),
1171
1449
  [content]
1172
1450
  );
1173
- return /* @__PURE__ */ jsx2(Fragment2, { children: blocks.map((block, index) => /* @__PURE__ */ jsx2(
1451
+ return /* @__PURE__ */ jsx3(Fragment2, { children: blocks.map((block, index) => /* @__PURE__ */ jsx3(
1174
1452
  MemoizedMarkdownBlock,
1175
1453
  {
1176
1454
  content: block.content,
@@ -1183,7 +1461,7 @@ var MemoizedMarkdownBlock = memo(function MemoizedMarkdownBlock2({
1183
1461
  content,
1184
1462
  components
1185
1463
  }) {
1186
- return /* @__PURE__ */ jsx2(
1464
+ return /* @__PURE__ */ jsx3(
1187
1465
  ReactMarkdown,
1188
1466
  {
1189
1467
  remarkPlugins: [remarkGfm],
@@ -1287,11 +1565,11 @@ function activateMarkdownLinkFromPointer(event, href, onLinkClick) {
1287
1565
  activateMarkdownLink(event, href, onLinkClick);
1288
1566
  }
1289
1567
  function useDeferredMarkdownRenderReady(contentSignature, shouldDefer) {
1290
- const [readySignature, setReadySignature] = useState2(
1568
+ const [readySignature, setReadySignature] = useState4(
1291
1569
  shouldDefer ? null : contentSignature
1292
1570
  );
1293
1571
  const renderReady = !shouldDefer || readySignature === contentSignature;
1294
- useEffect2(() => {
1572
+ useEffect3(() => {
1295
1573
  if (!shouldDefer) {
1296
1574
  setReadySignature(contentSignature);
1297
1575
  return;
@@ -1367,7 +1645,7 @@ function MarkdownLink({
1367
1645
  t("agentHost.agentGui.workspaceAppFactoryMentionFallback")
1368
1646
  ) : null;
1369
1647
  if (mention) {
1370
- return /* @__PURE__ */ jsx2(
1648
+ return /* @__PURE__ */ jsx3(
1371
1649
  MentionLink,
1372
1650
  {
1373
1651
  ...props,
@@ -1383,7 +1661,7 @@ function MarkdownLink({
1383
1661
  textFromReactNode(props.children)
1384
1662
  ) : null;
1385
1663
  if (fileMention) {
1386
- return /* @__PURE__ */ jsx2(
1664
+ return /* @__PURE__ */ jsx3(
1387
1665
  WorkspaceFileMentionLink,
1388
1666
  {
1389
1667
  ...props,
@@ -1394,9 +1672,9 @@ function MarkdownLink({
1394
1672
  );
1395
1673
  }
1396
1674
  if (!isClickableMarkdownHref(targetHref)) {
1397
- return /* @__PURE__ */ jsx2(MarkdownLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx2("span", { className: props.className, title: props.title, children: props.children }) });
1675
+ return /* @__PURE__ */ jsx3(MarkdownLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx3("span", { className: props.className, title: props.title, children: props.children }) });
1398
1676
  }
1399
- return /* @__PURE__ */ jsx2(MarkdownLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx2(
1677
+ return /* @__PURE__ */ jsx3(MarkdownLinkContext.Provider, { value: true, children: /* @__PURE__ */ jsx3(
1400
1678
  "a",
1401
1679
  {
1402
1680
  ...props,
@@ -1480,7 +1758,7 @@ function WorkspaceFileMentionLink({
1480
1758
  ...props
1481
1759
  }) {
1482
1760
  "use memo";
1483
- return /* @__PURE__ */ jsxs2(
1761
+ return /* @__PURE__ */ jsxs3(
1484
1762
  "a",
1485
1763
  {
1486
1764
  ...props,
@@ -1507,8 +1785,8 @@ function WorkspaceFileMentionLink({
1507
1785
  activateMarkdownLinkFromKey(event, mention.href, onLinkClick);
1508
1786
  },
1509
1787
  children: [
1510
- /* @__PURE__ */ jsx2("span", { className: "tsh-agent-object-token__icon", "aria-hidden": "true" }),
1511
- /* @__PURE__ */ jsx2("span", { className: "tsh-agent-object-token__main", children: mention.label })
1788
+ /* @__PURE__ */ jsx3("span", { className: "tsh-agent-object-token__icon", "aria-hidden": "true" }),
1789
+ /* @__PURE__ */ jsx3("span", { className: "tsh-agent-object-token__main", children: mention.label })
1512
1790
  ]
1513
1791
  }
1514
1792
  );
@@ -1524,7 +1802,7 @@ function MentionLink({
1524
1802
  "use memo";
1525
1803
  const tooltipText = mention.kind === "session" ? `${mention.participant}${mention.summary ? ` ${mention.summary}` : ""}`.trim() : mention.label;
1526
1804
  const { ref: mainRef, overflowing } = useTextOverflow(tooltipText);
1527
- const link = /* @__PURE__ */ jsxs2(
1805
+ const link = /* @__PURE__ */ jsxs3(
1528
1806
  "a",
1529
1807
  {
1530
1808
  ...props,
@@ -1550,14 +1828,14 @@ function MentionLink({
1550
1828
  activateMarkdownLinkFromKey(event, href, onLinkClick);
1551
1829
  },
1552
1830
  children: [
1553
- mention.kind === "workspace-app" || mention.kind === "workspace-reference" ? /* @__PURE__ */ jsx2(
1831
+ mention.kind === "workspace-app" || mention.kind === "workspace-reference" ? /* @__PURE__ */ jsx3(
1554
1832
  "span",
1555
1833
  {
1556
1834
  className: "grid h-4 w-4 shrink-0 place-items-center overflow-hidden rounded-[4px] bg-block",
1557
1835
  "aria-hidden": "true",
1558
1836
  "data-agent-mention-app-icon": "true",
1559
1837
  "data-workspace-app-icon": "true",
1560
- children: mention.iconUrl ? /* @__PURE__ */ jsx2(
1838
+ children: mention.iconUrl ? /* @__PURE__ */ jsx3(
1561
1839
  "img",
1562
1840
  {
1563
1841
  src: mention.iconUrl,
@@ -1567,31 +1845,31 @@ function MentionLink({
1567
1845
  loading: "lazy",
1568
1846
  draggable: false
1569
1847
  }
1570
- ) : /* @__PURE__ */ jsx2("span", { className: "tsh-agent-object-token__kind-icon h-4 w-4" })
1848
+ ) : /* @__PURE__ */ jsx3("span", { className: "tsh-agent-object-token__kind-icon h-4 w-4" })
1571
1849
  }
1572
- ) : /* @__PURE__ */ jsx2("span", { className: "tsh-agent-object-token__kind", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(
1850
+ ) : /* @__PURE__ */ jsx3("span", { className: "tsh-agent-object-token__kind", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(
1573
1851
  "span",
1574
1852
  {
1575
1853
  className: "tsh-agent-object-token__kind-icon",
1576
1854
  "aria-hidden": "true"
1577
1855
  }
1578
1856
  ) }),
1579
- mention.kind === "session" ? /* @__PURE__ */ jsxs2("span", { className: "tsh-agent-object-token__main", ref: mainRef, children: [
1580
- /* @__PURE__ */ jsx2("span", { className: "tsh-agent-object-token__participant", children: mention.participant }),
1581
- mention.summary ? /* @__PURE__ */ jsxs2("span", { className: "tsh-agent-object-token__summary", children: [
1857
+ mention.kind === "session" ? /* @__PURE__ */ jsxs3("span", { className: "tsh-agent-object-token__main", ref: mainRef, children: [
1858
+ /* @__PURE__ */ jsx3("span", { className: "tsh-agent-object-token__participant", children: mention.participant }),
1859
+ mention.summary ? /* @__PURE__ */ jsxs3("span", { className: "tsh-agent-object-token__summary", children: [
1582
1860
  " ",
1583
1861
  mention.summary
1584
1862
  ] }) : null
1585
- ] }) : /* @__PURE__ */ jsx2("span", { className: "tsh-agent-object-token__main", ref: mainRef, children: mention.label })
1863
+ ] }) : /* @__PURE__ */ jsx3("span", { className: "tsh-agent-object-token__main", ref: mainRef, children: mention.label })
1586
1864
  ]
1587
1865
  }
1588
1866
  );
1589
1867
  if (previewMode) {
1590
1868
  return link;
1591
1869
  }
1592
- return /* @__PURE__ */ jsx2(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs2(Tooltip, { children: [
1593
- /* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: link }),
1594
- overflowing ? /* @__PURE__ */ jsx2(TooltipContent, { className: "max-w-[min(420px,calc(100vw-32px))] whitespace-normal text-left [overflow-wrap:anywhere]", children: tooltipText }) : null
1870
+ return /* @__PURE__ */ jsx3(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs3(Tooltip, { children: [
1871
+ /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: link }),
1872
+ overflowing ? /* @__PURE__ */ jsx3(TooltipContent, { className: "max-w-[min(420px,calc(100vw-32px))] whitespace-normal text-left [overflow-wrap:anywhere]", children: tooltipText }) : null
1595
1873
  ] }) });
1596
1874
  }
1597
1875
  function MarkdownCode({
@@ -1606,9 +1884,9 @@ function MarkdownCode({
1606
1884
  const text = textFromReactNode(children).trim();
1607
1885
  const isLinkablePath = !isInsideLink && onLinkClick && !className && (isExplicitWorkspaceFilePath(text) || isHttpUrl(text));
1608
1886
  if (isLinkablePath) {
1609
- return /* @__PURE__ */ jsx2(PathLink, { href: text, onLinkClick, children });
1887
+ return /* @__PURE__ */ jsx3(PathLink, { href: text, onLinkClick, children });
1610
1888
  }
1611
- return /* @__PURE__ */ jsx2("code", { ...props, className, children });
1889
+ return /* @__PURE__ */ jsx3("code", { ...props, className, children });
1612
1890
  }
1613
1891
  var cachedMarkdownMedia = /* @__PURE__ */ new Map();
1614
1892
  var CACHED_MARKDOWN_MEDIA_REVOKE_DELAY_MS = 250;
@@ -1631,10 +1909,10 @@ function MarkdownMedia({
1631
1909
  const shouldEnableZoom = enableZoom && !isInsideLink;
1632
1910
  const fallbackMediaKind = typeof src === "string" ? resolveMarkdownMediaKind(src) : null;
1633
1911
  const resolvedSrc = typeof src === "string" ? resolveRenderableMarkdownMediaSrc(src) : src;
1634
- const [state, setState] = useState2(
1912
+ const [state, setState] = useState4(
1635
1913
  () => canReadWorkspaceImage && workspacePath ? peekCachedMarkdownMediaState(workspacePath) ?? { status: "loading" } : null
1636
1914
  );
1637
- useEffect2(() => {
1915
+ useEffect3(() => {
1638
1916
  if (!workspacePath || !readWorkspaceImage) {
1639
1917
  setState(null);
1640
1918
  return;
@@ -1701,9 +1979,9 @@ function MarkdownMedia({
1701
1979
  if (!workspacePath || !readWorkspaceImage) {
1702
1980
  if (fallbackMediaKind === "video") {
1703
1981
  if (!canRenderMarkdownVideoFallback(src)) {
1704
- return /* @__PURE__ */ jsx2(UnsupportedMarkdownMediaPreview, {});
1982
+ return /* @__PURE__ */ jsx3(UnsupportedMarkdownMediaPreview, {});
1705
1983
  }
1706
- return /* @__PURE__ */ jsx2(
1984
+ return /* @__PURE__ */ jsx3(
1707
1985
  "video",
1708
1986
  {
1709
1987
  src: resolvedSrc,
@@ -1720,7 +1998,7 @@ function MarkdownMedia({
1720
1998
  );
1721
1999
  }
1722
2000
  if (!shouldEnableZoom) {
1723
- return /* @__PURE__ */ jsx2(
2001
+ return /* @__PURE__ */ jsx3(
1724
2002
  "img",
1725
2003
  {
1726
2004
  ...props,
@@ -1731,13 +2009,14 @@ function MarkdownMedia({
1731
2009
  }
1732
2010
  );
1733
2011
  }
1734
- return /* @__PURE__ */ jsx2(
2012
+ return /* @__PURE__ */ jsx3(
1735
2013
  ZoomableImage,
1736
2014
  {
1737
2015
  ...props,
1738
2016
  src: resolvedSrc,
1739
2017
  alt,
1740
2018
  title,
2019
+ downloadName: resolveMarkdownImageDownloadName(src, alt),
1741
2020
  className,
1742
2021
  wrapElement: "span"
1743
2022
  }
@@ -1745,7 +2024,7 @@ function MarkdownMedia({
1745
2024
  }
1746
2025
  if (state?.status === "ready") {
1747
2026
  if (state.kind === "video") {
1748
- return /* @__PURE__ */ jsx2(
2027
+ return /* @__PURE__ */ jsx3(
1749
2028
  "video",
1750
2029
  {
1751
2030
  src: state.src,
@@ -1762,7 +2041,7 @@ function MarkdownMedia({
1762
2041
  );
1763
2042
  }
1764
2043
  if (!shouldEnableZoom) {
1765
- return /* @__PURE__ */ jsx2(
2044
+ return /* @__PURE__ */ jsx3(
1766
2045
  "img",
1767
2046
  {
1768
2047
  ...props,
@@ -1776,13 +2055,14 @@ function MarkdownMedia({
1776
2055
  }
1777
2056
  );
1778
2057
  }
1779
- return /* @__PURE__ */ jsx2(
2058
+ return /* @__PURE__ */ jsx3(
1780
2059
  ZoomableImage,
1781
2060
  {
1782
2061
  ...props,
1783
2062
  src: state.src,
1784
2063
  alt,
1785
2064
  title,
2065
+ downloadName: resolveMarkdownImageDownloadName(workspacePath, alt),
1786
2066
  className: cn(
1787
2067
  "mt-2 block max-h-[360px] max-w-full rounded-[8px] bg-[var(--transparency-block)] object-contain",
1788
2068
  className
@@ -1791,13 +2071,22 @@ function MarkdownMedia({
1791
2071
  }
1792
2072
  );
1793
2073
  }
1794
- return /* @__PURE__ */ jsx2("span", { className: "mt-2 flex min-h-[160px] w-full items-center justify-center rounded-[8px] bg-[var(--transparency-block)] px-5 py-5 text-center text-[13px] leading-5 text-[var(--text-tertiary)]", children: state?.status === "error" ? state.reason === "unsupported" ? t("agentHost.workspaceFileManager.previewUnsupported") : t("agentHost.workspaceFileManager.previewReadFailed", {
2074
+ return /* @__PURE__ */ jsx3("span", { className: "mt-2 flex min-h-[160px] w-full items-center justify-center rounded-[8px] bg-[var(--transparency-block)] px-5 py-5 text-center text-[13px] leading-5 text-[var(--text-tertiary)]", children: state?.status === "error" ? state.reason === "unsupported" ? t("agentHost.workspaceFileManager.previewUnsupported") : t("agentHost.workspaceFileManager.previewReadFailed", {
1795
2075
  message: state.detail ?? ""
1796
2076
  }) : t("agentHost.workspaceFileManager.previewLoading") });
1797
2077
  }
1798
2078
  function UnsupportedMarkdownMediaPreview() {
1799
2079
  const { t } = useTranslation();
1800
- return /* @__PURE__ */ jsx2("span", { className: "mt-2 flex min-h-[160px] w-full items-center justify-center rounded-[8px] bg-[var(--transparency-block)] px-5 py-5 text-center text-[13px] leading-5 text-[var(--text-tertiary)]", children: t("agentHost.workspaceFileManager.previewUnsupported") });
2080
+ return /* @__PURE__ */ jsx3("span", { className: "mt-2 flex min-h-[160px] w-full items-center justify-center rounded-[8px] bg-[var(--transparency-block)] px-5 py-5 text-center text-[13px] leading-5 text-[var(--text-tertiary)]", children: t("agentHost.workspaceFileManager.previewUnsupported") });
2081
+ }
2082
+ function resolveMarkdownImageDownloadName(src, alt) {
2083
+ if (typeof src === "string") {
2084
+ const pathName = basenameWorkspacePath(src.trim());
2085
+ if (pathName) {
2086
+ return pathName;
2087
+ }
2088
+ }
2089
+ return typeof alt === "string" ? alt.trim() || void 0 : void 0;
1801
2090
  }
1802
2091
  var MARKDOWN_ORDERED_LIST_STYLE = {
1803
2092
  listStylePosition: "outside",
@@ -1819,7 +2108,7 @@ function MarkdownUnorderedList({
1819
2108
  ...props
1820
2109
  }) {
1821
2110
  "use memo";
1822
- return /* @__PURE__ */ jsx2(
2111
+ return /* @__PURE__ */ jsx3(
1823
2112
  "ul",
1824
2113
  {
1825
2114
  ...props,
@@ -1837,7 +2126,7 @@ function MarkdownOrderedList({
1837
2126
  ...props
1838
2127
  }) {
1839
2128
  "use memo";
1840
- return /* @__PURE__ */ jsx2(
2129
+ return /* @__PURE__ */ jsx3(
1841
2130
  "ol",
1842
2131
  {
1843
2132
  ...props,
@@ -1855,7 +2144,7 @@ function MarkdownListItem({
1855
2144
  ...props
1856
2145
  }) {
1857
2146
  "use memo";
1858
- return /* @__PURE__ */ jsx2("li", { ...props, style: { ...MARKDOWN_LIST_ITEM_STYLE, ...style } });
2147
+ return /* @__PURE__ */ jsx3("li", { ...props, style: { ...MARKDOWN_LIST_ITEM_STYLE, ...style } });
1859
2148
  }
1860
2149
  function MarkdownParagraph({
1861
2150
  node: _node,
@@ -1864,9 +2153,9 @@ function MarkdownParagraph({
1864
2153
  }) {
1865
2154
  "use memo";
1866
2155
  if (inline) {
1867
- return /* @__PURE__ */ jsx2("span", { ...props });
2156
+ return /* @__PURE__ */ jsx3("span", { ...props });
1868
2157
  }
1869
- return /* @__PURE__ */ jsx2("p", { ...props });
2158
+ return /* @__PURE__ */ jsx3("p", { ...props });
1870
2159
  }
1871
2160
  function isLocalAbsolutePath(path) {
1872
2161
  const candidate = path.trim();
@@ -2245,7 +2534,7 @@ function PathLink({
2245
2534
  onLinkClick
2246
2535
  }) {
2247
2536
  "use memo";
2248
- return /* @__PURE__ */ jsx2(
2537
+ return /* @__PURE__ */ jsx3(
2249
2538
  "a",
2250
2539
  {
2251
2540
  className: "cursor-pointer",
@@ -2309,17 +2598,17 @@ var AgentGUIConversation_styles_default = styles;
2309
2598
  // app/renderer/components/icons/MessageSquareMoreIcon.tsx
2310
2599
  import {
2311
2600
  forwardRef,
2312
- useCallback as useCallback2,
2313
- useEffect as useEffect3,
2601
+ useCallback as useCallback4,
2602
+ useEffect as useEffect4,
2314
2603
  useImperativeHandle,
2315
- useRef as useRef2
2604
+ useRef as useRef3
2316
2605
  } from "react";
2317
2606
  import {
2318
2607
  motion,
2319
2608
  useAnimation,
2320
2609
  useReducedMotion
2321
2610
  } from "framer-motion";
2322
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2611
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2323
2612
  var DOT_TRANSITION = {
2324
2613
  times: [0, 0.1, 0.1, 0.2, 0.5, 0.6, 0.6, 0.7],
2325
2614
  duration: 1.5
@@ -2363,14 +2652,14 @@ var MessageSquareMoreIcon = forwardRef(
2363
2652
  }, ref) => {
2364
2653
  const controls = useAnimation();
2365
2654
  const reduceMotion = useReducedMotion();
2366
- const isControlledRef = useRef2(false);
2367
- const startAnimation = useCallback2(() => {
2655
+ const isControlledRef = useRef3(false);
2656
+ const startAnimation = useCallback4(() => {
2368
2657
  if (reduceMotion) {
2369
2658
  return;
2370
2659
  }
2371
2660
  void controls.start(active ? "active" : "animate");
2372
2661
  }, [active, controls, reduceMotion]);
2373
- const stopAnimation = useCallback2(() => {
2662
+ const stopAnimation = useCallback4(() => {
2374
2663
  void controls.start("normal");
2375
2664
  }, [controls]);
2376
2665
  useImperativeHandle(ref, () => {
@@ -2380,14 +2669,14 @@ var MessageSquareMoreIcon = forwardRef(
2380
2669
  stopAnimation
2381
2670
  };
2382
2671
  });
2383
- useEffect3(() => {
2672
+ useEffect4(() => {
2384
2673
  if (active) {
2385
2674
  startAnimation();
2386
2675
  return;
2387
2676
  }
2388
2677
  stopAnimation();
2389
2678
  }, [active, startAnimation, stopAnimation]);
2390
- const handleMouseEnter = useCallback2(
2679
+ const handleMouseEnter = useCallback4(
2391
2680
  (event) => {
2392
2681
  if (isControlledRef.current) {
2393
2682
  onMouseEnter?.(event);
@@ -2397,7 +2686,7 @@ var MessageSquareMoreIcon = forwardRef(
2397
2686
  },
2398
2687
  [onMouseEnter, startAnimation]
2399
2688
  );
2400
- const handleMouseLeave = useCallback2(
2689
+ const handleMouseLeave = useCallback4(
2401
2690
  (event) => {
2402
2691
  if (isControlledRef.current) {
2403
2692
  onMouseLeave?.(event);
@@ -2407,14 +2696,14 @@ var MessageSquareMoreIcon = forwardRef(
2407
2696
  },
2408
2697
  [onMouseLeave, stopAnimation]
2409
2698
  );
2410
- return /* @__PURE__ */ jsx3(
2699
+ return /* @__PURE__ */ jsx4(
2411
2700
  "div",
2412
2701
  {
2413
2702
  className: cn("inline-flex items-center justify-center", className),
2414
2703
  onMouseEnter: handleMouseEnter,
2415
2704
  onMouseLeave: handleMouseLeave,
2416
2705
  ...props,
2417
- children: /* @__PURE__ */ jsxs3(
2706
+ children: /* @__PURE__ */ jsxs4(
2418
2707
  "svg",
2419
2708
  {
2420
2709
  fill: "none",
@@ -2427,8 +2716,8 @@ var MessageSquareMoreIcon = forwardRef(
2427
2716
  width: size,
2428
2717
  xmlns: "http://www.w3.org/2000/svg",
2429
2718
  children: [
2430
- /* @__PURE__ */ jsx3("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }),
2431
- /* @__PURE__ */ jsx3(
2719
+ /* @__PURE__ */ jsx4("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }),
2720
+ /* @__PURE__ */ jsx4(
2432
2721
  motion.path,
2433
2722
  {
2434
2723
  animate: controls,
@@ -2437,7 +2726,7 @@ var MessageSquareMoreIcon = forwardRef(
2437
2726
  variants: DOT_VARIANTS
2438
2727
  }
2439
2728
  ),
2440
- /* @__PURE__ */ jsx3(
2729
+ /* @__PURE__ */ jsx4(
2441
2730
  motion.path,
2442
2731
  {
2443
2732
  animate: controls,
@@ -2446,7 +2735,7 @@ var MessageSquareMoreIcon = forwardRef(
2446
2735
  variants: DOT_VARIANTS
2447
2736
  }
2448
2737
  ),
2449
- /* @__PURE__ */ jsx3(
2738
+ /* @__PURE__ */ jsx4(
2450
2739
  motion.path,
2451
2740
  {
2452
2741
  animate: controls,
@@ -2467,12 +2756,12 @@ MessageSquareMoreIcon.displayName = "MessageSquareMoreIcon";
2467
2756
  // app/renderer/components/ui/custom-scroll-area.tsx
2468
2757
  import {
2469
2758
  forwardRef as forwardRef2,
2470
- useCallback as useCallback3,
2471
- useEffect as useEffect4,
2472
- useRef as useRef3,
2473
- useState as useState3
2759
+ useCallback as useCallback5,
2760
+ useEffect as useEffect5,
2761
+ useRef as useRef4,
2762
+ useState as useState5
2474
2763
  } from "react";
2475
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2764
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2476
2765
  var MIN_THUMB_HEIGHT = 24;
2477
2766
  function CustomScrollbar({
2478
2767
  getViewport,
@@ -2483,15 +2772,15 @@ function CustomScrollbar({
2483
2772
  syncKey
2484
2773
  }) {
2485
2774
  "use memo";
2486
- const trackRef = useRef3(null);
2487
- const dragStateRef = useRef3(null);
2488
- const [scrollbarState, setScrollbarState] = useState3({
2775
+ const trackRef = useRef4(null);
2776
+ const dragStateRef = useRef4(null);
2777
+ const [scrollbarState, setScrollbarState] = useState5({
2489
2778
  scrollable: false,
2490
2779
  thumbHeight: 0,
2491
2780
  thumbTop: 0
2492
2781
  });
2493
- const [dragging, setDragging] = useState3(false);
2494
- const syncScrollbarState = useCallback3(() => {
2782
+ const [dragging, setDragging] = useState5(false);
2783
+ const syncScrollbarState = useCallback5(() => {
2495
2784
  const viewport = getViewport();
2496
2785
  if (!viewport) {
2497
2786
  setScrollbarState({ scrollable: false, thumbHeight: 0, thumbTop: 0 });
@@ -2514,7 +2803,7 @@ function CustomScrollbar({
2514
2803
  (previous) => previous.scrollable && previous.thumbHeight === thumbHeight && previous.thumbTop === thumbTop ? previous : { scrollable: true, thumbHeight, thumbTop }
2515
2804
  );
2516
2805
  }, [getViewport]);
2517
- const scrollViewportToThumbTop = useCallback3(
2806
+ const scrollViewportToThumbTop = useCallback5(
2518
2807
  (thumbTop) => {
2519
2808
  const viewport = getViewport();
2520
2809
  const track = trackRef.current;
@@ -2537,7 +2826,7 @@ function CustomScrollbar({
2537
2826
  },
2538
2827
  [getViewport, scrollbarState.thumbHeight, syncScrollbarState]
2539
2828
  );
2540
- const handleTrackMouseDown = useCallback3(
2829
+ const handleTrackMouseDown = useCallback5(
2541
2830
  (event) => {
2542
2831
  if (event.button !== 0 || !scrollbarState.scrollable) {
2543
2832
  return;
@@ -2559,7 +2848,7 @@ function CustomScrollbar({
2559
2848
  scrollbarState.thumbHeight
2560
2849
  ]
2561
2850
  );
2562
- const handleThumbMouseDown = useCallback3(
2851
+ const handleThumbMouseDown = useCallback5(
2563
2852
  (event) => {
2564
2853
  if (event.button !== 0 || !scrollbarState.scrollable) {
2565
2854
  return;
@@ -2592,7 +2881,7 @@ function CustomScrollbar({
2592
2881
  },
2593
2882
  [getViewport, scrollbarState.scrollable, scrollbarState.thumbHeight]
2594
2883
  );
2595
- useEffect4(() => {
2884
+ useEffect5(() => {
2596
2885
  if (!dragging) {
2597
2886
  return;
2598
2887
  }
@@ -2617,7 +2906,7 @@ function CustomScrollbar({
2617
2906
  window.removeEventListener("mouseup", handleMouseUp);
2618
2907
  };
2619
2908
  }, [dragging, getViewport, syncScrollbarState]);
2620
- useEffect4(() => {
2909
+ useEffect5(() => {
2621
2910
  const viewport = getViewport();
2622
2911
  if (!viewport) {
2623
2912
  setScrollbarState({ scrollable: false, thumbHeight: 0, thumbTop: 0 });
@@ -2634,7 +2923,7 @@ function CustomScrollbar({
2634
2923
  resizeObserver?.disconnect();
2635
2924
  };
2636
2925
  }, [getViewport, syncKey, syncScrollbarState]);
2637
- return /* @__PURE__ */ jsx4(
2926
+ return /* @__PURE__ */ jsx5(
2638
2927
  "div",
2639
2928
  {
2640
2929
  ref: trackRef,
@@ -2644,7 +2933,7 @@ function CustomScrollbar({
2644
2933
  "data-testid": testId,
2645
2934
  "aria-hidden": "true",
2646
2935
  onMouseDown: handleTrackMouseDown,
2647
- children: /* @__PURE__ */ jsx4(
2936
+ children: /* @__PURE__ */ jsx5(
2648
2937
  "div",
2649
2938
  {
2650
2939
  className: cn("tsh-custom-scrollbar__thumb", thumbClassName),
@@ -2671,9 +2960,9 @@ var CustomScrollArea = forwardRef2(function CustomScrollArea2({
2671
2960
  ...viewportProps
2672
2961
  }, forwardedRef) {
2673
2962
  "use memo";
2674
- const viewportRef = useRef3(null);
2675
- const getViewport = useCallback3(() => viewportRef.current, []);
2676
- return /* @__PURE__ */ jsxs4(
2963
+ const viewportRef = useRef4(null);
2964
+ const getViewport = useCallback5(() => viewportRef.current, []);
2965
+ return /* @__PURE__ */ jsxs5(
2677
2966
  "div",
2678
2967
  {
2679
2968
  className: cn(
@@ -2681,7 +2970,7 @@ var CustomScrollArea = forwardRef2(function CustomScrollArea2({
2681
2970
  className
2682
2971
  ),
2683
2972
  children: [
2684
- /* @__PURE__ */ jsx4(
2973
+ /* @__PURE__ */ jsx5(
2685
2974
  "div",
2686
2975
  {
2687
2976
  ref: setRefs(viewportRef, forwardedRef),
@@ -2693,7 +2982,7 @@ var CustomScrollArea = forwardRef2(function CustomScrollArea2({
2693
2982
  children
2694
2983
  }
2695
2984
  ),
2696
- /* @__PURE__ */ jsx4(
2985
+ /* @__PURE__ */ jsx5(
2697
2986
  CustomScrollbar,
2698
2987
  {
2699
2988
  getViewport,
@@ -2729,10 +3018,11 @@ export {
2729
3018
  resolveWorkspaceFilePathCandidate,
2730
3019
  resolveWorkspaceFileLinkAction,
2731
3020
  resolveWorkspaceLinkAction,
3021
+ ConversationImageContextMenu,
2732
3022
  ZoomableImage,
2733
3023
  AgentMessageMarkdown,
2734
3024
  AgentGUIConversation_styles_default,
2735
3025
  CustomScrollArea,
2736
3026
  MessageSquareMoreIcon
2737
3027
  };
2738
- //# sourceMappingURL=chunk-44YASHVW.js.map
3028
+ //# sourceMappingURL=chunk-5HQDW73P.js.map