@invergent/agent-chat-react 2.1.4 → 2.1.7

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.cjs CHANGED
@@ -882,7 +882,7 @@ var ConversationEmptyState = ({
882
882
  icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center size-14 rounded-2xl bg-muted/60 text-muted-foreground/60", children: icon }),
883
883
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
884
884
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-base text-foreground/80", children: title }),
885
- description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground/60 text-sm max-w-sm", children: description })
885
+ description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-foreground/60 text-sm max-w-sm", children: description })
886
886
  ] })
887
887
  ] })
888
888
  }
@@ -5281,12 +5281,16 @@ var PromptInput = ({
5281
5281
  const formData = new FormData(form);
5282
5282
  return formData.get("message") || "";
5283
5283
  })();
5284
+ const submittedFiles = files;
5284
5285
  if (!usingProvider) {
5285
5286
  form.reset();
5287
+ } else {
5288
+ controller.textInput.clear();
5286
5289
  }
5290
+ clear();
5287
5291
  try {
5288
5292
  const convertedFiles = await Promise.all(
5289
- files.map(async (entry) => {
5293
+ submittedFiles.map(async (entry) => {
5290
5294
  const isBlob = entry.url?.startsWith("blob:");
5291
5295
  const isImage = entry.mediaType?.startsWith("image/");
5292
5296
  if (isBlob && isImage && entry.url) {
@@ -5299,22 +5303,7 @@ var PromptInput = ({
5299
5303
  return entry;
5300
5304
  })
5301
5305
  );
5302
- const result = onSubmit({ files: convertedFiles, text }, event);
5303
- if (result instanceof Promise) {
5304
- try {
5305
- await result;
5306
- clear();
5307
- if (usingProvider) {
5308
- controller.textInput.clear();
5309
- }
5310
- } catch {
5311
- }
5312
- } else {
5313
- clear();
5314
- if (usingProvider) {
5315
- controller.textInput.clear();
5316
- }
5317
- }
5306
+ await onSubmit({ files: convertedFiles, text }, event);
5318
5307
  } catch {
5319
5308
  }
5320
5309
  },
@@ -6392,36 +6381,6 @@ function ChatComposerInner({
6392
6381
  }
6393
6382
  )
6394
6383
  ] }),
6395
- onViewModeChange && /* @__PURE__ */ jsxRuntime.jsxs(
6396
- "div",
6397
- {
6398
- role: "group",
6399
- "aria-label": "Chat view mode",
6400
- className: "inline-flex overflow-hidden rounded-md border border-border",
6401
- children: [
6402
- /* @__PURE__ */ jsxRuntime.jsx(
6403
- "button",
6404
- {
6405
- type: "button",
6406
- "aria-pressed": viewMode === "simple",
6407
- onClick: () => onViewModeChange("simple"),
6408
- className: viewMode === "simple" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
6409
- children: "Simple"
6410
- }
6411
- ),
6412
- /* @__PURE__ */ jsxRuntime.jsx(
6413
- "button",
6414
- {
6415
- type: "button",
6416
- "aria-pressed": viewMode === "expert",
6417
- onClick: () => onViewModeChange("expert"),
6418
- className: viewMode === "expert" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
6419
- children: "Expert"
6420
- }
6421
- )
6422
- ]
6423
- }
6424
- ),
6425
6384
  canShowBrowser && onToggleBrowser && /* @__PURE__ */ jsxRuntime.jsx(
6426
6385
  PromptInputButton,
6427
6386
  {
@@ -6501,7 +6460,46 @@ function ChatComposerInner({
6501
6460
  }
6502
6461
  )
6503
6462
  ] }),
