@volter-ai-dev/supercode-ui 0.1.18 → 0.1.21

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
@@ -501,6 +501,16 @@ function readTranscript(value) {
501
501
  }] : [];
502
502
  });
503
503
  }
504
+ if (Array.isArray(item.images)) {
505
+ entry.images = item.images.flatMap((raw) => {
506
+ const image = record(raw);
507
+ return image && typeof image.label === "string" ? [{
508
+ ...typeof image.id === "string" ? { id: image.id } : {},
509
+ label: image.label,
510
+ ...typeof image.url === "string" ? { url: image.url } : {}
511
+ }] : [];
512
+ }).slice(0, 4);
513
+ }
504
514
  const request = record(item.request);
505
515
  if (request && typeof request.requestKind === "string" && typeof request.payloadText === "string") {
506
516
  entry.request = {
@@ -681,7 +691,7 @@ function sessionActivity(state, row) {
681
691
  function filterSessions(rows, query) {
682
692
  const needle = query.trim().toLocaleLowerCase();
683
693
  if (!needle) return [...rows];
684
- return rows.filter((row) => [row.name, row.title, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => value.toLocaleLowerCase().includes(needle)));
694
+ return rows.filter((row) => [row.name, row.title, row.preview, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => typeof value === "string" && value.toLocaleLowerCase().includes(needle)));
685
695
  }
686
696
  function groupConversation(entries) {
687
697
  const blocks = [];
@@ -761,6 +771,7 @@ function boundedSet(map, key, value) {
761
771
  // src/icon.jsx
762
772
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
763
773
  var ICONS = {
774
+ attach: () => /* @__PURE__ */ jsx("path", { d: "M6.25 9.75 10.6 5.4a2.1 2.1 0 0 1 2.97 2.97l-5.4 5.4a3.3 3.3 0 0 1-4.67-4.66l5.52-5.52" }),
764
775
  back: () => /* @__PURE__ */ jsx("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
765
776
  check: () => /* @__PURE__ */ jsx("path", { d: "m4 9 3.25 3.25L14 5.5" }),
766
777
  chevron: () => /* @__PURE__ */ jsx("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
@@ -776,6 +787,11 @@ var ICONS = {
776
787
  /* @__PURE__ */ jsx("path", { d: "M9 3.5v10" }),
777
788
  /* @__PURE__ */ jsx("path", { d: "m4.75 9.5 4.25 4 4.25-4" })
778
789
  ] }),
790
+ image: () => /* @__PURE__ */ jsxs(Fragment, { children: [
791
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "3.5", width: "12", height: "11", rx: "1.75" }),
792
+ /* @__PURE__ */ jsx("circle", { cx: "6.5", cy: "7", r: "1.25" }),
793
+ /* @__PURE__ */ jsx("path", { d: "m4.5 13 3.25-3 2.1 1.85 1.65-1.5L14 13" })
794
+ ] }),
779
795
  menu: () => /* @__PURE__ */ jsxs(Fragment, { children: [
780
796
  /* @__PURE__ */ jsx("circle", { cx: "4", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
781
797
  /* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
@@ -801,6 +817,114 @@ function UiIcon({ name, size = 16, class: className = "" }) {
801
817
  return /* @__PURE__ */ jsx("svg", { class: `scui-icon ${className}`, style: { "--scui-icon-size": `${size}px` }, viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Glyph, {}) });
802
818
  }
803
819
 
820
+ // src/context.jsx
821
+ import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
822
+ var MAX_CONTEXT_ITEMS = 32;
823
+ var MAX_IMAGE_ITEMS = 4;
824
+ var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
825
+ var IMAGE_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
826
+ function normalizeContext(value) {
827
+ return (Array.isArray(value) ? value : value ? [value] : []).flatMap((item) => {
828
+ if (!item || typeof item.label !== "string" || typeof item.detail !== "string") return [];
829
+ const label = item.label.trim().slice(0, 200);
830
+ const detail = item.detail.slice(0, 2e4);
831
+ if (!label || !detail) return [];
832
+ return [{
833
+ ...typeof item.id === "string" && item.id ? { id: item.id.slice(0, 2e3) } : {},
834
+ ...typeof item.kind === "string" && item.kind ? { kind: item.kind.slice(0, 100) } : {},
835
+ label,
836
+ detail
837
+ }];
838
+ }).slice(0, MAX_CONTEXT_ITEMS);
839
+ }
840
+ function mergeContext(current, picked) {
841
+ const next = [...current];
842
+ const seen = new Set(current.map((item) => item.id ? `id:${item.id}` : `value:${item.kind ?? ""}\0${item.label}\0${item.detail}`));
843
+ for (const item of normalizeContext(picked)) {
844
+ const key = item.id ? `id:${item.id}` : `value:${item.kind ?? ""}\0${item.label}\0${item.detail}`;
845
+ if (seen.has(key)) continue;
846
+ seen.add(key);
847
+ next.push(item);
848
+ if (next.length === MAX_CONTEXT_ITEMS) break;
849
+ }
850
+ return next;
851
+ }
852
+ function normalizeImages(value) {
853
+ const seen = /* @__PURE__ */ new Set();
854
+ return (Array.isArray(value) ? value : value ? [value] : []).flatMap((item) => {
855
+ if (!item || typeof item.label !== "string" || typeof item.url !== "string") return [];
856
+ const label = item.label.trim().slice(0, 200);
857
+ const url = item.url;
858
+ if (!label || seen.has(url) || !(url.startsWith("data:image/") || url.startsWith("https://") || url.startsWith("http://"))) return [];
859
+ seen.add(url);
860
+ return [{
861
+ ...typeof item.id === "string" && item.id ? { id: item.id.slice(0, 2e3) } : {},
862
+ label,
863
+ url
864
+ }];
865
+ }).slice(0, MAX_IMAGE_ITEMS);
866
+ }
867
+ function mergeImages(current, picked) {
868
+ const next = [...current];
869
+ const seen = new Set(current.map((item) => item.url));
870
+ for (const item of normalizeImages(picked)) {
871
+ if (seen.has(item.url)) continue;
872
+ seen.add(item.url);
873
+ next.push(item);
874
+ if (next.length === MAX_IMAGE_ITEMS) break;
875
+ }
876
+ return next;
877
+ }
878
+ function partitionAttachments(value) {
879
+ const values = Array.isArray(value) ? value : value ? [value] : [];
880
+ const context = [];
881
+ const images = [];
882
+ for (const item of values) {
883
+ if (item && typeof item.label === "string" && item.label.trim() && typeof item.detail === "string" && item.detail) context.push(item);
884
+ else if (item && typeof item.label === "string" && item.label.trim() && typeof item.url === "string" && (item.url.startsWith("data:image/") || item.url.startsWith("https://") || item.url.startsWith("http://"))) images.push(item);
885
+ else throw new Error("The attachment picker returned an invalid item.");
886
+ }
887
+ return { context, images };
888
+ }
889
+ async function imageAttachmentsFromFiles(value) {
890
+ const files = Array.from(value ?? []).filter((file) => file?.type?.startsWith("image/"));
891
+ if (files.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images at a time.`);
892
+ return Promise.all(files.map(async (file) => {
893
+ if (!IMAGE_TYPES.has(file.type)) throw new Error(`${file.name || "That image"} is not PNG, JPEG, GIF, or WebP.`);
894
+ if (file.size > MAX_IMAGE_BYTES) throw new Error(`${file.name || "That image"} is larger than 5 MB.`);
895
+ const url = await new Promise((resolve, reject) => {
896
+ const reader = new FileReader();
897
+ reader.onload = () => resolve(reader.result);
898
+ reader.onerror = () => reject(reader.error ?? new Error(`Could not read ${file.name || "image"}.`));
899
+ reader.readAsDataURL(file);
900
+ });
901
+ return { id: `${file.name}:${file.size}:${file.lastModified}`, label: file.name || "Pasted image", url };
902
+ }));
903
+ }
904
+ function ContextTray({ items, onRemove }) {
905
+ if (!items.length) return null;
906
+ return /* @__PURE__ */ jsx2("div", { class: "scui-compose-context", "aria-label": "Attached context", children: items.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
907
+ /* @__PURE__ */ jsx2(UiIcon, { name: "attach", size: 12 }),
908
+ /* @__PURE__ */ jsx2("strong", { children: item.label }),
909
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove context ${item.label}`, onClick: () => onRemove(index), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 12 }) })
910
+ ] }, item.id ?? `${item.label}:${index}`)) });
911
+ }
912
+ function ImageTray({ items, onRemove }) {
913
+ if (!items.length) return null;
914
+ return /* @__PURE__ */ jsx2("div", { class: "scui-compose-images", "aria-label": "Attached images", children: items.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
915
+ /* @__PURE__ */ jsx2("img", { src: item.url, alt: "" }),
916
+ /* @__PURE__ */ jsx2("strong", { children: item.label }),
917
+ 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
+ ] }, item.id ?? `${item.label}:${index}`)) });
919
+ }
920
+ function MessageImages({ items }) {
921
+ 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}`)) });
926
+ }
927
+
804
928
  // src/textarea.js
805
929
  import { useLayoutEffect } from "preact/hooks";
806
930
  function useAutosizeTextarea(ref, value) {
@@ -816,7 +940,7 @@ function useAutosizeTextarea(ref, value) {
816
940
  }
817
941
 
818
942
  // src/composer.jsx
819
- import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
943
+ import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
820
944
  var composerMemory = /* @__PURE__ */ new Map();
821
945
  function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
822
946
  if (state.mode !== "mirror" || state.canSend) return null;
@@ -826,29 +950,36 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
826
950
  const resume = canContinueHere(state);
827
951
  const join = state.canAttach;
828
952
  const branch = state.canBranch;
829
- if (!resume && !join && !branch) return /* @__PURE__ */ jsx2("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs2("span", { children: [
830
- /* @__PURE__ */ jsx2("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
831
- /* @__PURE__ */ jsx2("small", { children: "This session cannot be continued by an available harness." })
953
+ if (!resume && !join && !branch) return /* @__PURE__ */ jsx3("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
954
+ /* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
955
+ /* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
832
956
  ] }) });
833
- return /* @__PURE__ */ jsxs2("div", { class: "scui-continuation", children: [
834
- /* @__PURE__ */ jsxs2("span", { children: [
835
- /* @__PURE__ */ jsx2("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
836
- /* @__PURE__ */ jsx2("small", { children: join ? "Join the proven live runtime without taking it over." : resume ? `Resume this ${harnessDisplayName(state.harness)} session here.` : "Start an independent continuation." })
957
+ return /* @__PURE__ */ jsxs3("div", { class: "scui-continuation", children: [
958
+ /* @__PURE__ */ jsxs3("span", { children: [
959
+ /* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
960
+ /* @__PURE__ */ jsx3("small", { children: join ? "Join the proven live runtime without taking it over." : resume ? `Resume this ${harnessDisplayName(state.harness)} session here.` : "Start an independent continuation." })
837
961
  ] }),
838
- /* @__PURE__ */ jsx2("button", { type: "button", disabled: Boolean(state.operation), onClick: () => adapter.onIntent(join ? { action: "join" } : resume ? { action: "resume" } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
962
+ /* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => adapter.onIntent(join ? { action: "join" } : resume ? { action: "resume" } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
839
963
  ] });
840
964
  }
841
965
  function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
842
- const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
966
+ const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, context: [], images: [], queue: [] };
843
967
  const [draft, setDraft] = useState(remembered.draft);
844
- const [queue, setQueue] = useState(remembered.queue);
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 ?? [] })));
845
971
  const [dispatching, setDispatching] = useState(false);
972
+ const [picking, setPicking] = useState(false);
973
+ const [pickerError, setPickerError] = useState(null);
846
974
  const textarea = useRef(null);
847
975
  useAutosizeTextarea(textarea, draft);
848
- const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
976
+ const remember = (nextDraft, nextContext, nextImages, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, context: nextContext, images: nextImages, queue: nextQueue });
977
+ useEffect(() => {
978
+ remember(draft, context, images, queue);
979
+ }, [draft, context, images, memoryKey, queue]);
849
980
  const updateQueue = (update) => setQueue((items) => {
850
981
  const next = update(items);
851
- remember(draft, next);
982
+ remember(draft, context, images, next);
852
983
  return next;
853
984
  });
854
985
  const queueBlocked = state.busy || pendingStatus !== null || dispatching;
@@ -858,9 +989,9 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
858
989
  const [next, ...rest] = queue;
859
990
  setDispatching(true);
860
991
  setQueue(rest);
861
- remember(draft, rest);
862
- onPending?.(next);
863
- adapter.onIntent({ action: "send", text: next });
992
+ remember(draft, context, images, rest);
993
+ onPending?.(next.text, next.context, next.images);
994
+ adapter.onIntent({ action: "send", text: next.text, ...next.context.length ? { context: next.context } : {}, ...next.images.length ? { images: next.images } : {} });
864
995
  }
865
996
  }, [adapter, draft, memoryKey, onPending, queue, queueBlocked, state.canSend]);
866
997
  useEffect(() => {
@@ -872,7 +1003,11 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
872
1003
  useEffect(() => {
873
1004
  if (!restoreDraft) return;
874
1005
  setDraft(restoreDraft.text);
875
- remember(restoreDraft.text, queue);
1006
+ const restoredContext = normalizeContext(restoreDraft.context);
1007
+ const restoredImages = normalizeImages(restoreDraft.images);
1008
+ setContext(restoredContext);
1009
+ setImages(restoredImages);
1010
+ remember(restoreDraft.text, restoredContext, restoredImages, queue);
876
1011
  textarea.current?.focus({ preventScroll: true });
877
1012
  onDraftRestored?.(restoreDraft.id);
878
1013
  }, [onDraftRestored, restoreDraft?.id]);
@@ -880,43 +1015,100 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
880
1015
  const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
881
1016
  return () => clearTimeout(timer);
882
1017
  }, [adapter, draft]);
1018
+ const pickContext = () => {
1019
+ if (!adapter.pickContext || state.mode !== "control" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS) return;
1020
+ setPicking(true);
1021
+ setPickerError(null);
1022
+ Promise.resolve().then(() => adapter.pickContext()).then((picked) => {
1023
+ const attachments = partitionAttachments(picked);
1024
+ if (context.length + attachments.context.length > MAX_CONTEXT_ITEMS) throw new Error(`Attach at most ${MAX_CONTEXT_ITEMS} text items.`);
1025
+ if (images.length + attachments.images.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
1026
+ setContext((current) => {
1027
+ const next = mergeContext(current, attachments.context);
1028
+ remember(draft, next, images, queue);
1029
+ return next;
1030
+ });
1031
+ setImages((current) => {
1032
+ const next = mergeImages(current, attachments.images);
1033
+ remember(draft, context, next, queue);
1034
+ return next;
1035
+ });
1036
+ }).catch((error) => setPickerError(error instanceof Error ? error.message : "Could not attach context.")).finally(() => setPicking(false));
1037
+ };
1038
+ const pasteImages = (event) => {
1039
+ const files = Array.from(event.clipboardData?.files ?? []).filter((file) => file.type.startsWith("image/"));
1040
+ if (!files.length) return;
1041
+ event.preventDefault();
1042
+ if (images.length + files.length > MAX_IMAGE_ITEMS) {
1043
+ setPickerError(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
1044
+ return;
1045
+ }
1046
+ setPicking(true);
1047
+ setPickerError(null);
1048
+ imageAttachmentsFromFiles(files).then((picked) => setImages((current) => {
1049
+ const next = mergeImages(current, picked);
1050
+ remember(draft, context, next, queue);
1051
+ return next;
1052
+ }), (error) => setPickerError(error instanceof Error ? error.message : "Could not paste image.")).finally(() => setPicking(false));
1053
+ };
883
1054
  const send = () => {
884
1055
  const text = draft.trim();
885
1056
  if (!text) return;
886
- if (queuesNewMessage) updateQueue((items) => [...items, text]);
1057
+ const message = { text, context, images };
1058
+ if (queuesNewMessage) updateQueue((items) => [...items, message]);
887
1059
  else if (state.canSend) {
888
1060
  if (onPending) setDispatching(true);
889
- onPending?.(text);
890
- adapter.onIntent({ action: "send", text });
1061
+ onPending?.(text, context, images);
1062
+ adapter.onIntent({ action: "send", text, ...context.length ? { context } : {}, ...images.length ? { images } : {} });
891
1063
  } else return;
892
1064
  setDraft("");
893
- remember("", queuesNewMessage ? [...queue, text] : queue);
1065
+ setContext([]);
1066
+ setImages([]);
1067
+ remember("", [], [], queuesNewMessage ? [...queue, message] : queue);
894
1068
  };
895
- return /* @__PURE__ */ jsxs2("div", { class: "scui-compose", children: [
896
- queue.length ? /* @__PURE__ */ jsxs2("div", { class: "scui-queue", children: [
897
- /* @__PURE__ */ jsxs2("strong", { children: [
1069
+ return /* @__PURE__ */ jsxs3("div", { class: "scui-compose", children: [
1070
+ queue.length ? /* @__PURE__ */ jsxs3("div", { class: "scui-queue", children: [
1071
+ /* @__PURE__ */ jsxs3("strong", { children: [
898
1072
  queue.length,
899
1073
  " queued"
900
1074
  ] }),
901
- queue.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
902
- item,
903
- /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 13 }) })
904
- ] }, `${index}:${item}`))
1075
+ queue.map((item, index) => /* @__PURE__ */ jsxs3("span", { children: [
1076
+ /* @__PURE__ */ jsxs3("span", { children: [
1077
+ item.text,
1078
+ item.context.length + item.images.length ? /* @__PURE__ */ jsxs3("small", { children: [
1079
+ item.context.length + item.images.length,
1080
+ " attached"
1081
+ ] }) : null
1082
+ ] }),
1083
+ /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: /* @__PURE__ */ jsx3(UiIcon, { name: "close", size: 13 }) })
1084
+ ] }, `${index}:${item.text}`))
905
1085
  ] }) : null,
906
- /* @__PURE__ */ jsxs2("div", { class: "scui-envelope", children: [
907
- /* @__PURE__ */ jsx2("textarea", { ref: textarea, rows: 1, "aria-label": `Message ${harnessDisplayName(state.harness) || "agent"}`, placeholder: state.startup !== "ready" ? "Connecting\u2026" : pendingStatus === "failed" ? "Retry or edit the unsent message\u2026" : pendingStatus === "editing" ? "Edit and resend\u2026" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onInput: (event) => {
1086
+ /* @__PURE__ */ jsx3(ImageTray, { items: images, onRemove: (index) => setImages((items) => {
1087
+ const next = items.filter((_, itemIndex) => itemIndex !== index);
1088
+ remember(draft, context, next, queue);
1089
+ return next;
1090
+ }) }),
1091
+ /* @__PURE__ */ jsx3(ContextTray, { items: context, onRemove: (index) => setContext((items) => {
1092
+ const next = items.filter((_, itemIndex) => itemIndex !== index);
1093
+ remember(draft, next, images, queue);
1094
+ return next;
1095
+ }) }),
1096
+ pickerError ? /* @__PURE__ */ jsx3("small", { class: "scui-context-error", role: "alert", children: pickerError }) : null,
1097
+ /* @__PURE__ */ jsxs3("div", { class: "scui-envelope", children: [
1098
+ adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { class: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS, onClick: pickContext, children: picking ? /* @__PURE__ */ jsx3("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx3(UiIcon, { name: "attach", size: 17 }) }) : null,
1099
+ /* @__PURE__ */ jsx3("textarea", { ref: textarea, rows: 1, "aria-label": `Message ${harnessDisplayName(state.harness) || "agent"}`, placeholder: state.startup !== "ready" ? "Connecting\u2026" : pendingStatus === "failed" ? "Retry or edit the unsent message\u2026" : pendingStatus === "editing" ? "Edit and resend\u2026" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onPaste: pasteImages, onInput: (event) => {
908
1100
  const value = event.currentTarget.value;
909
1101
  setDraft(value);
910
- remember(value, queue);
1102
+ remember(value, context, images, queue);
911
1103
  }, onKeyDown: (event) => {
912
1104
  if (isSendKey(event)) {
913
1105
  event.preventDefault();
914
1106
  send();
915
1107
  }
916
1108
  } }),
917
- /* @__PURE__ */ jsxs2("span", { children: [
918
- state.busy ? /* @__PURE__ */ jsx2("button", { class: "scui-stop", type: "button", "aria-label": "Stop agent", disabled: !state.canInterrupt, onClick: () => adapter.onIntent({ action: "interrupt" }), children: /* @__PURE__ */ jsx2(UiIcon, { name: "stop", size: 15 }) }) : null,
919
- /* @__PURE__ */ jsx2("button", { class: "scui-send", type: "button", "aria-label": queuesNewMessage ? "Queue message" : "Send message", disabled: !draft.trim() || !queuesNewMessage && !state.canSend, onClick: send, children: /* @__PURE__ */ jsx2(UiIcon, { name: queuesNewMessage ? "plus" : "send", size: 17 }) })
1109
+ /* @__PURE__ */ jsxs3("span", { children: [
1110
+ state.busy ? /* @__PURE__ */ jsx3("button", { class: "scui-stop", type: "button", "aria-label": "Stop agent", disabled: !state.canInterrupt, onClick: () => adapter.onIntent({ action: "interrupt" }), children: /* @__PURE__ */ jsx3(UiIcon, { name: "stop", size: 15 }) }) : null,
1111
+ /* @__PURE__ */ jsx3("button", { class: "scui-send", type: "button", "aria-label": queuesNewMessage ? "Queue message" : "Send message", disabled: !draft.trim() || !queuesNewMessage && !state.canSend, onClick: send, children: /* @__PURE__ */ jsx3(UiIcon, { name: queuesNewMessage ? "plus" : "send", size: 17 }) })
920
1112
  ] })
921
1113
  ] })
922
1114
  ] });
@@ -929,7 +1121,7 @@ import { useEffect as useEffect3, useId, useLayoutEffect as useLayoutEffect2, us
929
1121
  // src/markdown.jsx
930
1122
  import MarkdownIt from "markdown-it";
931
1123
  import { useEffect as useEffect2, useMemo, useRef as useRef2 } from "preact/hooks";
932
- import { jsx as jsx3 } from "preact/jsx-runtime";
1124
+ import { jsx as jsx4 } from "preact/jsx-runtime";
933
1125
  var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
934
1126
  var LANGUAGE_LABELS = {
935
1127
  bash: "Shell",
@@ -1016,11 +1208,11 @@ function Markdown({ value, copyText }) {
1016
1208
  }, 1500);
1017
1209
  resets.current.set(button, timer);
1018
1210
  };
1019
- return /* @__PURE__ */ jsx3("div", { class: "scui-markdown", "data-copyable": Boolean(copyText), onClick: copyCode, dangerouslySetInnerHTML: { __html: html } });
1211
+ return /* @__PURE__ */ jsx4("div", { class: "scui-markdown", "data-copyable": Boolean(copyText), onClick: copyCode, dangerouslySetInnerHTML: { __html: html } });
1020
1212
  }
1021
1213
 
1022
1214
  // src/conversation.jsx
1023
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "preact/jsx-runtime";
1215
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
1024
1216
  function LoadingStatus({ state, compact = false }) {
1025
1217
  const copy = {
1026
1218
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -1028,43 +1220,43 @@ function LoadingStatus({ state, compact = false }) {
1028
1220
  discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
1029
1221
  ready: ["Ready", "Coding sessions are up to date.", 3]
1030
1222
  }[state.startup];
1031
- return /* @__PURE__ */ jsxs3("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
1032
- /* @__PURE__ */ jsx4("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("i", {}) }),
1033
- /* @__PURE__ */ jsxs3("span", { class: "scui-loading-copy", children: [
1034
- /* @__PURE__ */ jsx4("strong", { children: copy[0] }),
1035
- /* @__PURE__ */ jsx4("small", { children: copy[1] })
1223
+ return /* @__PURE__ */ jsxs4("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
1224
+ /* @__PURE__ */ jsx5("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx5("i", {}) }),
1225
+ /* @__PURE__ */ jsxs4("span", { class: "scui-loading-copy", children: [
1226
+ /* @__PURE__ */ jsx5("strong", { children: copy[0] }),
1227
+ /* @__PURE__ */ jsx5("small", { children: copy[1] })
1036
1228
  ] }),
1037
- /* @__PURE__ */ jsx4("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx4("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
1229
+ /* @__PURE__ */ jsx5("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx5("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
1038
1230
  ] });
1039
1231
  }
1040
1232
  function RequestCard({ entry, adapter, canRespond }) {
1041
1233
  const request = entry.request;
1042
1234
  if (!request) return null;
1043
1235
  if (request.status === "responded") {
1044
- return /* @__PURE__ */ jsxs3("div", { class: "scui-request-done", children: [
1236
+ return /* @__PURE__ */ jsxs4("div", { class: "scui-request-done", children: [
1045
1237
  "\u2713 Request answered \xB7 ",
1046
1238
  request.resolution?.name ?? request.requestKind
1047
1239
  ] });
1048
1240
  }
1049
- return /* @__PURE__ */ jsxs3("section", { class: "scui-request", role: "alert", "aria-label": `${request.requestKind} needs input`, children: [
1050
- /* @__PURE__ */ jsx4("strong", { children: "Agent needs input" }),
1051
- /* @__PURE__ */ jsx4(Markdown, { value: request.payloadText || entry.text, copyText: adapter?.copyText }),
1052
- /* @__PURE__ */ jsxs3("div", { class: "scui-request-actions", children: [
1053
- request.options.map((option) => /* @__PURE__ */ jsx4("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: option.optionId }), children: option.name }, option.optionId)),
1054
- request.cancellable ? /* @__PURE__ */ jsx4("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
1241
+ return /* @__PURE__ */ jsxs4("section", { class: "scui-request", role: "alert", "aria-label": `${request.requestKind} needs input`, children: [
1242
+ /* @__PURE__ */ jsx5("strong", { children: "Agent needs input" }),
1243
+ /* @__PURE__ */ jsx5(Markdown, { value: request.payloadText || entry.text, copyText: adapter?.copyText }),
1244
+ /* @__PURE__ */ jsxs4("div", { class: "scui-request-actions", children: [
1245
+ request.options.map((option) => /* @__PURE__ */ jsx5("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: option.optionId }), children: option.name }, option.optionId)),
1246
+ request.cancellable ? /* @__PURE__ */ jsx5("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
1055
1247
  ] })
1056
1248
  ] });
1057
1249
  }
1058
1250
  function ContextDisclosure({ context }) {
1059
1251
  if (!context?.length) return null;
1060
- return /* @__PURE__ */ jsxs3("details", { class: "scui-context", children: [
1061
- /* @__PURE__ */ jsxs3("summary", { children: [
1252
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-context", children: [
1253
+ /* @__PURE__ */ jsxs4("summary", { children: [
1062
1254
  "Context \xB7 ",
1063
1255
  context.length
1064
1256
  ] }),
1065
- /* @__PURE__ */ jsx4("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs3("p", { children: [
1066
- /* @__PURE__ */ jsx4("strong", { children: item.label }),
1067
- /* @__PURE__ */ jsx4("span", { children: item.detail })
1257
+ /* @__PURE__ */ jsx5("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs4("p", { children: [
1258
+ /* @__PURE__ */ jsx5("strong", { children: item.label }),
1259
+ /* @__PURE__ */ jsx5("span", { children: item.detail })
1068
1260
  ] }, item.id ?? index)) })
1069
1261
  ] });
1070
1262
  }
@@ -1086,46 +1278,46 @@ function MessageMeta({ entry, adapter }) {
1086
1278
  reset.current = setTimeout(() => setCopyState2("idle"), 1500);
1087
1279
  };
1088
1280
  const copyLabel = copyState === "copied" ? "Message copied" : copyState === "failed" ? "Copy failed \xB7 retry" : "Copy message";
1089
- return /* @__PURE__ */ jsxs3("footer", { class: "scui-message-meta", children: [
1090
- validDate ? /* @__PURE__ */ jsx4("time", { dateTime: validDate.toISOString(), title: validDate.toLocaleString(), children: validDate.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }) : null,
1091
- adapter?.copyText && entry.text ? /* @__PURE__ */ jsx4("button", { type: "button", "aria-label": copyLabel, title: copyLabel, onClick: copy, "data-status": copyState, children: /* @__PURE__ */ jsx4(UiIcon, { name: "copy", size: 13 }) }) : null
1281
+ return /* @__PURE__ */ jsxs4("footer", { class: "scui-message-meta", children: [
1282
+ validDate ? /* @__PURE__ */ jsx5("time", { dateTime: validDate.toISOString(), title: validDate.toLocaleString(), children: validDate.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }) : null,
1283
+ adapter?.copyText && entry.text ? /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": copyLabel, title: copyLabel, onClick: copy, "data-status": copyState, children: /* @__PURE__ */ jsx5(UiIcon, { name: "copy", size: 13 }) }) : null
1092
1284
  ] });
1093
1285
  }
1094
1286
  var TOOL_ICONS = {
1095
- read: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1096
- /* @__PURE__ */ jsx4("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" }),
1097
- /* @__PURE__ */ jsx4("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
1287
+ read: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1288
+ /* @__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" }),
1289
+ /* @__PURE__ */ jsx5("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
1098
1290
  ] }),
1099
- search: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1100
- /* @__PURE__ */ jsx4("circle", { cx: "8", cy: "8", r: "4.5" }),
1101
- /* @__PURE__ */ jsx4("path", { d: "m11.5 11.5 3 3" })
1291
+ search: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1292
+ /* @__PURE__ */ jsx5("circle", { cx: "8", cy: "8", r: "4.5" }),
1293
+ /* @__PURE__ */ jsx5("path", { d: "m11.5 11.5 3 3" })
1102
1294
  ] }),
1103
- edit: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1104
- /* @__PURE__ */ jsx4("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
1105
- /* @__PURE__ */ jsx4("path", { d: "m10 5 3 3" })
1295
+ edit: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1296
+ /* @__PURE__ */ jsx5("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
1297
+ /* @__PURE__ */ jsx5("path", { d: "m10 5 3 3" })
1106
1298
  ] }),
1107
- command: () => /* @__PURE__ */ jsx4(Fragment3, { children: /* @__PURE__ */ jsx4("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
1108
- test: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1109
- /* @__PURE__ */ jsx4("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" }),
1110
- /* @__PURE__ */ jsx4("path", { d: "M5 2.5h8" })
1299
+ command: () => /* @__PURE__ */ jsx5(Fragment3, { children: /* @__PURE__ */ jsx5("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
1300
+ test: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1301
+ /* @__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" }),
1302
+ /* @__PURE__ */ jsx5("path", { d: "M5 2.5h8" })
1111
1303
  ] }),
1112
- web: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1113
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "6.5" }),
1114
- /* @__PURE__ */ jsx4("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" })
1304
+ web: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1305
+ /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "6.5" }),
1306
+ /* @__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" })
1115
1307
  ] }),
1116
- agent: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1117
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "6", r: "2.5" }),
1118
- /* @__PURE__ */ jsx4("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
1308
+ agent: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1309
+ /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "6", r: "2.5" }),
1310
+ /* @__PURE__ */ jsx5("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
1119
1311
  ] }),
1120
- plan: () => /* @__PURE__ */ jsx4(Fragment3, { children: /* @__PURE__ */ jsx4("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
1121
- other: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1122
- /* @__PURE__ */ jsx4("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
1123
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "3.5" })
1312
+ 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" }) }),
1313
+ other: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1314
+ /* @__PURE__ */ jsx5("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
1315
+ /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "3.5" })
1124
1316
  ] })
1125
1317
  };
1126
1318
  function ToolIcon({ category }) {
1127
1319
  const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
1128
- return /* @__PURE__ */ jsx4("svg", { class: "scui-tool-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.35", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(Glyph, {}) });
1320
+ return /* @__PURE__ */ jsx5("svg", { class: "scui-tool-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.35", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx5(Glyph, {}) });
1129
1321
  }
1130
1322
  function toolAction2(entry, category, presentation) {
1131
1323
  if (presentation?.action) return presentation.action;
@@ -1180,7 +1372,7 @@ function ToolMetrics({ presentation }) {
1180
1372
  presentation.exitCode === null ? "" : `exit ${presentation.exitCode}`,
1181
1373
  formatDuration(presentation.durationMs)
1182
1374
  ].filter(Boolean);
1183
- return metrics.length ? /* @__PURE__ */ jsx4("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx4("span", { children: metric }, metric)) }) : null;
1375
+ return metrics.length ? /* @__PURE__ */ jsx5("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx5("span", { children: metric }, metric)) }) : null;
1184
1376
  }
1185
1377
  function PendingElapsed({ now }) {
1186
1378
  const clock = now ?? Date.now;
@@ -1190,74 +1382,74 @@ function PendingElapsed({ now }) {
1190
1382
  const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
1191
1383
  return () => clearInterval(timer);
1192
1384
  }, [clock]);
1193
- return /* @__PURE__ */ jsx4("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
1385
+ return /* @__PURE__ */ jsx5("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
1194
1386
  }
1195
1387
  function LinePreview({ value, kind }) {
1196
1388
  if (!value) return null;
1197
- return /* @__PURE__ */ jsx4("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
1389
+ return /* @__PURE__ */ jsx5("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
1198
1390
  const tone = kind === "diff" ? line.startsWith("+") && !line.startsWith("+++") ? "add" : line.startsWith("-") && !line.startsWith("---") ? "remove" : line.startsWith("@@") ? "hunk" : "plain" : "plain";
1199
- return /* @__PURE__ */ jsxs3("li", { "data-tone": tone, children: [
1200
- /* @__PURE__ */ jsx4("span", { children: index + 1 }),
1201
- /* @__PURE__ */ jsx4("code", { children: line || " " })
1391
+ return /* @__PURE__ */ jsxs4("li", { "data-tone": tone, children: [
1392
+ /* @__PURE__ */ jsx5("span", { children: index + 1 }),
1393
+ /* @__PURE__ */ jsx5("code", { children: line || " " })
1202
1394
  ] }, index);
1203
1395
  }) });
1204
1396
  }
1205
1397
  function TerminalPreview({ presentation, pending, failed }) {
1206
- return /* @__PURE__ */ jsxs3("section", { class: "scui-terminal", children: [
1207
- /* @__PURE__ */ jsxs3("header", { children: [
1208
- /* @__PURE__ */ jsxs3("span", { "aria-hidden": "true", children: [
1209
- /* @__PURE__ */ jsx4("i", {}),
1210
- /* @__PURE__ */ jsx4("i", {}),
1211
- /* @__PURE__ */ jsx4("i", {})
1398
+ return /* @__PURE__ */ jsxs4("section", { class: "scui-terminal", children: [
1399
+ /* @__PURE__ */ jsxs4("header", { children: [
1400
+ /* @__PURE__ */ jsxs4("span", { "aria-hidden": "true", children: [
1401
+ /* @__PURE__ */ jsx5("i", {}),
1402
+ /* @__PURE__ */ jsx5("i", {}),
1403
+ /* @__PURE__ */ jsx5("i", {})
1212
1404
  ] }),
1213
- /* @__PURE__ */ jsx4("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
1405
+ /* @__PURE__ */ jsx5("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
1214
1406
  ] }),
1215
- presentation.preview ? /* @__PURE__ */ jsx4("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs3("div", { class: "scui-terminal-wait", children: [
1216
- /* @__PURE__ */ jsx4("i", {}),
1407
+ presentation.preview ? /* @__PURE__ */ jsx5("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs4("div", { class: "scui-terminal-wait", children: [
1408
+ /* @__PURE__ */ jsx5("i", {}),
1217
1409
  " Waiting for output"
1218
- ] }) : /* @__PURE__ */ jsx4("div", { class: "scui-terminal-empty", children: "No output" })
1410
+ ] }) : /* @__PURE__ */ jsx5("div", { class: "scui-terminal-empty", children: "No output" })
1219
1411
  ] });
1220
1412
  }
1221
1413
  function SearchPreview({ presentation }) {
1222
1414
  const lines = stripAnsi(presentation.preview).split("\n").filter(Boolean);
1223
- return /* @__PURE__ */ jsxs3("section", { class: "scui-search-preview", children: [
1224
- presentation.query ? /* @__PURE__ */ jsxs3("header", { children: [
1225
- /* @__PURE__ */ jsx4("span", { children: "Search" }),
1226
- /* @__PURE__ */ jsx4("code", { children: presentation.query })
1415
+ return /* @__PURE__ */ jsxs4("section", { class: "scui-search-preview", children: [
1416
+ presentation.query ? /* @__PURE__ */ jsxs4("header", { children: [
1417
+ /* @__PURE__ */ jsx5("span", { children: "Search" }),
1418
+ /* @__PURE__ */ jsx5("code", { children: presentation.query })
1227
1419
  ] }) : null,
1228
- lines.length ? /* @__PURE__ */ jsx4("ol", { children: lines.map((line, index) => {
1420
+ lines.length ? /* @__PURE__ */ jsx5("ol", { children: lines.map((line, index) => {
1229
1421
  const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
1230
- return /* @__PURE__ */ jsx4("li", { children: match ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
1231
- /* @__PURE__ */ jsx4("code", { children: match[1] }),
1232
- /* @__PURE__ */ jsxs3("small", { children: [
1422
+ return /* @__PURE__ */ jsx5("li", { children: match ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
1423
+ /* @__PURE__ */ jsx5("code", { children: match[1] }),
1424
+ /* @__PURE__ */ jsxs4("small", { children: [
1233
1425
  match[2],
1234
1426
  match[3] ? `:${match[3]}` : ""
1235
1427
  ] }),
1236
- /* @__PURE__ */ jsx4("span", { children: match[4] })
1237
- ] }) : /* @__PURE__ */ jsx4("span", { children: line }) }, index);
1238
- }) }) : /* @__PURE__ */ jsx4("p", { children: "No textual results" })
1428
+ /* @__PURE__ */ jsx5("span", { children: match[4] })
1429
+ ] }) : /* @__PURE__ */ jsx5("span", { children: line }) }, index);
1430
+ }) }) : /* @__PURE__ */ jsx5("p", { children: "No textual results" })
1239
1431
  ] });
1240
1432
  }
1241
1433
  function ToolPreview({ presentation, entry }) {
1242
1434
  const pending = entry.status === "pending";
1243
1435
  const failed = entry.status === "error";
1244
- if (presentation.detail === "terminal") return /* @__PURE__ */ jsx4(TerminalPreview, { presentation, pending, failed });
1245
- if (presentation.detail === "diff") return presentation.preview ? /* @__PURE__ */ jsx4(LinePreview, { value: presentation.preview, kind: "diff" }) : /* @__PURE__ */ jsx4("div", { class: "scui-tool-empty", children: "Edit completed without a textual diff" });
1246
- if (presentation.detail === "file") return presentation.preview ? /* @__PURE__ */ jsx4(LinePreview, { value: presentation.preview, kind: "file" }) : /* @__PURE__ */ jsx4("div", { class: "scui-tool-empty", children: "File contents were not included in this event" });
1247
- if (presentation.detail === "matches") return /* @__PURE__ */ jsx4(SearchPreview, { presentation });
1248
- if (presentation.detail === "web") return /* @__PURE__ */ jsxs3("section", { class: "scui-web-preview", children: [
1249
- presentation.url ? /* @__PURE__ */ jsx4("code", { children: presentation.url }) : null,
1250
- presentation.preview ? /* @__PURE__ */ jsx4("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx4("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
1436
+ if (presentation.detail === "terminal") return /* @__PURE__ */ jsx5(TerminalPreview, { presentation, pending, failed });
1437
+ if (presentation.detail === "diff") return presentation.preview ? /* @__PURE__ */ jsx5(LinePreview, { value: presentation.preview, kind: "diff" }) : /* @__PURE__ */ jsx5("div", { class: "scui-tool-empty", children: "Edit completed without a textual diff" });
1438
+ if (presentation.detail === "file") return presentation.preview ? /* @__PURE__ */ jsx5(LinePreview, { value: presentation.preview, kind: "file" }) : /* @__PURE__ */ jsx5("div", { class: "scui-tool-empty", children: "File contents were not included in this event" });
1439
+ if (presentation.detail === "matches") return /* @__PURE__ */ jsx5(SearchPreview, { presentation });
1440
+ if (presentation.detail === "web") return /* @__PURE__ */ jsxs4("section", { class: "scui-web-preview", children: [
1441
+ presentation.url ? /* @__PURE__ */ jsx5("code", { children: presentation.url }) : null,
1442
+ presentation.preview ? /* @__PURE__ */ jsx5("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx5("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
1251
1443
  ] });
1252
- if (presentation.detail === "agent") return /* @__PURE__ */ jsx4("section", { class: "scui-agent-preview", children: presentation.items?.length ? /* @__PURE__ */ jsx4("ol", { class: "scui-agent-roster", children: presentation.items.map((item, index) => /* @__PURE__ */ jsxs3("li", { children: [
1253
- /* @__PURE__ */ jsx4("strong", { children: item.label }),
1254
- /* @__PURE__ */ jsx4("small", { children: item.status })
1255
- ] }, `${item.label}:${index}`)) }) : presentation.preview ? /* @__PURE__ */ jsx4("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx4("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
1256
- if (presentation.detail === "plan") return /* @__PURE__ */ jsx4("ol", { class: "scui-plan-preview", children: presentation.items?.map((item, index) => /* @__PURE__ */ jsxs3("li", { "data-status": item.status, children: [
1257
- /* @__PURE__ */ jsx4("i", { "aria-hidden": "true" }),
1258
- /* @__PURE__ */ jsx4("span", { children: item.label })
1444
+ if (presentation.detail === "agent") return /* @__PURE__ */ jsx5("section", { class: "scui-agent-preview", children: presentation.items?.length ? /* @__PURE__ */ jsx5("ol", { class: "scui-agent-roster", children: presentation.items.map((item, index) => /* @__PURE__ */ jsxs4("li", { children: [
1445
+ /* @__PURE__ */ jsx5("strong", { children: item.label }),
1446
+ /* @__PURE__ */ jsx5("small", { children: item.status })
1447
+ ] }, `${item.label}:${index}`)) }) : presentation.preview ? /* @__PURE__ */ jsx5("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx5("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
1448
+ if (presentation.detail === "plan") return /* @__PURE__ */ jsx5("ol", { class: "scui-plan-preview", children: presentation.items?.map((item, index) => /* @__PURE__ */ jsxs4("li", { "data-status": item.status, children: [
1449
+ /* @__PURE__ */ jsx5("i", { "aria-hidden": "true" }),
1450
+ /* @__PURE__ */ jsx5("span", { children: item.label })
1259
1451
  ] }, `${item.label}:${index}`)) });
1260
- return presentation.preview ? /* @__PURE__ */ jsx4("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
1452
+ return presentation.preview ? /* @__PURE__ */ jsx5("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
1261
1453
  }
1262
1454
  function ToolActions({ presentation, adapter }) {
1263
1455
  const [copied, setCopied] = useState2(false);
@@ -1271,27 +1463,27 @@ function ToolActions({ presentation, adapter }) {
1271
1463
  clearTimeout(reset.current);
1272
1464
  reset.current = setTimeout(() => setCopied(false), 1500);
1273
1465
  };
1274
- return action ? /* @__PURE__ */ jsx4("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx4("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
1466
+ return action ? /* @__PURE__ */ jsx5("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx5("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
1275
1467
  }
1276
1468
  function ToolStack({ tools }) {
1277
1469
  if (tools.length < 2) return null;
1278
- return /* @__PURE__ */ jsx4("div", { class: "scui-tool-stack", "aria-label": "Coordinated tools", children: tools.map((tool) => /* @__PURE__ */ jsx4("span", { children: tool.replaceAll("__", " \xB7 ").replaceAll("_", " ") }, tool)) });
1470
+ return /* @__PURE__ */ jsx5("div", { class: "scui-tool-stack", "aria-label": "Coordinated tools", children: tools.map((tool) => /* @__PURE__ */ jsx5("span", { children: tool.replaceAll("__", " \xB7 ").replaceAll("_", " ") }, tool)) });
1279
1471
  }
1280
1472
  function TechnicalDetails({ entry }) {
1281
1473
  if (!entry.arguments && !entry.resultText) return null;
1282
- return /* @__PURE__ */ jsxs3("details", { class: "scui-tool-technical", children: [
1283
- /* @__PURE__ */ jsx4("summary", { children: "Technical details" }),
1284
- /* @__PURE__ */ jsxs3("div", { children: [
1285
- entry.arguments ? /* @__PURE__ */ jsxs3("section", { children: [
1286
- /* @__PURE__ */ jsx4("strong", { children: "Native arguments" }),
1287
- /* @__PURE__ */ jsx4("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs3("div", { children: [
1288
- /* @__PURE__ */ jsx4("dt", { children: row.label }),
1289
- /* @__PURE__ */ jsx4("dd", { children: /* @__PURE__ */ jsx4("pre", { children: row.value }) })
1474
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-tool-technical", children: [
1475
+ /* @__PURE__ */ jsx5("summary", { children: "Technical details" }),
1476
+ /* @__PURE__ */ jsxs4("div", { children: [
1477
+ entry.arguments ? /* @__PURE__ */ jsxs4("section", { children: [
1478
+ /* @__PURE__ */ jsx5("strong", { children: "Native arguments" }),
1479
+ /* @__PURE__ */ jsx5("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs4("div", { children: [
1480
+ /* @__PURE__ */ jsx5("dt", { children: row.label }),
1481
+ /* @__PURE__ */ jsx5("dd", { children: /* @__PURE__ */ jsx5("pre", { children: row.value }) })
1290
1482
  ] }, row.key)) })
1291
1483
  ] }) : null,
1292
- entry.resultText ? /* @__PURE__ */ jsxs3("section", { children: [
1293
- /* @__PURE__ */ jsx4("strong", { children: "Native result" }),
1294
- /* @__PURE__ */ jsxs3("pre", { "data-error": entry.status === "error", children: [
1484
+ entry.resultText ? /* @__PURE__ */ jsxs4("section", { children: [
1485
+ /* @__PURE__ */ jsx5("strong", { children: "Native result" }),
1486
+ /* @__PURE__ */ jsxs4("pre", { "data-error": entry.status === "error", children: [
1295
1487
  entry.resultText,
1296
1488
  entry.truncated ? "\n[truncated]" : ""
1297
1489
  ] })
@@ -1300,19 +1492,20 @@ function TechnicalDetails({ entry }) {
1300
1492
  ] });
1301
1493
  }
1302
1494
  function TranscriptEntry({ entry, state, adapter }) {
1303
- if (entry.role === "request") return /* @__PURE__ */ jsx4(RequestCard, { entry, adapter, canRespond: state.canRespond });
1495
+ if (entry.role === "request") return /* @__PURE__ */ jsx5(RequestCard, { entry, adapter, canRespond: state.canRespond });
1304
1496
  if (entry.role === "reasoning") {
1305
- return /* @__PURE__ */ jsxs3("details", { class: "scui-reasoning", open: entry.streaming, children: [
1306
- /* @__PURE__ */ jsx4("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
1307
- /* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText })
1497
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-reasoning", open: entry.streaming, children: [
1498
+ /* @__PURE__ */ jsx5("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
1499
+ /* @__PURE__ */ jsx5(Markdown, { value: entry.text, copyText: adapter?.copyText })
1308
1500
  ] });
1309
1501
  }
1310
- if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx4("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
1311
- return /* @__PURE__ */ jsxs3("article", { class: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
1312
- /* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText }),
1313
- /* @__PURE__ */ jsx4(ContextDisclosure, { context: entry.context }),
1314
- entry.truncated ? /* @__PURE__ */ jsx4("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
1315
- /* @__PURE__ */ jsx4(MessageMeta, { entry, adapter })
1502
+ if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx5("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
1503
+ return /* @__PURE__ */ jsxs4("article", { class: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
1504
+ /* @__PURE__ */ jsx5(MessageImages, { items: entry.images }),
1505
+ /* @__PURE__ */ jsx5(Markdown, { value: entry.text, copyText: adapter?.copyText }),
1506
+ /* @__PURE__ */ jsx5(ContextDisclosure, { context: entry.context }),
1507
+ entry.truncated ? /* @__PURE__ */ jsx5("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
1508
+ /* @__PURE__ */ jsx5(MessageMeta, { entry, adapter })
1316
1509
  ] });
1317
1510
  }
1318
1511
  function ToolRow({ entry, workspace, open = false, adapter }) {
@@ -1324,102 +1517,102 @@ function ToolRow({ entry, workspace, open = false, adapter }) {
1324
1517
  const target = compactToolTarget(presentation.target, workspace);
1325
1518
  const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
1326
1519
  const category = presentation.category ?? toolCategory(entry);
1327
- const summary = /* @__PURE__ */ jsxs3(Fragment3, { children: [
1328
- /* @__PURE__ */ jsx4(ToolIcon, { category }),
1329
- /* @__PURE__ */ jsx4("strong", { children: toolAction2(entry, category, presentation) }),
1330
- target ? /* @__PURE__ */ jsx4("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
1331
- /* @__PURE__ */ jsx4("span", { class: "scui-spacer" }),
1332
- entry.status === "pending" ? /* @__PURE__ */ jsx4(PendingElapsed, { now: adapter?.now }) : null,
1333
- /* @__PURE__ */ jsx4("span", { class: "scui-tool-status", role: "status", "data-status": entry.status ?? "completed", "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? /* @__PURE__ */ jsx4("i", {}) : /* @__PURE__ */ jsx4(UiIcon, { name: entry.status === "error" ? "close" : "check", size: 12 }) }),
1334
- hasDetail ? /* @__PURE__ */ jsx4(UiIcon, { name: "chevron", size: 14, class: "scui-tool-chevron" }) : null
1520
+ const summary = /* @__PURE__ */ jsxs4(Fragment3, { children: [
1521
+ /* @__PURE__ */ jsx5(ToolIcon, { category }),
1522
+ /* @__PURE__ */ jsx5("strong", { children: toolAction2(entry, category, presentation) }),
1523
+ target ? /* @__PURE__ */ jsx5("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
1524
+ /* @__PURE__ */ jsx5("span", { class: "scui-spacer" }),
1525
+ entry.status === "pending" ? /* @__PURE__ */ jsx5(PendingElapsed, { now: adapter?.now }) : null,
1526
+ /* @__PURE__ */ jsx5("span", { class: "scui-tool-status", role: "status", "data-status": entry.status ?? "completed", "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? /* @__PURE__ */ jsx5("i", {}) : /* @__PURE__ */ jsx5(UiIcon, { name: entry.status === "error" ? "close" : "check", size: 12 }) }),
1527
+ hasDetail ? /* @__PURE__ */ jsx5(UiIcon, { name: "chevron", size: 14, class: "scui-tool-chevron" }) : null
1335
1528
  ] });
1336
- if (!hasDetail) return /* @__PURE__ */ jsx4("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: /* @__PURE__ */ jsx4("div", { class: "scui-tool-head", children: summary }) });
1337
- return /* @__PURE__ */ jsxs3("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
1338
- /* @__PURE__ */ jsx4("summary", { class: "scui-tool-head", children: summary }),
1339
- /* @__PURE__ */ jsxs3("div", { class: "scui-tool-detail", children: [
1340
- /* @__PURE__ */ jsx4(ToolMetrics, { presentation }),
1341
- /* @__PURE__ */ jsx4(ToolStack, { tools: presentation.tools ?? [] }),
1342
- /* @__PURE__ */ jsx4(ToolPreview, { presentation, entry }),
1343
- presentation.fields.length ? /* @__PURE__ */ jsx4("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs3("div", { children: [
1344
- /* @__PURE__ */ jsx4("dt", { children: field.label }),
1345
- /* @__PURE__ */ jsx4("dd", { children: field.value })
1529
+ if (!hasDetail) return /* @__PURE__ */ jsx5("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: /* @__PURE__ */ jsx5("div", { class: "scui-tool-head", children: summary }) });
1530
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
1531
+ /* @__PURE__ */ jsx5("summary", { class: "scui-tool-head", children: summary }),
1532
+ /* @__PURE__ */ jsxs4("div", { class: "scui-tool-detail", children: [
1533
+ /* @__PURE__ */ jsx5(ToolMetrics, { presentation }),
1534
+ /* @__PURE__ */ jsx5(ToolStack, { tools: presentation.tools ?? [] }),
1535
+ /* @__PURE__ */ jsx5(ToolPreview, { presentation, entry }),
1536
+ presentation.fields.length ? /* @__PURE__ */ jsx5("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs4("div", { children: [
1537
+ /* @__PURE__ */ jsx5("dt", { children: field.label }),
1538
+ /* @__PURE__ */ jsx5("dd", { children: field.value })
1346
1539
  ] }, field.label)) }) : null,
1347
- /* @__PURE__ */ jsx4(ToolActions, { presentation, adapter }),
1348
- /* @__PURE__ */ jsx4(TechnicalDetails, { entry })
1540
+ /* @__PURE__ */ jsx5(ToolActions, { presentation, adapter }),
1541
+ /* @__PURE__ */ jsx5(TechnicalDetails, { entry })
1349
1542
  ] })
1350
1543
  ] });
1351
1544
  }
1352
1545
  function ActivityGroup({ entries, state, adapter }) {
1353
- if (entries.length === 1) return /* @__PURE__ */ jsx4("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx4(ToolRow, { entry: entries[0], workspace: state.workspace, adapter }) });
1546
+ 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 }) });
1354
1547
  const active = entries.some((entry) => entry.status === "pending");
1355
1548
  const [open, setOpen] = useState2(active);
1356
1549
  const id = useId();
1357
1550
  useEffect3(() => {
1358
1551
  if (active) setOpen(true);
1359
1552
  }, [active]);
1360
- return /* @__PURE__ */ jsxs3("section", { class: "scui-activity", children: [
1361
- /* @__PURE__ */ jsxs3("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
1362
- /* @__PURE__ */ jsx4("span", { class: "scui-fold", "data-open": open, children: /* @__PURE__ */ jsx4(UiIcon, { name: "chevron", size: 14 }) }),
1363
- /* @__PURE__ */ jsx4("strong", { children: activitySummary(entries) }),
1364
- /* @__PURE__ */ jsx4("span", { class: "scui-spacer" }),
1365
- /* @__PURE__ */ jsxs3("small", { children: [
1553
+ return /* @__PURE__ */ jsxs4("section", { class: "scui-activity", children: [
1554
+ /* @__PURE__ */ jsxs4("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
1555
+ /* @__PURE__ */ jsx5("span", { class: "scui-fold", "data-open": open, children: /* @__PURE__ */ jsx5(UiIcon, { name: "chevron", size: 14 }) }),
1556
+ /* @__PURE__ */ jsx5("strong", { children: activitySummary(entries) }),
1557
+ /* @__PURE__ */ jsx5("span", { class: "scui-spacer" }),
1558
+ /* @__PURE__ */ jsxs4("small", { children: [
1366
1559
  entries.filter((entry) => entry.status !== "pending").length,
1367
1560
  "/",
1368
1561
  entries.length
1369
1562
  ] })
1370
1563
  ] }),
1371
- open ? /* @__PURE__ */ jsx4("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx4(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
1564
+ open ? /* @__PURE__ */ jsx5("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx5(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
1372
1565
  ] });
1373
1566
  }
1374
1567
  function TaskPlan({ plan }) {
1375
1568
  if (!plan.items.length) return null;
1376
1569
  const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
1377
- return /* @__PURE__ */ jsxs3("details", { class: "scui-plan", children: [
1378
- /* @__PURE__ */ jsxs3("summary", { children: [
1379
- /* @__PURE__ */ jsx4("span", { children: "Plan" }),
1380
- /* @__PURE__ */ jsxs3("small", { children: [
1570
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-plan", children: [
1571
+ /* @__PURE__ */ jsxs4("summary", { children: [
1572
+ /* @__PURE__ */ jsx5("span", { children: "Plan" }),
1573
+ /* @__PURE__ */ jsxs4("small", { children: [
1381
1574
  complete,
1382
1575
  "/",
1383
1576
  plan.items.length
1384
1577
  ] })
1385
1578
  ] }),
1386
- /* @__PURE__ */ jsx4("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs3("li", { "data-status": item.status, children: [
1387
- /* @__PURE__ */ jsx4("i", { "aria-hidden": "true" }),
1579
+ /* @__PURE__ */ jsx5("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs4("li", { "data-status": item.status, children: [
1580
+ /* @__PURE__ */ jsx5("i", { "aria-hidden": "true" }),
1388
1581
  " ",
1389
- /* @__PURE__ */ jsx4("span", { children: item.title })
1582
+ /* @__PURE__ */ jsx5("span", { children: item.title })
1390
1583
  ] }, item.id)) })
1391
1584
  ] });
1392
1585
  }
1393
1586
  function SessionDetails({ semantics }) {
1394
1587
  if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
1395
- return /* @__PURE__ */ jsxs3("details", { class: "scui-details", children: [
1396
- /* @__PURE__ */ jsx4("summary", { children: "Session details" }),
1397
- /* @__PURE__ */ jsxs3("div", { children: [
1398
- semantics.fidelity ? /* @__PURE__ */ jsxs3("p", { children: [
1399
- /* @__PURE__ */ jsx4("strong", { children: "Fidelity" }),
1400
- /* @__PURE__ */ jsx4("span", { children: semantics.fidelity.replaceAll("_", " ") })
1588
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-details", children: [
1589
+ /* @__PURE__ */ jsx5("summary", { children: "Session details" }),
1590
+ /* @__PURE__ */ jsxs4("div", { children: [
1591
+ semantics.fidelity ? /* @__PURE__ */ jsxs4("p", { children: [
1592
+ /* @__PURE__ */ jsx5("strong", { children: "Fidelity" }),
1593
+ /* @__PURE__ */ jsx5("span", { children: semantics.fidelity.replaceAll("_", " ") })
1401
1594
  ] }) : null,
1402
- /* @__PURE__ */ jsxs3("p", { children: [
1403
- /* @__PURE__ */ jsx4("strong", { children: "Native records" }),
1404
- /* @__PURE__ */ jsx4("span", { children: semantics.rawRecords })
1595
+ /* @__PURE__ */ jsxs4("p", { children: [
1596
+ /* @__PURE__ */ jsx5("strong", { children: "Native records" }),
1597
+ /* @__PURE__ */ jsx5("span", { children: semantics.rawRecords })
1405
1598
  ] }),
1406
- semantics.residueCount ? /* @__PURE__ */ jsxs3("p", { children: [
1407
- /* @__PURE__ */ jsx4("strong", { children: "Residue" }),
1408
- /* @__PURE__ */ jsxs3("span", { children: [
1599
+ semantics.residueCount ? /* @__PURE__ */ jsxs4("p", { children: [
1600
+ /* @__PURE__ */ jsx5("strong", { children: "Residue" }),
1601
+ /* @__PURE__ */ jsxs4("span", { children: [
1409
1602
  semantics.residueCount,
1410
1603
  " retained"
1411
1604
  ] })
1412
1605
  ] }) : null,
1413
- semantics.parseErrors ? /* @__PURE__ */ jsxs3("p", { children: [
1414
- /* @__PURE__ */ jsx4("strong", { children: "Parse diagnostics" }),
1415
- /* @__PURE__ */ jsx4("span", { children: semantics.parseErrors })
1606
+ semantics.parseErrors ? /* @__PURE__ */ jsxs4("p", { children: [
1607
+ /* @__PURE__ */ jsx5("strong", { children: "Parse diagnostics" }),
1608
+ /* @__PURE__ */ jsx5("span", { children: semantics.parseErrors })
1416
1609
  ] }) : null,
1417
- semantics.subagents.map((agent) => /* @__PURE__ */ jsxs3("p", { children: [
1418
- /* @__PURE__ */ jsxs3("strong", { children: [
1610
+ semantics.subagents.map((agent) => /* @__PURE__ */ jsxs4("p", { children: [
1611
+ /* @__PURE__ */ jsxs4("strong", { children: [
1419
1612
  agent.source,
1420
1613
  " subagent"
1421
1614
  ] }),
1422
- /* @__PURE__ */ jsxs3("span", { children: [
1615
+ /* @__PURE__ */ jsxs4("span", { children: [
1423
1616
  agent.messages,
1424
1617
  " messages \xB7 ",
1425
1618
  agent.fidelity.replaceAll("_", " ")
@@ -1438,7 +1631,7 @@ function ConversationAnnouncements({ state }) {
1438
1631
  }
1439
1632
  previousBusy.current = state.busy;
1440
1633
  }, [state.busy, state.error, state.harness]);
1441
- return /* @__PURE__ */ jsx4("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
1634
+ return /* @__PURE__ */ jsx5("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
1442
1635
  }
1443
1636
  function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null, unreadAfterMessages = null }) {
1444
1637
  const scroller = useRef3(null);
@@ -1470,65 +1663,72 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
1470
1663
  const element = scroller.current;
1471
1664
  if (!element) return;
1472
1665
  const anchor = earlierAnchor.current;
1473
- if (anchor && state.transcript.length > anchor.entries) {
1474
- element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
1475
- earlierAnchor.current = null;
1476
- remember({ top: element.scrollTop, atBottom: false });
1477
- return;
1666
+ if (anchor) {
1667
+ if (state.operation === "loadEarlier") anchor.seenOperation = true;
1668
+ const prepended = state.transcript.length > anchor.entries && state.transcript[0]?.id !== anchor.firstId;
1669
+ if (prepended) {
1670
+ element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
1671
+ earlierAnchor.current = null;
1672
+ remember({ top: element.scrollTop, atBottom: false });
1673
+ return;
1674
+ }
1675
+ if (state.error || anchor.seenOperation && state.operation !== "loadEarlier") earlierAnchor.current = null;
1478
1676
  }
1479
1677
  if (!restored.current) {
1480
1678
  restored.current = true;
1481
1679
  if (remembered.top !== null && !remembered.atBottom) element.scrollTop = remembered.top;
1482
1680
  else pin();
1483
1681
  } else if (atBottom) pin();
1484
- }, [memoryKey, state.transcript, state.busy, state.operation, pendingMessage?.text, pendingMessage?.status]);
1485
- return /* @__PURE__ */ jsxs3("div", { class: "scui-conversation-wrap", children: [
1486
- /* @__PURE__ */ jsx4(ConversationAnnouncements, { state }),
1487
- /* @__PURE__ */ jsx4("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
1682
+ }, [memoryKey, state.transcript, state.busy, state.operation, state.error, pendingMessage?.text, pendingMessage?.status]);
1683
+ return /* @__PURE__ */ jsxs4("div", { class: "scui-conversation-wrap", children: [
1684
+ /* @__PURE__ */ jsx5(ConversationAnnouncements, { state }),
1685
+ /* @__PURE__ */ jsx5("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
1488
1686
  const element = event.currentTarget;
1489
1687
  const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
1490
1688
  setAtBottom(bottom);
1491
1689
  remember({ top: element.scrollTop, atBottom: bottom });
1492
- }, children: /* @__PURE__ */ jsxs3("div", { children: [
1493
- Before ? /* @__PURE__ */ jsx4(Before, { state, adapter, value: null }) : null,
1494
- /* @__PURE__ */ jsx4(Plan, { plan: state.taskPlan, value: state.taskPlan, state, adapter }),
1495
- /* @__PURE__ */ jsx4(SessionDetails, { semantics: state.semantics }),
1496
- state.history.hasEarlier ? /* @__PURE__ */ jsx4("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
1690
+ }, children: /* @__PURE__ */ jsxs4("div", { children: [
1691
+ Before ? /* @__PURE__ */ jsx5(Before, { state, adapter, value: null }) : null,
1692
+ /* @__PURE__ */ jsx5(Plan, { plan: state.taskPlan, value: state.taskPlan, state, adapter }),
1693
+ /* @__PURE__ */ jsx5(SessionDetails, { semantics: state.semantics }),
1694
+ state.history.hasEarlier ? /* @__PURE__ */ jsx5("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
1497
1695
  const element = scroller.current;
1498
- if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
1696
+ if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length, firstId: state.transcript[0]?.id, seenOperation: false };
1499
1697
  setAtBottom(false);
1500
1698
  adapter.onIntent({ action: "loadEarlier" });
1501
1699
  }, children: "Load earlier messages" }) : null,
1502
- !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx4(LoadingStatus, { state }) : null,
1503
- !blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx4(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx4("div", { class: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
1504
- blocks.map((block, index) => /* @__PURE__ */ jsxs3(Fragment2, { children: [
1505
- index === unreadBlock ? /* @__PURE__ */ jsx4("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx4("span", { children: "New" }) }) : null,
1506
- block.kind === "activity" ? /* @__PURE__ */ jsx4(Group, { value: block.entries, entries: block.entries, state, adapter }) : /* @__PURE__ */ jsx4(Entry, { value: block.entry, entry: block.entry, state, adapter })
1700
+ !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx5(LoadingStatus, { state }) : null,
1701
+ !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,
1702
+ blocks.map((block, index) => /* @__PURE__ */ jsxs4(Fragment2, { children: [
1703
+ index === unreadBlock ? /* @__PURE__ */ jsx5("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx5("span", { children: "New" }) }) : null,
1704
+ 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 })
1507
1705
  ] }, block.id)),
1508
- pendingMessage ? /* @__PURE__ */ jsxs3("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
1509
- /* @__PURE__ */ jsx4(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
1510
- /* @__PURE__ */ jsxs3("footer", { children: [
1511
- /* @__PURE__ */ jsx4("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
1512
- pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs3("span", { children: [
1513
- /* @__PURE__ */ jsx4("button", { type: "button", onClick: pendingMessage.onRetry, children: "Retry" }),
1514
- /* @__PURE__ */ jsx4("button", { type: "button", onClick: pendingMessage.onEdit, children: "Edit" })
1706
+ pendingMessage ? /* @__PURE__ */ jsxs4("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
1707
+ /* @__PURE__ */ jsx5(MessageImages, { items: pendingMessage.images }),
1708
+ /* @__PURE__ */ jsx5(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
1709
+ /* @__PURE__ */ jsx5(ContextDisclosure, { context: pendingMessage.context }),
1710
+ /* @__PURE__ */ jsxs4("footer", { children: [
1711
+ /* @__PURE__ */ jsx5("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
1712
+ pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs4("span", { children: [
1713
+ /* @__PURE__ */ jsx5("button", { type: "button", onClick: pendingMessage.onRetry, children: "Retry" }),
1714
+ /* @__PURE__ */ jsx5("button", { type: "button", onClick: pendingMessage.onEdit, children: "Edit" })
1515
1715
  ] }) : null
1516
1716
  ] })
1517
1717
  ] }) : null,
1518
- state.busy ? /* @__PURE__ */ jsxs3("div", { class: "scui-working", role: "status", children: [
1519
- /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "\u2726" }),
1520
- /* @__PURE__ */ jsx4("i", {}),
1521
- /* @__PURE__ */ jsx4("i", {}),
1522
- /* @__PURE__ */ jsx4("i", {}),
1523
- /* @__PURE__ */ jsxs3("small", { children: [
1718
+ state.busy ? /* @__PURE__ */ jsxs4("div", { class: "scui-working", role: "status", children: [
1719
+ /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: "\u2726" }),
1720
+ /* @__PURE__ */ jsx5("i", {}),
1721
+ /* @__PURE__ */ jsx5("i", {}),
1722
+ /* @__PURE__ */ jsx5("i", {}),
1723
+ /* @__PURE__ */ jsxs4("small", { children: [
1524
1724
  harnessDisplayName(state.harness),
1525
1725
  " is working"
1526
1726
  ] })
1527
1727
  ] }) : null,
1528
- After ? /* @__PURE__ */ jsx4(After, { state, adapter, value: null }) : null
1728
+ After ? /* @__PURE__ */ jsx5(After, { state, adapter, value: null }) : null
1529
1729
  ] }) }),
1530
- !atBottom ? /* @__PURE__ */ jsxs3("button", { class: "scui-latest", type: "button", onClick: pin, children: [
1531
- /* @__PURE__ */ jsx4(UiIcon, { name: "down", size: 13 }),
1730
+ !atBottom ? /* @__PURE__ */ jsxs4("button", { class: "scui-latest", type: "button", onClick: pin, children: [
1731
+ /* @__PURE__ */ jsx5(UiIcon, { name: "down", size: 13 }),
1532
1732
  " Latest"
1533
1733
  ] }) : null
1534
1734
  ] });
@@ -1536,7 +1736,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
1536
1736
 
1537
1737
  // src/logo.jsx
1538
1738
  import { useEffect as useEffect4 } from "preact/hooks";
1539
- import { jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
1739
+ import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
1540
1740
  var LOGOS = {
1541
1741
  "claude-code": {
1542
1742
  viewBox: "-1 3.5 26 18",
@@ -1587,30 +1787,30 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
1587
1787
  if (!logo) onMissingLogo?.(id);
1588
1788
  }, [id, logo, onMissingLogo]);
1589
1789
  if (!logo) return null;
1590
- return /* @__PURE__ */ jsxs4("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
1591
- /* @__PURE__ */ jsx5("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx5(Tag, { ...props }, index)) }),
1592
- activity && activity !== "idle" ? /* @__PURE__ */ jsx5("i", {}) : null
1790
+ return /* @__PURE__ */ jsxs5("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
1791
+ /* @__PURE__ */ jsx6("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx6(Tag, { ...props }, index)) }),
1792
+ activity && activity !== "idle" ? /* @__PURE__ */ jsx6("i", {}) : null
1593
1793
  ] });
1594
1794
  }
1595
1795
 
1596
1796
  // src/sessions.jsx
1597
1797
  import { useEffect as useEffect5, useLayoutEffect as useLayoutEffect3, useRef as useRef4, useState as useState3 } from "preact/hooks";
1598
- import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
1798
+ import { jsx as jsx7, jsxs as jsxs6 } from "preact/jsx-runtime";
1599
1799
  var sessionListMemory = /* @__PURE__ */ new Map();
1600
1800
  function SessionRow({ row, state, onOpen }) {
1601
1801
  const activity = sessionActivity(state, row);
1602
1802
  const attentionPreview = state.attention.find((item) => item.key === row.key)?.preview;
1603
1803
  const title = sessionDisplayName(row);
1604
1804
  const detail = attentionPreview || row.preview || (row.name && row.name !== title ? row.name : row.cwd);
1605
- return /* @__PURE__ */ jsxs5("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, "data-session-key": row.key, type: "button", "aria-label": `${title} \xB7 ${harnessDisplayName(row.harness)}${row.age ? ` \xB7 ${row.age}` : ""}`, "aria-current": row.active ? "true" : void 0, onClick: () => onOpen(row), children: [
1606
- /* @__PURE__ */ jsx6(HarnessLogo, { id: row.harness, activity, size: 34 }),
1607
- /* @__PURE__ */ jsxs5("span", { class: "scui-session-copy", children: [
1608
- /* @__PURE__ */ jsxs5("span", { children: [
1609
- /* @__PURE__ */ jsx6("strong", { children: title }),
1610
- /* @__PURE__ */ jsx6("small", { children: row.age })
1805
+ return /* @__PURE__ */ jsxs6("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, "data-session-key": row.key, type: "button", "aria-label": `${title} \xB7 ${harnessDisplayName(row.harness)}${detail ? ` \xB7 ${detail}` : ""}${row.age ? ` \xB7 ${row.age}` : ""}`, "aria-current": row.active ? "true" : void 0, onClick: () => onOpen(row), children: [
1806
+ /* @__PURE__ */ jsx7(HarnessLogo, { id: row.harness, activity, size: 34 }),
1807
+ /* @__PURE__ */ jsxs6("span", { class: "scui-session-copy", children: [
1808
+ /* @__PURE__ */ jsxs6("span", { children: [
1809
+ /* @__PURE__ */ jsx7("strong", { children: title }),
1810
+ /* @__PURE__ */ jsx7("small", { children: row.age })
1611
1811
  ] }),
1612
- detail ? /* @__PURE__ */ jsx6("span", { children: /* @__PURE__ */ jsx6("small", { title: row.cwd, children: detail }) }) : null,
1613
- state.attachError?.key === row.key ? /* @__PURE__ */ jsx6("em", { children: state.attachError.message }) : null
1812
+ detail ? /* @__PURE__ */ jsx7("span", { children: /* @__PURE__ */ jsx7("small", { title: row.cwd, children: detail }) }) : null,
1813
+ state.attachError?.key === row.key ? /* @__PURE__ */ jsx7("em", { children: state.attachError.message }) : null
1614
1814
  ] })
1615
1815
  ] });
1616
1816
  }
@@ -1641,48 +1841,48 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
1641
1841
  Promise.resolve(result).then(() => setLoadingMore(false), () => setLoadingMore(false));
1642
1842
  }
1643
1843
  };
1644
- return /* @__PURE__ */ jsxs5("section", { class: "scui-list", ref: root, children: [
1645
- /* @__PURE__ */ jsxs5("header", { class: "scui-head", children: [
1646
- /* @__PURE__ */ jsxs5("span", { class: "scui-head-copy", children: [
1647
- /* @__PURE__ */ jsx6("strong", { children: labels.chats }),
1648
- /* @__PURE__ */ jsxs5("small", { children: [
1844
+ return /* @__PURE__ */ jsxs6("section", { class: "scui-list", ref: root, children: [
1845
+ /* @__PURE__ */ jsxs6("header", { class: "scui-head", children: [
1846
+ /* @__PURE__ */ jsxs6("span", { class: "scui-head-copy", children: [
1847
+ /* @__PURE__ */ jsx7("strong", { children: labels.chats }),
1848
+ /* @__PURE__ */ jsxs6("small", { children: [
1649
1849
  state.sessions.length,
1650
1850
  " recent conversations"
1651
1851
  ] })
1652
1852
  ] }),
1653
- /* @__PURE__ */ jsx6("button", { type: "button", "data-list-focus": "new", "aria-label": labels.newChat, disabled: !state.harnesses.some((item) => item.startable), onClick: onNew, children: /* @__PURE__ */ jsx6(UiIcon, { name: "plus", size: 18 }) }),
1654
- onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx6(UiIcon, { name: "close", size: 18 }) }) : null
1853
+ /* @__PURE__ */ jsx7("button", { type: "button", "data-list-focus": "new", "aria-label": labels.newChat, disabled: !state.harnesses.some((item) => item.startable), onClick: onNew, children: /* @__PURE__ */ jsx7(UiIcon, { name: "plus", size: 18 }) }),
1854
+ onClose ? /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx7(UiIcon, { name: "close", size: 18 }) }) : null
1655
1855
  ] }),
1656
- state.startup !== "ready" ? /* @__PURE__ */ jsx6(LoadingStatus, { state, compact: rows.length > 0 }) : null,
1657
- state.sessions.length > 4 ? /* @__PURE__ */ jsxs5("label", { class: "scui-search", children: [
1658
- /* @__PURE__ */ jsx6(UiIcon, { name: "search", size: 15 }),
1659
- /* @__PURE__ */ jsx6("input", { type: "search", "aria-label": labels.searchChats, placeholder: labels.searchChats, value: query, onInput: (event) => {
1856
+ state.startup !== "ready" ? /* @__PURE__ */ jsx7(LoadingStatus, { state, compact: rows.length > 0 }) : null,
1857
+ state.sessions.length > 4 ? /* @__PURE__ */ jsxs6("label", { class: "scui-search", children: [
1858
+ /* @__PURE__ */ jsx7(UiIcon, { name: "search", size: 15 }),
1859
+ /* @__PURE__ */ jsx7("input", { type: "search", "aria-label": labels.searchChats, placeholder: labels.searchChats, value: query, onInput: (event) => {
1660
1860
  const value = event.currentTarget.value;
1661
1861
  setQuery(value);
1662
1862
  boundedSet(sessionListMemory, memoryKey, { query: value, top: 0 });
1663
1863
  if (rowScroller.current) rowScroller.current.scrollTop = 0;
1664
1864
  } }),
1665
- /* @__PURE__ */ jsx6("small", { children: rows.length })
1865
+ /* @__PURE__ */ jsx7("small", { children: rows.length })
1666
1866
  ] }) : null,
1667
- /* @__PURE__ */ jsxs5("div", { class: "scui-session-rows", ref: rowScroller, onScroll: (event) => boundedSet(sessionListMemory, memoryKey, { query, top: event.currentTarget.scrollTop }), children: [
1668
- !rows.length && state.startup === "ready" ? /* @__PURE__ */ jsx6("div", { class: "scui-empty", children: query ? "No chats match your search." : state.error ?? "No coding chats found." }) : null,
1669
- rows.map((row) => /* @__PURE__ */ jsx6(Row, { value: row, row, state, adapter, onOpen }, row.key)),
1670
- state.history.hasMoreSessions ? /* @__PURE__ */ jsx6("button", { class: "scui-load", type: "button", disabled: loadingMore, onClick: loadMore, children: loadingMore ? "Loading older chats\u2026" : "Load older chats" }) : null
1867
+ /* @__PURE__ */ jsxs6("div", { class: "scui-session-rows", ref: rowScroller, onScroll: (event) => boundedSet(sessionListMemory, memoryKey, { query, top: event.currentTarget.scrollTop }), children: [
1868
+ !rows.length && state.startup === "ready" ? /* @__PURE__ */ jsx7("div", { class: "scui-empty", children: query ? "No chats match your search." : state.error ?? "No coding chats found." }) : null,
1869
+ rows.map((row) => /* @__PURE__ */ jsx7(Row, { value: row, row, state, adapter, onOpen }, row.key)),
1870
+ state.history.hasMoreSessions ? /* @__PURE__ */ jsx7("button", { class: "scui-load", type: "button", disabled: loadingMore, onClick: loadMore, children: loadingMore ? "Loading older chats\u2026" : "Load older chats" }) : null
1671
1871
  ] })
1672
1872
  ] });
1673
1873
  }
1674
1874
 
1675
1875
  // src/messenger.jsx
1676
- import { jsx as jsx7, jsxs as jsxs6 } from "preact/jsx-runtime";
1876
+ import { jsx as jsx8, jsxs as jsxs7 } from "preact/jsx-runtime";
1677
1877
  var pendingMessageMemory = /* @__PURE__ */ new Map();
1678
1878
  var messengerViewMemory = /* @__PURE__ */ new Map();
1679
1879
  var newChatMemory = /* @__PURE__ */ new Map();
1680
1880
  var TRACKED_ACTIONS = /* @__PURE__ */ new Set(["resume", "join", "detach", "branch", "reduce", "terminal", "export", "interrupt", "respond", "refresh", "loadEarlier", "loadSessions"]);
1681
1881
  function Receipt({ state, adapter }) {
1682
1882
  const receipt = state.reductionReceipt;
1683
- if (receipt) return /* @__PURE__ */ jsx7("div", { class: "scui-receipt", children: /* @__PURE__ */ jsxs6("span", { children: [
1684
- /* @__PURE__ */ jsx7("strong", { children: "Reduced and verified" }),
1685
- /* @__PURE__ */ jsxs6("small", { children: [
1883
+ if (receipt) return /* @__PURE__ */ jsx8("div", { class: "scui-receipt", children: /* @__PURE__ */ jsxs7("span", { children: [
1884
+ /* @__PURE__ */ jsx8("strong", { children: "Reduced and verified" }),
1885
+ /* @__PURE__ */ jsxs7("small", { children: [
1686
1886
  receipt.sourceTokens.toLocaleString(),
1687
1887
  " \u2192 ",
1688
1888
  receipt.reducedTokens.toLocaleString(),
@@ -1691,27 +1891,27 @@ function Receipt({ state, adapter }) {
1691
1891
  "\xD7 \xB7 reversible"
1692
1892
  ] })
1693
1893
  ] }) });
1694
- if (state.exportReceipt) return /* @__PURE__ */ jsxs6("div", { class: "scui-receipt", children: [
1695
- /* @__PURE__ */ jsxs6("span", { children: [
1696
- /* @__PURE__ */ jsxs6("strong", { children: [
1894
+ if (state.exportReceipt) return /* @__PURE__ */ jsxs7("div", { class: "scui-receipt", children: [
1895
+ /* @__PURE__ */ jsxs7("span", { children: [
1896
+ /* @__PURE__ */ jsxs7("strong", { children: [
1697
1897
  "Lossless export ready \xB7 ",
1698
1898
  harnessDisplayName(state.exportReceipt.targetHarness)
1699
1899
  ] }),
1700
- /* @__PURE__ */ jsxs6("small", { children: [
1900
+ /* @__PURE__ */ jsxs7("small", { children: [
1701
1901
  state.exportReceipt.path,
1702
1902
  " \xB7 ",
1703
1903
  state.exportReceipt.files,
1704
1904
  " files"
1705
1905
  ] })
1706
1906
  ] }),
1707
- /* @__PURE__ */ jsx7("button", { type: "button", onClick: () => adapter.copyText?.(state.exportReceipt.path), children: "Copy path" })
1907
+ /* @__PURE__ */ jsx8("button", { type: "button", onClick: () => adapter.copyText?.(state.exportReceipt.path), children: "Copy path" })
1708
1908
  ] });
1709
- if (state.terminalHandoff) return /* @__PURE__ */ jsxs6("div", { class: "scui-receipt", children: [
1710
- /* @__PURE__ */ jsxs6("span", { children: [
1711
- /* @__PURE__ */ jsx7("strong", { children: "Terminal handoff ready" }),
1712
- /* @__PURE__ */ jsx7("small", { children: state.terminalHandoff.cwd })
1909
+ if (state.terminalHandoff) return /* @__PURE__ */ jsxs7("div", { class: "scui-receipt", children: [
1910
+ /* @__PURE__ */ jsxs7("span", { children: [
1911
+ /* @__PURE__ */ jsx8("strong", { children: "Terminal handoff ready" }),
1912
+ /* @__PURE__ */ jsx8("small", { children: state.terminalHandoff.cwd })
1713
1913
  ] }),
1714
- /* @__PURE__ */ jsx7("button", { type: "button", onClick: () => adapter.copyText?.(terminalCommand(state.terminalHandoff)), children: "Copy command" })
1914
+ /* @__PURE__ */ jsx8("button", { type: "button", onClick: () => adapter.copyText?.(terminalCommand(state.terminalHandoff)), children: "Copy command" })
1715
1915
  ] });
1716
1916
  return null;
1717
1917
  }
@@ -1779,13 +1979,13 @@ function ConversationActions({ state, adapter, actionPending }) {
1779
1979
  const index = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : event.key === "ArrowDown" ? (current + 1) % items.length : (current <= 0 ? items.length : current) - 1;
1780
1980
  items[index].focus({ preventScroll: true });
1781
1981
  };
1782
- return /* @__PURE__ */ jsxs6("div", { class: "scui-menu", ref: root, onBlur: (event) => {
1982
+ return /* @__PURE__ */ jsxs7("div", { class: "scui-menu", ref: root, onBlur: (event) => {
1783
1983
  if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
1784
1984
  }, children: [
1785
- /* @__PURE__ */ jsx7("button", { ref: trigger, class: "scui-menu-trigger", type: "button", "aria-label": "Conversation actions", "aria-haspopup": "menu", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((value) => !value), children: /* @__PURE__ */ jsx7(UiIcon, { name: "menu", size: 18 }) }),
1786
- open ? /* @__PURE__ */ jsx7("div", { ref: panel, id: menuId, class: "scui-menu-panel", role: "menu", "aria-label": "Conversation actions", onKeyDown: navigate, children: groups.map((group) => /* @__PURE__ */ jsxs6("section", { role: "group", "aria-label": group.label, children: [
1787
- /* @__PURE__ */ jsx7("strong", { children: group.label }),
1788
- group.items.map((item) => /* @__PURE__ */ jsx7("button", { role: "menuitem", type: "button", disabled: actionPending, onClick: () => dispatch(item.intent), children: item.label }, item.key))
1985
+ /* @__PURE__ */ jsx8("button", { ref: trigger, class: "scui-menu-trigger", type: "button", "aria-label": "Conversation actions", "aria-haspopup": "menu", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((value) => !value), children: /* @__PURE__ */ jsx8(UiIcon, { name: "menu", size: 18 }) }),
1986
+ open ? /* @__PURE__ */ jsx8("div", { ref: panel, id: menuId, class: "scui-menu-panel", role: "menu", "aria-label": "Conversation actions", onKeyDown: navigate, children: groups.map((group) => /* @__PURE__ */ jsxs7("section", { role: "group", "aria-label": group.label, children: [
1987
+ /* @__PURE__ */ jsx8("strong", { children: group.label }),
1988
+ group.items.map((item) => /* @__PURE__ */ jsx8("button", { role: "menuitem", type: "button", disabled: actionPending, onClick: () => dispatch(item.intent), children: item.label }, item.key))
1789
1989
  ] }, group.label)) }) : null
1790
1990
  ] });
1791
1991
  }
@@ -1798,20 +1998,20 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
1798
1998
  useEffect6(() => {
1799
1999
  if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
1800
2000
  }, []);
1801
- return /* @__PURE__ */ jsxs6("header", { class: "scui-head scui-chat-head", children: [
1802
- /* @__PURE__ */ jsx7("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx7(UiIcon, { name: "back", size: 18 }) }),
1803
- /* @__PURE__ */ jsx7(HarnessLogo, { id: harness, size: 28 }),
1804
- /* @__PURE__ */ jsxs6("span", { class: "scui-head-copy", children: [
1805
- /* @__PURE__ */ jsx7("strong", { children: title }),
1806
- /* @__PURE__ */ jsxs6("small", { children: [
2001
+ return /* @__PURE__ */ jsxs7("header", { class: "scui-head scui-chat-head", children: [
2002
+ /* @__PURE__ */ jsx8("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx8(UiIcon, { name: "back", size: 18 }) }),
2003
+ /* @__PURE__ */ jsx8(HarnessLogo, { id: harness, size: 28 }),
2004
+ /* @__PURE__ */ jsxs7("span", { class: "scui-head-copy", children: [
2005
+ /* @__PURE__ */ jsx8("strong", { children: title }),
2006
+ /* @__PURE__ */ jsxs7("small", { children: [
1807
2007
  harnessDisplayName(harness),
1808
2008
  " \xB7 ",
1809
2009
  status
1810
2010
  ] })
1811
2011
  ] }),
1812
- menu ? /* @__PURE__ */ jsx7(ConversationActions, { state, adapter, actionPending }) : null,
1813
- /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: /* @__PURE__ */ jsx7(UiIcon, { name: "plus", size: 18 }) }),
1814
- onClose ? /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx7(UiIcon, { name: "close", size: 18 }) }) : null
2012
+ menu ? /* @__PURE__ */ jsx8(ConversationActions, { state, adapter, actionPending }) : null,
2013
+ /* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: /* @__PURE__ */ jsx8(UiIcon, { name: "plus", size: 18 }) }),
2014
+ onClose ? /* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx8(UiIcon, { name: "close", size: 18 }) }) : null
1815
2015
  ] });
1816
2016
  }
1817
2017
  function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
@@ -1843,8 +2043,10 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
1843
2043
  if (pending.status === "sending" && state.busy && !pending.seenBusy) setPending({ ...pending, seenBusy: true });
1844
2044
  else if (pending.status === "sending" && state.error && !state.busy && !state.operation && (pending.seenBusy || state.error !== pending.initialError)) setPending({ ...pending, status: "failed" });
1845
2045
  }, [pending, state.busy, state.error, state.operation, state.transcript]);
1846
- const beginPending = (text) => setPending({
2046
+ const beginPending = (text, context = [], images = []) => setPending({
1847
2047
  text,
2048
+ context,
2049
+ images,
1848
2050
  status: "sending",
1849
2051
  initialError: state.error,
1850
2052
  seenBusy: state.busy,
@@ -1852,13 +2054,13 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
1852
2054
  });
1853
2055
  const retryPending = () => {
1854
2056
  if (!pending) return;
1855
- adapter.onIntent({ action: "send", text: pending.text });
2057
+ adapter.onIntent({ action: "send", text: pending.text, ...pending.context?.length ? { context: pending.context } : {}, ...pending.images?.length ? { images: pending.images } : {} });
1856
2058
  setPending({ ...pending, status: "sending", initialError: state.error, seenBusy: state.busy });
1857
2059
  };
1858
2060
  const editPending = () => {
1859
2061
  if (!pending) return;
1860
2062
  restoreSequence.current += 1;
1861
- setRestoreDraft({ id: restoreSequence.current, text: pending.text });
2063
+ setRestoreDraft({ id: restoreSequence.current, text: pending.text, context: pending.context, images: pending.images });
1862
2064
  setPending({ ...pending, status: "editing" });
1863
2065
  };
1864
2066
  useEffect6(() => {
@@ -1904,34 +2106,38 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
1904
2106
  setPendingAction(null);
1905
2107
  }
1906
2108
  }, [pendingAction, state.error, state.operation]);
1907
- const pendingMessage = pending && pending.status !== "editing" ? { text: pending.text, status: pending.status, onRetry: retryPending, onEdit: editPending } : null;
2109
+ const pendingMessage = pending && pending.status !== "editing" ? { text: pending.text, context: pending.context, images: pending.images, status: pending.status, onRetry: retryPending, onEdit: editPending } : null;
1908
2110
  const action = state.operation || pendingAction?.action || null;
1909
2111
  const actionLabel = operationLabel(action);
1910
2112
  const actionState = action ? { ...state, operation: action, canInterrupt: false, canRespond: false } : state;
1911
2113
  const unreadAfterMessages = state.attention.find((item) => item.key === state.attached?.key)?.afterMessages ?? null;
1912
- return /* @__PURE__ */ jsxs6("section", { class: "scui-chat", children: [
1913
- Header ? /* @__PURE__ */ jsx7(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx7(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose }),
1914
- actionLabel ? /* @__PURE__ */ jsxs6("div", { class: "scui-operation", role: "status", children: [
1915
- /* @__PURE__ */ jsx7("i", {}),
2114
+ return /* @__PURE__ */ jsxs7("section", { class: "scui-chat", children: [
2115
+ Header ? /* @__PURE__ */ jsx8(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx8(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose }),
2116
+ actionLabel ? /* @__PURE__ */ jsxs7("div", { class: "scui-operation", role: "status", children: [
2117
+ /* @__PURE__ */ jsx8("i", {}),
1916
2118
  actionLabel
1917
2119
  ] }) : null,
1918
- state.error ? /* @__PURE__ */ jsxs6("div", { class: "scui-error", role: "alert", children: [
1919
- /* @__PURE__ */ jsx7("span", { children: state.error }),
1920
- state.recoverable ? /* @__PURE__ */ jsx7("button", { type: "button", disabled: Boolean(action), onClick: () => trackedAdapter.onIntent({ action: "refresh" }), children: "Retry" }) : null
2120
+ state.error ? /* @__PURE__ */ jsxs7("div", { class: "scui-error", role: "alert", children: [
2121
+ /* @__PURE__ */ jsx8("span", { children: state.error }),
2122
+ state.recoverable ? /* @__PURE__ */ jsx8("button", { type: "button", disabled: Boolean(action), onClick: () => trackedAdapter.onIntent({ action: "refresh" }), children: "Retry" }) : null
1921
2123
  ] }) : null,
1922
- /* @__PURE__ */ jsx7(Receipt, { state, adapter }),
1923
- /* @__PURE__ */ jsx7(Conversation, { state: actionState, adapter: trackedAdapter, components, slots, memoryKey, pending: pendingMessage, unreadAfterMessages }, memoryKey),
1924
- /* @__PURE__ */ jsx7(ContinuationBar, { state: actionState, adapter: trackedAdapter, labels }),
1925
- state.mode !== "mirror" || state.canSend ? /* @__PURE__ */ jsx7(Composer, { state: actionState, adapter: trackedAdapter, labels, memoryKey, pendingStatus: pending?.status ?? null, restoreDraft, onDraftRestored: (id) => setRestoreDraft((value) => value?.id === id ? null : value), onPending: beginPending }, memoryKey) : null
2124
+ /* @__PURE__ */ jsx8(Receipt, { state, adapter }),
2125
+ /* @__PURE__ */ jsx8(Conversation, { state: actionState, adapter: trackedAdapter, components, slots, memoryKey, pending: pendingMessage, unreadAfterMessages }, memoryKey),
2126
+ /* @__PURE__ */ jsx8(ContinuationBar, { state: actionState, adapter: trackedAdapter, labels }),
2127
+ state.mode !== "mirror" || state.canSend ? /* @__PURE__ */ jsx8(Composer, { state: actionState, adapter: trackedAdapter, labels, memoryKey, pendingStatus: pending?.status ?? null, restoreDraft, onDraftRestored: (id) => setRestoreDraft((value) => value?.id === id ? null : value), onPending: beginPending }, memoryKey) : null
1926
2128
  ] });
1927
2129
  }
1928
2130
  function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey }) {
1929
2131
  const startable = state.harnesses.filter((item) => item.startable);
1930
2132
  const startableKey = startable.map((item) => item.id).join("\0");
1931
- const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "" };
2133
+ const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "", context: [], images: [] };
1932
2134
  const [harness, setHarness] = useState4(remembered.harness);
1933
2135
  const [draft, setDraft] = useState4(remembered.draft);
2136
+ const [context, setContext] = useState4(remembered.context);
2137
+ const [images, setImages] = useState4(remembered.images ?? []);
1934
2138
  const [starting, setStarting] = useState4(null);
2139
+ const [picking, setPicking] = useState4(false);
2140
+ const [pickerError, setPickerError] = useState4(null);
1935
2141
  const startSequence = useRef5(0);
1936
2142
  const textarea = useRef5(null);
1937
2143
  useAutosizeTextarea(textarea, draft);
@@ -1939,7 +2145,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
1939
2145
  if (startable.some((item) => item.id === harness)) return;
1940
2146
  const next = startable[0]?.id ?? "";
1941
2147
  setHarness(next);
1942
- boundedSet(newChatMemory, memoryKey, { harness: next, draft });
2148
+ boundedSet(newChatMemory, memoryKey, { harness: next, draft, context, images });
1943
2149
  }, [harness, startableKey]);
1944
2150
  useEffect6(() => {
1945
2151
  if (!starting) return;
@@ -1955,60 +2161,108 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
1955
2161
  useEffect6(() => {
1956
2162
  textarea.current?.focus({ preventScroll: true });
1957
2163
  }, []);
2164
+ const pickContext = () => {
2165
+ if (!adapter.pickContext || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS) return;
2166
+ setPicking(true);
2167
+ setPickerError(null);
2168
+ Promise.resolve().then(() => adapter.pickContext()).then((picked) => {
2169
+ const attachments = partitionAttachments(picked);
2170
+ if (context.length + attachments.context.length > MAX_CONTEXT_ITEMS) throw new Error(`Attach at most ${MAX_CONTEXT_ITEMS} text items.`);
2171
+ if (images.length + attachments.images.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
2172
+ setContext((current) => {
2173
+ const next = mergeContext(current, attachments.context);
2174
+ boundedSet(newChatMemory, memoryKey, { harness, draft, context: next, images });
2175
+ return next;
2176
+ });
2177
+ setImages((current) => {
2178
+ const next = mergeImages(current, attachments.images);
2179
+ boundedSet(newChatMemory, memoryKey, { harness, draft, context, images: next });
2180
+ return next;
2181
+ });
2182
+ }).catch((error) => setPickerError(error instanceof Error ? error.message : "Could not attach context.")).finally(() => setPicking(false));
2183
+ };
2184
+ const pasteImages = (event) => {
2185
+ const files = Array.from(event.clipboardData?.files ?? []).filter((file) => file.type.startsWith("image/"));
2186
+ if (!files.length) return;
2187
+ event.preventDefault();
2188
+ if (images.length + files.length > MAX_IMAGE_ITEMS) {
2189
+ setPickerError(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
2190
+ return;
2191
+ }
2192
+ setPicking(true);
2193
+ setPickerError(null);
2194
+ imageAttachmentsFromFiles(files).then((picked) => setImages((current) => {
2195
+ const next = mergeImages(current, picked);
2196
+ boundedSet(newChatMemory, memoryKey, { harness, draft, context, images: next });
2197
+ return next;
2198
+ }), (error) => setPickerError(error instanceof Error ? error.message : "Could not paste image.")).finally(() => setPicking(false));
2199
+ };
1958
2200
  const send = () => {
1959
2201
  const text = draft.trim();
1960
2202
  if (!text || !harness || starting) return;
1961
2203
  const id = startSequence.current + 1;
1962
2204
  startSequence.current = id;
1963
2205
  setStarting({ id, attachedKey: state.attached?.key ?? null, busy: state.busy, initialError: state.error });
1964
- const result = adapter.onIntent({ action: "new", harness, text });
2206
+ const result = adapter.onIntent({ action: "new", harness, text, ...context.length ? { context } : {}, ...images.length ? { images } : {} });
1965
2207
  if (result && typeof result.then === "function") {
1966
2208
  Promise.resolve(result).catch(() => setStarting((current) => current?.id === id ? null : current));
1967
2209
  }
1968
2210
  };
1969
- return /* @__PURE__ */ jsxs6("section", { class: "scui-chat", children: [
1970
- /* @__PURE__ */ jsxs6("header", { class: "scui-head", children: [
1971
- /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Back", onClick: onBack, children: /* @__PURE__ */ jsx7(UiIcon, { name: "back", size: 18 }) }),
1972
- /* @__PURE__ */ jsxs6("span", { class: "scui-head-copy", children: [
1973
- /* @__PURE__ */ jsx7("strong", { children: labels.newChat }),
1974
- /* @__PURE__ */ jsx7("small", { children: "No session is created until you send" })
2211
+ return /* @__PURE__ */ jsxs7("section", { class: "scui-chat", children: [
2212
+ /* @__PURE__ */ jsxs7("header", { class: "scui-head", children: [
2213
+ /* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "Back", onClick: onBack, children: /* @__PURE__ */ jsx8(UiIcon, { name: "back", size: 18 }) }),
2214
+ /* @__PURE__ */ jsxs7("span", { class: "scui-head-copy", children: [
2215
+ /* @__PURE__ */ jsx8("strong", { children: labels.newChat }),
2216
+ /* @__PURE__ */ jsx8("small", { children: "No session is created until you send" })
1975
2217
  ] }),
1976
- onClose ? /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx7(UiIcon, { name: "close", size: 18 }) }) : null
2218
+ onClose ? /* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx8(UiIcon, { name: "close", size: 18 }) }) : null
1977
2219
  ] }),
1978
- starting ? /* @__PURE__ */ jsxs6("div", { class: "scui-operation", role: "status", children: [
1979
- /* @__PURE__ */ jsx7("i", {}),
2220
+ starting ? /* @__PURE__ */ jsxs7("div", { class: "scui-operation", role: "status", children: [
2221
+ /* @__PURE__ */ jsx8("i", {}),
1980
2222
  operationLabel("start")
1981
2223
  ] }) : null,
1982
- /* @__PURE__ */ jsxs6("div", { class: "scui-new", children: [
1983
- /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\u2726" }),
1984
- /* @__PURE__ */ jsx7("strong", { children: "What should the agent build or fix?" }),
1985
- /* @__PURE__ */ jsx7("small", { children: "Choose a coding harness and send the first message." })
2224
+ /* @__PURE__ */ jsxs7("div", { class: "scui-new", children: [
2225
+ /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", children: "\u2726" }),
2226
+ /* @__PURE__ */ jsx8("strong", { children: "What should the agent build or fix?" }),
2227
+ /* @__PURE__ */ jsx8("small", { children: "Choose a coding harness and send the first message." })
1986
2228
  ] }),
1987
- /* @__PURE__ */ jsxs6("div", { class: "scui-compose", children: [
1988
- /* @__PURE__ */ jsxs6("label", { class: "scui-harness-picker", children: [
1989
- /* @__PURE__ */ jsx7(HarnessLogo, { id: harness, size: 24 }),
1990
- /* @__PURE__ */ jsx7("span", { children: "Coding harness" }),
1991
- /* @__PURE__ */ jsx7("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
2229
+ /* @__PURE__ */ jsxs7("div", { class: "scui-compose", children: [
2230
+ /* @__PURE__ */ jsxs7("label", { class: "scui-harness-picker", children: [
2231
+ /* @__PURE__ */ jsx8(HarnessLogo, { id: harness, size: 24 }),
2232
+ /* @__PURE__ */ jsx8("span", { children: "Coding harness" }),
2233
+ /* @__PURE__ */ jsx8("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
1992
2234
  const value = event.currentTarget.value;
1993
2235
  setHarness(value);
1994
- boundedSet(newChatMemory, memoryKey, { harness: value, draft });
1995
- }, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs6("option", { value: item.id, disabled: !item.startable, children: [
2236
+ boundedSet(newChatMemory, memoryKey, { harness: value, draft, context, images });
2237
+ }, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs7("option", { value: item.id, disabled: !item.startable, children: [
1996
2238
  item.label,
1997
2239
  item.startable ? "" : " \xB7 unavailable"
1998
2240
  ] }, item.id)) })
1999
2241
  ] }),
2000
- /* @__PURE__ */ jsxs6("div", { class: "scui-envelope", children: [
2001
- /* @__PURE__ */ jsx7("textarea", { ref: textarea, rows: 3, "aria-label": "Message coding agent", placeholder: startable.length ? "What should the agent do?" : "No coding harness is available", value: draft, disabled: !startable.length || Boolean(starting), onInput: (event) => {
2242
+ /* @__PURE__ */ jsx8(ImageTray, { items: images, onRemove: (index) => setImages((items) => {
2243
+ const next = items.filter((_, itemIndex) => itemIndex !== index);
2244
+ boundedSet(newChatMemory, memoryKey, { harness, draft, context, images: next });
2245
+ return next;
2246
+ }) }),
2247
+ /* @__PURE__ */ jsx8(ContextTray, { items: context, onRemove: (index) => setContext((items) => {
2248
+ const next = items.filter((_, itemIndex) => itemIndex !== index);
2249
+ boundedSet(newChatMemory, memoryKey, { harness, draft, context: next, images });
2250
+ return next;
2251
+ }) }),
2252
+ pickerError ? /* @__PURE__ */ jsx8("small", { class: "scui-context-error", role: "alert", children: pickerError }) : null,
2253
+ /* @__PURE__ */ jsxs7("div", { class: "scui-envelope", children: [
2254
+ adapter.pickContext ? /* @__PURE__ */ jsx8("button", { class: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx8("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx8(UiIcon, { name: "attach", size: 17 }) }) : null,
2255
+ /* @__PURE__ */ jsx8("textarea", { ref: textarea, rows: 3, "aria-label": "Message coding agent", placeholder: startable.length ? "What should the agent do?" : "No coding harness is available", value: draft, disabled: !startable.length || Boolean(starting), onPaste: pasteImages, onInput: (event) => {
2002
2256
  const value = event.currentTarget.value;
2003
2257
  setDraft(value);
2004
- boundedSet(newChatMemory, memoryKey, { harness, draft: value });
2258
+ boundedSet(newChatMemory, memoryKey, { harness, draft: value, context, images });
2005
2259
  }, onKeyDown: (event) => {
2006
2260
  if (isSendKey(event)) {
2007
2261
  event.preventDefault();
2008
2262
  send();
2009
2263
  }
2010
2264
  } }),
2011
- /* @__PURE__ */ jsx7("span", { children: /* @__PURE__ */ jsx7("button", { type: "button", class: "scui-send", "aria-label": "Start chat", disabled: !draft.trim() || !harness || Boolean(starting), onClick: send, children: starting ? /* @__PURE__ */ jsx7("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx7(UiIcon, { name: "send", size: 17 }) }) })
2265
+ /* @__PURE__ */ jsx8("span", { children: /* @__PURE__ */ jsx8("button", { type: "button", class: "scui-send", "aria-label": "Start chat", disabled: !draft.trim() || !harness || Boolean(starting), onClick: send, children: starting ? /* @__PURE__ */ jsx8("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx8(UiIcon, { name: "send", size: 17 }) }) })
2012
2266
  ] })
2013
2267
  ] })
2014
2268
  ] });
@@ -2040,31 +2294,31 @@ function SupercodeMessenger({ state: stateInput, adapter, class: className = "",
2040
2294
  };
2041
2295
  const close = () => adapter.onClose?.();
2042
2296
  const Footer = slots.footer;
2043
- return /* @__PURE__ */ jsxs6("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
2044
- view === "list" ? /* @__PURE__ */ jsx7(SessionList, { state, adapter, focusKey: listFocus, onOpen: open, onNew: () => {
2297
+ return /* @__PURE__ */ jsxs7("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
2298
+ view === "list" ? /* @__PURE__ */ jsx8(SessionList, { state, adapter, focusKey: listFocus, onOpen: open, onNew: () => {
2045
2299
  setListFocus("@new");
2046
2300
  setView("new");
2047
2301
  }, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey }) : null,
2048
- view === "new" ? /* @__PURE__ */ jsx7(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: () => setView("chat"), labels: copy, memoryKey }) : null,
2049
- view === "chat" ? /* @__PURE__ */ jsx7(Chat, { state, adapter, onBack: () => {
2302
+ view === "new" ? /* @__PURE__ */ jsx8(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: () => setView("chat"), labels: copy, memoryKey }) : null,
2303
+ view === "chat" ? /* @__PURE__ */ jsx8(Chat, { state, adapter, onBack: () => {
2050
2304
  setListFocus(state.attached?.key ?? listFocus);
2051
2305
  setView("list");
2052
2306
  }, onNew: () => {
2053
2307
  setListFocus("@new");
2054
2308
  setView("new");
2055
2309
  }, onClose: adapter.onClose ? close : void 0, components, slots, labels: copy }) : null,
2056
- opening ? /* @__PURE__ */ jsxs6("div", { class: "scui-opening", role: "status", "aria-busy": "true", children: [
2057
- /* @__PURE__ */ jsx7(HarnessLogo, { id: opening.harness, size: 34 }),
2058
- /* @__PURE__ */ jsxs6("span", { children: [
2059
- /* @__PURE__ */ jsxs6("strong", { children: [
2310
+ opening ? /* @__PURE__ */ jsxs7("div", { class: "scui-opening", role: "status", "aria-busy": "true", children: [
2311
+ /* @__PURE__ */ jsx8(HarnessLogo, { id: opening.harness, size: 34 }),
2312
+ /* @__PURE__ */ jsxs7("span", { children: [
2313
+ /* @__PURE__ */ jsxs7("strong", { children: [
2060
2314
  "Opening ",
2061
2315
  sessionDisplayName(opening)
2062
2316
  ] }),
2063
- /* @__PURE__ */ jsx7("small", { children: "Loading the latest transcript window\u2026" })
2317
+ /* @__PURE__ */ jsx8("small", { children: "Loading the latest transcript window\u2026" })
2064
2318
  ] }),
2065
- /* @__PURE__ */ jsx7("i", {})
2319
+ /* @__PURE__ */ jsx8("i", {})
2066
2320
  ] }) : null,
2067
- Footer ? /* @__PURE__ */ jsx7(Footer, { state, adapter, value: copy }) : null
2321
+ Footer ? /* @__PURE__ */ jsx8(Footer, { state, adapter, value: copy }) : null
2068
2322
  ] });
2069
2323
  }
2070
2324
  export {