@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/components.mjs CHANGED
@@ -501,6 +501,16 @@ function readTranscript(value) {
501
501
  }] : [];
502
502
  });
503
503
  }
504
+ if (Array.isArray(item.images)) {
505
+ entry.images = item.images.flatMap((raw) => {
506
+ const image = record(raw);
507
+ return image && typeof image.label === "string" ? [{
508
+ ...typeof image.id === "string" ? { id: image.id } : {},
509
+ label: image.label,
510
+ ...typeof image.url === "string" ? { url: image.url } : {}
511
+ }] : [];
512
+ }).slice(0, 4);
513
+ }
504
514
  const request = record(item.request);
505
515
  if (request && typeof request.requestKind === "string" && typeof request.payloadText === "string") {
506
516
  entry.request = {
@@ -681,7 +691,7 @@ function sessionActivity(state, row) {
681
691
  function filterSessions(rows, query) {
682
692
  const needle = query.trim().toLocaleLowerCase();
683
693
  if (!needle) return [...rows];
684
- return rows.filter((row) => [row.name, row.title, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => value.toLocaleLowerCase().includes(needle)));
694
+ return rows.filter((row) => [row.name, row.title, row.preview, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => typeof value === "string" && value.toLocaleLowerCase().includes(needle)));
685
695
  }
686
696
  function groupConversation(entries) {
687
697
  const blocks = [];
@@ -758,6 +768,7 @@ function boundedSet(map, key, value) {
758
768
  // src/icon.jsx
759
769
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
760
770
  var ICONS = {
771
+ 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" }),
761
772
  back: () => /* @__PURE__ */ jsx("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
762
773
  check: () => /* @__PURE__ */ jsx("path", { d: "m4 9 3.25 3.25L14 5.5" }),
763
774
  chevron: () => /* @__PURE__ */ jsx("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
@@ -773,6 +784,11 @@ var ICONS = {
773
784
  /* @__PURE__ */ jsx("path", { d: "M9 3.5v10" }),
774
785
  /* @__PURE__ */ jsx("path", { d: "m4.75 9.5 4.25 4 4.25-4" })
775
786
  ] }),
787
+ image: () => /* @__PURE__ */ jsxs(Fragment, { children: [
788
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "3.5", width: "12", height: "11", rx: "1.75" }),
789
+ /* @__PURE__ */ jsx("circle", { cx: "6.5", cy: "7", r: "1.25" }),
790
+ /* @__PURE__ */ jsx("path", { d: "m4.5 13 3.25-3 2.1 1.85 1.65-1.5L14 13" })
791
+ ] }),
776
792
  menu: () => /* @__PURE__ */ jsxs(Fragment, { children: [
777
793
  /* @__PURE__ */ jsx("circle", { cx: "4", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
778
794
  /* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
@@ -798,6 +814,114 @@ function UiIcon({ name, size = 16, class: className = "" }) {
798
814
  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, {}) });
799
815
  }
800
816
 
817
+ // src/context.jsx
818
+ import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
819
+ var MAX_CONTEXT_ITEMS = 32;
820
+ var MAX_IMAGE_ITEMS = 4;
821
+ var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
822
+ var IMAGE_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
823
+ function normalizeContext(value) {
824
+ return (Array.isArray(value) ? value : value ? [value] : []).flatMap((item) => {
825
+ if (!item || typeof item.label !== "string" || typeof item.detail !== "string") return [];
826
+ const label = item.label.trim().slice(0, 200);
827
+ const detail = item.detail.slice(0, 2e4);
828
+ if (!label || !detail) return [];
829
+ return [{
830
+ ...typeof item.id === "string" && item.id ? { id: item.id.slice(0, 2e3) } : {},
831
+ ...typeof item.kind === "string" && item.kind ? { kind: item.kind.slice(0, 100) } : {},
832
+ label,
833
+ detail
834
+ }];
835
+ }).slice(0, MAX_CONTEXT_ITEMS);
836
+ }
837
+ function mergeContext(current, picked) {
838
+ const next = [...current];
839
+ const seen = new Set(current.map((item) => item.id ? `id:${item.id}` : `value:${item.kind ?? ""}\0${item.label}\0${item.detail}`));
840
+ for (const item of normalizeContext(picked)) {
841
+ const key = item.id ? `id:${item.id}` : `value:${item.kind ?? ""}\0${item.label}\0${item.detail}`;
842
+ if (seen.has(key)) continue;
843
+ seen.add(key);
844
+ next.push(item);
845
+ if (next.length === MAX_CONTEXT_ITEMS) break;
846
+ }
847
+ return next;
848
+ }
849
+ function normalizeImages(value) {
850
+ const seen = /* @__PURE__ */ new Set();
851
+ return (Array.isArray(value) ? value : value ? [value] : []).flatMap((item) => {
852
+ if (!item || typeof item.label !== "string" || typeof item.url !== "string") return [];
853
+ const label = item.label.trim().slice(0, 200);
854
+ const url = item.url;
855
+ if (!label || seen.has(url) || !(url.startsWith("data:image/") || url.startsWith("https://") || url.startsWith("http://"))) return [];
856
+ seen.add(url);
857
+ return [{
858
+ ...typeof item.id === "string" && item.id ? { id: item.id.slice(0, 2e3) } : {},
859
+ label,
860
+ url
861
+ }];
862
+ }).slice(0, MAX_IMAGE_ITEMS);
863
+ }
864
+ function mergeImages(current, picked) {
865
+ const next = [...current];
866
+ const seen = new Set(current.map((item) => item.url));
867
+ for (const item of normalizeImages(picked)) {
868
+ if (seen.has(item.url)) continue;
869
+ seen.add(item.url);
870
+ next.push(item);
871
+ if (next.length === MAX_IMAGE_ITEMS) break;
872
+ }
873
+ return next;
874
+ }
875
+ function partitionAttachments(value) {
876
+ const values = Array.isArray(value) ? value : value ? [value] : [];
877
+ const context = [];
878
+ const images = [];
879
+ for (const item of values) {
880
+ if (item && typeof item.label === "string" && item.label.trim() && typeof item.detail === "string" && item.detail) context.push(item);
881
+ 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);
882
+ else throw new Error("The attachment picker returned an invalid item.");
883
+ }
884
+ return { context, images };
885
+ }
886
+ async function imageAttachmentsFromFiles(value) {
887
+ const files = Array.from(value ?? []).filter((file) => file?.type?.startsWith("image/"));
888
+ if (files.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images at a time.`);
889
+ return Promise.all(files.map(async (file) => {
890
+ if (!IMAGE_TYPES.has(file.type)) throw new Error(`${file.name || "That image"} is not PNG, JPEG, GIF, or WebP.`);
891
+ if (file.size > MAX_IMAGE_BYTES) throw new Error(`${file.name || "That image"} is larger than 5 MB.`);
892
+ const url = await new Promise((resolve, reject) => {
893
+ const reader = new FileReader();
894
+ reader.onload = () => resolve(reader.result);
895
+ reader.onerror = () => reject(reader.error ?? new Error(`Could not read ${file.name || "image"}.`));
896
+ reader.readAsDataURL(file);
897
+ });
898
+ return { id: `${file.name}:${file.size}:${file.lastModified}`, label: file.name || "Pasted image", url };
899
+ }));
900
+ }
901
+ function ContextTray({ items, onRemove }) {
902
+ if (!items.length) return null;
903
+ return /* @__PURE__ */ jsx2("div", { class: "scui-compose-context", "aria-label": "Attached context", children: items.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
904
+ /* @__PURE__ */ jsx2(UiIcon, { name: "attach", size: 12 }),
905
+ /* @__PURE__ */ jsx2("strong", { children: item.label }),
906
+ /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove context ${item.label}`, onClick: () => onRemove(index), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 12 }) })
907
+ ] }, item.id ?? `${item.label}:${index}`)) });
908
+ }
909
+ function ImageTray({ items, onRemove }) {
910
+ if (!items.length) return null;
911
+ return /* @__PURE__ */ jsx2("div", { class: "scui-compose-images", "aria-label": "Attached images", children: items.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
912
+ /* @__PURE__ */ jsx2("img", { src: item.url, alt: "" }),
913
+ /* @__PURE__ */ jsx2("strong", { children: item.label }),
914
+ onRemove ? /* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove image ${item.label}`, onClick: () => onRemove(index), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 12 }) }) : null
915
+ ] }, item.id ?? `${item.label}:${index}`)) });
916
+ }
917
+ function MessageImages({ items }) {
918
+ if (!items?.length) return null;
919
+ 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: [
920
+ /* @__PURE__ */ jsx2(UiIcon, { name: "image", size: 14 }),
921
+ item.label
922
+ ] }, item.id ?? `${item.label}:${index}`)) });
923
+ }
924
+
801
925
  // src/textarea.js