6504
- /* @__PURE__ */ jsxRuntime.jsx(PromptInputSubmit, { status, onStop })
6463
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
6464
+ onViewModeChange && /* @__PURE__ */ jsxRuntime.jsxs(
6465
+ "div",
6466
+ {
6467
+ role: "group",
6468
+ "aria-label": "Chat view mode",
6469
+ className: "inline-flex overflow-hidden rounded-md border border-border",
6470
+ children: [
6471
+ /* @__PURE__ */ jsxRuntime.jsx(
6472
+ "button",
6473
+ {
6474
+ type: "button",
6475
+ "aria-pressed": viewMode === "simple",
6476
+ onClick: () => onViewModeChange("simple"),
6477
+ className: viewMode === "simple" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
6478
+ children: "Simple"
6479
+ }
6480
+ ),
6481
+ /* @__PURE__ */ jsxRuntime.jsx(
6482
+ "button",
6483
+ {
6484
+ type: "button",
6485
+ "aria-pressed": viewMode === "expert",
6486
+ onClick: () => onViewModeChange("expert"),
6487
+ className: viewMode === "expert" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
6488
+ children: "Advanced"
6489
+ }
6490
+ )
6491
+ ]
6492
+ }
6493
+ ),
6494
+ /* @__PURE__ */ jsxRuntime.jsx(
6495
+ PromptInputSubmit,
6496
+ {
6497
+ status,
6498
+ onStop,
6499
+ className: "md:size-8"
6500
+ }
6501
+ )
6502
+ ] })
6505
6503
  ] })
6506
6504
  ]
6507
6505
  }
@@ -6678,7 +6676,7 @@ function TurnFeedback({ msg }) {
6678
6676
  {
6679
6677
  type: "button",
6680
6678
  variant: "ghost",
6681
- size: "icon-xs",
6679
+ size: "icon-sm",
6682
6680
  "aria-label": "Good response",
6683
6681
  title: alreadyRated && rating === "up" ? "Good response (recorded)" : "Good response",
6684
6682
  disabled: pending !== null || alreadyRated,
@@ -6686,7 +6684,7 @@ function TurnFeedback({ msg }) {
6686
6684
  className: cn(
6687
6685
  rating === "up" ? "text-foreground" : "text-muted-foreground/60"
6688
6686
  ),
6689
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ThumbsUpIcon, { className: "size-3.5" })
6687
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ThumbsUpIcon, { className: "size-4.5" })
6690
6688
  }
6691
6689
  ),
6692
6690
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -6694,7 +6692,7 @@ function TurnFeedback({ msg }) {
6694
6692
  {
6695
6693
  type: "button",
6696
6694
  variant: "ghost",
6697
- size: "icon-xs",
6695
+ size: "icon-sm",
6698
6696
  "aria-label": "Poor response",
6699
6697
  title: alreadyRated && rating === "down" ? "Poor response (recorded)" : "Poor response",
6700
6698
  disabled: pending !== null || reasonDraft !== null || alreadyRated,
@@ -6702,7 +6700,7 @@ function TurnFeedback({ msg }) {
6702
6700
  className: cn(
6703
6701
  rating === "down" ? "text-foreground" : "text-muted-foreground/60"
6704
6702
  ),
6705
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ThumbsDownIcon, { className: "size-3.5" })
6703
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ThumbsDownIcon, { className: "size-4.5" })
6706
6704
  }
6707
6705
  ),
6708
6706
  alreadyRated && msg.userFeedback?.reason && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -7472,7 +7470,8 @@ function FileViewer({
7472
7470
  error,
7473
7471
  downloadUrl,
7474
7472
  onDelete,
7475
- onClose
7473
+ onClose,
7474
+ hideHeader = false
7476
7475
  }) {
7477
7476
  const visible = loading || file !== null || error !== null;
7478
7477
  if (!visible) return null;
@@ -7482,7 +7481,7 @@ function FileViewer({
7482
7481
  const isImage = file?.encoding === "base64" && !isPdf;
7483
7482
  const HeaderIcon = isImage ? lucideReact.ImageIcon : lucideReact.FileTextIcon;
7484
7483
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col border-t border-line", children: [
7485
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-line px-3 py-2", children: [
7484
+ !hideHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-line px-3 py-2", children: [
7486
7485
  /* @__PURE__ */ jsxRuntime.jsx(HeaderIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }),
7487
7486
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
7488
7487
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-xs font-medium", children: fileName2 }),
@@ -7527,7 +7526,12 @@ function FileViewer({
7527
7526
  }
7528
7527
  )
7529
7528
  ] }),
