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