802
926
  import { useLayoutEffect } from "preact/hooks";
803
927
  function useAutosizeTextarea(ref, value) {
@@ -813,7 +937,7 @@ function useAutosizeTextarea(ref, value) {
813
937
  }
814
938
 
815
939
  // src/composer.jsx
816
- import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
940
+ import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
817
941
  var composerMemory = /* @__PURE__ */ new Map();
818
942
  function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
819
943
  if (state.mode !== "mirror" || state.canSend) return null;
@@ -823,29 +947,36 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
823
947
  const resume = canContinueHere(state);
824
948
  const join = state.canAttach;
825
949
  const branch = state.canBranch;
826
- if (!resume && !join && !branch) return /* @__PURE__ */ jsx2("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs2("span", { children: [
827
- /* @__PURE__ */ jsx2("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
828
- /* @__PURE__ */ jsx2("small", { children: "This session cannot be continued by an available harness." })
950
+ if (!resume && !join && !branch) return /* @__PURE__ */ jsx3("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
951
+ /* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
952
+ /* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
829
953
  ] }) });
830
- return /* @__PURE__ */ jsxs2("div", { class: "scui-continuation", children: [
831
- /* @__PURE__ */ jsxs2("span", { children: [
832
- /* @__PURE__ */ jsx2("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
833
- /* @__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." })
954
+ return /* @__PURE__ */ jsxs3("div", { class: "scui-continuation", children: [
955
+ /* @__PURE__ */ jsxs3("span", { children: [
956
+ /* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
957
+ /* @__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." })
834
958
  ] }),
835
- /* @__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 })
959
+ /* @__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 })
836
960
  ] });
837
961
  }
838
962
  function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
839
- const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
963
+ const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, context: [], images: [], queue: [] };
840
964
  const [draft, setDraft] = useState(remembered.draft);
841
- const [queue, setQueue] = useState(remembered.queue);
965
+ const [context, setContext] = useState(remembered.context ?? []);
966
+ const [images, setImages] = useState(remembered.images ?? []);
967
+ const [queue, setQueue] = useState((remembered.queue ?? []).map((item) => ({ ...item, context: item.context ?? [], images: item.images ?? [] })));
842
968
  const [dispatching, setDispatching] = useState(false);
969
+ const [picking, setPicking] = useState(false);
970
+ const [pickerError, setPickerError] = useState(null);
843
971
  const textarea = useRef(null);
844
972
  useAutosizeTextarea(textarea, draft);
845
- const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
973
+ const remember = (nextDraft, nextContext, nextImages, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, context: nextContext, images: nextImages, queue: nextQueue });
974
+ useEffect(() => {
975
+ remember(draft, context, images, queue);
976
+ }, [draft, context, images, memoryKey, queue]);
846
977
  const updateQueue = (update) => setQueue((items) => {
847
978
  const next = update(items);
848
- remember(draft, next);
979
+ remember(draft, context, images, next);
849
980
  return next;
850
981
  });
851
982
  const queueBlocked = state.busy || pendingStatus !== null || dispatching;
@@ -855,9 +986,9 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
855
986
  const [next, ...rest] = queue;
856
987
  setDispatching(true);
857
988
  setQueue(rest);
858
- remember(draft, rest);
859
- onPending?.(next);
860
- adapter.onIntent({ action: "send", text: next });
989
+ remember(draft, context, images, rest);
990
+ onPending?.(next.text, next.context, next.images);
991
+ adapter.onIntent({ action: "send", text: next.text, ...next.context.length ? { context: next.context } : {}, ...next.images.length ? { images: next.images } : {} });
861
992
  }
862
993
  }, [adapter, draft, memoryKey, onPending, queue, queueBlocked, state.canSend]);
863
994
  useEffect(() => {
@@ -869,7 +1000,11 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
869
1000
  useEffect(() => {
870
1001
  if (!restoreDraft) return;
871
1002
  setDraft(restoreDraft.text);
872
- remember(restoreDraft.text, queue);
1003
+ const restoredContext = normalizeContext(restoreDraft.context);
1004
+ const restoredImages = normalizeImages(restoreDraft.images);
1005
+ setContext(restoredContext);
1006
+ setImages(restoredImages);
1007
+ remember(restoreDraft.text, restoredContext, restoredImages, queue);
873
1008
  textarea.current?.focus({ preventScroll: true });
874
1009
  onDraftRestored?.(restoreDraft.id);
875
1010
  }, [onDraftRestored, restoreDraft?.id]);
@@ -877,43 +1012,100 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
877
1012
  const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
878
1013
  return () => clearTimeout(timer);
879
1014
  }, [adapter, draft]);
1015
+ const pickContext = () => {
1016
+ if (!adapter.pickContext || state.mode !== "control" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS) return;
1017
+ setPicking(true);
1018
+ setPickerError(null);
1019
+ Promise.resolve().then(() => adapter.pickContext()).then((picked) => {
1020
+ const attachments = partitionAttachments(picked);
1021
+ if (context.length + attachments.context.length > MAX_CONTEXT_ITEMS) throw new Error(`Attach at most ${MAX_CONTEXT_ITEMS} text items.`);
1022
+ if (images.length + attachments.images.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
1023
+ setContext((current) => {
1024
+ const next = mergeContext(current, attachments.context);
1025
+ remember(draft, next, images, queue);
1026
+ return next;
1027
+ });
1028
+ setImages((current) => {
1029
+ const next = mergeImages(current, attachments.images);
1030
+ remember(draft, context, next, queue);
1031
+ return next;
1032
+ });
1033
+ }).catch((error) => setPickerError(error instanceof Error ? error.message : "Could not attach context.")).finally(() => setPicking(false));
1034
+ };
1035
+ const pasteImages = (event) => {
1036
+ const files = Array.from(event.clipboardData?.files ?? []).filter((file) => file.type.startsWith("image/"));
1037
+ if (!files.length) return;
1038
+ event.preventDefault();
1039
+ if (images.length + files.length > MAX_IMAGE_ITEMS) {
1040
+ setPickerError(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
1041
+ return;
1042
+ }
1043
+ setPicking(true);
1044
+ setPickerError(null);
1045
+ imageAttachmentsFromFiles(files).then((picked) => setImages((current) => {
1046
+ const next = mergeImages(current, picked);
1047
+ remember(draft, context, next, queue);
1048
+ return next;
1049
+ }), (error) => setPickerError(error instanceof Error ? error.message : "Could not paste image.")).finally(() => setPicking(false));
1050
+ };
880
1051
  const send = () => {
881
1052
  const text = draft.trim();
882
1053
  if (!text) return;
883
- if (queuesNewMessage) updateQueue((items) => [...items, text]);
1054
+ const message = { text, context, images };
1055
+ if (queuesNewMessage) updateQueue((items) => [...items, message]);
884
1056
  else if (state.canSend) {
885
1057
  if (onPending) setDispatching(true);
886
- onPending?.(text);
887
- adapter.onIntent({ action: "send", text });
1058
+ onPending?.(text, context, images);
1059
+ adapter.onIntent({ action: "send", text, ...context.length ? { context } : {}, ...images.length ? { images } : {} });
888
1060
  } else return;
889
1061
  setDraft("");
890
- remember("", queuesNewMessage ? [...queue, text] : queue);
1062
+ setContext([]);
1063
+ setImages([]);
1064
+ remember("", [], [], queuesNewMessage ? [...queue, message] : queue);
891
1065
  };
892
- return /* @__PURE__ */ jsxs2("div", { class: "scui-compose", children: [
893
- queue.length ? /* @__PURE__ */ jsxs2("div", { class: "scui-queue", children: [
894
- /* @__PURE__ */ jsxs2("strong", { children: [
1066
+ return /* @__PURE__ */ jsxs3("div", { class: "scui-compose", children: [
1067
+ queue.length ? /* @__PURE__ */ jsxs3("div", { class: "scui-queue", children: [
1068
+ /* @__PURE__ */ jsxs3("strong", { children: [
895
1069
  queue.length,
896
1070
  " queued"
897
1071
  ] }),
898
- queue.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
899
- item,
900
- /* @__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 }) })
901
- ] }, `${index}:${item}`))
1072
+ queue.map((item, index) => /* @__PURE__ */ jsxs3("span", { children: [
1073
+ /* @__PURE__ */ jsxs3("span", { children: [
1074
+ item.text,
1075
+ item.context.length + item.images.length ? /* @__PURE__ */ jsxs3("small", { children: [
1076
+ item.context.length + item.images.length,
1077
+ " attached"
1078
+ ] }) : null
1079
+ ] }),
1080
+ /* @__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 }) })
1081
+ ] }, `${index}:${item.text}`))
902
1082
  ] }) : null,
903
- /* @__PURE__ */ jsxs2("div", { class: "scui-envelope", children: [
904
- /* @__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) => {
1083
+ /* @__PURE__ */ jsx3(ImageTray, { items: images, onRemove: (index) => setImages((items) => {
1084
+ const next = items.filter((_, itemIndex) => itemIndex !== index);
1085
+ remember(draft, context, next, queue);
1086
+ return next;
1087
+ }) }),
1088
+ /* @__PURE__ */ jsx3(ContextTray, { items: context, onRemove: (index) => setContext((items) => {
1089
+ const next = items.filter((_, itemIndex) => itemIndex !== index);
1090
+ remember(draft, next, images, queue);
1091
+ return next;
1092
+ }) }),
1093
+ pickerError ? /* @__PURE__ */ jsx3("small", { class: "scui-context-error", role: "alert", children: pickerError }) : null,
1094
+ /* @__PURE__ */ jsxs3("div", { class: "scui-envelope", children: [
1095
+ 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,
1096
+ /* @__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) => {
905
1097
  const value = event.currentTarget.value;
906
1098
  setDraft(value);
907
- remember(value, queue);
1099
+ remember(value, context, images, queue);
908
1100
  }, onKeyDown: (event) => {
909
1101
  if (isSendKey(event)) {
910
1102
  event.preventDefault();
911
1103
  send();
912
1104
  }
913
1105
  } }),
914
- /* @__PURE__ */ jsxs2("span", { children: [
915
- 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,
916
- /* @__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 }) })
1106
+ /* @__PURE__ */ jsxs3("span", { children: [
1107
+ 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,
1108
+ /* @__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 }) })
917
1109
  ] })
918
1110
  ] })
919
1111
  ] });
@@ -926,7 +1118,7 @@ import { useEffect as useEffect3, useId, useLayoutEffect as useLayoutEffect2, us
926
1118
  // src/markdown.jsx
927
1119
  import MarkdownIt from "markdown-it";
928
1120
  import { useEffect as useEffect2, useMemo, useRef as useRef2 } from "preact/hooks";
929
- import { jsx as jsx3 } from "preact/jsx-runtime";
1121
+ import { jsx as jsx4 } from "preact/jsx-runtime";
930
1122
  var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
931
1123
  var LANGUAGE_LABELS = {
932
1124
  bash: "Shell",
@@ -1013,11 +1205,11 @@ function Markdown({ value, copyText }) {
1013
1205
  }, 1500);
1014
1206
  resets.current.set(button, timer);
1015
1207
  };
1016
- return /* @__PURE__ */ jsx3("div", { class: "scui-markdown", "data-copyable": Boolean(copyText), onClick: copyCode, dangerouslySetInnerHTML: { __html: html } });
1208
+ return /* @__PURE__ */ jsx4("div", { class: "scui-markdown", "data-copyable": Boolean(copyText), onClick: copyCode, dangerouslySetInnerHTML: { __html: html } });
1017
1209
  }
1018
1210
 
1019
1211
  // src/conversation.jsx
1020
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "preact/jsx-runtime";
1212
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
1021
1213
  function LoadingStatus({ state, compact = false }) {
1022
1214
  const copy = {
1023
1215
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -1025,43 +1217,43 @@ function LoadingStatus({ state, compact = false }) {
1025
1217
  discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
1026
1218
  ready: ["Ready", "Coding sessions are up to date.", 3]
1027
1219
  }[state.startup];
1028
- return /* @__PURE__ */ jsxs3("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
1029
- /* @__PURE__ */ jsx4("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("i", {}) }),
1030
- /* @__PURE__ */ jsxs3("span", { class: "scui-loading-copy", children: [
1031
- /* @__PURE__ */ jsx4("strong", { children: copy[0] }),
1032
- /* @__PURE__ */ jsx4("small", { children: copy[1] })
1220
+ return /* @__PURE__ */ jsxs4("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
1221
+ /* @__PURE__ */ jsx5("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx5("i", {}) }),
1222
+ /* @__PURE__ */ jsxs4("span", { class: "scui-loading-copy", children: [
1223
+ /* @__PURE__ */ jsx5("strong", { children: copy[0] }),
1224
+ /* @__PURE__ */ jsx5("small", { children: copy[1] })
1033
1225
  ] }),
1034
- /* @__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)) })
1226
+ /* @__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)) })
1035
1227
  ] });
1036
1228
  }
1037
1229
  function RequestCard({ entry, adapter, canRespond }) {
1038
1230
  const request = entry.request;
1039
1231
  if (!request) return null;
1040
1232
  if (request.status === "responded") {
1041
- return /* @__PURE__ */ jsxs3("div", { class: "scui-request-done", children: [
1233
+ return /* @__PURE__ */ jsxs4("div", { class: "scui-request-done", children: [
1042
1234
  "\u2713 Request answered \xB7 ",
1043
1235
  request.resolution?.name ?? request.requestKind
1044
1236
  ] });
1045
1237
  }
1046
- return /* @__PURE__ */ jsxs3("section", { class: "scui-request", role: "alert", "aria-label": `${request.requestKind} needs input`, children: [
1047
- /* @__PURE__ */ jsx4("strong", { children: "Agent needs input" }),
1048
- /* @__PURE__ */ jsx4(Markdown, { value: request.payloadText || entry.text, copyText: adapter?.copyText }),
1049
- /* @__PURE__ */ jsxs3("div", { class: "scui-request-actions", children: [
1050
- 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)),
1051
- request.cancellable ? /* @__PURE__ */ jsx4("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
1238
+ return /* @__PURE__ */ jsxs4("section", { class: "scui-request", role: "alert", "aria-label": `${request.requestKind} needs input`, children: [
1239
+ /* @__PURE__ */ jsx5("strong", { children: "Agent needs input" }),
1240
+ /* @__PURE__ */ jsx5(Markdown, { value: request.payloadText || entry.text, copyText: adapter?.copyText }),
1241
+ /* @__PURE__ */ jsxs4("div", { class: "scui-request-actions", children: [
1242
+ 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)),
1243
+ request.cancellable ? /* @__PURE__ */ jsx5("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
1052
1244
  ] })
1053
1245
  ] });
1054
1246
  }
1055
1247
  function ContextDisclosure({ context }) {
1056
1248
  if (!context?.length) return null;
1057
- return /* @__PURE__ */ jsxs3("details", { class: "scui-context", children: [
1058
- /* @__PURE__ */ jsxs3("summary", { children: [
1249
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-context", children: [
1250
+ /* @__PURE__ */ jsxs4("summary", { children: [
1059
1251
  "Context \xB7 ",
1060
1252
  context.length
1061
1253
  ] }),
1062
- /* @__PURE__ */ jsx4("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs3("p", { children: [
1063
- /* @__PURE__ */ jsx4("strong", { children: item.label }),
1064
- /* @__PURE__ */ jsx4("span", { children: item.detail })
1254
+ /* @__PURE__ */ jsx5("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs4("p", { children: [
1255
+ /* @__PURE__ */ jsx5("strong", { children: item.label }),
1256
+ /* @__PURE__ */ jsx5("span", { children: item.detail })
1065
1257
  ] }, item.id ?? index)) })
1066
1258
  ] });
1067
1259
  }
@@ -1083,46 +1275,46 @@ function MessageMeta({ entry, adapter }) {
1083
1275
  reset.current = setTimeout(() => setCopyState2("idle"), 1500);
1084
1276
  };
1085
1277
  const copyLabel = copyState === "copied" ? "Message copied" : copyState === "failed" ? "Copy failed \xB7 retry" : "Copy message";
1086
- return /* @__PURE__ */ jsxs3("footer", { class: "scui-message-meta", children: [
1087
- validDate ? /* @__PURE__ */ jsx4("time", { dateTime: validDate.toISOString(), title: validDate.toLocaleString(), children: validDate.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }) : null,
1088
- 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
1278
+ return /* @__PURE__ */ jsxs4("footer", { class: "scui-message-meta", children: [
1279
+ validDate ? /* @__PURE__ */ jsx5("time", { dateTime: validDate.toISOString(), title: validDate.toLocaleString(), children: validDate.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }) : null,
1280
+ 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
1089
1281
  ] });
1090
1282
  }
1091
1283
  var TOOL_ICONS = {
1092
- read: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1093
- /* @__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" }),
1094
- /* @__PURE__ */ jsx4("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
1284
+ read: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1285
+ /* @__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" }),
1286
+ /* @__PURE__ */ jsx5("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
1095
1287
  ] }),
1096
- search: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1097
- /* @__PURE__ */ jsx4("circle", { cx: "8", cy: "8", r: "4.5" }),
1098
- /* @__PURE__ */ jsx4("path", { d: "m11.5 11.5 3 3" })
1288
+ search: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1289
+ /* @__PURE__ */ jsx5("circle", { cx: "8", cy: "8", r: "4.5" }),
1290
+ /* @__PURE__ */ jsx5("path", { d: "m11.5 11.5 3 3" })
1099
1291
  ] }),
1100
- edit: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1101
- /* @__PURE__ */ jsx4("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
1102
- /* @__PURE__ */ jsx4("path", { d: "m10 5 3 3" })
1292
+ edit: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1293
+ /* @__PURE__ */ jsx5("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
1294
+ /* @__PURE__ */ jsx5("path", { d: "m10 5 3 3" })
1103
1295
  ] }),
1104
- command: () => /* @__PURE__ */ jsx4(Fragment3, { children: /* @__PURE__ */ jsx4("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
1105
- test: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1106
- /* @__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" }),
1107
- /* @__PURE__ */ jsx4("path", { d: "M5 2.5h8" })
1296
+ command: () => /* @__PURE__ */ jsx5(Fragment3, { children: /* @__PURE__ */ jsx5("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
1297
+ test: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1298
+ /* @__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" }),
1299
+ /* @__PURE__ */ jsx5("path", { d: "M5 2.5h8" })
1108
1300
  ] }),
1109
- web: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1110
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "6.5" }),
1111
- /* @__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" })
1301
+ web: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1302
+ /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "6.5" }),
1303
+ /* @__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" })
1112
1304
  ] }),
1113
- agent: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1114
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "6", r: "2.5" }),
1115
- /* @__PURE__ */ jsx4("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
1305
+ agent: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1306
+ /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "6", r: "2.5" }),
1307
+ /* @__PURE__ */ jsx5("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
1116
1308
  ] }),
1117
- 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" }) }),
1118
- other: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1119
- /* @__PURE__ */ jsx4("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
1120
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "3.5" })
1309
+ 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" }) }),
1310
+ other: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
1311
+ /* @__PURE__ */ jsx5("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
1312
+ /* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "3.5" })
1121
1313
  ] })
1122
1314
  };
1123
1315
  function ToolIcon({ category }) {
1124
1316
  const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
1125
- 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, {}) });
1317
+ 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, {}) });
1126
1318
  }
1127
1319
  function toolAction2(entry, category, presentation) {
1128
1320
  if (presentation?.action) return presentation.action;
@@ -1177,7 +1369,7 @@ function ToolMetrics({ presentation }) {
1177
1369
  presentation.exitCode === null ? "" : `exit ${presentation.exitCode}`,
1178
1370
  formatDuration(presentation.durationMs)
1179
1371
  ].filter(Boolean);
1180
- return metrics.length ? /* @__PURE__ */ jsx4("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx4("span", { children: metric }, metric)) }) : null;
1372
+ return metrics.length ? /* @__PURE__ */ jsx5("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx5("span", { children: metric }, metric)) }) : null;
1181
1373
  }
1182
1374
  function PendingElapsed({ now }) {
1183
1375
  const clock = now ?? Date.now;
@@ -1187,74 +1379,74 @@ function PendingElapsed({ now }) {
1187
1379
  const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
1188
1380
  return () => clearInterval(timer);
1189
1381
  }, [clock]);
1190
- return /* @__PURE__ */ jsx4("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
1382
+ return /* @__PURE__ */ jsx5("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
1191
1383
  }
1192
1384
  function LinePreview({ value, kind }) {
1193
1385
  if (!value) return null;
1194
- return /* @__PURE__ */ jsx4("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
1386
+ return /* @__PURE__ */ jsx5("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
1195
1387
  const tone = kind === "diff" ? line.startsWith("+") && !line.startsWith("+++") ? "add" : line.startsWith("-") && !line.startsWith("---") ? "remove" : line.startsWith("@@") ? "hunk" : "plain" : "plain";
1196
- return /* @__PURE__ */ jsxs3("li", { "data-tone": tone, children: [
1197
- /* @__PURE__ */ jsx4("span", { children: index + 1 }),
1198
- /* @__PURE__ */ jsx4("code", { children: line || " " })
1388
+ return /* @__PURE__ */ jsxs4("li", { "data-tone": tone, children: [
1389
+ /* @__PURE__ */ jsx5("span", { children: index + 1 }),
1390
+ /* @__PURE__ */ jsx5("code", { children: line || " " })
1199
1391
  ] }, index);
1200
1392
  }) });
1201
1393
  }
1202
1394
  function TerminalPreview({ presentation, pending, failed }) {
1203
- return /* @__PURE__ */ jsxs3("section", { class: "scui-terminal", children: [
1204
- /* @__PURE__ */ jsxs3("header", { children: [
1205
- /* @__PURE__ */ jsxs3("span", { "aria-hidden": "true", children: [
1206
- /* @__PURE__ */ jsx4("i", {}),
1207
- /* @__PURE__ */ jsx4("i", {}),
1208
- /* @__PURE__ */ jsx4("i", {})
1395
+ return /* @__PURE__ */ jsxs4("section", { class: "scui-terminal", children: [
1396
+ /* @__PURE__ */ jsxs4("header", { children: [
1397
+ /* @__PURE__ */ jsxs4("span", { "aria-hidden": "true", children: [
1398
+ /* @__PURE__ */ jsx5("i", {}),
1399
+ /* @__PURE__ */ jsx5("i", {}),
1400
+ /* @__PURE__ */ jsx5("i", {})
1209
1401
  ] }),
1210
- /* @__PURE__ */ jsx4("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
1402
+ /* @__PURE__ */ jsx5("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
1211
1403
  ] }),
1212
- presentation.preview ? /* @__PURE__ */ jsx4("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs3("div", { class: "scui-terminal-wait", children: [
1213
- /* @__PURE__ */ jsx4("i", {}),
1404
+ presentation.preview ? /* @__PURE__ */ jsx5("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs4("div", { class: "scui-terminal-wait", children: [
1405
+ /* @__PURE__ */ jsx5("i", {}),
1214
1406
  " Waiting for output"
1215
- ] }) : /* @__PURE__ */ jsx4("div", { class: "scui-terminal-empty", children: "No output" })
1407
+ ] }) : /* @__PURE__ */ jsx5("div", { class: "scui-terminal-empty", children: "No output" })
1216
1408
  ] });
1217
1409
  }
1218
1410
  function SearchPreview({ presentation }) {
1219
1411
  const lines = stripAnsi(presentation.preview).split("\n").filter(Boolean);
1220
- return /* @__PURE__ */ jsxs3("section", { class: "scui-search-preview", children: [
1221
- presentation.query ? /* @__PURE__ */ jsxs3("header", { children: [
1222
- /* @__PURE__ */ jsx4("span", { children: "Search" }),
1223
- /* @__PURE__ */ jsx4("code", { children: presentation.query })
1412
+ return /* @__PURE__ */ jsxs4("section", { class: "scui-search-preview", children: [
1413
+ presentation.query ? /* @__PURE__ */ jsxs4("header", { children: [
1414
+ /* @__PURE__ */ jsx5("span", { children: "Search" }),
1415
+ /* @__PURE__ */ jsx5("code", { children: presentation.query })
1224
1416
  ] }) : null,
1225
- lines.length ? /* @__PURE__ */ jsx4("ol", { children: lines.map((line, index) => {
1417
+ lines.length ? /* @__PURE__ */ jsx5("ol", { children: lines.map((line, index) => {
1226
1418
  const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
1227
- return /* @__PURE__ */ jsx4("li", { children: match ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
1228
- /* @__PURE__ */ jsx4("code", { children: match[1] }),
1229
- /* @__PURE__ */ jsxs3("small", { children: [
1419
+ return /* @__PURE__ */ jsx5("li", { children: match ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
1420
+ /* @__PURE__ */ jsx5("code", { children: match[1] }),
1421
+ /* @__PURE__ */ jsxs4("small", { children: [
1230
1422
  match[2],
1231
1423
  match[3] ? `:${match[3]}` : ""
1232
1424
  ] }),
1233
- /* @__PURE__ */ jsx4("span", { children: match[4] })
1234
- ] }) : /* @__PURE__ */ jsx4("span", { children: line }) }, index);
1235
- }) }) : /* @__PURE__ */ jsx4("p", { children: "No textual results" })
1425
+ /* @__PURE__ */ jsx5("span", { children: match[4] })
1426
+ ] }) : /* @__PURE__ */ jsx5("span", { children: line }) }, index);
1427
+ }) }) : /* @__PURE__ */ jsx5("p", { children: "No textual results" })
1236
1428
  ] });
1237
1429
  }
1238
1430
  function ToolPreview({ presentation, entry }) {
1239
1431
  const pending = entry.status === "pending";
1240
1432
  const failed = entry.status === "error";
1241
- if (presentation.detail === "terminal") return /* @__PURE__ */ jsx4(TerminalPreview, { presentation, pending, failed });
1242
- 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" });
1243
- 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" });
1244
- if (presentation.detail === "matches") return /* @__PURE__ */ jsx4(SearchPreview, { presentation });
1245
- if (presentation.detail === "web") return /* @__PURE__ */ jsxs3("section", { class: "scui-web-preview", children: [
1246
- presentation.url ? /* @__PURE__ */ jsx4("code", { children: presentation.url }) : null,
1247
- presentation.preview ? /* @__PURE__ */ jsx4("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx4("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
1433
+ if (presentation.detail === "terminal") return /* @__PURE__ */ jsx5(TerminalPreview, { presentation, pending, failed });
1434
+ 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" });
1435
+ 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" });
1436
+ if (presentation.detail === "matches") return /* @__PURE__ */ jsx5(SearchPreview, { presentation });
1437
+ if (presentation.detail === "web") return /* @__PURE__ */ jsxs4("section", { class: "scui-web-preview", children: [
1438
+ presentation.url ? /* @__PURE__ */ jsx5("code", { children: presentation.url }) : null,
1439
+ presentation.preview ? /* @__PURE__ */ jsx5("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx5("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
1248
1440
  ] });
1249
- 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: [
1250
- /* @__PURE__ */ jsx4("strong", { children: item.label }),
1251
- /* @__PURE__ */ jsx4("small", { children: item.status })
1252
- ] }, `${item.label}:${index}`)) }) : presentation.preview ? /* @__PURE__ */ jsx4("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx4("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
1253
- 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: [
1254
- /* @__PURE__ */ jsx4("i", { "aria-hidden": "true" }),
1255
- /* @__PURE__ */ jsx4("span", { children: item.label })
1441
+ 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: [
1442
+ /* @__PURE__ */ jsx5("strong", { children: item.label }),
1443
+ /* @__PURE__ */ jsx5("small", { children: item.status })
1444
+ ] }, `${item.label}:${index}`)) }) : presentation.preview ? /* @__PURE__ */ jsx5("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx5("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
1445
+ 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: [
1446
+ /* @__PURE__ */ jsx5("i", { "aria-hidden": "true" }),
1447
+ /* @__PURE__ */ jsx5("span", { children: item.label })
1256
1448
  ] }, `${item.label}:${index}`)) });
1257
- return presentation.preview ? /* @__PURE__ */ jsx4("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
1449
+ return presentation.preview ? /* @__PURE__ */ jsx5("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
1258
1450
  }
1259
1451
  function ToolActions({ presentation, adapter }) {
1260
1452
  const [copied, setCopied] = useState2(false);
@@ -1268,27 +1460,27 @@ function ToolActions({ presentation, adapter }) {
1268
1460
  clearTimeout(reset.current);
1269
1461
  reset.current = setTimeout(() => setCopied(false), 1500);
1270
1462
  };
1271
- return action ? /* @__PURE__ */ jsx4("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx4("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
1463
+ return action ? /* @__PURE__ */ jsx5("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx5("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
1272
1464
  }
1273
1465
  function ToolStack({ tools }) {
1274
1466
  if (tools.length < 2) return null;
1275
- 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)) });
1467
+ 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)) });
1276
1468
  }
1277
1469
  function TechnicalDetails({ entry }) {
1278
1470
  if (!entry.arguments && !entry.resultText) return null;
1279
- return /* @__PURE__ */ jsxs3("details", { class: "scui-tool-technical", children: [
1280
- /* @__PURE__ */ jsx4("summary", { children: "Technical details" }),
1281
- /* @__PURE__ */ jsxs3("div", { children: [
1282
- entry.arguments ? /* @__PURE__ */ jsxs3("section", { children: [
1283
- /* @__PURE__ */ jsx4("strong", { children: "Native arguments" }),
1284
- /* @__PURE__ */ jsx4("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs3("div", { children: [
1285
- /* @__PURE__ */ jsx4("dt", { children: row.label }),
1286
- /* @__PURE__ */ jsx4("dd", { children: /* @__PURE__ */ jsx4("pre", { children: row.value }) })
1471
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-tool-technical", children: [
1472
+ /* @__PURE__ */ jsx5("summary", { children: "Technical details" }),
1473
+ /* @__PURE__ */ jsxs4("div", { children: [
1474
+ entry.arguments ? /* @__PURE__ */ jsxs4("section", { children: [
1475
+ /* @__PURE__ */ jsx5("strong", { children: "Native arguments" }),
1476
+ /* @__PURE__ */ jsx5("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs4("div", { children: [
1477
+ /* @__PURE__ */ jsx5("dt", { children: row.label }),
1478
+ /* @__PURE__ */ jsx5("dd", { children: /* @__PURE__ */ jsx5("pre", { children: row.value }) })
1287
1479
  ] }, row.key)) })
1288
1480
  ] }) : null,
1289
- entry.resultText ? /* @__PURE__ */ jsxs3("section", { children: [
1290
- /* @__PURE__ */ jsx4("strong", { children: "Native result" }),
1291
- /* @__PURE__ */ jsxs3("pre", { "data-error": entry.status === "error", children: [
1481
+ entry.resultText ? /* @__PURE__ */ jsxs4("section", { children: [
1482
+ /* @__PURE__ */ jsx5("strong", { children: "Native result" }),
1483
+ /* @__PURE__ */ jsxs4("pre", { "data-error": entry.status === "error", children: [
1292
1484
  entry.resultText,
1293
1485
  entry.truncated ? "\n[truncated]" : ""
1294
1486
  ] })
@@ -1297,19 +1489,20 @@ function TechnicalDetails({ entry }) {
1297
1489
  ] });
1298
1490
  }
1299
1491
  function TranscriptEntry({ entry, state, adapter }) {
1300
- if (entry.role === "request") return /* @__PURE__ */ jsx4(RequestCard, { entry, adapter, canRespond: state.canRespond });
1492
+ if (entry.role === "request") return /* @__PURE__ */ jsx5(RequestCard, { entry, adapter, canRespond: state.canRespond });
1301
1493
  if (entry.role === "reasoning") {
1302
- return /* @__PURE__ */ jsxs3("details", { class: "scui-reasoning", open: entry.streaming, children: [
1303
- /* @__PURE__ */ jsx4("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
1304
- /* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText })
1494
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-reasoning", open: entry.streaming, children: [
1495
+ /* @__PURE__ */ jsx5("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
1496
+ /* @__PURE__ */ jsx5(Markdown, { value: entry.text, copyText: adapter?.copyText })
1305
1497
  ] });
1306
1498
  }
1307
- if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx4("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
1308
- return /* @__PURE__ */ jsxs3("article", { class: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
1309
- /* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText }),
1310
- /* @__PURE__ */ jsx4(ContextDisclosure, { context: entry.context }),
1311
- entry.truncated ? /* @__PURE__ */ jsx4("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
1312
- /* @__PURE__ */ jsx4(MessageMeta, { entry, adapter })
1499
+ if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx5("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
1500
+ return /* @__PURE__ */ jsxs4("article", { class: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
1501
+ /* @__PURE__ */ jsx5(MessageImages, { items: entry.images }),
1502
+ /* @__PURE__ */ jsx5(Markdown, { value: entry.text, copyText: adapter?.copyText }),
1503
+ /* @__PURE__ */ jsx5(ContextDisclosure, { context: entry.context }),
1504
+ entry.truncated ? /* @__PURE__ */ jsx5("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
1505
+ /* @__PURE__ */ jsx5(MessageMeta, { entry, adapter })
1313
1506
  ] });
1314
1507
  }
1315
1508
  function ToolRow({ entry, workspace, open = false, adapter }) {
@@ -1321,102 +1514,102 @@ function ToolRow({ entry, workspace, open = false, adapter }) {
1321
1514
  const target = compactToolTarget(presentation.target, workspace);
1322
1515
  const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
1323
1516
  const category = presentation.category ?? toolCategory(entry);
1324
- const summary = /* @__PURE__ */ jsxs3(Fragment3, { children: [
1325
- /* @__PURE__ */ jsx4(ToolIcon, { category }),
1326
- /* @__PURE__ */ jsx4("strong", { children: toolAction2(entry, category, presentation) }),
1327
- target ? /* @__PURE__ */ jsx4("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
1328
- /* @__PURE__ */ jsx4("span", { class: "scui-spacer" }),
1329
- entry.status === "pending" ? /* @__PURE__ */ jsx4(PendingElapsed, { now: adapter?.now }) : null,
1330
- /* @__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 }) }),
1331
- hasDetail ? /* @__PURE__ */ jsx4(UiIcon, { name: "chevron", size: 14, class: "scui-tool-chevron" }) : null
1517
+ const summary = /* @__PURE__ */ jsxs4(Fragment3, { children: [
1518
+ /* @__PURE__ */ jsx5(ToolIcon, { category }),
1519
+ /* @__PURE__ */ jsx5("strong", { children: toolAction2(entry, category, presentation) }),
1520
+ target ? /* @__PURE__ */ jsx5("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
1521
+ /* @__PURE__ */ jsx5("span", { class: "scui-spacer" }),
1522
+ entry.status === "pending" ? /* @__PURE__ */ jsx5(PendingElapsed, { now: adapter?.now }) : null,
1523
+ /* @__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 }) }),
1524
+ hasDetail ? /* @__PURE__ */ jsx5(UiIcon, { name: "chevron", size: 14, class: "scui-tool-chevron" }) : null
1332
1525
  ] });
1333
- 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 }) });
1334
- return /* @__PURE__ */ jsxs3("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
1335
- /* @__PURE__ */ jsx4("summary", { class: "scui-tool-head", children: summary }),
1336
- /* @__PURE__ */ jsxs3("div", { class: "scui-tool-detail", children: [
1337
- /* @__PURE__ */ jsx4(ToolMetrics, { presentation }),
1338
- /* @__PURE__ */ jsx4(ToolStack, { tools: presentation.tools ?? [] }),
1339
- /* @__PURE__ */ jsx4(ToolPreview, { presentation, entry }),
1340
- presentation.fields.length ? /* @__PURE__ */ jsx4("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs3("div", { children: [
1341
- /* @__PURE__ */ jsx4("dt", { children: field.label }),
1342
- /* @__PURE__ */ jsx4("dd", { children: field.value })
1526
+ 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 }) });
1527
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
1528
+ /* @__PURE__ */ jsx5("summary", { class: "scui-tool-head", children: summary }),
1529
+ /* @__PURE__ */ jsxs4("div", { class: "scui-tool-detail", children: [
1530
+ /* @__PURE__ */ jsx5(ToolMetrics, { presentation }),
1531
+ /* @__PURE__ */ jsx5(ToolStack, { tools: presentation.tools ?? [] }),
1532
+ /* @__PURE__ */ jsx5(ToolPreview, { presentation, entry }),
1533
+ presentation.fields.length ? /* @__PURE__ */ jsx5("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs4("div", { children: [
1534
+ /* @__PURE__ */ jsx5("dt", { children: field.label }),
1535
+ /* @__PURE__ */ jsx5("dd", { children: field.value })
1343
1536
  ] }, field.label)) }) : null,
1344
- /* @__PURE__ */ jsx4(ToolActions, { presentation, adapter }),
1345
- /* @__PURE__ */ jsx4(TechnicalDetails, { entry })
1537
+ /* @__PURE__ */ jsx5(ToolActions, { presentation, adapter }),
1538
+ /* @__PURE__ */ jsx5(TechnicalDetails, { entry })
1346
1539
  ] })
1347
1540
  ] });
1348
1541
  }
1349
1542
  function ActivityGroup({ entries, state, adapter }) {
1350
- 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 }) });
1543
+ 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 }) });
1351
1544
  const active = entries.some((entry) => entry.status === "pending");
1352
1545
  const [open, setOpen] = useState2(active);
1353
1546
  const id = useId();
1354
1547
  useEffect3(() => {
1355
1548
  if (active) setOpen(true);
1356
1549
  }, [active]);
1357
- return /* @__PURE__ */ jsxs3("section", { class: "scui-activity", children: [
1358
- /* @__PURE__ */ jsxs3("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
1359
- /* @__PURE__ */ jsx4("span", { class: "scui-fold", "data-open": open, children: /* @__PURE__ */ jsx4(UiIcon, { name: "chevron", size: 14 }) }),
1360
- /* @__PURE__ */ jsx4("strong", { children: activitySummary(entries) }),
1361
- /* @__PURE__ */ jsx4("span", { class: "scui-spacer" }),
1362
- /* @__PURE__ */ jsxs3("small", { children: [
1550
+ return /* @__PURE__ */ jsxs4("section", { class: "scui-activity", children: [
1551
+ /* @__PURE__ */ jsxs4("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
1552
+ /* @__PURE__ */ jsx5("span", { class: "scui-fold", "data-open": open, children: /* @__PURE__ */ jsx5(UiIcon, { name: "chevron", size: 14 }) }),
1553
+ /* @__PURE__ */ jsx5("strong", { children: activitySummary(entries) }),
1554
+ /* @__PURE__ */ jsx5("span", { class: "scui-spacer" }),
1555
+ /* @__PURE__ */ jsxs4("small", { children: [
1363
1556
  entries.filter((entry) => entry.status !== "pending").length,
1364
1557
  "/",
1365
1558
  entries.length
1366
1559
  ] })
1367
1560
  ] }),
1368
- open ? /* @__PURE__ */ jsx4("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx4(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
1561
+ open ? /* @__PURE__ */ jsx5("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx5(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
1369
1562
  ] });
1370
1563
  }
1371
1564
  function TaskPlan({ plan }) {
1372
1565
  if (!plan.items.length) return null;
1373
1566
  const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
1374
- return /* @__PURE__ */ jsxs3("details", { class: "scui-plan", children: [
1375
- /* @__PURE__ */ jsxs3("summary", { children: [
1376
- /* @__PURE__ */ jsx4("span", { children: "Plan" }),
1377
- /* @__PURE__ */ jsxs3("small", { children: [
1567
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-plan", children: [
1568
+ /* @__PURE__ */ jsxs4("summary", { children: [
1569
+ /* @__PURE__ */ jsx5("span", { children: "Plan" }),
1570
+ /* @__PURE__ */ jsxs4("small", { children: [
1378
1571
  complete,
1379
1572
  "/",
1380
1573
  plan.items.length
1381
1574
  ] })
1382
1575
  ] }),
1383
- /* @__PURE__ */ jsx4("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs3("li", { "data-status": item.status, children: [
1384
- /* @__PURE__ */ jsx4("i", { "aria-hidden": "true" }),
1576
+ /* @__PURE__ */ jsx5("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs4("li", { "data-status": item.status, children: [
1577
+ /* @__PURE__ */ jsx5("i", { "aria-hidden": "true" }),
1385
1578
  " ",
1386
- /* @__PURE__ */ jsx4("span", { children: item.title })
1579
+ /* @__PURE__ */ jsx5("span", { children: item.title })
1387
1580
  ] }, item.id)) })
1388
1581
  ] });
1389
1582
  }
1390
1583
  function SessionDetails({ semantics }) {
1391
1584
  if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
1392
- return /* @__PURE__ */ jsxs3("details", { class: "scui-details", children: [
1393
- /* @__PURE__ */ jsx4("summary", { children: "Session details" }),
1394
- /* @__PURE__ */ jsxs3("div", { children: [
1395
- semantics.fidelity ? /* @__PURE__ */ jsxs3("p", { children: [
1396
- /* @__PURE__ */ jsx4("strong", { children: "Fidelity" }),
1397
- /* @__PURE__ */ jsx4("span", { children: semantics.fidelity.replaceAll("_", " ") })
1585
+ return /* @__PURE__ */ jsxs4("details", { class: "scui-details", children: [
1586
+ /* @__PURE__ */ jsx5("summary", { children: "Session details" }),
1587
+ /* @__PURE__ */ jsxs4("div", { children: [
1588
+ semantics.fidelity ? /* @__PURE__ */ jsxs4("p", { children: [
1589
+ /* @__PURE__ */ jsx5("strong", { children: "Fidelity" }),
1590
+ /* @__PURE__ */ jsx5("span", { children: semantics.fidelity.replaceAll("_", " ") })
1398
1591
  ] }) : null,
1399
- /* @__PURE__ */ jsxs3("p", { children: [
1400
- /* @__PURE__ */ jsx4("strong", { children: "Native records" }),
1401
- /* @__PURE__ */ jsx4("span", { children: semantics.rawRecords })
1592
+ /* @__PURE__ */ jsxs4("p", { children: [
1593
+ /* @__PURE__ */ jsx5("strong", { children: "Native records" }),
1594
+ /* @__PURE__ */ jsx5("span", { children: semantics.rawRecords })
1402
1595
  ] }),
1403
- semantics.residueCount ? /* @__PURE__ */ jsxs3("p", { children: [
1404
- /* @__PURE__ */ jsx4("strong", { children: "Residue" }),
1405
- /* @__PURE__ */ jsxs3("span", { children: [
1596
+ semantics.residueCount ? /* @__PURE__ */ jsxs4("p", { children: [
1597
+ /* @__PURE__ */ jsx5("strong", { children: "Residue" }),
1598
+ /* @__PURE__ */ jsxs4("span", { children: [
1406
1599
  semantics.residueCount,
1407
1600
  " retained"
1408
1601
  ] })
1409
1602
  ] }) : null,
1410
- semantics.parseErrors ? /* @__PURE__ */ jsxs3("p", { children: [
1411
- /* @__PURE__ */ jsx4("strong", { children: "Parse diagnostics" }),
1412
- /* @__PURE__ */ jsx4("span", { children: semantics.parseErrors })
1603
+ semantics.parseErrors ? /* @__PURE__ */ jsxs4("p", { children: [
1604
+ /* @__PURE__ */ jsx5("strong", { children: "Parse diagnostics" }),
1605
+ /* @__PURE__ */ jsx5("span", { children: semantics.parseErrors })
1413
1606
  ] }) : null,
1414
- semantics.subagents.map((agent) => /* @__PURE__ */ jsxs3("p", { children: [
1415
- /* @__PURE__ */ jsxs3("strong", { children: [
1607
+ semantics.subagents.map((agent) => /* @__PURE__ */ jsxs4("p", { children: [
1608
+ /* @__PURE__ */ jsxs4("strong", { children: [
1416
1609
  agent.source,
1417
1610
  " subagent"
1418
1611
  ] }),
1419
- /* @__PURE__ */ jsxs3("span", { children: [
1612
+ /* @__PURE__ */ jsxs4("span", { children: [
1420
1613
  agent.messages,
1421
1614
  " messages \xB7 ",
1422
1615
  agent.fidelity.replaceAll("_", " ")
@@ -1435,7 +1628,7 @@ function ConversationAnnouncements({ state }) {
1435
1628
  }
1436
1629
  previousBusy.current = state.busy;
1437
1630
  }, [state.busy, state.error, state.harness]);
1438
- return /* @__PURE__ */ jsx4("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
1631
+ return /* @__PURE__ */ jsx5("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
1439
1632
  }
1440
1633
  function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null, unreadAfterMessages = null }) {
1441
1634
  const scroller = useRef3(null);
@@ -1467,65 +1660,72 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
1467
1660
  const element = scroller.current;
1468
1661
  if (!element) return;
1469
1662
  const anchor = earlierAnchor.current;
1470
- if (anchor && state.transcript.length > anchor.entries) {
1471
- element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
1472
- earlierAnchor.current = null;
1473
- remember({ top: element.scrollTop, atBottom: false });
1474
- return;
1663
+ if (anchor) {
1664
+ if (state.operation === "loadEarlier") anchor.seenOperation = true;
1665
+ const prepended = state.transcript.length > anchor.entries && state.transcript[0]?.id !== anchor.firstId;
1666
+ if (prepended) {
1667
+ element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
1668
+ earlierAnchor.current = null;
1669
+ remember({ top: element.scrollTop, atBottom: false });
1670
+ return;
1671
+ }
1672
+ if (state.error || anchor.seenOperation && state.operation !== "loadEarlier") earlierAnchor.current = null;
1475
1673
  }
1476
1674
  if (!restored.current) {
1477
1675
  restored.current = true;
1478
1676
  if (remembered.top !== null && !remembered.atBottom) element.scrollTop = remembered.top;
1479
1677
  else pin();
1480
1678
  } else if (atBottom) pin();
1481
- }, [memoryKey, state.transcript, state.busy, state.operation, pendingMessage?.text, pendingMessage?.status]);
1482
- return /* @__PURE__ */ jsxs3("div", { class: "scui-conversation-wrap", children: [
1483
- /* @__PURE__ */ jsx4(ConversationAnnouncements, { state }),
1484
- /* @__PURE__ */ jsx4("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
1679
+ }, [memoryKey, state.transcript, state.busy, state.operation, state.error, pendingMessage?.text, pendingMessage?.status]);
1680
+ return /* @__PURE__ */ jsxs4("div", { class: "scui-conversation-wrap", children: [
1681
+ /* @__PURE__ */ jsx5(ConversationAnnouncements, { state }),
1682
+ /* @__PURE__ */ jsx5("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
1485
1683
  const element = event.currentTarget;
1486
1684
  const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
1487
1685
  setAtBottom(bottom);
1488
1686
  remember({ top: element.scrollTop, atBottom: bottom });
1489
- }, children: /* @__PURE__ */ jsxs3("div", { children: [
1490
- Before ? /* @__PURE__ */ jsx4(Before, { state, adapter, value: null }) : null,
1491
- /* @__PURE__ */ jsx4(Plan, { plan: state.taskPlan, value: state.taskPlan, state, adapter }),
1492
- /* @__PURE__ */ jsx4(SessionDetails, { semantics: state.semantics }),
1493
- state.history.hasEarlier ? /* @__PURE__ */ jsx4("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
1687
+ }, children: /* @__PURE__ */ jsxs4("div", { children: [
1688
+ Before ? /* @__PURE__ */ jsx5(Before, { state, adapter, value: null }) : null,
1689
+ /* @__PURE__ */ jsx5(Plan, { plan: state.taskPlan, value: state.taskPlan, state, adapter }),
1690
+ /* @__PURE__ */ jsx5(SessionDetails, { semantics: state.semantics }),
1691
+ state.history.hasEarlier ? /* @__PURE__ */ jsx5("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
1494
1692
  const element = scroller.current;
1495
- if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
1693
+ if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length, firstId: state.transcript[0]?.id, seenOperation: false };
1496
1694
  setAtBottom(false);
1497
1695
  adapter.onIntent({ action: "loadEarlier" });
1498
1696
  }, children: "Load earlier messages" }) : null,
1499
- !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx4(LoadingStatus, { state }) : null,
1500
- !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,
1501
- blocks.map((block, index) => /* @__PURE__ */ jsxs3(Fragment2, { children: [
1502
- index === unreadBlock ? /* @__PURE__ */ jsx4("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx4("span", { children: "New" }) }) : null,
1503
- 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 })
1697
+ !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx5(LoadingStatus, { state }) : null,
1698
+ !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,
1699
+ blocks.map((block, index) => /* @__PURE__ */ jsxs4(Fragment2, { children: [
1700
+ index === unreadBlock ? /* @__PURE__ */ jsx5("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx5("span", { children: "New" }) }) : null,
1701
+ 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 })
1504
1702
  ] }, block.id)),
1505
- pendingMessage ? /* @__PURE__ */ jsxs3("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
1506
- /* @__PURE__ */ jsx4(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
1507
- /* @__PURE__ */ jsxs3("footer", { children: [
1508
- /* @__PURE__ */ jsx4("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
1509
- pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs3("span", { children: [
1510
- /* @__PURE__ */ jsx4("button", { type: "button", onClick: pendingMessage.onRetry, children: "Retry" }),
1511
- /* @__PURE__ */ jsx4("button", { type: "button", onClick: pendingMessage.onEdit, children: "Edit" })
1703
+ pendingMessage ? /* @__PURE__ */ jsxs4("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
1704
+ /* @__PURE__ */ jsx5(MessageImages, { items: pendingMessage.images }),
1705
+ /* @__PURE__ */ jsx5(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
1706
+ /* @__PURE__ */ jsx5(ContextDisclosure, { context: pendingMessage.context }),
1707
+ /* @__PURE__ */ jsxs4("footer", { children: [
1708
+ /* @__PURE__ */ jsx5("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
1709
+ pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs4("span", { children: [
1710
+ /* @__PURE__ */ jsx5("button", { type: "button", onClick: pendingMessage.onRetry, children: "Retry" }),
1711
+ /* @__PURE__ */ jsx5("button", { type: "button", onClick: pendingMessage.onEdit, children: "Edit" })
1512
1712
  ] }) : null
1513
1713
  ] })
1514
1714
  ] }) : null,
1515
- state.busy ? /* @__PURE__ */ jsxs3("div", { class: "scui-working", role: "status", children: [
1516
- /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "\u2726" }),
1517
- /* @__PURE__ */ jsx4("i", {}),
1518
- /* @__PURE__ */ jsx4("i", {}),
1519
- /* @__PURE__ */ jsx4("i", {}),
1520
- /* @__PURE__ */ jsxs3("small", { children: [
1715
+ state.busy ? /* @__PURE__ */ jsxs4("div", { class: "scui-working", role: "status", children: [
1716
+ /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: "\u2726" }),
1717
+ /* @__PURE__ */ jsx5("i", {}),
1718
+ /* @__PURE__ */ jsx5("i", {}),
1719
+ /* @__PURE__ */ jsx5("i", {}),
1720
+ /* @__PURE__ */ jsxs4("small", { children: [
1521
1721
  harnessDisplayName(state.harness),
1522
1722
  " is working"
1523
1723
  ] })
1524
1724
  ] }) : null,
1525
- After ? /* @__PURE__ */ jsx4(After, { state, adapter, value: null }) : null
1725
+ After ? /* @__PURE__ */ jsx5(After, { state, adapter, value: null }) : null
1526
1726
  ] }) }),
1527
- !atBottom ? /* @__PURE__ */ jsxs3("button", { class: "scui-latest", type: "button", onClick: pin, children: [
1528
- /* @__PURE__ */ jsx4(UiIcon, { name: "down", size: 13 }),
1727
+ !atBottom ? /* @__PURE__ */ jsxs4("button", { class: "scui-latest", type: "button", onClick: pin, children: [
1728
+ /* @__PURE__ */ jsx5(UiIcon, { name: "down", size: 13 }),
1529
1729
  " Latest"
1530
1730
  ] }) : null
1531
1731
  ] });
@@ -1533,7 +1733,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
1533
1733
 
1534
1734
  // src/logo.jsx
1535
1735
  import { useEffect as useEffect4 } from "preact/hooks";
1536
- import { jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
1736
+ import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
1537
1737
  var LOGOS = {
1538
1738
  "claude-code": {
1539
1739
  viewBox: "-1 3.5 26 18",
@@ -1587,9 +1787,9 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
1587
1787
  if (!logo) onMissingLogo?.(id);
1588
1788
  }, [id, logo, onMissingLogo]);
1589
1789
  if (!logo) return null;
1590
- return /* @__PURE__ */ jsxs4("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
1591
- /* @__PURE__ */ jsx5("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx5(Tag, { ...props }, index)) }),
1592
- activity && activity !== "idle" ? /* @__PURE__ */ jsx5("i", {}) : null
1790
+ return /* @__PURE__ */ jsxs5("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
1791
+ /* @__PURE__ */ jsx6("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx6(Tag, { ...props }, index)) }),
1792
+ activity && activity !== "idle" ? /* @__PURE__ */ jsx6("i", {}) : null
1593
1793
  ] });
1594
1794
  }
1595
1795
 
@@ -1598,22 +1798,22 @@ import { useEffect as useEffect6, useId as useId2, useMemo as useMemo2, useRef a
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,31 +2297,31 @@ 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
  export {