7530
- /* @__PURE__ */ jsxRuntime.jsxs(ScrollArea, { className: "min-h-0 flex-1", children: [
7529
+ file && isPdf && file.encoding === "base64" ? (
7530
+ // PDF has its own scrollable container — bypass ScrollArea so
7531
+ // it can grow with the parent's flex height (Radix Viewport's
7532
+ // internal table wrapper sizes to content and breaks h-full).
7533
+ /* @__PURE__ */ jsxRuntime.jsx(PdfPreview, { file, fileName: fileName2 })
7534
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(ScrollArea, { className: "min-h-0 flex-1", children: [
7531
7535
  loading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5 p-3", children: Array.from({ length: 10 }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
7532
7536
  Skeleton,
7533
7537
  {
@@ -7543,7 +7547,6 @@ function FileViewer({
7543
7547
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: error })
7544
7548
  ] }),
7545
7549
  file && isPdf && file.encoding !== "base64" && /* @__PURE__ */ jsxRuntime.jsx(FileViewerError, { message: "PDF preview requires base64 file content." }),
7546
- file && isPdf && file.encoding === "base64" && /* @__PURE__ */ jsxRuntime.jsx(PdfPreview, { file, fileName: fileName2 }),
7547
7550
  file && isImage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsxRuntime.jsx(
7548
7551
  "img",
7549
7552
  {
@@ -7807,7 +7810,7 @@ function PdfPreview({
7807
7810
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
7808
7811
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: error })
7809
7812
  ] }),
7810
- !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-[70vh] min-h-[420px] flex-1 bg-muted/20", children: /* @__PURE__ */ jsxRuntime.jsx(
7813
+ !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative min-h-105 flex-1 bg-muted/20", children: /* @__PURE__ */ jsxRuntime.jsx(
7811
7814
  "div",
7812
7815
  {
7813
7816
  ref: containerRef,
@@ -8008,8 +8011,23 @@ function WorkspaceFilePreviewDialog({
8008
8011
  cancelled = true;
8009
8012
  };
8010
8013
  }, [adapter, sessionId, path, open]);
8011
- return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "flex h-[80vh] w-full max-w-5xl flex-col gap-0 overflow-hidden p-0", children: [
8012
- /* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { className: "border-b border-line px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "truncate text-sm", children: _basename(path) }) }),
8014
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "flex h-[85vh] w-[95vw] max-w-350! flex-col gap-0 overflow-hidden p-0", children: [
8015
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "flex flex-row items-center gap-2 border-b border-line px-4 py-3", children: [
8016
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "min-w-0 flex-1 truncate text-sm", children: _basename(path) }),
8017
+ /* @__PURE__ */ jsxRuntime.jsxs(
8018
+ "a",
8019
+ {
8020
+ href: downloadUrl,
8021
+ download: _basename(path),
8022
+ className: "mr-8 inline-flex shrink-0 items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1 text-xs font-medium text-foreground transition-colors hover:bg-muted",
8023
+ "aria-label": `Download ${_basename(path)}`,
8024
+ children: [
8025
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.DownloadIcon, { className: "size-3.5", "aria-hidden": true }),
8026
+ "Download"
8027
+ ]
8028
+ }
8029
+ )
8030
+ ] }),
8013
8031
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsxRuntime.jsx(
8014
8032
  FileViewer,
8015
8033
  {
@@ -8018,7 +8036,8 @@ function WorkspaceFilePreviewDialog({
8018
8036
  error,
8019
8037
  downloadUrl,
8020
8038
  onDelete: null,
8021
- onClose: () => onOpenChange(false)
8039
+ onClose: () => onOpenChange(false),
8040
+ hideHeader: true
8022
8041
  }
8023
8042
  ) })
8024
8043
  ] }) });
@@ -8045,7 +8064,8 @@ function TurnSummaryCard({
8045
8064
  const hasRecap = summary.recap.trim().length > 0;
8046
8065
  const hasArtifacts = summary.artifacts.length > 0;
8047
8066
  if (!hasRecap && !hasArtifacts) return null;
8048
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded border border-border bg-muted/20 px-3 py-2 text-sm", children: [
8067
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded border border-border bg-muted/50 px-3 py-2 text-sm", children: [
8068
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 text-xs font-semibold uppercase tracking-wide", children: "Summary" }),
8049
8069
  hasRecap && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 whitespace-pre-wrap text-foreground", children: summary.recap }),
8050
8070
  hasArtifacts && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: summary.artifacts.map((artifact, i) => {
8051
8071
  const key = `${artifact.kind}:${artifact.ref}:${i}`;
@@ -8099,6 +8119,16 @@ function TurnSummaryCard({
8099
8119
  }) })
8100
8120
  ] });
