@volter-ai-dev/supercode-ui 0.1.22 → 0.1.23
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/README.md +5 -0
- package/components.d.ts +2 -0
- package/components.mjs +200 -108
- package/composer.mjs +18 -17
- package/conversation.d.ts +2 -0
- package/conversation.mjs +136 -44
- package/embed.mjs +198 -108
- package/index.d.ts +2 -0
- package/messenger.mjs +198 -108
- package/package.json +1 -1
- package/sessions.mjs +14 -13
- package/styles.css +2 -1
package/messenger.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/messenger.jsx
|
|
2
|
-
import { useEffect as
|
|
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({
|
|
@@ -758,7 +758,7 @@ function isSendKey(event) {
|
|
|
758
758
|
}
|
|
759
759
|
|
|
760
760
|
// src/composer.jsx
|
|
761
|
-
import { useEffect, useRef, useState } from "preact/hooks";
|
|
761
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "preact/hooks";
|
|
762
762
|
|
|
763
763
|
// src/memory.js
|
|
764
764
|
var MEMORY_LIMIT = 100;
|
|
@@ -818,7 +818,8 @@ function UiIcon({ name, size = 16, class: className = "" }) {
|
|
|
818
818
|
}
|
|
819
819
|
|
|
820
820
|
// src/context.jsx
|
|
821
|
-
import {
|
|
821
|
+
import { useEffect, useRef, useState } from "preact/hooks";
|
|
822
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
822
823
|
var MAX_CONTEXT_ITEMS = 32;
|
|
823
824
|
var MAX_IMAGE_ITEMS = 4;
|
|
824
825
|
var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
@@ -917,12 +918,101 @@ function ImageTray({ items, onRemove }) {
|
|
|
917
918
|
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
919
|
] }, item.id ?? `${item.label}:${index}`)) });
|
|
919
920
|
}
|
|
920
|
-
function
|
|
921
|
+
function imageFilename(label) {
|
|
922
|
+
const value = label.trim().replace(/[\\/:*?"<>|]+/g, "-");
|
|
923
|
+
return value || "image";
|
|
924
|
+
}
|
|
925
|
+
function ImageViewer({ items, index, adapter, onChange, onClose }) {
|
|
926
|
+
const dialog = useRef(null);
|
|
927
|
+
const reset = useRef(null);
|
|
928
|
+
const [copyState, setCopyState2] = useState("idle");
|
|
929
|
+
const item = items[index];
|
|
930
|
+
const remote = item?.url?.startsWith("http://") || item?.url?.startsWith("https://");
|
|
931
|
+
useEffect(() => {
|
|
932
|
+
if (!dialog.current?.open) dialog.current?.showModal();
|
|
933
|
+
return () => clearTimeout(reset.current);
|
|
934
|
+
}, []);
|
|
935
|
+
useEffect(() => {
|
|
936
|
+
clearTimeout(reset.current);
|
|
937
|
+
setCopyState2("idle");
|
|
938
|
+
}, [index]);
|
|
939
|
+
if (!item?.url) return null;
|
|
940
|
+
const move = (amount) => onChange((index + amount + items.length) % items.length);
|
|
941
|
+
const copy = async () => {
|
|
942
|
+
try {
|
|
943
|
+
await adapter.copyText(item.url);
|
|
944
|
+
setCopyState2("copied");
|
|
945
|
+
} catch {
|
|
946
|
+
setCopyState2("failed");
|
|
947
|
+
}
|
|
948
|
+
clearTimeout(reset.current);
|
|
949
|
+
reset.current = setTimeout(() => setCopyState2("idle"), 1500);
|
|
950
|
+
};
|
|
951
|
+
const close = () => dialog.current?.close();
|
|
952
|
+
return /* @__PURE__ */ jsxs2(
|
|
953
|
+
"dialog",
|
|
954
|
+
{
|
|
955
|
+
ref: dialog,
|
|
956
|
+
class: "scui-image-viewer",
|
|
957
|
+
"aria-label": `Image preview: ${item.label}`,
|
|
958
|
+
onClose,
|
|
959
|
+
onClick: (event) => {
|
|
960
|
+
if (event.target === event.currentTarget) close();
|
|
961
|
+
},
|
|
962
|
+
onKeyDown: (event) => {
|
|
963
|
+
if (items.length < 2 || !["ArrowLeft", "ArrowRight"].includes(event.key)) return;
|
|
964
|
+
event.preventDefault();
|
|
965
|
+
move(event.key === "ArrowLeft" ? -1 : 1);
|
|
966
|
+
},
|
|
967
|
+
children: [
|
|
968
|
+
/* @__PURE__ */ jsxs2("header", { children: [
|
|
969
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
970
|
+
/* @__PURE__ */ jsx2("strong", { children: item.label }),
|
|
971
|
+
items.length > 1 ? /* @__PURE__ */ jsxs2("small", { children: [
|
|
972
|
+
index + 1,
|
|
973
|
+
" of ",
|
|
974
|
+
items.length
|
|
975
|
+
] }) : null
|
|
976
|
+
] }),
|
|
977
|
+
/* @__PURE__ */ jsxs2("nav", { "aria-label": "Image actions", children: [
|
|
978
|
+
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,
|
|
979
|
+
remote ? /* @__PURE__ */ jsx2("a", { href: item.url, 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: item.url, download: imageFilename(item.label), "aria-label": "Download image", title: "Download image", children: /* @__PURE__ */ jsx2(UiIcon, { name: "down", size: 16 }) }),
|
|
980
|
+
/* @__PURE__ */ jsx2("button", { type: "button", "aria-label": "Close image preview", title: "Close", onClick: close, children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 17 }) })
|
|
981
|
+
] })
|
|
982
|
+
] }),
|
|
983
|
+
/* @__PURE__ */ jsxs2("figure", { children: [
|
|
984
|
+
/* @__PURE__ */ jsx2("img", { src: item.url, alt: item.label }),
|
|
985
|
+
items.length > 1 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
986
|
+
/* @__PURE__ */ jsx2("button", { type: "button", class: "scui-image-previous", "aria-label": "Previous image", onClick: () => move(-1), children: /* @__PURE__ */ jsx2(UiIcon, { name: "chevron", size: 19 }) }),
|
|
987
|
+
/* @__PURE__ */ jsx2("button", { type: "button", class: "scui-image-next", "aria-label": "Next image", onClick: () => move(1), children: /* @__PURE__ */ jsx2(UiIcon, { name: "chevron", size: 19 }) })
|
|
988
|
+
] }) : null
|
|
989
|
+
] })
|
|
990
|
+
]
|
|
991
|
+
}
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
function MessageImages({ items, adapter }) {
|
|
995
|
+
const [active, setActive] = useState(null);
|
|
996
|
+
const opener = useRef(null);
|
|
921
997
|
if (!items?.length) return null;
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
998
|
+
const viewable = items.filter((item) => item.url);
|
|
999
|
+
const close = () => {
|
|
1000
|
+
setActive(null);
|
|
1001
|
+
requestAnimationFrame(() => opener.current?.focus({ preventScroll: true }));
|
|
1002
|
+
};
|
|
1003
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1004
|
+
/* @__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) => {
|
|
1005
|
+
opener.current = event.currentTarget;
|
|
1006
|
+
setActive(viewable.indexOf(item));
|
|
1007
|
+
}, children: /* @__PURE__ */ jsx2("img", { src: item.url, alt: "" }) }, item.id ?? `${item.label}:${index}`) : /* @__PURE__ */ jsxs2("span", { "data-unavailable": "true", children: [
|
|
1008
|
+
/* @__PURE__ */ jsx2(UiIcon, { name: "image", size: 14 }),
|
|
1009
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
1010
|
+
/* @__PURE__ */ jsx2("strong", { children: item.label }),
|
|
1011
|
+
/* @__PURE__ */ jsx2("small", { children: "Preview unavailable" })
|
|
1012
|
+
] })
|
|
1013
|
+
] }, item.id ?? `${item.label}:${index}`)) }),
|
|
1014
|
+
active !== null && viewable[active] ? /* @__PURE__ */ jsx2(ImageViewer, { items: viewable, index: active, adapter, onChange: setActive, onClose: close }) : null
|
|
1015
|
+
] });
|
|
926
1016
|
}
|
|
927
1017
|
|
|
928
1018
|
// src/textarea.js
|
|
@@ -964,18 +1054,18 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
964
1054
|
}
|
|
965
1055
|
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
|
|
966
1056
|
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, context: [], images: [], queue: [] };
|
|
967
|
-
const [draft, setDraft] =
|
|
968
|
-
const [context, setContext] =
|
|
969
|
-
const [images, setImages] =
|
|
970
|
-
const [queue, setQueue] =
|
|
971
|
-
const [dispatching, setDispatching] =
|
|
972
|
-
const [picking, setPicking] =
|
|
973
|
-
const [dragging, setDragging] =
|
|
974
|
-
const [pickerError, setPickerError] =
|
|
975
|
-
const textarea =
|
|
1057
|
+
const [draft, setDraft] = useState2(remembered.draft);
|
|
1058
|
+
const [context, setContext] = useState2(remembered.context ?? []);
|
|
1059
|
+
const [images, setImages] = useState2(remembered.images ?? []);
|
|
1060
|
+
const [queue, setQueue] = useState2((remembered.queue ?? []).map((item) => ({ ...item, context: item.context ?? [], images: item.images ?? [] })));
|
|
1061
|
+
const [dispatching, setDispatching] = useState2(false);
|
|
1062
|
+
const [picking, setPicking] = useState2(false);
|
|
1063
|
+
const [dragging, setDragging] = useState2(false);
|
|
1064
|
+
const [pickerError, setPickerError] = useState2(null);
|
|
1065
|
+
const textarea = useRef2(null);
|
|
976
1066
|
useAutosizeTextarea(textarea, draft);
|
|
977
1067
|
const remember = (nextDraft, nextContext, nextImages, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, context: nextContext, images: nextImages, queue: nextQueue });
|
|
978
|
-
|
|
1068
|
+
useEffect2(() => {
|
|
979
1069
|
remember(draft, context, images, queue);
|
|
980
1070
|
}, [draft, context, images, memoryKey, queue]);
|
|
981
1071
|
const updateQueue = (update) => setQueue((items) => {
|
|
@@ -985,7 +1075,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
985
1075
|
});
|
|
986
1076
|
const queueBlocked = state.busy || pendingStatus !== null || dispatching;
|
|
987
1077
|
const queuesNewMessage = state.busy || pendingStatus === "sending" || pendingStatus === "failed" || dispatching;
|
|
988
|
-
|
|
1078
|
+
useEffect2(() => {
|
|
989
1079
|
if (!queueBlocked && state.canSend && queue.length) {
|
|
990
1080
|
const [next, ...rest] = queue;
|
|
991
1081
|
setDispatching(true);
|
|
@@ -995,13 +1085,13 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
995
1085
|
adapter.onIntent({ action: "send", text: next.text, ...next.context.length ? { context: next.context } : {}, ...next.images.length ? { images: next.images } : {} });
|
|
996
1086
|
}
|
|
997
1087
|
}, [adapter, draft, memoryKey, onPending, queue, queueBlocked, state.canSend]);
|
|
998
|
-
|
|
1088
|
+
useEffect2(() => {
|
|
999
1089
|
if (pendingStatus !== null || state.busy) setDispatching(false);
|
|
1000
1090
|
}, [pendingStatus, state.busy]);
|
|
1001
|
-
|
|
1091
|
+
useEffect2(() => {
|
|
1002
1092
|
textarea.current?.focus({ preventScroll: true });
|
|
1003
1093
|
}, [memoryKey]);
|
|
1004
|
-
|
|
1094
|
+
useEffect2(() => {
|
|
1005
1095
|
if (!restoreDraft) return;
|
|
1006
1096
|
setDraft(restoreDraft.text);
|
|
1007
1097
|
const restoredContext = normalizeContext(restoreDraft.context);
|
|
@@ -1012,7 +1102,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
1012
1102
|
textarea.current?.focus({ preventScroll: true });
|
|
1013
1103
|
onDraftRestored?.(restoreDraft.id);
|
|
1014
1104
|
}, [onDraftRestored, restoreDraft?.id]);
|
|
1015
|
-
|
|
1105
|
+
useEffect2(() => {
|
|
1016
1106
|
const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
|
|
1017
1107
|
return () => clearTimeout(timer);
|
|
1018
1108
|
}, [adapter, draft]);
|
|
@@ -1137,12 +1227,12 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
1137
1227
|
}
|
|
1138
1228
|
|
|
1139
1229
|
// src/conversation.jsx
|
|
1140
|
-
import { Fragment as
|
|
1141
|
-
import { useEffect as
|
|
1230
|
+
import { Fragment as Fragment3 } from "preact";
|
|
1231
|
+
import { useEffect as useEffect4, useId, useLayoutEffect as useLayoutEffect2, useRef as useRef4, useState as useState3 } from "preact/hooks";
|
|
1142
1232
|
|
|
1143
1233
|
// src/markdown.jsx
|
|
1144
1234
|
import MarkdownIt from "markdown-it";
|
|
1145
|
-
import { useEffect as
|
|
1235
|
+
import { useEffect as useEffect3, useMemo, useRef as useRef3 } from "preact/hooks";
|
|
1146
1236
|
import { jsx as jsx4 } from "preact/jsx-runtime";
|
|
1147
1237
|
var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
|
|
1148
1238
|
var LANGUAGE_LABELS = {
|
|
@@ -1204,8 +1294,8 @@ function setCopyState(button, status) {
|
|
|
1204
1294
|
}
|
|
1205
1295
|
function Markdown({ value, copyText }) {
|
|
1206
1296
|
const html = useMemo(() => markdown.render(value), [value]);
|
|
1207
|
-
const resets =
|
|
1208
|
-
|
|
1297
|
+
const resets = useRef3(/* @__PURE__ */ new Map());
|
|
1298
|
+
useEffect3(() => () => {
|
|
1209
1299
|
for (const timer of resets.current.values()) clearTimeout(timer);
|
|
1210
1300
|
resets.current.clear();
|
|
1211
1301
|
}, []);
|
|
@@ -1234,7 +1324,7 @@ function Markdown({ value, copyText }) {
|
|
|
1234
1324
|
}
|
|
1235
1325
|
|
|
1236
1326
|
// src/conversation.jsx
|
|
1237
|
-
import { Fragment as
|
|
1327
|
+
import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
1238
1328
|
function LoadingStatus({ state, compact = false }) {
|
|
1239
1329
|
const copy = {
|
|
1240
1330
|
connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
|
|
@@ -1283,9 +1373,9 @@ function ContextDisclosure({ context }) {
|
|
|
1283
1373
|
] });
|
|
1284
1374
|
}
|
|
1285
1375
|
function MessageMeta({ entry, adapter }) {
|
|
1286
|
-
const [copyState, setCopyState2] =
|
|
1287
|
-
const reset =
|
|
1288
|
-
|
|
1376
|
+
const [copyState, setCopyState2] = useState3("idle");
|
|
1377
|
+
const reset = useRef4(null);
|
|
1378
|
+
useEffect4(() => () => clearTimeout(reset.current), []);
|
|
1289
1379
|
const date = entry.ts === null ? null : new Date(entry.ts);
|
|
1290
1380
|
const validDate = date && Number.isFinite(date.valueOf()) ? date : null;
|
|
1291
1381
|
if (!validDate && (!adapter?.copyText || !entry.text)) return null;
|
|
@@ -1306,33 +1396,33 @@ function MessageMeta({ entry, adapter }) {
|
|
|
1306
1396
|
] });
|
|
1307
1397
|
}
|
|
1308
1398
|
var TOOL_ICONS = {
|
|
1309
|
-
read: () => /* @__PURE__ */ jsxs4(
|
|
1399
|
+
read: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1310
1400
|
/* @__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
1401
|
/* @__PURE__ */ jsx5("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
|
|
1312
1402
|
] }),
|
|
1313
|
-
search: () => /* @__PURE__ */ jsxs4(
|
|
1403
|
+
search: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1314
1404
|
/* @__PURE__ */ jsx5("circle", { cx: "8", cy: "8", r: "4.5" }),
|
|
1315
1405
|
/* @__PURE__ */ jsx5("path", { d: "m11.5 11.5 3 3" })
|
|
1316
1406
|
] }),
|
|
1317
|
-
edit: () => /* @__PURE__ */ jsxs4(
|
|
1407
|
+
edit: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1318
1408
|
/* @__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
1409
|
/* @__PURE__ */ jsx5("path", { d: "m10 5 3 3" })
|
|
1320
1410
|
] }),
|
|
1321
|
-
command: () => /* @__PURE__ */ jsx5(
|
|
1322
|
-
test: () => /* @__PURE__ */ jsxs4(
|
|
1411
|
+
command: () => /* @__PURE__ */ jsx5(Fragment4, { children: /* @__PURE__ */ jsx5("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
|
|
1412
|
+
test: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1323
1413
|
/* @__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
1414
|
/* @__PURE__ */ jsx5("path", { d: "M5 2.5h8" })
|
|
1325
1415
|
] }),
|
|
1326
|
-
web: () => /* @__PURE__ */ jsxs4(
|
|
1416
|
+
web: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1327
1417
|
/* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "6.5" }),
|
|
1328
1418
|
/* @__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
1419
|
] }),
|
|
1330
|
-
agent: () => /* @__PURE__ */ jsxs4(
|
|
1420
|
+
agent: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1331
1421
|
/* @__PURE__ */ jsx5("circle", { cx: "9", cy: "6", r: "2.5" }),
|
|
1332
1422
|
/* @__PURE__ */ jsx5("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
|
|
1333
1423
|
] }),
|
|
1334
|
-
plan: () => /* @__PURE__ */ jsx5(
|
|
1335
|
-
other: () => /* @__PURE__ */ jsxs4(
|
|
1424
|
+
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" }) }),
|
|
1425
|
+
other: () => /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1336
1426
|
/* @__PURE__ */ jsx5("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
|
|
1337
1427
|
/* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "3.5" })
|
|
1338
1428
|
] })
|
|
@@ -1398,9 +1488,9 @@ function ToolMetrics({ presentation }) {
|
|
|
1398
1488
|
}
|
|
1399
1489
|
function PendingElapsed({ now }) {
|
|
1400
1490
|
const clock = now ?? Date.now;
|
|
1401
|
-
const started =
|
|
1402
|
-
const [elapsed, setElapsed] =
|
|
1403
|
-
|
|
1491
|
+
const started = useRef4(clock());
|
|
1492
|
+
const [elapsed, setElapsed] = useState3(0);
|
|
1493
|
+
useEffect4(() => {
|
|
1404
1494
|
const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
|
|
1405
1495
|
return () => clearInterval(timer);
|
|
1406
1496
|
}, [clock]);
|
|
@@ -1441,7 +1531,7 @@ function SearchPreview({ presentation }) {
|
|
|
1441
1531
|
] }) : null,
|
|
1442
1532
|
lines.length ? /* @__PURE__ */ jsx5("ol", { children: lines.map((line, index) => {
|
|
1443
1533
|
const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
|
|
1444
|
-
return /* @__PURE__ */ jsx5("li", { children: match ? /* @__PURE__ */ jsxs4(
|
|
1534
|
+
return /* @__PURE__ */ jsx5("li", { children: match ? /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1445
1535
|
/* @__PURE__ */ jsx5("code", { children: match[1] }),
|
|
1446
1536
|
/* @__PURE__ */ jsxs4("small", { children: [
|
|
1447
1537
|
match[2],
|
|
@@ -1474,9 +1564,9 @@ function ToolPreview({ presentation, entry }) {
|
|
|
1474
1564
|
return presentation.preview ? /* @__PURE__ */ jsx5("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
|
|
1475
1565
|
}
|
|
1476
1566
|
function ToolActions({ presentation, adapter }) {
|
|
1477
|
-
const [copied, setCopied] =
|
|
1478
|
-
const reset =
|
|
1479
|
-
|
|
1567
|
+
const [copied, setCopied] = useState3(false);
|
|
1568
|
+
const reset = useRef4(null);
|
|
1569
|
+
useEffect4(() => () => clearTimeout(reset.current), []);
|
|
1480
1570
|
if (!adapter?.copyText) return null;
|
|
1481
1571
|
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
1572
|
const copy = async () => {
|
|
@@ -1523,7 +1613,7 @@ function TranscriptEntry({ entry, state, adapter }) {
|
|
|
1523
1613
|
}
|
|
1524
1614
|
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx5("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
|
|
1525
1615
|
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 }),
|
|
1616
|
+
/* @__PURE__ */ jsx5(MessageImages, { items: entry.images, adapter }),
|
|
1527
1617
|
/* @__PURE__ */ jsx5(Markdown, { value: entry.text, copyText: adapter?.copyText }),
|
|
1528
1618
|
/* @__PURE__ */ jsx5(ContextDisclosure, { context: entry.context }),
|
|
1529
1619
|
entry.truncated ? /* @__PURE__ */ jsx5("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
|
|
@@ -1532,14 +1622,14 @@ function TranscriptEntry({ entry, state, adapter }) {
|
|
|
1532
1622
|
}
|
|
1533
1623
|
function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
1534
1624
|
const presentation = entry.presentation ?? createToolPresentation(entry);
|
|
1535
|
-
const [expanded, setExpanded] =
|
|
1536
|
-
|
|
1625
|
+
const [expanded, setExpanded] = useState3(open || entry.status === "pending");
|
|
1626
|
+
useEffect4(() => {
|
|
1537
1627
|
if (entry.status === "pending") setExpanded(true);
|
|
1538
1628
|
}, [entry.status]);
|
|
1539
1629
|
const target = compactToolTarget(presentation.target, workspace);
|
|
1540
1630
|
const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
|
|
1541
1631
|
const category = presentation.category ?? toolCategory(entry);
|
|
1542
|
-
const summary = /* @__PURE__ */ jsxs4(
|
|
1632
|
+
const summary = /* @__PURE__ */ jsxs4(Fragment4, { children: [
|
|
1543
1633
|
/* @__PURE__ */ jsx5(ToolIcon, { category }),
|
|
1544
1634
|
/* @__PURE__ */ jsx5("strong", { children: toolAction2(entry, category, presentation) }),
|
|
1545
1635
|
target ? /* @__PURE__ */ jsx5("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
|
|
@@ -1567,9 +1657,9 @@ function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
|
1567
1657
|
function ActivityGroup({ entries, state, adapter }) {
|
|
1568
1658
|
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
1659
|
const active = entries.some((entry) => entry.status === "pending");
|
|
1570
|
-
const [open, setOpen] =
|
|
1660
|
+
const [open, setOpen] = useState3(active);
|
|
1571
1661
|
const id = useId();
|
|
1572
|
-
|
|
1662
|
+
useEffect4(() => {
|
|
1573
1663
|
if (active) setOpen(true);
|
|
1574
1664
|
}, [active]);
|
|
1575
1665
|
return /* @__PURE__ */ jsxs4("section", { class: "scui-activity", children: [
|
|
@@ -1645,9 +1735,9 @@ function SessionDetails({ semantics }) {
|
|
|
1645
1735
|
}
|
|
1646
1736
|
var conversationMemory = /* @__PURE__ */ new Map();
|
|
1647
1737
|
function ConversationAnnouncements({ state }) {
|
|
1648
|
-
const previousBusy =
|
|
1649
|
-
const [announcement, setAnnouncement] =
|
|
1650
|
-
|
|
1738
|
+
const previousBusy = useRef4(state.busy);
|
|
1739
|
+
const [announcement, setAnnouncement] = useState3("");
|
|
1740
|
+
useEffect4(() => {
|
|
1651
1741
|
if (previousBusy.current && !state.busy && !state.error) {
|
|
1652
1742
|
setAnnouncement(`${harnessDisplayName(state.harness) || "Coding agent"} finished working`);
|
|
1653
1743
|
}
|
|
@@ -1656,13 +1746,13 @@ function ConversationAnnouncements({ state }) {
|
|
|
1656
1746
|
return /* @__PURE__ */ jsx5("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
|
|
1657
1747
|
}
|
|
1658
1748
|
function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null, unreadAfterMessages = null }) {
|
|
1659
|
-
const scroller =
|
|
1749
|
+
const scroller = useRef4(null);
|
|
1660
1750
|
const remembered = conversationMemory.get(memoryKey) ?? { top: null, atBottom: true };
|
|
1661
|
-
const [atBottom, setAtBottom] =
|
|
1662
|
-
const earlierAnchor =
|
|
1663
|
-
const restored =
|
|
1751
|
+
const [atBottom, setAtBottom] = useState3(remembered.atBottom);
|
|
1752
|
+
const earlierAnchor = useRef4(null);
|
|
1753
|
+
const restored = useRef4(false);
|
|
1664
1754
|
const blocks = groupConversation(state.transcript);
|
|
1665
|
-
const unreadBoundary =
|
|
1755
|
+
const unreadBoundary = useRef4(Number.isSafeInteger(unreadAfterMessages) && unreadAfterMessages >= 0 ? unreadAfterMessages : null);
|
|
1666
1756
|
const unreadBlock = unreadBoundary.current === null ? -1 : blocks.findIndex((block) => {
|
|
1667
1757
|
const entries = block.kind === "activity" ? block.entries : [block.entry];
|
|
1668
1758
|
return entries.some((entry) => Number.isSafeInteger(entry.messageIndex) && entry.messageIndex > unreadBoundary.current);
|
|
@@ -1721,12 +1811,12 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1721
1811
|
}, children: "Load earlier messages" }) : null,
|
|
1722
1812
|
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx5(LoadingStatus, { state }) : null,
|
|
1723
1813
|
!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(
|
|
1814
|
+
blocks.map((block, index) => /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1725
1815
|
index === unreadBlock ? /* @__PURE__ */ jsx5("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx5("span", { children: "New" }) }) : null,
|
|
1726
1816
|
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
1817
|
] }, block.id)),
|
|
1728
1818
|
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 }),
|
|
1819
|
+
/* @__PURE__ */ jsx5(MessageImages, { items: pendingMessage.images, adapter }),
|
|
1730
1820
|
/* @__PURE__ */ jsx5(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
|
|
1731
1821
|
/* @__PURE__ */ jsx5(ContextDisclosure, { context: pendingMessage.context }),
|
|
1732
1822
|
/* @__PURE__ */ jsxs4("footer", { children: [
|
|
@@ -1757,7 +1847,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1757
1847
|
}
|
|
1758
1848
|
|
|
1759
1849
|
// src/logo.jsx
|
|
1760
|
-
import { useEffect as
|
|
1850
|
+
import { useEffect as useEffect5 } from "preact/hooks";
|
|
1761
1851
|
import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
1762
1852
|
var LOGOS = {
|
|
1763
1853
|
"claude-code": {
|
|
@@ -1805,7 +1895,7 @@ var LOGOS = {
|
|
|
1805
1895
|
};
|
|
1806
1896
|
function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
1807
1897
|
const logo = LOGOS[id];
|
|
1808
|
-
|
|
1898
|
+
useEffect5(() => {
|
|
1809
1899
|
if (!logo) onMissingLogo?.(id);
|
|
1810
1900
|
}, [id, logo, onMissingLogo]);
|
|
1811
1901
|
if (!logo) return null;
|
|
@@ -1816,7 +1906,7 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
|
1816
1906
|
}
|
|
1817
1907
|
|
|
1818
1908
|
// src/sessions.jsx
|
|
1819
|
-
import { useEffect as
|
|
1909
|
+
import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useRef as useRef5, useState as useState4 } from "preact/hooks";
|
|
1820
1910
|
import { jsx as jsx7, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
1821
1911
|
var sessionListMemory = /* @__PURE__ */ new Map();
|
|
1822
1912
|
function SessionRow({ row, state, onOpen }) {
|
|
@@ -1838,21 +1928,21 @@ function SessionRow({ row, state, onOpen }) {
|
|
|
1838
1928
|
}
|
|
1839
1929
|
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default" }) {
|
|
1840
1930
|
const remembered = sessionListMemory.get(memoryKey) ?? { query: "", top: 0 };
|
|
1841
|
-
const [query, setQuery] =
|
|
1842
|
-
const [loadingMore, setLoadingMore] =
|
|
1843
|
-
const root =
|
|
1844
|
-
const rowScroller =
|
|
1931
|
+
const [query, setQuery] = useState4(remembered.query);
|
|
1932
|
+
const [loadingMore, setLoadingMore] = useState4(false);
|
|
1933
|
+
const root = useRef5(null);
|
|
1934
|
+
const rowScroller = useRef5(null);
|
|
1845
1935
|
const rows = filterSessions(state.sessions, query);
|
|
1846
1936
|
const Row = components.SessionRow ?? SessionRow;
|
|
1847
1937
|
useLayoutEffect3(() => {
|
|
1848
1938
|
if (rowScroller.current) rowScroller.current.scrollTop = remembered.top;
|
|
1849
1939
|
}, [memoryKey]);
|
|
1850
|
-
|
|
1940
|
+
useEffect6(() => {
|
|
1851
1941
|
if (!focusKey || !root.current) return;
|
|
1852
1942
|
const target = focusKey === "@new" ? root.current.querySelector('[data-list-focus="new"]') : [...root.current.querySelectorAll("[data-session-key]")].find((element) => element.dataset.sessionKey === focusKey);
|
|
1853
1943
|
(target ?? root.current.querySelector("input,button"))?.focus({ preventScroll: true });
|
|
1854
1944
|
}, [focusKey, rows.length]);
|
|
1855
|
-
|
|
1945
|
+
useEffect6(() => {
|
|
1856
1946
|
if (loadingMore) setLoadingMore(false);
|
|
1857
1947
|
}, [state.error, state.history.hasMoreSessions, state.sessions.length]);
|
|
1858
1948
|
const loadMore = () => {
|
|
@@ -1938,10 +2028,10 @@ function Receipt({ state, adapter }) {
|
|
|
1938
2028
|
return null;
|
|
1939
2029
|
}
|
|
1940
2030
|
function ConversationActions({ state, adapter, actionPending }) {
|
|
1941
|
-
const [open, setOpen] =
|
|
1942
|
-
const root =
|
|
1943
|
-
const panel =
|
|
1944
|
-
const trigger =
|
|
2031
|
+
const [open, setOpen] = useState5(false);
|
|
2032
|
+
const root = useRef6(null);
|
|
2033
|
+
const panel = useRef6(null);
|
|
2034
|
+
const trigger = useRef6(null);
|
|
1945
2035
|
const menuId = useId2();
|
|
1946
2036
|
const targets = state.harnesses.filter((item) => item.startable);
|
|
1947
2037
|
const groups = [
|
|
@@ -1962,7 +2052,7 @@ function ConversationActions({ state, adapter, actionPending }) {
|
|
|
1962
2052
|
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
2053
|
}
|
|
1964
2054
|
].filter((group) => group.items.length);
|
|
1965
|
-
|
|
2055
|
+
useEffect7(() => {
|
|
1966
2056
|
if (!open) return;
|
|
1967
2057
|
panel.current?.querySelector("button:not(:disabled)")?.focus({ preventScroll: true });
|
|
1968
2058
|
const dismiss = (event) => {
|
|
@@ -2012,12 +2102,12 @@ function ConversationActions({ state, adapter, actionPending }) {
|
|
|
2012
2102
|
] });
|
|
2013
2103
|
}
|
|
2014
2104
|
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose }) {
|
|
2015
|
-
const back =
|
|
2105
|
+
const back = useRef6(null);
|
|
2016
2106
|
const harness = state.attached?.harness ?? state.harness;
|
|
2017
2107
|
const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
|
|
2018
2108
|
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
2109
|
const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce;
|
|
2020
|
-
|
|
2110
|
+
useEffect7(() => {
|
|
2021
2111
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
2022
2112
|
}, []);
|
|
2023
2113
|
return /* @__PURE__ */ jsxs7("header", { class: "scui-head scui-chat-head", children: [
|
|
@@ -2039,24 +2129,24 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2039
2129
|
function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
|
|
2040
2130
|
const Header = slots.header;
|
|
2041
2131
|
const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
|
|
2042
|
-
const [pending, setPendingState] =
|
|
2043
|
-
const [pendingAction, setPendingAction] =
|
|
2044
|
-
const [restoreDraft, setRestoreDraft] =
|
|
2045
|
-
const restoreSequence =
|
|
2046
|
-
const actionSequence =
|
|
2047
|
-
const acknowledged =
|
|
2132
|
+
const [pending, setPendingState] = useState5(() => pendingMessageMemory.get(memoryKey) ?? null);
|
|
2133
|
+
const [pendingAction, setPendingAction] = useState5(null);
|
|
2134
|
+
const [restoreDraft, setRestoreDraft] = useState5(null);
|
|
2135
|
+
const restoreSequence = useRef6(0);
|
|
2136
|
+
const actionSequence = useRef6(0);
|
|
2137
|
+
const acknowledged = useRef6(/* @__PURE__ */ new Set());
|
|
2048
2138
|
const setPending = (update) => setPendingState((current) => {
|
|
2049
2139
|
const next = typeof update === "function" ? update(current) : update;
|
|
2050
2140
|
if (next) boundedSet(pendingMessageMemory, memoryKey, next);
|
|
2051
2141
|
else pendingMessageMemory.delete(memoryKey);
|
|
2052
2142
|
return next;
|
|
2053
2143
|
});
|
|
2054
|
-
|
|
2144
|
+
useEffect7(() => {
|
|
2055
2145
|
setPendingState(pendingMessageMemory.get(memoryKey) ?? null);
|
|
2056
2146
|
setPendingAction(null);
|
|
2057
2147
|
setRestoreDraft(null);
|
|
2058
2148
|
}, [memoryKey]);
|
|
2059
|
-
|
|
2149
|
+
useEffect7(() => {
|
|
2060
2150
|
if (!pending) return;
|
|
2061
2151
|
if (state.transcript.some((entry) => entry.role === "user" && entry.text.trim() === pending.text.trim() && !pending.baselineIds.includes(entry.id))) {
|
|
2062
2152
|
setPending(null);
|
|
@@ -2085,7 +2175,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2085
2175
|
setRestoreDraft({ id: restoreSequence.current, text: pending.text, context: pending.context, images: pending.images });
|
|
2086
2176
|
setPending({ ...pending, status: "editing" });
|
|
2087
2177
|
};
|
|
2088
|
-
|
|
2178
|
+
useEffect7(() => {
|
|
2089
2179
|
const key = state.attached?.key;
|
|
2090
2180
|
if (!key || !state.attention.some((item) => item.key === key)) {
|
|
2091
2181
|
if (key) acknowledged.current.delete(key);
|
|
@@ -2120,7 +2210,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2120
2210
|
return result;
|
|
2121
2211
|
}
|
|
2122
2212
|
}), [adapter, state.error]);
|
|
2123
|
-
|
|
2213
|
+
useEffect7(() => {
|
|
2124
2214
|
if (!pendingAction) return;
|
|
2125
2215
|
if (state.operation && !pendingAction.seenOperation) {
|
|
2126
2216
|
setPendingAction({ ...pendingAction, seenOperation: true });
|
|
@@ -2153,24 +2243,24 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2153
2243
|
const startable = state.harnesses.filter((item) => item.startable);
|
|
2154
2244
|
const startableKey = startable.map((item) => item.id).join("\0");
|
|
2155
2245
|
const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "", context: [], images: [] };
|
|
2156
|
-
const [harness, setHarness] =
|
|
2157
|
-
const [draft, setDraft] =
|
|
2158
|
-
const [context, setContext] =
|
|
2159
|
-
const [images, setImages] =
|
|
2160
|
-
const [starting, setStarting] =
|
|
2161
|
-
const [picking, setPicking] =
|
|
2162
|
-
const [dragging, setDragging] =
|
|
2163
|
-
const [pickerError, setPickerError] =
|
|
2164
|
-
const startSequence =
|
|
2165
|
-
const textarea =
|
|
2246
|
+
const [harness, setHarness] = useState5(remembered.harness);
|
|
2247
|
+
const [draft, setDraft] = useState5(remembered.draft);
|
|
2248
|
+
const [context, setContext] = useState5(remembered.context);
|
|
2249
|
+
const [images, setImages] = useState5(remembered.images ?? []);
|
|
2250
|
+
const [starting, setStarting] = useState5(null);
|
|
2251
|
+
const [picking, setPicking] = useState5(false);
|
|
2252
|
+
const [dragging, setDragging] = useState5(false);
|
|
2253
|
+
const [pickerError, setPickerError] = useState5(null);
|
|
2254
|
+
const startSequence = useRef6(0);
|
|
2255
|
+
const textarea = useRef6(null);
|
|
2166
2256
|
useAutosizeTextarea(textarea, draft);
|
|
2167
|
-
|
|
2257
|
+
useEffect7(() => {
|
|
2168
2258
|
if (startable.some((item) => item.id === harness)) return;
|
|
2169
2259
|
const next = startable[0]?.id ?? "";
|
|
2170
2260
|
setHarness(next);
|
|
2171
2261
|
boundedSet(newChatMemory, memoryKey, { harness: next, draft, context, images });
|
|
2172
2262
|
}, [harness, startableKey]);
|
|
2173
|
-
|
|
2263
|
+
useEffect7(() => {
|
|
2174
2264
|
if (!starting) return;
|
|
2175
2265
|
const sessionChanged = (state.attached?.key ?? null) !== starting.attachedKey;
|
|
2176
2266
|
const beganWorking = !starting.busy && state.busy;
|
|
@@ -2178,10 +2268,10 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2178
2268
|
newChatMemory.delete(memoryKey);
|
|
2179
2269
|
onStarted();
|
|
2180
2270
|
}, [memoryKey, onStarted, starting, state.attached?.key, state.busy]);
|
|
2181
|
-
|
|
2271
|
+
useEffect7(() => {
|
|
2182
2272
|
if (starting && state.error !== starting.initialError && !state.busy && !state.operation) setStarting(null);
|
|
2183
2273
|
}, [starting, state.busy, state.error, state.operation]);
|
|
2184
|
-
|
|
2274
|
+
useEffect7(() => {
|
|
2185
2275
|
textarea.current?.focus({ preventScroll: true });
|
|
2186
2276
|
}, []);
|
|
2187
2277
|
const pickContext = () => {
|
|
@@ -2315,14 +2405,14 @@ function SupercodeMessenger({ state: stateInput, adapter, class: className = "",
|
|
|
2315
2405
|
const state = useMemo2(() => normalizeUiState(stateInput), [stateInput]);
|
|
2316
2406
|
const copy = { ...DEFAULT_LABELS, ...labels };
|
|
2317
2407
|
const memoryKey = state.workspace || "@default";
|
|
2318
|
-
const [view, setViewState] =
|
|
2319
|
-
const [opening, setOpening] =
|
|
2320
|
-
const [listFocus, setListFocus] =
|
|
2408
|
+
const [view, setViewState] = useState5(initialView ?? (state.attention.length ? "list" : messengerViewMemory.get(memoryKey) ?? (state.attached || state.transcript.length ? "chat" : "list")));
|
|
2409
|
+
const [opening, setOpening] = useState5(null);
|
|
2410
|
+
const [listFocus, setListFocus] = useState5(null);
|
|
2321
2411
|
const setView = (next) => {
|
|
2322
2412
|
boundedSet(messengerViewMemory, memoryKey, next);
|
|
2323
2413
|
setViewState(next);
|
|
2324
2414
|
};
|
|
2325
|
-
|
|
2415
|
+
useEffect7(() => {
|
|
2326
2416
|
if (!opening) return;
|
|
2327
2417
|
if (state.attached?.key === opening.key) {
|
|
2328
2418
|
setOpening(null);
|