@volter-ai-dev/supercode-ui 0.1.22 → 0.1.24

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/messenger.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/messenger.jsx
2
- import { useEffect as useEffect6, useId as useId2, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "preact/hooks";
2
+ import { useEffect as useEffect7, useId as useId2, useMemo as useMemo2, useRef as useRef6, useState as useState5 } from "preact/hooks";
3
3
 
4
4
  // core.mjs
5
5
  var HARNESS_NAMES = Object.freeze({
@@ -507,7 +507,10 @@ function readTranscript(value) {
507
507
  return image && typeof image.label === "string" ? [{
508
508
  ...typeof image.id === "string" ? { id: image.id } : {},
509
509
  label: image.label,
510
- ...typeof image.url === "string" ? { url: image.url } : {}
510
+ ...typeof image.url === "string" ? { url: image.url } : {},
511
+ ...typeof image.reference === "string" && image.reference.length <= 4e3 ? { reference: image.reference } : {},
512
+ ...typeof image.mediaType === "string" && image.mediaType.startsWith("image/") && image.mediaType.length <= 100 ? { mediaType: image.mediaType } : {},
513
+ ...Number.isSafeInteger(image.byteSize) && image.byteSize >= 0 ? { byteSize: image.byteSize } : {}
511
514
  }] : [];
512
515
  }).slice(0, 4);
513
516
  }
@@ -758,7 +761,7 @@ function isSendKey(event) {
758
761
  }
759
762
 
760
763
  // src/composer.jsx
761
- import { useEffect, useRef, useState } from "preact/hooks";
764
+ import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "preact/hooks";
762
765
 
763
766
  // src/memory.js
764
767
  var MEMORY_LIMIT = 100;
@@ -818,10 +821,12 @@ function UiIcon({ name, size = 16, class: className = "" }) {
818
821
  }
819
822
 
820
823
  // src/context.jsx
821
- import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
824
+ import { useEffect, useRef, useState } from "preact/hooks";
825
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
822
826
  var MAX_CONTEXT_ITEMS = 32;
823
827
  var MAX_IMAGE_ITEMS = 4;
824
828
  var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
829
+ var MAX_RESOLVED_IMAGE_BYTES = 16 * 1024 * 1024;
825
830
  var IMAGE_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
826
831
  function normalizeContext(value) {
827
832
  return (Array.isArray(value) ? value : value ? [value] : []).flatMap((item) => {
@@ -917,12 +922,156 @@ function ImageTray({ items, onRemove }) {
917
922
  onRemove ? /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove image ${item.label}`, onClick: () => onRemove(index), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 12 }) }) : null
918
923
  ] }, item.id ?? `${item.label}:${index}`)) });
919
924
  }
920
- function MessageImages({ items }) {
925
+ function imageFilename(label) {
926
+ const value = label.trim().replace(/[\\/:*?"<>|]+/g, "-");
927
+ return value || "image";
928
+ }
929
+ function ImageViewer({ items, index, adapter, onChange, onClose }) {
930
+ const dialog = useRef(null);
931
+ const reset = useRef(null);
932
+ const resolutions = useRef(/* @__PURE__ */ new Map());
933
+ const alive = useRef(true);
934
+ const [, redraw] = useState(0);
935
+ const [copyState, setCopyState2] = useState("idle");
936
+ const item = items[index];
937
+ const key = item?.reference ?? item?.url ?? `${item?.id ?? ""}:${index}`;
938
+ const resolution = item?.url ? null : resolutions.current.get(key);
939
+ const imageUrl = item?.url ?? (resolution?.status === "ready" ? resolution.url : null);
940
+ const remote = imageUrl?.startsWith("http://") || imageUrl?.startsWith("https://");
941
+ const resolve = (candidate, force = false) => {
942
+ if (candidate?.url || !candidate?.reference || !adapter?.resolveImage) return;
943
+ const candidateKey = candidate.reference;
944
+ const current = resolutions.current.get(candidateKey);
945
+ if (!force && (current?.status === "loading" || current?.status === "ready")) return;
946
+ if (current?.url) URL.revokeObjectURL(current.url);
947
+ resolutions.current.set(candidateKey, { status: "loading" });
948
+ redraw((value) => value + 1);
949
+ Promise.resolve().then(() => adapter.resolveImage(candidate)).then((blob) => {
950
+ if (!(blob instanceof Blob) || !blob.type.startsWith("image/")) throw new Error("The host returned an invalid image.");
951
+ if (blob.size > MAX_RESOLVED_IMAGE_BYTES) throw new Error("This image is too large to preview safely.");
952
+ if (!alive.current) return;
953
+ const url = URL.createObjectURL(blob);
954
+ resolutions.current.set(candidateKey, { status: "ready", url });
955
+ redraw((value) => value + 1);
956
+ }).catch((error) => {
957
+ if (!alive.current) return;
958
+ resolutions.current.set(candidateKey, {
959
+ status: "error",
960
+ message: error instanceof Error && error.message ? error.message : "Could not load this image."
961
+ });
962
+ redraw((value) => value + 1);
963
+ });
964
+ };
965
+ useEffect(() => {
966
+ alive.current = true;
967
+ if (!dialog.current?.open) dialog.current?.showModal();
968
+ return () => {
969
+ alive.current = false;
970
+ clearTimeout(reset.current);
971
+ for (const value of resolutions.current.values()) if (value.url) URL.revokeObjectURL(value.url);
972
+ resolutions.current.clear();
973
+ };
974
+ }, []);
975
+ useEffect(() => {
976
+ clearTimeout(reset.current);
977
+ setCopyState2("idle");
978
+ resolve(item);
979
+ }, [index, item?.reference]);
980
+ if (!item || !item.url && (!item.reference || !adapter?.resolveImage)) return null;
981
+ const move = (amount) => onChange((index + amount + items.length) % items.length);
982
+ const copy = async () => {
983
+ try {
984
+ await adapter.copyText(imageUrl);
985
+ setCopyState2("copied");
986
+ } catch {
987
+ setCopyState2("failed");
988
+ }
989
+ clearTimeout(reset.current);
990
+ reset.current = setTimeout(() => setCopyState2("idle"), 1500);
991
+ };
992
+ const close = () => dialog.current?.close();
993
+ return /* @__PURE__ */ jsxs2(
994
+ "dialog",
995
+ {
996
+ ref: dialog,
997
+ class: "scui-image-viewer",
998
+ "aria-label": `Image preview: ${item.label}`,
999
+ onClose,
1000
+ onClick: (event) => {
1001
+ if (event.target === event.currentTarget) close();
1002
+ },
1003
+ onKeyDown: (event) => {
1004
+ if (items.length < 2 || !["ArrowLeft", "ArrowRight"].includes(event.key)) return;
1005
+ event.preventDefault();
1006
+ move(event.key === "ArrowLeft" ? -1 : 1);
1007
+ },
1008
+ children: [
1009
+ /* @__PURE__ */ jsxs2("header", { children: [
1010
+ /* @__PURE__ */ jsxs2("span", { children: [
1011
+ /* @__PURE__ */ jsx2("strong", { children: item.label }),
1012
+ items.length > 1 ? /* @__PURE__ */ jsxs2("small", { children: [
1013
+ index + 1,
1014
+ " of ",
1015
+ items.length
1016
+ ] }) : null
1017
+ ] }),
1018
+ /* @__PURE__ */ jsxs2("nav", { "aria-label": "Image actions", children: [
1019
+ remote && adapter?.copyText ? /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": copyState === "copied" ? "Image link copied" : copyState === "failed" ? "Could not copy image link" : "Copy image link", title: "Copy image link", "data-status": copyState, onClick: copy, children: /* @__PURE__ */ jsx2(UiIcon, { name: copyState === "copied" ? "check" : "copy", size: 16 }) }) : null,
1020
+ imageUrl ? remote ? /* @__PURE__ */ jsx2("a", { href: imageUrl, target: "_blank", rel: "noreferrer", "aria-label": "Open original image", title: "Open original image", children: /* @__PURE__ */ jsx2(UiIcon, { name: "image", size: 16 }) }) : /* @__PURE__ */ jsx2("a", { href: imageUrl, download: imageFilename(item.label), "aria-label": "Download image", title: "Download image", children: /* @__PURE__ */ jsx2(UiIcon, { name: "down", size: 16 }) }) : null,
1021
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": "Close image preview", title: "Close", onClick: close, children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 17 }) })
1022
+ ] })
1023
+ ] }),
1024
+ /* @__PURE__ */ jsxs2("figure", { children: [
1025
+ imageUrl ? /* @__PURE__ */ jsx2("img", { src: imageUrl, alt: item.label }) : resolution?.status === "error" ? /* @__PURE__ */ jsxs2("div", { class: "scui-image-resolution", role: "alert", children: [
1026
+ /* @__PURE__ */ jsx2(UiIcon, { name: "image", size: 28 }),
1027
+ /* @__PURE__ */ jsx2("strong", { children: "Could not load image" }),
1028
+ /* @__PURE__ */ jsx2("small", { children: resolution.message }),
1029
+ /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => resolve(item, true), children: "Retry" })
1030
+ ] }) : /* @__PURE__ */ jsxs2("div", { class: "scui-image-resolution", role: "status", children: [
1031
+ /* @__PURE__ */ jsx2("i", { class: "scui-control-spinner" }),
1032
+ /* @__PURE__ */ jsx2("strong", { children: "Loading image\u2026" }),
1033
+ /* @__PURE__ */ jsx2("small", { children: "The original stays out of the transcript payload." })
1034
+ ] }),
1035
+ items.length > 1 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
1036
+ /* @__PURE__ */ jsx2("button", { type: "button", class: "scui-image-previous", "aria-label": "Previous image", onClick: () => move(-1), children: /* @__PURE__ */ jsx2(UiIcon, { name: "chevron", size: 19 }) }),
1037
+ /* @__PURE__ */ jsx2("button", { type: "button", class: "scui-image-next", "aria-label": "Next image", onClick: () => move(1), children: /* @__PURE__ */ jsx2(UiIcon, { name: "chevron", size: 19 }) })
1038
+ ] }) : null
1039
+ ] })
1040
+ ]
1041
+ }
1042
+ );
1043
+ }
1044
+ function MessageImages({ items, adapter }) {
1045
+ const [active, setActive] = useState(null);
1046
+ const opener = useRef(null);
921
1047
  if (!items?.length) return null;
922
- return /* @__PURE__ */ jsx2("div", { class: "scui-message-images", children: items.map((item, index) => item.url ? /* @__PURE__ */ jsx2("img", { src: item.url, alt: item.label }, item.id ?? `${item.label}:${index}`) : /* @__PURE__ */ jsxs2("span", { children: [
923
- /* @__PURE__ */ jsx2(UiIcon, { name: "image", size: 14 }),
924
- item.label
925
- ] }, item.id ?? `${item.label}:${index}`)) });
1048
+ const viewable = items.filter((item) => item.url || item.reference && adapter?.resolveImage);
1049
+ const close = () => {
1050
+ setActive(null);
1051
+ requestAnimationFrame(() => opener.current?.focus({ preventScroll: true }));
1052
+ };
1053
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
1054
+ /* @__PURE__ */ jsx2("div", { class: "scui-message-images", "aria-label": "Message images", children: items.map((item, index) => item.url ? /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `View image ${item.label}`, onClick: (event) => {
1055
+ opener.current = event.currentTarget;
1056
+ setActive(viewable.indexOf(item));
1057
+ }, children: /* @__PURE__ */ jsx2("img", { src: item.url, alt: "" }) }, item.id ?? `${item.label}:${index}`) : item.reference && adapter?.resolveImage ? /* @__PURE__ */ jsxs2("button", { type: "button", "data-lazy": "true", "aria-label": `Load image ${item.label}`, onClick: (event) => {
1058
+ opener.current = event.currentTarget;
1059
+ setActive(viewable.indexOf(item));
1060
+ }, children: [
1061
+ /* @__PURE__ */ jsx2(UiIcon, { name: "image", size: 16 }),
1062
+ /* @__PURE__ */ jsxs2("span", { children: [
1063
+ /* @__PURE__ */ jsx2("strong", { children: item.label }),
1064
+ /* @__PURE__ */ jsx2("small", { children: "Load preview" })
1065
+ ] })
1066
+ ] }, item.id ?? `${item.label}:${index}`) : /* @__PURE__ */ jsxs2("span", { "data-unavailable": "true", children: [
1067
+ /* @__PURE__ */ jsx2(UiIcon, { name: "image", size: 14 }),
1068
+ /* @__PURE__ */ jsxs2("span", { children: [
1069
+ /* @__PURE__ */ jsx2("strong", { children: item.label }),
1070
+ /* @__PURE__ */ jsx2("small", { children: "Preview unavailable" })
1071
+ ] })
1072
+ ] }, item.id ?? `${item.label}:${index}`)) }),
1073
+ active !== null && viewable[active] ? /* @__PURE__ */ jsx2(ImageViewer, { items: viewable, index: active, adapter, onChange: setActive, onClose: close }) : null
1074
+ ] });
926
1075
  }
927
1076
 
928
1077
  // src/textarea.js
@@ -964,18 +1113,18 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
964
1113
  }
965
1114
  function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
966
1115
  const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, context: [], images: [], queue: [] };
967
- const [draft, setDraft] = useState(remembered.draft);
968
- const [context, setContext] = useState(remembered.context ?? []);
969
- const [images, setImages] = useState(remembered.images ?? []);
970
- const [queue, setQueue] = useState((remembered.queue ?? []).map((item) => ({ ...item, context: item.context ?? [], images: item.images ?? [] })));
971
- const [dispatching, setDispatching] = useState(false);
972
- const [picking, setPicking] = useState(false);
973
- const [dragging, setDragging] = useState(false);
974
- const [pickerError, setPickerError] = useState(null);
975
- const textarea = useRef(null);
1116
+ const [draft, setDraft] = useState2(remembered.draft);
1117
+ const [context, setContext] = useState2(remembered.context ?? []);
1118
+ const [images, setImages] = useState2(remembered.images ?? []);
1119
+ const [queue, setQueue] = useState2((remembered.queue ?? []).map((item) => ({ ...item, context: item.context ?? [], images: item.images ?? [] })));
1120
+ const [dispatching, setDispatching] = useState2(false);
1121
+ const [picking, setPicking] = useState2(false);
1122
+ const [dragging, setDragging] = useState2(false);
1123
+ const [pickerError, setPickerError] = useState2(null);
1124
+ const textarea = useRef2(null);
976
1125
  useAutosizeTextarea(textarea, draft);
977
1126
  const remember = (nextDraft, nextContext, nextImages, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, context: nextContext, images: nextImages, queue: nextQueue });
978
- useEffect(() => {
1127
+ useEffect2(() => {
979
1128
  remember(draft, context, images, queue);
980
1129
  }, [draft, context, images, memoryKey, queue]);
981
1130
  const updateQueue = (update) => setQueue((items) => {
@@ -985,7 +1134,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
985
1134
  });
986
1135
  const queueBlocked = state.busy || pendingStatus !== null || dispatching;
987
1136
  const queuesNewMessage = state.busy || pendingStatus === "sending" || pendingStatus === "failed" || dispatching;
988
- useEffect(() => {
1137
+ useEffect2(() => {
989
1138
  if (!queueBlocked && state.canSend && queue.length) {
990
1139
  const [next, ...rest] = queue;
991
1140
  setDispatching(true);
@@ -995,13 +1144,13 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
995
1144
  adapter.onIntent({ action: "send", text: next.text, ...next.context.length ? { context: next.context } : {}, ...next.images.length ? { images: next.images } : {} });
996
1145
  }
997
1146
  }, [adapter, draft, memoryKey, onPending, queue, queueBlocked, state.canSend]);
998
- useEffect(() => {
1147
+ useEffect2(() => {
999
1148
  if (pendingStatus !== null || state.busy) setDispatching(false);
1000
1149
  }, [pendingStatus, state.busy]);
1001
- useEffect(() => {
1150
+ useEffect2(() => {
1002
1151
  textarea.current?.focus({ preventScroll: true });
1003
1152
  }, [memoryKey]);
1004
- useEffect(() => {
1153
+ useEffect2(() => {
1005
1154
  if (!restoreDraft) return;
1006
1155
  setDraft(restoreDraft.text);
1007
1156
  const restoredContext = normalizeContext(restoreDraft.context);
@@ -1012,7 +1161,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
1012
1161
  textarea.current?.focus({ preventScroll: true });
1013
1162
  onDraftRestored?.(restoreDraft.id);
1014
1163
  }, [onDraftRestored, restoreDraft?.id]);
1015
- useEffect(() => {
1164
+ useEffect2(() => {
1016
1165
  const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
1017
1166
  return () => clearTimeout(timer);
1018
1167
  }, [adapter, draft]);
@@ -1137,12 +1286,12 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
1137
1286
  }
1138
1287
 
1139
1288
  // src/conversation.jsx
1140
- import { Fragment as Fragment2 } from "preact";
1141
- import { useEffect as useEffect3, useId, useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState2 } from "preact/hooks";
1289
+ import { Fragment as Fragment3 } from "preact";
1290
+ import { useEffect as useEffect4, useId, useLayoutEffect as useLayoutEffect2, useRef as useRef4, useState as useState3 } from "preact/hooks";
1142
1291
 
1143
1292
  // src/markdown.jsx
1144
1293
  import MarkdownIt from "markdown-it";
1145
- import { useEffect as useEffect2, useMemo, useRef as useRef2 } from "preact/hooks";
1294
+ import { useEffect as useEffect3, useMemo, useRef as useRef3 } from "preact/hooks";
1146
1295
  import { jsx as jsx4 } from "preact/jsx-runtime";
1147
1296
  var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
1148
1297
  var LANGUAGE_LABELS = {
@@ -1204,8 +1353,8 @@ function setCopyState(button, status) {
1204
1353
  }
1205
1354
  function Markdown({ value, copyText }) {
1206
1355
  const html = useMemo(() => markdown.render(value), [value]);
1207
- const resets = useRef2(/* @__PURE__ */ new Map());
1208
- useEffect2(() => () => {
1356
+ const resets = useRef3(/* @__PURE__ */ new Map());
1357
+ useEffect3(() => () => {
1209
1358
  for (const timer of resets.current.values()) clearTimeout(timer);
1210
1359
  resets.current.clear();
1211
1360
  }, []);
@@ -1234,7 +1383,7 @@ function Markdown({ value, copyText }) {
1234
1383
  }
1235
1384
 
1236
1385
  // src/conversation.jsx
1237
- import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
1386
+ import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
1238
1387
  function LoadingStatus({ state, compact = false }) {
1239
1388
  const copy = {
1240
1389
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -1283,9 +1432,9 @@ function ContextDisclosure({ context }) {
1283
1432
  ] });
1284
1433
  }
1285
1434
  function MessageMeta({ entry, adapter }) {
1286
- const [copyState, setCopyState2] = useState2("idle");
1287
- const reset = useRef3(null);
1288
- useEffect3(() => () => clearTimeout(reset.current), []);
1435
+ const [copyState, setCopyState2] = useState3("idle");
1436
+ const reset = useRef4(null);
1437
+ useEffect4(() => () => clearTimeout(reset.current), []);
1289
1438
  const date = entry.ts === null ? null : new Date(entry.ts);
1290
1439
  const validDate = date && Number.isFinite(date.valueOf()) ? date : null;
1291
1440
  if (!validDate && (!adapter?.copyText || !entry.text)) return null;
@@ -1306,33 +1455,33 @@ function MessageMeta({ entry, adapter }) {
1306
1455
  ] });
1307
1456
  }
1308
1457
  var TOOL_ICONS = {
1309
- read: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1458
+ read: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
1310
1459
  /* @__PURE__ */ jsx5("path", { d: "M5 2.75h7.25L15 5.5v7.75A1.75 1.75 0 0 1 13.25 15h-8.5A1.75 1.75 0 0 1 3 13.25v-8.5A2 2 0 0 1 5 2.75Z" }),
1311
1460
  /* @__PURE__ */ jsx5("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
1312
1461
  ] }),
1313
- search: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1462
+ search: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
1314
1463
  /* @__PURE__ */ jsx5("circle", { cx: "8", cy: "8", r: "4.5" }),
1315
1464
  /* @__PURE__ */ jsx5("path", { d: "m11.5 11.5 3 3" })
1316
1465
  ] }),
1317
- edit: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1466
+ edit: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
1318
1467
  /* @__PURE__ */ jsx5("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
1319
1468
  /* @__PURE__ */ jsx5("path", { d: "m10 5 3 3" })
1320
1469
  ] }),
1321
- command: () => /* @__PURE__ */ jsx5(Fragment3, { children: /* @__PURE__ */ jsx5("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
1322
- test: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1470
+ command: () => /* @__PURE__ */ jsx5(Fragment4, { children: /* @__PURE__ */ jsx5("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
1471
+ test: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
1323
1472
  /* @__PURE__ */ jsx5("path", { d: "M6 2.5v3L3 12a2 2 0 0 0 1.8 3h8.4a2 2 0 0 0 1.8-3l-3-6.5v-3M5 9h8" }),
1324
1473
  /* @__PURE__ */ jsx5("path", { d: "M5 2.5h8" })
1325
1474
  ] }),
1326
- web: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1475
+ web: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
1327
1476
  /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "6.5" }),
1328
1477
  /* @__PURE__ */ jsx5("path", { d: "M2.75 9h12.5M9 2.5c2 1.8 3 4 3 6.5s-1 4.7-3 6.5c-2-1.8-3-4-3-6.5s1-4.7 3-6.5Z" })
1329
1478
  ] }),
1330
- agent: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1479
+ agent: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
1331
1480
  /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "6", r: "2.5" }),
1332
1481
  /* @__PURE__ */ jsx5("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
1333
1482
  ] }),
1334
- plan: () => /* @__PURE__ */ jsx5(Fragment3, { children: /* @__PURE__ */ jsx5("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
1335
- other: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1483
+ plan: () => /* @__PURE__ */ jsx5(Fragment4, { children: /* @__PURE__ */ jsx5("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
1484
+ other: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
1336
1485
  /* @__PURE__ */ jsx5("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
1337
1486
  /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "3.5" })
1338
1487
  ] })
@@ -1398,9 +1547,9 @@ function ToolMetrics({ presentation }) {
1398
1547
  }
1399
1548
  function PendingElapsed({ now }) {
1400
1549
  const clock = now ?? Date.now;
1401
- const started = useRef3(clock());
1402
- const [elapsed, setElapsed] = useState2(0);
1403
- useEffect3(() => {
1550
+ const started = useRef4(clock());
1551
+ const [elapsed, setElapsed] = useState3(0);
1552
+ useEffect4(() => {
1404
1553
  const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
1405
1554
  return () => clearInterval(timer);
1406
1555
  }, [clock]);
@@ -1441,7 +1590,7 @@ function SearchPreview({ presentation }) {
1441
1590
  ] }) : null,
1442
1591
  lines.length ? /* @__PURE__ */ jsx5("ol", { children: lines.map((line, index) => {
1443
1592
  const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
1444
- return /* @__PURE__ */ jsx5("li", { children: match ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
1593
+ return /* @__PURE__ */ jsx5("li", { children: match ? /* @__PURE__ */ jsxs4(Fragment4, { children: [
1445
1594
  /* @__PURE__ */ jsx5("code", { children: match[1] }),
1446
1595
  /* @__PURE__ */ jsxs4("small", { children: [
1447
1596
  match[2],
@@ -1474,9 +1623,9 @@ function ToolPreview({ presentation, entry }) {
1474
1623
  return presentation.preview ? /* @__PURE__ */ jsx5("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
1475
1624
  }
1476
1625
  function ToolActions({ presentation, adapter }) {
1477
- const [copied, setCopied] = useState2(false);
1478
- const reset = useRef3(null);
1479
- useEffect3(() => () => clearTimeout(reset.current), []);
1626
+ const [copied, setCopied] = useState3(false);
1627
+ const reset = useRef4(null);
1628
+ useEffect4(() => () => clearTimeout(reset.current), []);
1480
1629
  if (!adapter?.copyText) return null;
1481
1630
  const action = presentation.command ? ["Copy command", presentation.command] : presentation.path ? ["Copy path", presentation.path] : presentation.url ? ["Copy URL", presentation.url] : presentation.query ? ["Copy query", presentation.query] : null;
1482
1631
  const copy = async () => {
@@ -1523,7 +1672,7 @@ function TranscriptEntry({ entry, state, adapter }) {
1523
1672
  }
1524
1673
  if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx5("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
1525
1674
  return /* @__PURE__ */ jsxs4("article", { class: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
1526
- /* @__PURE__ */ jsx5(MessageImages, { items: entry.images }),
1675
+ /* @__PURE__ */ jsx5(MessageImages, { items: entry.images, adapter }),
1527
1676
  /* @__PURE__ */ jsx5(Markdown, { value: entry.text, copyText: adapter?.copyText }),
1528
1677
  /* @__PURE__ */ jsx5(ContextDisclosure, { context: entry.context }),
1529
1678
  entry.truncated ? /* @__PURE__ */ jsx5("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
@@ -1532,14 +1681,14 @@ function TranscriptEntry({ entry, state, adapter }) {
1532
1681
  }
1533
1682
  function ToolRow({ entry, workspace, open = false, adapter }) {
1534
1683
  const presentation = entry.presentation ?? createToolPresentation(entry);
1535
- const [expanded, setExpanded] = useState2(open || entry.status === "pending");
1536
- useEffect3(() => {
1684
+ const [expanded, setExpanded] = useState3(open || entry.status === "pending");
1685
+ useEffect4(() => {
1537
1686
  if (entry.status === "pending") setExpanded(true);
1538
1687
  }, [entry.status]);
1539
1688
  const target = compactToolTarget(presentation.target, workspace);
1540
1689
  const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
1541
1690
  const category = presentation.category ?? toolCategory(entry);
1542
- const summary = /* @__PURE__ */ jsxs4(Fragment3, { children: [
1691
+ const summary = /* @__PURE__ */ jsxs4(Fragment4, { children: [
1543
1692
  /* @__PURE__ */ jsx5(ToolIcon, { category }),
1544
1693
  /* @__PURE__ */ jsx5("strong", { children: toolAction2(entry, category, presentation) }),
1545
1694
  target ? /* @__PURE__ */ jsx5("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
@@ -1567,9 +1716,9 @@ function ToolRow({ entry, workspace, open = false, adapter }) {
1567
1716
  function ActivityGroup({ entries, state, adapter }) {
1568
1717
  if (entries.length === 1) return /* @__PURE__ */ jsx5("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx5(ToolRow, { entry: entries[0], workspace: state.workspace, adapter }) });
1569
1718
  const active = entries.some((entry) => entry.status === "pending");
1570
- const [open, setOpen] = useState2(active);
1719
+ const [open, setOpen] = useState3(active);
1571
1720
  const id = useId();
1572
- useEffect3(() => {
1721
+ useEffect4(() => {
1573
1722
  if (active) setOpen(true);
1574
1723
  }, [active]);
1575
1724
  return /* @__PURE__ */ jsxs4("section", { class: "scui-activity", children: [
@@ -1645,9 +1794,9 @@ function SessionDetails({ semantics }) {
1645
1794
  }
1646
1795
  var conversationMemory = /* @__PURE__ */ new Map();
1647
1796
  function ConversationAnnouncements({ state }) {
1648
- const previousBusy = useRef3(state.busy);
1649
- const [announcement, setAnnouncement] = useState2("");
1650
- useEffect3(() => {
1797
+ const previousBusy = useRef4(state.busy);
1798
+ const [announcement, setAnnouncement] = useState3("");
1799
+ useEffect4(() => {
1651
1800
  if (previousBusy.current && !state.busy && !state.error) {
1652
1801
  setAnnouncement(`${harnessDisplayName(state.harness) || "Coding agent"} finished working`);
1653
1802
  }
@@ -1656,13 +1805,13 @@ function ConversationAnnouncements({ state }) {
1656
1805
  return /* @__PURE__ */ jsx5("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
1657
1806
  }
1658
1807
  function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null, unreadAfterMessages = null }) {
1659
- const scroller = useRef3(null);
1808
+ const scroller = useRef4(null);
1660
1809
  const remembered = conversationMemory.get(memoryKey) ?? { top: null, atBottom: true };
1661
- const [atBottom, setAtBottom] = useState2(remembered.atBottom);
1662
- const earlierAnchor = useRef3(null);
1663
- const restored = useRef3(false);
1810
+ const [atBottom, setAtBottom] = useState3(remembered.atBottom);
1811
+ const earlierAnchor = useRef4(null);
1812
+ const restored = useRef4(false);
1664
1813
  const blocks = groupConversation(state.transcript);
1665
- const unreadBoundary = useRef3(Number.isSafeInteger(unreadAfterMessages) && unreadAfterMessages >= 0 ? unreadAfterMessages : null);
1814
+ const unreadBoundary = useRef4(Number.isSafeInteger(unreadAfterMessages) && unreadAfterMessages >= 0 ? unreadAfterMessages : null);
1666
1815
  const unreadBlock = unreadBoundary.current === null ? -1 : blocks.findIndex((block) => {
1667
1816
  const entries = block.kind === "activity" ? block.entries : [block.entry];
1668
1817
  return entries.some((entry) => Number.isSafeInteger(entry.messageIndex) && entry.messageIndex > unreadBoundary.current);
@@ -1721,12 +1870,12 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
1721
1870
  }, children: "Load earlier messages" }) : null,
1722
1871
  !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx5(LoadingStatus, { state }) : null,
1723
1872
  !blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx5(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx5("div", { class: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
1724
- blocks.map((block, index) => /* @__PURE__ */ jsxs4(Fragment2, { children: [
1873
+ blocks.map((block, index) => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1725
1874
  index === unreadBlock ? /* @__PURE__ */ jsx5("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx5("span", { children: "New" }) }) : null,
1726
1875
  block.kind === "activity" ? /* @__PURE__ */ jsx5(Group, { value: block.entries, entries: block.entries, state, adapter }) : /* @__PURE__ */ jsx5(Entry, { value: block.entry, entry: block.entry, state, adapter })
1727
1876
  ] }, block.id)),
1728
1877
  pendingMessage ? /* @__PURE__ */ jsxs4("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
1729
- /* @__PURE__ */ jsx5(MessageImages, { items: pendingMessage.images }),
1878
+ /* @__PURE__ */ jsx5(MessageImages, { items: pendingMessage.images, adapter }),
1730
1879
  /* @__PURE__ */ jsx5(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
1731
1880
  /* @__PURE__ */ jsx5(ContextDisclosure, { context: pendingMessage.context }),
1732
1881
  /* @__PURE__ */ jsxs4("footer", { children: [
@@ -1757,7 +1906,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
1757
1906
  }
1758
1907
 
1759
1908
  // src/logo.jsx
1760
- import { useEffect as useEffect4 } from "preact/hooks";
1909
+ import { useEffect as useEffect5 } from "preact/hooks";
1761
1910
  import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
1762
1911
  var LOGOS = {
1763
1912
  "claude-code": {
@@ -1805,7 +1954,7 @@ var LOGOS = {
1805
1954
  };
1806
1955
  function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
1807
1956
  const logo = LOGOS[id];
1808
- useEffect4(() => {
1957
+ useEffect5(() => {
1809
1958
  if (!logo) onMissingLogo?.(id);
1810
1959
  }, [id, logo, onMissingLogo]);
1811
1960
  if (!logo) return null;
@@ -1816,7 +1965,7 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
1816
1965
  }
1817
1966
 
1818
1967
  // src/sessions.jsx
1819
- import { useEffect as useEffect5, useLayoutEffect as useLayoutEffect3, useRef as useRef4, useState as useState3 } from "preact/hooks";
1968
+ import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useRef as useRef5, useState as useState4 } from "preact/hooks";
1820
1969
  import { jsx as jsx7, jsxs as jsxs6 } from "preact/jsx-runtime";
1821
1970
  var sessionListMemory = /* @__PURE__ */ new Map();
1822
1971
  function SessionRow({ row, state, onOpen }) {
@@ -1838,21 +1987,21 @@ function SessionRow({ row, state, onOpen }) {
1838
1987
  }
1839
1988
  function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default" }) {
1840
1989
  const remembered = sessionListMemory.get(memoryKey) ?? { query: "", top: 0 };
1841
- const [query, setQuery] = useState3(remembered.query);
1842
- const [loadingMore, setLoadingMore] = useState3(false);
1843
- const root = useRef4(null);
1844
- const rowScroller = useRef4(null);
1990
+ const [query, setQuery] = useState4(remembered.query);
1991
+ const [loadingMore, setLoadingMore] = useState4(false);
1992
+ const root = useRef5(null);
1993
+ const rowScroller = useRef5(null);
1845
1994
  const rows = filterSessions(state.sessions, query);
1846
1995
  const Row = components.SessionRow ?? SessionRow;
1847
1996
  useLayoutEffect3(() => {
1848
1997
  if (rowScroller.current) rowScroller.current.scrollTop = remembered.top;
1849
1998
  }, [memoryKey]);
1850
- useEffect5(() => {
1999
+ useEffect6(() => {
1851
2000
  if (!focusKey || !root.current) return;
1852
2001
  const target = focusKey === "@new" ? root.current.querySelector('[data-list-focus="new"]') : [...root.current.querySelectorAll("[data-session-key]")].find((element) => element.dataset.sessionKey === focusKey);
1853
2002
  (target ?? root.current.querySelector("input,button"))?.focus({ preventScroll: true });
1854
2003
  }, [focusKey, rows.length]);
1855
- useEffect5(() => {
2004
+ useEffect6(() => {
1856
2005
  if (loadingMore) setLoadingMore(false);
1857
2006
  }, [state.error, state.history.hasMoreSessions, state.sessions.length]);
1858
2007
  const loadMore = () => {
@@ -1938,10 +2087,10 @@ function Receipt({ state, adapter }) {
1938
2087
  return null;
1939
2088
  }
1940
2089
  function ConversationActions({ state, adapter, actionPending }) {
1941
- const [open, setOpen] = useState4(false);
1942
- const root = useRef5(null);
1943
- const panel = useRef5(null);
1944
- const trigger = useRef5(null);
2090
+ const [open, setOpen] = useState5(false);
2091
+ const root = useRef6(null);
2092
+ const panel = useRef6(null);
2093
+ const trigger = useRef6(null);
1945
2094
  const menuId = useId2();
1946
2095
  const targets = state.harnesses.filter((item) => item.startable);
1947
2096
  const groups = [
@@ -1962,7 +2111,7 @@ function ConversationActions({ state, adapter, actionPending }) {
1962
2111
  items: state.canBranch ? targets.map((target) => ({ key: `branch:${target.id}`, label: target.id === state.harness ? `Fork in ${target.label}` : `Continue with ${target.label}`, intent: { action: "branch", targetHarness: target.id } })) : []
1963
2112
  }
1964
2113
  ].filter((group) => group.items.length);
1965
- useEffect6(() => {
2114
+ useEffect7(() => {
1966
2115
  if (!open) return;
1967
2116
  panel.current?.querySelector("button:not(:disabled)")?.focus({ preventScroll: true });
1968
2117
  const dismiss = (event) => {
@@ -2012,12 +2161,12 @@ function ConversationActions({ state, adapter, actionPending }) {
2012
2161
  ] });
2013
2162
  }
2014
2163
  function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose }) {
2015
- const back = useRef5(null);
2164
+ const back = useRef6(null);
2016
2165
  const harness = state.attached?.harness ?? state.harness;
2017
2166
  const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
2018
2167
  const status = state.needsInput ? "Needs input" : pendingStatus === "failed" ? "Send failed" : state.busy ? "Working" : pendingStatus === "sending" ? "Sending" : pendingStatus === "editing" ? "Editing message" : state.mode === "mirror" ? "Read-only" : "Ready";
2019
2168
  const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce;
2020
- useEffect6(() => {
2169
+ useEffect7(() => {
2021
2170
  if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
2022
2171
  }, []);
2023
2172
  return /* @__PURE__ */ jsxs7("header", { class: "scui-head scui-chat-head", children: [
@@ -2039,24 +2188,24 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
2039
2188
  function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
2040
2189
  const Header = slots.header;
2041
2190
  const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
2042
- const [pending, setPendingState] = useState4(() => pendingMessageMemory.get(memoryKey) ?? null);
2043
- const [pendingAction, setPendingAction] = useState4(null);
2044
- const [restoreDraft, setRestoreDraft] = useState4(null);
2045
- const restoreSequence = useRef5(0);
2046
- const actionSequence = useRef5(0);
2047
- const acknowledged = useRef5(/* @__PURE__ */ new Set());
2191
+ const [pending, setPendingState] = useState5(() => pendingMessageMemory.get(memoryKey) ?? null);
2192
+ const [pendingAction, setPendingAction] = useState5(null);
2193
+ const [restoreDraft, setRestoreDraft] = useState5(null);
2194
+ const restoreSequence = useRef6(0);
2195
+ const actionSequence = useRef6(0);
2196
+ const acknowledged = useRef6(/* @__PURE__ */ new Set());
2048
2197
  const setPending = (update) => setPendingState((current) => {
2049
2198
  const next = typeof update === "function" ? update(current) : update;
2050
2199
  if (next) boundedSet(pendingMessageMemory, memoryKey, next);
2051
2200
  else pendingMessageMemory.delete(memoryKey);
2052
2201
  return next;
2053
2202
  });
2054
- useEffect6(() => {
2203
+ useEffect7(() => {
2055
2204
  setPendingState(pendingMessageMemory.get(memoryKey) ?? null);
2056
2205
  setPendingAction(null);
2057
2206
  setRestoreDraft(null);
2058
2207
  }, [memoryKey]);
2059
- useEffect6(() => {
2208
+ useEffect7(() => {
2060
2209
  if (!pending) return;
2061
2210
  if (state.transcript.some((entry) => entry.role === "user" && entry.text.trim() === pending.text.trim() && !pending.baselineIds.includes(entry.id))) {
2062
2211
  setPending(null);
@@ -2085,7 +2234,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
2085
2234
  setRestoreDraft({ id: restoreSequence.current, text: pending.text, context: pending.context, images: pending.images });
2086
2235
  setPending({ ...pending, status: "editing" });
2087
2236
  };
2088
- useEffect6(() => {
2237
+ useEffect7(() => {
2089
2238
  const key = state.attached?.key;
2090
2239
  if (!key || !state.attention.some((item) => item.key === key)) {
2091
2240
  if (key) acknowledged.current.delete(key);
@@ -2120,7 +2269,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
2120
2269
  return result;
2121
2270
  }
2122
2271
  }), [adapter, state.error]);
2123
- useEffect6(() => {
2272
+ useEffect7(() => {
2124
2273
  if (!pendingAction) return;
2125
2274
  if (state.operation && !pendingAction.seenOperation) {
2126
2275
  setPendingAction({ ...pendingAction, seenOperation: true });
@@ -2153,24 +2302,24 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
2153
2302
  const startable = state.harnesses.filter((item) => item.startable);
2154
2303
  const startableKey = startable.map((item) => item.id).join("\0");
2155
2304
  const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "", context: [], images: [] };
2156
- const [harness, setHarness] = useState4(remembered.harness);
2157
- const [draft, setDraft] = useState4(remembered.draft);
2158
- const [context, setContext] = useState4(remembered.context);
2159
- const [images, setImages] = useState4(remembered.images ?? []);
2160
- const [starting, setStarting] = useState4(null);
2161
- const [picking, setPicking] = useState4(false);
2162
- const [dragging, setDragging] = useState4(false);
2163
- const [pickerError, setPickerError] = useState4(null);
2164
- const startSequence = useRef5(0);
2165
- const textarea = useRef5(null);
2305
+ const [harness, setHarness] = useState5(remembered.harness);
2306
+ const [draft, setDraft] = useState5(remembered.draft);
2307
+ const [context, setContext] = useState5(remembered.context);
2308
+ const [images, setImages] = useState5(remembered.images ?? []);
2309
+ const [starting, setStarting] = useState5(null);
2310
+ const [picking, setPicking] = useState5(false);
2311
+ const [dragging, setDragging] = useState5(false);
2312
+ const [pickerError, setPickerError] = useState5(null);
2313
+ const startSequence = useRef6(0);
2314
+ const textarea = useRef6(null);
2166
2315
  useAutosizeTextarea(textarea, draft);
2167
- useEffect6(() => {
2316
+ useEffect7(() => {
2168
2317
  if (startable.some((item) => item.id === harness)) return;
2169
2318
  const next = startable[0]?.id ?? "";
2170
2319
  setHarness(next);
2171
2320
  boundedSet(newChatMemory, memoryKey, { harness: next, draft, context, images });
2172
2321
  }, [harness, startableKey]);
2173
- useEffect6(() => {
2322
+ useEffect7(() => {
2174
2323
  if (!starting) return;
2175
2324
  const sessionChanged = (state.attached?.key ?? null) !== starting.attachedKey;
2176
2325
  const beganWorking = !starting.busy && state.busy;
@@ -2178,10 +2327,10 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
2178
2327
  newChatMemory.delete(memoryKey);
2179
2328
  onStarted();
2180
2329
  }, [memoryKey, onStarted, starting, state.attached?.key, state.busy]);
2181
- useEffect6(() => {
2330
+ useEffect7(() => {
2182
2331
  if (starting && state.error !== starting.initialError && !state.busy && !state.operation) setStarting(null);
2183
2332
  }, [starting, state.busy, state.error, state.operation]);
2184
- useEffect6(() => {
2333
+ useEffect7(() => {
2185
2334
  textarea.current?.focus({ preventScroll: true });
2186
2335
  }, []);
2187
2336
  const pickContext = () => {
@@ -2315,14 +2464,14 @@ function SupercodeMessenger({ state: stateInput, adapter, class: className = "",
2315
2464
  const state = useMemo2(() => normalizeUiState(stateInput), [stateInput]);
2316
2465
  const copy = { ...DEFAULT_LABELS, ...labels };
2317
2466
  const memoryKey = state.workspace || "@default";
2318
- const [view, setViewState] = useState4(initialView ?? (state.attention.length ? "list" : messengerViewMemory.get(memoryKey) ?? (state.attached || state.transcript.length ? "chat" : "list")));
2319
- const [opening, setOpening] = useState4(null);
2320
- const [listFocus, setListFocus] = useState4(null);
2467
+ const [view, setViewState] = useState5(initialView ?? (state.attention.length ? "list" : messengerViewMemory.get(memoryKey) ?? (state.attached || state.transcript.length ? "chat" : "list")));
2468
+ const [opening, setOpening] = useState5(null);
2469
+ const [listFocus, setListFocus] = useState5(null);
2321
2470
  const setView = (next) => {
2322
2471
  boundedSet(messengerViewMemory, memoryKey, next);
2323
2472
  setViewState(next);
2324
2473
  };
2325
- useEffect6(() => {
2474
+ useEffect7(() => {
2326
2475
  if (!opening) return;
2327
2476
  if (state.attached?.key === opening.key) {
2328
2477
  setOpening(null);