8101
8121
  }
8122
+ function TurnSummaryPending() {
8123
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 rounded border border-border bg-muted/50 px-3 py-2 text-sm", children: [
8124
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 text-xs font-semibold uppercase tracking-wide", children: "Summary" }),
8125
+ /* @__PURE__ */ jsxRuntime.jsx(Shimmer, { duration: 3, spread: 3, className: "mb-2 text-sm", children: "Summarizing conversation..." }),
8126
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
8127
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-3 w-3/4" }),
8128
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-3 w-2/3" })
8129
+ ] })
8130
+ ] });
8131
+ }
8102
8132
  function ArtifactRow({
8103
8133
  artifact,
8104
8134
  sessionId,
@@ -8835,7 +8865,7 @@ function IterationGroup({
8835
8865
  type: "button",
8836
8866
  onClick: () => setOpen((prev) => !prev),
8837
8867
  "aria-expanded": open,
8838
- className: "flex w-full items-center gap-2 rounded px-1 py-0.5 text-left text-sm hover:bg-muted/40",
8868
+ className: "flex w-full items-center gap-2 rounded py-0.5 text-left text-sm hover:bg-muted/40",
8839
8869
  children: [
8840
8870
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-1 truncate", labelTone), children: label }),
8841
8871
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -8863,6 +8893,18 @@ function IterationGroup({
8863
8893
  ] });
8864
8894
  }
8865
8895
  function deriveFileArtifactsFromMessages(messages) {
8896
+ const terminalCommands = [];
8897
+ for (const msg of messages) {
8898
+ if (msg.role !== "assistant" || !msg.toolCalls) continue;
8899
+ for (const tc of msg.toolCalls) {
8900
+ if (tc.toolName !== "terminal") continue;
8901
+ const status = effectiveStatus(tc);
8902
+ if (status === "error" || status === "cancelled") continue;
8903
+ const args = parseArgs(tc.args);
8904
+ const cmd = typeof args?.command === "string" ? args.command : "";
8905
+ if (cmd) terminalCommands.push(cmd);
8906
+ }
8907
+ }
8866
8908
  const seen = /* @__PURE__ */ new Set();
8867
8909
  const out = [];
8868
8910
  for (const msg of messages) {
@@ -8875,6 +8917,8 @@ function deriveFileArtifactsFromMessages(messages) {
8875
8917
  if (tc.toolName === "write_file" || tc.toolName === "patch") {
8876
8918
  const path = typeof args.path === "string" ? args.path : typeof args.file_path === "string" ? args.file_path : "";
8877
8919
  if (!path || seen.has(`file:${path}`)) continue;
8920
+ const executed = terminalCommands.some((cmd) => cmd.includes(path));
8921
+ if (executed) continue;
8878
8922
  seen.add(`file:${path}`);
8879
8923
  out.push({
8880
8924
  kind: "file",
@@ -8915,11 +8959,13 @@ function SimpleAssistantGroup({
8915
8959
  const isTailGroup = lastGlobalIndex === totalMessages - 1;
8916
8960
  const showThinkingShim = isTailGroup && isRunning && (!tail && messages.some((m) => m.role !== "assistant") || tailIsTextOnly && tail.status === "streaming" && !tail.content);
8917
8961
  const showErrorInfo = !!tail && tail.status === "error" && !!tail.errorInfo;
8962
+ const turnComplete = !isRunning && tail?.status === "complete";
8918
8963
  const effectiveTurnSummary = (() => {
8919
8964
  const fromHarness = tail?.turnSummary;
8920
8965
  if (fromHarness && fromHarness.artifacts.length > 0) {
8921
8966
  return fromHarness;
8922
8967
  }
8968
+ if (!turnComplete) return fromHarness;
8923
8969
  const derived = deriveFileArtifactsFromMessages(messages);
8924
8970
  if (derived.length === 0) return fromHarness;
8925
8971
  return {
@@ -8960,7 +9006,7 @@ function SimpleAssistantGroup({
8960
9006
  /* @__PURE__ */ jsxRuntime.jsx(MessageResponse, { children: finalText }),
8961
9007
  tail?.status === "complete" && /* @__PURE__ */ jsxRuntime.jsx(TurnFeedback, { msg: tail })
8962
9008
  ] }),
8963
- effectiveTurnSummary && /* @__PURE__ */ jsxRuntime.jsx(
9009
+ effectiveTurnSummary ? /* @__PURE__ */ jsxRuntime.jsx(
8964
9010
  TurnSummaryCard,
8965
9011
  {
8966
9012
  summary: effectiveTurnSummary,
@@ -8968,6 +9014,14 @@ function SimpleAssistantGroup({
8968
9014
  messages,
8969
9015
  onFileSelect
8970
9016
  }
9017
+ ) : (
9018
+ // The harness summarizer runs after the last assistant
9019
+ // response and before ``session.complete``. Show a pending
9020
+ // placeholder during that window so users aren't surprised
9021
+ // when the Summary card pops in. Gated on the tail group +
9022
+ // a complete final answer + still-running session so the
9023
+ // placeholder doesn't show on historic turns or mid-stream.
9024
+ isTailGroup && isRunning && !!finalText && tail?.status === "complete" && /* @__PURE__ */ jsxRuntime.jsx(TurnSummaryPending, {})
8971
9025
  ),
8972
9026
  showErrorInfo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsx(ErrorMessage, { errorInfo: tail.errorInfo, onRetry }) })
8973
9027
  ] }) });
@@ -9419,6 +9473,27 @@ function findEntry(entries, path) {
9419
9473
  }
9420
9474
  return null;
9421
9475
  }
9476
+ var FILENAME_MAX_CHARS = 42;
9477
+ function truncateFilename(name, max) {
9478
+ if (name.length <= max) return name;
9479
+ const dot = name.lastIndexOf(".");
9480
+ if (dot > 0 && name.length - dot <= 12) {
9481
+ const ext = name.slice(dot);
9482
+ const head = name.slice(0, Math.max(1, max - ext.length - 1));
9483
+ return `${head}\u2026${ext}`;
9484
+ }
9485
+ return `${name.slice(0, max - 1)}\u2026`;
9486
+ }
9487
+ function TruncatedFileName({ name }) {
9488
+ const truncated = truncateFilename(name, FILENAME_MAX_CHARS);
9489
+ const isTruncated = truncated !== name;
9490
+ const node = /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: truncated });
9491
+ if (!isTruncated) return node;
9492
+ return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
9493
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: node }),
9494
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "top", className: "max-w-md break-all", children: name })
9495
+ ] });
9496
+ }
9422
9497
  function RenderEntries({
9423
9498
  entries,
9424
9499
  onDelete,
@@ -9438,7 +9513,7 @@ function RenderEntries({
9438
9513
  const fileName2 = entry.name;
9439
9514
  return /* @__PURE__ */ jsxRuntime.jsxs(FileTreeFile, { name: entry.name, path: entry.path, children: [
9440
9515
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-4 shrink-0" }),
9441
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: entry.name }),
9516
+ /* @__PURE__ */ jsxRuntime.jsx(TruncatedFileName, { name: entry.name }),
9442
9517
  entry.size != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 shrink-0 text-xs text-muted-foreground/60", children: formatFileSize(entry.size) }),
9443
9518
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-1 flex shrink-0 items-center gap-0 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100", children: [
9444
9519
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -9482,7 +9557,6 @@ function WorkspacePanel({
9482
9557
  }) {
9483
9558
  const fileInputRef = react.useRef(null);
9484
9559
  const [entries, setEntries] = react.useState([]);
9485
- const [rootName, setRootName] = react.useState("workspace");
9486
9560
  const [treeLoading, setTreeLoading] = react.useState(false);
9487
9561
  const [treeError, setTreeError] = react.useState(null);
9488
9562
  const [file, setFile] = react.useState(null);
@@ -9501,7 +9575,6 @@ function WorkspacePanel({
9501
9575
  const fetchTree = react.useCallback(async () => {
9502
9576
  if (!sessionId) {
9503
9577
  setEntries([]);
9504
- setRootName("workspace");
9505
9578
  setExpandedPaths(/* @__PURE__ */ new Set());
9506
9579
  setTreeLoading(false);
9507
9580
  setTreeError(null);
@@ -9516,12 +9589,10 @@ function WorkspacePanel({
9516
9589
  });
9517
9590
  if (sessionIdRef.current !== requestedSessionId) return;
9518
9591
  setEntries(tree.entries);
9519
- setRootName(tree.root || "workspace");
9520
9592
  setExpandedPaths(new Set(collectExpandedPaths(tree.entries)));
9521
9593
  } catch (error) {
9522
9594
  if (sessionIdRef.current !== requestedSessionId) return;
9523
9595
  setEntries([]);
9524
- setRootName("workspace");
9525
9596
  setTreeError(error.message);
9526
9597
  } finally {
9527
9598
  if (sessionIdRef.current === requestedSessionId) {
@@ -9711,10 +9782,7 @@ function WorkspacePanel({
9711
9782
  ),
9712
9783
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-14 items-center gap-2 border-b border-line px-3 py-3", children: [
9713
9784
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpenIcon, { className: "size-4 shrink-0 text-amber-500" }),
9714
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
9715
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm font-medium text-foreground", children: rootName }),
9716
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-xs text-faint", children: disabled ? "Workspace - Read-only" : "Workspace" })
9717
- ] }),
9785
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-sm font-medium text-foreground", children: disabled ? "Workspace - Read-only" : "Workspace" }) }),
9718
9786
  /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
9719
9787
  /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
9720
9788
  Button,
@@ -10834,6 +10902,7 @@ function readTurnMeta(data) {
10834
10902
 
10835
10903
  // src/runtime/use-agent-chat-runtime.ts
10836
10904
  var VIEW_MODE_KEY = "@invergent/agent-chat-react:viewMode";
10905
+ var VIEW_MODE_EVENT = "@invergent/agent-chat-react:viewMode:change";
10837
10906
  function readPersistedViewMode() {
10838
10907
  if (typeof window === "undefined") return null;
10839
10908
  try {
@@ -10849,6 +10918,36 @@ function writePersistedViewMode(mode) {
10849
10918
  window.localStorage.setItem(VIEW_MODE_KEY, mode);
10850
10919
  } catch {
10851
10920
  }
10921
+ try {
10922
+ window.dispatchEvent(
10923
+ new CustomEvent(VIEW_MODE_EVENT, { detail: mode })
10924
+ );
10925
+ } catch {
10926
+ }
10927
+ }
10928
+ function useChatViewMode() {
10929
+ const [mode, setMode] = react.useState(
10930
+ () => readPersistedViewMode() ?? "simple"
10931
+ );
10932
+ react.useEffect(() => {
10933
+ if (typeof window === "undefined") return;
10934
+ const onSameTab = (event) => {
10935
+ const detail = event.detail;
10936
+ if (detail === "simple" || detail === "expert") setMode(detail);
10937
+ };
10938
+ const onCrossTab = (event) => {
10939
+ if (event.key !== VIEW_MODE_KEY) return;
10940
+ const next = event.newValue;
10941
+ if (next === "simple" || next === "expert") setMode(next);
10942
+ };
10943
+ window.addEventListener(VIEW_MODE_EVENT, onSameTab);
10944
+ window.addEventListener("storage", onCrossTab);
10945
+ return () => {
10946
+ window.removeEventListener(VIEW_MODE_EVENT, onSameTab);
10947
+ window.removeEventListener("storage", onCrossTab);
10948
+ };
10949
+ }, []);
10950
+ return mode;
10852
10951
  }
10853
10952
  function useAgentChatRuntime({
10854
10953
  adapter,
@@ -13905,6 +14004,7 @@ exports.isTerminalMissionStatus = isTerminalMissionStatus;
13905
14004
  exports.missionTaskBucket = missionTaskBucket;
13906
14005
  exports.useAgentChatAdapterContext = useAgentChatAdapterContext;
13907
14006
  exports.useAgentChatRuntime = useAgentChatRuntime;
14007
+ exports.useChatViewMode = useChatViewMode;
13908
14008
  exports.useInboxUnreadCount = useInboxUnreadCount;
13909
14009
  //# sourceMappingURL=index.cjs.map
13910
14010
  //# sourceMappingURL=index.cjs.map