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