@volter-ai-dev/supercode-ui 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/components.mjs +447 -347
- package/composer.mjs +104 -33
- package/controller.mjs +2 -2
- package/conversation.mjs +14 -7
- package/core.mjs +1 -1
- package/embed.mjs +449 -349
- package/icon.mjs +1 -0
- package/index.d.ts +7 -4
- package/messenger.mjs +447 -347
- package/package.json +1 -1
- package/sessions.mjs +3 -2
- package/styles.css +3 -1
package/embed.mjs
CHANGED
|
@@ -684,7 +684,7 @@ function sessionActivity(state, row) {
|
|
|
684
684
|
function filterSessions(rows, query) {
|
|
685
685
|
const needle = query.trim().toLocaleLowerCase();
|
|
686
686
|
if (!needle) return [...rows];
|
|
687
|
-
return rows.filter((row) => [row.name, row.title, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => value.toLocaleLowerCase().includes(needle)));
|
|
687
|
+
return rows.filter((row) => [row.name, row.title, row.preview, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => typeof value === "string" && value.toLocaleLowerCase().includes(needle)));
|
|
688
688
|
}
|
|
689
689
|
function groupConversation(entries) {
|
|
690
690
|
const blocks = [];
|
|
@@ -764,6 +764,7 @@ function boundedSet(map, key, value) {
|
|
|
764
764
|
// src/icon.jsx
|
|
765
765
|
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
766
766
|
var ICONS = {
|
|
767
|
+
attach: () => /* @__PURE__ */ jsx("path", { d: "M6.25 9.75 10.6 5.4a2.1 2.1 0 0 1 2.97 2.97l-5.4 5.4a3.3 3.3 0 0 1-4.67-4.66l5.52-5.52" }),
|
|
767
768
|
back: () => /* @__PURE__ */ jsx("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
|
|
768
769
|
check: () => /* @__PURE__ */ jsx("path", { d: "m4 9 3.25 3.25L14 5.5" }),
|
|
769
770
|
chevron: () => /* @__PURE__ */ jsx("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
|
|
@@ -804,6 +805,44 @@ function UiIcon({ name, size = 16, class: className = "" }) {
|
|
|
804
805
|
return /* @__PURE__ */ jsx("svg", { class: `scui-icon ${className}`, style: { "--scui-icon-size": `${size}px` }, viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Glyph, {}) });
|
|
805
806
|
}
|
|
806
807
|
|
|
808
|
+
// src/context.jsx
|
|
809
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
810
|
+
var MAX_CONTEXT_ITEMS = 32;
|
|
811
|
+
function normalizeContext(value) {
|
|
812
|
+
return (Array.isArray(value) ? value : value ? [value] : []).flatMap((item) => {
|
|
813
|
+
if (!item || typeof item.label !== "string" || typeof item.detail !== "string") return [];
|
|
814
|
+
const label = item.label.trim().slice(0, 200);
|
|
815
|
+
const detail = item.detail.slice(0, 2e4);
|
|
816
|
+
if (!label || !detail) return [];
|
|
817
|
+
return [{
|
|
818
|
+
...typeof item.id === "string" && item.id ? { id: item.id.slice(0, 2e3) } : {},
|
|
819
|
+
...typeof item.kind === "string" && item.kind ? { kind: item.kind.slice(0, 100) } : {},
|
|
820
|
+
label,
|
|
821
|
+
detail
|
|
822
|
+
}];
|
|
823
|
+
}).slice(0, MAX_CONTEXT_ITEMS);
|
|
824
|
+
}
|
|
825
|
+
function mergeContext(current, picked) {
|
|
826
|
+
const next = [...current];
|
|
827
|
+
const seen = new Set(current.map((item) => item.id ? `id:${item.id}` : `value:${item.kind ?? ""}\0${item.label}\0${item.detail}`));
|
|
828
|
+
for (const item of normalizeContext(picked)) {
|
|
829
|
+
const key = item.id ? `id:${item.id}` : `value:${item.kind ?? ""}\0${item.label}\0${item.detail}`;
|
|
830
|
+
if (seen.has(key)) continue;
|
|
831
|
+
seen.add(key);
|
|
832
|
+
next.push(item);
|
|
833
|
+
if (next.length === MAX_CONTEXT_ITEMS) break;
|
|
834
|
+
}
|
|
835
|
+
return next;
|
|
836
|
+
}
|
|
837
|
+
function ContextTray({ items, onRemove }) {
|
|
838
|
+
if (!items.length) return null;
|
|
839
|
+
return /* @__PURE__ */ jsx2("div", { class: "scui-compose-context", "aria-label": "Attached context", children: items.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
|
|
840
|
+
/* @__PURE__ */ jsx2(UiIcon, { name: "attach", size: 12 }),
|
|
841
|
+
/* @__PURE__ */ jsx2("strong", { children: item.label }),
|
|
842
|
+
/* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove context ${item.label}`, onClick: () => onRemove(index), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 12 }) })
|
|
843
|
+
] }, item.id ?? `${item.label}:${index}`)) });
|
|
844
|
+
}
|
|
845
|
+
|
|
807
846
|
// src/textarea.js
|
|
808
847
|
import { useLayoutEffect } from "preact/hooks";
|
|
809
848
|
function useAutosizeTextarea(ref, value) {
|
|
@@ -819,7 +858,7 @@ function useAutosizeTextarea(ref, value) {
|
|
|
819
858
|
}
|
|
820
859
|
|
|
821
860
|
// src/composer.jsx
|
|
822
|
-
import { jsx as
|
|
861
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
823
862
|
var composerMemory = /* @__PURE__ */ new Map();
|
|
824
863
|
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
825
864
|
if (state.mode !== "mirror" || state.canSend) return null;
|
|
@@ -829,29 +868,32 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
829
868
|
const resume = canContinueHere(state);
|
|
830
869
|
const join = state.canAttach;
|
|
831
870
|
const branch = state.canBranch;
|
|
832
|
-
if (!resume && !join && !branch) return /* @__PURE__ */
|
|
833
|
-
/* @__PURE__ */
|
|
834
|
-
/* @__PURE__ */
|
|
871
|
+
if (!resume && !join && !branch) return /* @__PURE__ */ jsx3("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
872
|
+
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
873
|
+
/* @__PURE__ */ jsx3("small", { children: "This session cannot be continued by an available harness." })
|
|
835
874
|
] }) });
|
|
836
|
-
return /* @__PURE__ */
|
|
837
|
-
/* @__PURE__ */
|
|
838
|
-
/* @__PURE__ */
|
|
839
|
-
/* @__PURE__ */
|
|
875
|
+
return /* @__PURE__ */ jsxs3("div", { class: "scui-continuation", children: [
|
|
876
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
877
|
+
/* @__PURE__ */ jsx3("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
878
|
+
/* @__PURE__ */ jsx3("small", { children: join ? "Join the proven live runtime without taking it over." : resume ? `Resume this ${harnessDisplayName(state.harness)} session here.` : "Start an independent continuation." })
|
|
840
879
|
] }),
|
|
841
|
-
/* @__PURE__ */
|
|
880
|
+
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => adapter.onIntent(join ? { action: "join" } : resume ? { action: "resume" } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
842
881
|
] });
|
|
843
882
|
}
|
|
844
883
|
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
|
|
845
|
-
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
|
|
884
|
+
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, context: [], queue: [] };
|
|
846
885
|
const [draft, setDraft] = useState(remembered.draft);
|
|
886
|
+
const [context, setContext] = useState(remembered.context);
|
|
847
887
|
const [queue, setQueue] = useState(remembered.queue);
|
|
848
888
|
const [dispatching, setDispatching] = useState(false);
|
|
889
|
+
const [picking, setPicking] = useState(false);
|
|
890
|
+
const [pickerError, setPickerError] = useState(null);
|
|
849
891
|
const textarea = useRef(null);
|
|
850
892
|
useAutosizeTextarea(textarea, draft);
|
|
851
|
-
const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
|
|
893
|
+
const remember = (nextDraft, nextContext, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, context: nextContext, queue: nextQueue });
|
|
852
894
|
const updateQueue = (update) => setQueue((items) => {
|
|
853
895
|
const next = update(items);
|
|
854
|
-
remember(draft, next);
|
|
896
|
+
remember(draft, context, next);
|
|
855
897
|
return next;
|
|
856
898
|
});
|
|
857
899
|
const queueBlocked = state.busy || pendingStatus !== null || dispatching;
|
|
@@ -861,9 +903,9 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
861
903
|
const [next, ...rest] = queue;
|
|
862
904
|
setDispatching(true);
|
|
863
905
|
setQueue(rest);
|
|
864
|
-
remember(draft, rest);
|
|
865
|
-
onPending?.(next);
|
|
866
|
-
adapter.onIntent({ action: "send", text: next });
|
|
906
|
+
remember(draft, context, rest);
|
|
907
|
+
onPending?.(next.text, next.context);
|
|
908
|
+
adapter.onIntent({ action: "send", text: next.text, ...next.context.length ? { context: next.context } : {} });
|
|
867
909
|
}
|
|
868
910
|
}, [adapter, draft, memoryKey, onPending, queue, queueBlocked, state.canSend]);
|
|
869
911
|
useEffect(() => {
|
|
@@ -875,7 +917,9 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
875
917
|
useEffect(() => {
|
|
876
918
|
if (!restoreDraft) return;
|
|
877
919
|
setDraft(restoreDraft.text);
|
|
878
|
-
|
|
920
|
+
const restoredContext = normalizeContext(restoreDraft.context);
|
|
921
|
+
setContext(restoredContext);
|
|
922
|
+
remember(restoreDraft.text, restoredContext, queue);
|
|
879
923
|
textarea.current?.focus({ preventScroll: true });
|
|
880
924
|
onDraftRestored?.(restoreDraft.id);
|
|
881
925
|
}, [onDraftRestored, restoreDraft?.id]);
|
|
@@ -883,43 +927,70 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
883
927
|
const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
|
|
884
928
|
return () => clearTimeout(timer);
|
|
885
929
|
}, [adapter, draft]);
|
|
930
|
+
const pickContext = () => {
|
|
931
|
+
if (!adapter.pickContext || state.mode !== "control" || picking || context.length >= MAX_CONTEXT_ITEMS) return;
|
|
932
|
+
setPicking(true);
|
|
933
|
+
setPickerError(null);
|
|
934
|
+
Promise.resolve().then(() => adapter.pickContext()).then((picked) => {
|
|
935
|
+
setContext((current) => {
|
|
936
|
+
const next = mergeContext(current, picked);
|
|
937
|
+
remember(draft, next, queue);
|
|
938
|
+
return next;
|
|
939
|
+
});
|
|
940
|
+
}, (error) => setPickerError(error instanceof Error ? error.message : "Could not attach context.")).finally(() => setPicking(false));
|
|
941
|
+
};
|
|
886
942
|
const send = () => {
|
|
887
943
|
const text = draft.trim();
|
|
888
944
|
if (!text) return;
|
|
889
|
-
|
|
945
|
+
const message = { text, context };
|
|
946
|
+
if (queuesNewMessage) updateQueue((items) => [...items, message]);
|
|
890
947
|
else if (state.canSend) {
|
|
891
948
|
if (onPending) setDispatching(true);
|
|
892
|
-
onPending?.(text);
|
|
893
|
-
adapter.onIntent({ action: "send", text });
|
|
949
|
+
onPending?.(text, context);
|
|
950
|
+
adapter.onIntent({ action: "send", text, ...context.length ? { context } : {} });
|
|
894
951
|
} else return;
|
|
895
952
|
setDraft("");
|
|
896
|
-
|
|
953
|
+
setContext([]);
|
|
954
|
+
remember("", [], queuesNewMessage ? [...queue, message] : queue);
|
|
897
955
|
};
|
|
898
|
-
return /* @__PURE__ */
|
|
899
|
-
queue.length ? /* @__PURE__ */
|
|
900
|
-
/* @__PURE__ */
|
|
956
|
+
return /* @__PURE__ */ jsxs3("div", { class: "scui-compose", children: [
|
|
957
|
+
queue.length ? /* @__PURE__ */ jsxs3("div", { class: "scui-queue", children: [
|
|
958
|
+
/* @__PURE__ */ jsxs3("strong", { children: [
|
|
901
959
|
queue.length,
|
|
902
960
|
" queued"
|
|
903
961
|
] }),
|
|
904
|
-
queue.map((item, index) => /* @__PURE__ */
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
962
|
+
queue.map((item, index) => /* @__PURE__ */ jsxs3("span", { children: [
|
|
963
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
964
|
+
item.text,
|
|
965
|
+
item.context.length ? /* @__PURE__ */ jsxs3("small", { children: [
|
|
966
|
+
item.context.length,
|
|
967
|
+
" attached"
|
|
968
|
+
] }) : null
|
|
969
|
+
] }),
|
|
970
|
+
/* @__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 }) })
|
|
971
|
+
] }, `${index}:${item.text}`))
|
|
908
972
|
] }) : null,
|
|
909
|
-
/* @__PURE__ */
|
|
910
|
-
|
|
973
|
+
/* @__PURE__ */ jsx3(ContextTray, { items: context, onRemove: (index) => setContext((items) => {
|
|
974
|
+
const next = items.filter((_, itemIndex) => itemIndex !== index);
|
|
975
|
+
remember(draft, next, queue);
|
|
976
|
+
return next;
|
|
977
|
+
}) }),
|
|
978
|
+
pickerError ? /* @__PURE__ */ jsx3("small", { class: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
979
|
+
/* @__PURE__ */ jsxs3("div", { class: "scui-envelope", children: [
|
|
980
|
+
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { class: "scui-attach", type: "button", "aria-label": "Attach context", disabled: picking || context.length >= MAX_CONTEXT_ITEMS, onClick: pickContext, children: picking ? /* @__PURE__ */ jsx3("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx3(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
981
|
+
/* @__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, onInput: (event) => {
|
|
911
982
|
const value = event.currentTarget.value;
|
|
912
983
|
setDraft(value);
|
|
913
|
-
remember(value, queue);
|
|
984
|
+
remember(value, context, queue);
|
|
914
985
|
}, onKeyDown: (event) => {
|
|
915
986
|
if (isSendKey(event)) {
|
|
916
987
|
event.preventDefault();
|
|
917
988
|
send();
|
|
918
989
|
}
|
|
919
990
|
} }),
|
|
920
|
-
/* @__PURE__ */
|
|
921
|
-
state.busy ? /* @__PURE__ */
|
|
922
|
-
/* @__PURE__ */
|
|
991
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
992
|
+
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,
|
|
993
|
+
/* @__PURE__ */ jsx3("button", { class: "scui-send", type: "button", "aria-label": queuesNewMessage ? "Queue message" : "Send message", disabled: !draft.trim() || !queuesNewMessage && !state.canSend, onClick: send, children: /* @__PURE__ */ jsx3(UiIcon, { name: queuesNewMessage ? "plus" : "send", size: 17 }) })
|
|
923
994
|
] })
|
|
924
995
|
] })
|
|
925
996
|
] });
|
|
@@ -932,7 +1003,7 @@ import { useEffect as useEffect3, useId, useLayoutEffect as useLayoutEffect2, us
|
|
|
932
1003
|
// src/markdown.jsx
|
|
933
1004
|
import MarkdownIt from "markdown-it";
|
|
934
1005
|
import { useEffect as useEffect2, useMemo, useRef as useRef2 } from "preact/hooks";
|
|
935
|
-
import { jsx as
|
|
1006
|
+
import { jsx as jsx4 } from "preact/jsx-runtime";
|
|
936
1007
|
var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
|
|
937
1008
|
var LANGUAGE_LABELS = {
|
|
938
1009
|
bash: "Shell",
|
|
@@ -1019,11 +1090,11 @@ function Markdown({ value, copyText }) {
|
|
|
1019
1090
|
}, 1500);
|
|
1020
1091
|
resets.current.set(button, timer);
|
|
1021
1092
|
};
|
|
1022
|
-
return /* @__PURE__ */
|
|
1093
|
+
return /* @__PURE__ */ jsx4("div", { class: "scui-markdown", "data-copyable": Boolean(copyText), onClick: copyCode, dangerouslySetInnerHTML: { __html: html } });
|
|
1023
1094
|
}
|
|
1024
1095
|
|
|
1025
1096
|
// src/conversation.jsx
|
|
1026
|
-
import { Fragment as Fragment3, jsx as
|
|
1097
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
1027
1098
|
function LoadingStatus({ state, compact = false }) {
|
|
1028
1099
|
const copy = {
|
|
1029
1100
|
connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
|
|
@@ -1031,43 +1102,43 @@ function LoadingStatus({ state, compact = false }) {
|
|
|
1031
1102
|
discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
|
|
1032
1103
|
ready: ["Ready", "Coding sessions are up to date.", 3]
|
|
1033
1104
|
}[state.startup];
|
|
1034
|
-
return /* @__PURE__ */
|
|
1035
|
-
/* @__PURE__ */
|
|
1036
|
-
/* @__PURE__ */
|
|
1037
|
-
/* @__PURE__ */
|
|
1038
|
-
/* @__PURE__ */
|
|
1105
|
+
return /* @__PURE__ */ jsxs4("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
|
|
1106
|
+
/* @__PURE__ */ jsx5("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx5("i", {}) }),
|
|
1107
|
+
/* @__PURE__ */ jsxs4("span", { class: "scui-loading-copy", children: [
|
|
1108
|
+
/* @__PURE__ */ jsx5("strong", { children: copy[0] }),
|
|
1109
|
+
/* @__PURE__ */ jsx5("small", { children: copy[1] })
|
|
1039
1110
|
] }),
|
|
1040
|
-
/* @__PURE__ */
|
|
1111
|
+
/* @__PURE__ */ jsx5("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx5("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
|
|
1041
1112
|
] });
|
|
1042
1113
|
}
|
|
1043
1114
|
function RequestCard({ entry, adapter, canRespond }) {
|
|
1044
1115
|
const request = entry.request;
|
|
1045
1116
|
if (!request) return null;
|
|
1046
1117
|
if (request.status === "responded") {
|
|
1047
|
-
return /* @__PURE__ */
|
|
1118
|
+
return /* @__PURE__ */ jsxs4("div", { class: "scui-request-done", children: [
|
|
1048
1119
|
"\u2713 Request answered \xB7 ",
|
|
1049
1120
|
request.resolution?.name ?? request.requestKind
|
|
1050
1121
|
] });
|
|
1051
1122
|
}
|
|
1052
|
-
return /* @__PURE__ */
|
|
1053
|
-
/* @__PURE__ */
|
|
1054
|
-
/* @__PURE__ */
|
|
1055
|
-
/* @__PURE__ */
|
|
1056
|
-
request.options.map((option) => /* @__PURE__ */
|
|
1057
|
-
request.cancellable ? /* @__PURE__ */
|
|
1123
|
+
return /* @__PURE__ */ jsxs4("section", { class: "scui-request", role: "alert", "aria-label": `${request.requestKind} needs input`, children: [
|
|
1124
|
+
/* @__PURE__ */ jsx5("strong", { children: "Agent needs input" }),
|
|
1125
|
+
/* @__PURE__ */ jsx5(Markdown, { value: request.payloadText || entry.text, copyText: adapter?.copyText }),
|
|
1126
|
+
/* @__PURE__ */ jsxs4("div", { class: "scui-request-actions", children: [
|
|
1127
|
+
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)),
|
|
1128
|
+
request.cancellable ? /* @__PURE__ */ jsx5("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
|
|
1058
1129
|
] })
|
|
1059
1130
|
] });
|
|
1060
1131
|
}
|
|
1061
1132
|
function ContextDisclosure({ context }) {
|
|
1062
1133
|
if (!context?.length) return null;
|
|
1063
|
-
return /* @__PURE__ */
|
|
1064
|
-
/* @__PURE__ */
|
|
1134
|
+
return /* @__PURE__ */ jsxs4("details", { class: "scui-context", children: [
|
|
1135
|
+
/* @__PURE__ */ jsxs4("summary", { children: [
|
|
1065
1136
|
"Context \xB7 ",
|
|
1066
1137
|
context.length
|
|
1067
1138
|
] }),
|
|
1068
|
-
/* @__PURE__ */
|
|
1069
|
-
/* @__PURE__ */
|
|
1070
|
-
/* @__PURE__ */
|
|
1139
|
+
/* @__PURE__ */ jsx5("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs4("p", { children: [
|
|
1140
|
+
/* @__PURE__ */ jsx5("strong", { children: item.label }),
|
|
1141
|
+
/* @__PURE__ */ jsx5("span", { children: item.detail })
|
|
1071
1142
|
] }, item.id ?? index)) })
|
|
1072
1143
|
] });
|
|
1073
1144
|
}
|
|
@@ -1089,46 +1160,46 @@ function MessageMeta({ entry, adapter }) {
|
|
|
1089
1160
|
reset.current = setTimeout(() => setCopyState2("idle"), 1500);
|
|
1090
1161
|
};
|
|
1091
1162
|
const copyLabel = copyState === "copied" ? "Message copied" : copyState === "failed" ? "Copy failed \xB7 retry" : "Copy message";
|
|
1092
|
-
return /* @__PURE__ */
|
|
1093
|
-
validDate ? /* @__PURE__ */
|
|
1094
|
-
adapter?.copyText && entry.text ? /* @__PURE__ */
|
|
1163
|
+
return /* @__PURE__ */ jsxs4("footer", { class: "scui-message-meta", children: [
|
|
1164
|
+
validDate ? /* @__PURE__ */ jsx5("time", { dateTime: validDate.toISOString(), title: validDate.toLocaleString(), children: validDate.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }) : null,
|
|
1165
|
+
adapter?.copyText && entry.text ? /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": copyLabel, title: copyLabel, onClick: copy, "data-status": copyState, children: /* @__PURE__ */ jsx5(UiIcon, { name: "copy", size: 13 }) }) : null
|
|
1095
1166
|
] });
|
|
1096
1167
|
}
|
|
1097
1168
|
var TOOL_ICONS = {
|
|
1098
|
-
read: () => /* @__PURE__ */
|
|
1099
|
-
/* @__PURE__ */
|
|
1100
|
-
/* @__PURE__ */
|
|
1169
|
+
read: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1170
|
+
/* @__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" }),
|
|
1171
|
+
/* @__PURE__ */ jsx5("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
|
|
1101
1172
|
] }),
|
|
1102
|
-
search: () => /* @__PURE__ */
|
|
1103
|
-
/* @__PURE__ */
|
|
1104
|
-
/* @__PURE__ */
|
|
1173
|
+
search: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1174
|
+
/* @__PURE__ */ jsx5("circle", { cx: "8", cy: "8", r: "4.5" }),
|
|
1175
|
+
/* @__PURE__ */ jsx5("path", { d: "m11.5 11.5 3 3" })
|
|
1105
1176
|
] }),
|
|
1106
|
-
edit: () => /* @__PURE__ */
|
|
1107
|
-
/* @__PURE__ */
|
|
1108
|
-
/* @__PURE__ */
|
|
1177
|
+
edit: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1178
|
+
/* @__PURE__ */ jsx5("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
|
|
1179
|
+
/* @__PURE__ */ jsx5("path", { d: "m10 5 3 3" })
|
|
1109
1180
|
] }),
|
|
1110
|
-
command: () => /* @__PURE__ */
|
|
1111
|
-
test: () => /* @__PURE__ */
|
|
1112
|
-
/* @__PURE__ */
|
|
1113
|
-
/* @__PURE__ */
|
|
1181
|
+
command: () => /* @__PURE__ */ jsx5(Fragment3, { children: /* @__PURE__ */ jsx5("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
|
|
1182
|
+
test: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1183
|
+
/* @__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" }),
|
|
1184
|
+
/* @__PURE__ */ jsx5("path", { d: "M5 2.5h8" })
|
|
1114
1185
|
] }),
|
|
1115
|
-
web: () => /* @__PURE__ */
|
|
1116
|
-
/* @__PURE__ */
|
|
1117
|
-
/* @__PURE__ */
|
|
1186
|
+
web: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1187
|
+
/* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "6.5" }),
|
|
1188
|
+
/* @__PURE__ */ jsx5("path", { d: "M2.75 9h12.5M9 2.5c2 1.8 3 4 3 6.5s-1 4.7-3 6.5c-2-1.8-3-4-3-6.5s1-4.7 3-6.5Z" })
|
|
1118
1189
|
] }),
|
|
1119
|
-
agent: () => /* @__PURE__ */
|
|
1120
|
-
/* @__PURE__ */
|
|
1121
|
-
/* @__PURE__ */
|
|
1190
|
+
agent: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1191
|
+
/* @__PURE__ */ jsx5("circle", { cx: "9", cy: "6", r: "2.5" }),
|
|
1192
|
+
/* @__PURE__ */ jsx5("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
|
|
1122
1193
|
] }),
|
|
1123
|
-
plan: () => /* @__PURE__ */
|
|
1124
|
-
other: () => /* @__PURE__ */
|
|
1125
|
-
/* @__PURE__ */
|
|
1126
|
-
/* @__PURE__ */
|
|
1194
|
+
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" }) }),
|
|
1195
|
+
other: () => /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1196
|
+
/* @__PURE__ */ jsx5("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
|
|
1197
|
+
/* @__PURE__ */ jsx5("circle", { cx: "9", cy: "9", r: "3.5" })
|
|
1127
1198
|
] })
|
|
1128
1199
|
};
|
|
1129
1200
|
function ToolIcon({ category }) {
|
|
1130
1201
|
const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
|
|
1131
|
-
return /* @__PURE__ */
|
|
1202
|
+
return /* @__PURE__ */ jsx5("svg", { class: "scui-tool-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.35", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx5(Glyph, {}) });
|
|
1132
1203
|
}
|
|
1133
1204
|
function toolAction2(entry, category, presentation) {
|
|
1134
1205
|
if (presentation?.action) return presentation.action;
|
|
@@ -1183,7 +1254,7 @@ function ToolMetrics({ presentation }) {
|
|
|
1183
1254
|
presentation.exitCode === null ? "" : `exit ${presentation.exitCode}`,
|
|
1184
1255
|
formatDuration(presentation.durationMs)
|
|
1185
1256
|
].filter(Boolean);
|
|
1186
|
-
return metrics.length ? /* @__PURE__ */
|
|
1257
|
+
return metrics.length ? /* @__PURE__ */ jsx5("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx5("span", { children: metric }, metric)) }) : null;
|
|
1187
1258
|
}
|
|
1188
1259
|
function PendingElapsed({ now }) {
|
|
1189
1260
|
const clock = now ?? Date.now;
|
|
@@ -1193,74 +1264,74 @@ function PendingElapsed({ now }) {
|
|
|
1193
1264
|
const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
|
|
1194
1265
|
return () => clearInterval(timer);
|
|
1195
1266
|
}, [clock]);
|
|
1196
|
-
return /* @__PURE__ */
|
|
1267
|
+
return /* @__PURE__ */ jsx5("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
|
|
1197
1268
|
}
|
|
1198
1269
|
function LinePreview({ value, kind }) {
|
|
1199
1270
|
if (!value) return null;
|
|
1200
|
-
return /* @__PURE__ */
|
|
1271
|
+
return /* @__PURE__ */ jsx5("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
|
|
1201
1272
|
const tone = kind === "diff" ? line.startsWith("+") && !line.startsWith("+++") ? "add" : line.startsWith("-") && !line.startsWith("---") ? "remove" : line.startsWith("@@") ? "hunk" : "plain" : "plain";
|
|
1202
|
-
return /* @__PURE__ */
|
|
1203
|
-
/* @__PURE__ */
|
|
1204
|
-
/* @__PURE__ */
|
|
1273
|
+
return /* @__PURE__ */ jsxs4("li", { "data-tone": tone, children: [
|
|
1274
|
+
/* @__PURE__ */ jsx5("span", { children: index + 1 }),
|
|
1275
|
+
/* @__PURE__ */ jsx5("code", { children: line || " " })
|
|
1205
1276
|
] }, index);
|
|
1206
1277
|
}) });
|
|
1207
1278
|
}
|
|
1208
1279
|
function TerminalPreview({ presentation, pending, failed }) {
|
|
1209
|
-
return /* @__PURE__ */
|
|
1210
|
-
/* @__PURE__ */
|
|
1211
|
-
/* @__PURE__ */
|
|
1212
|
-
/* @__PURE__ */
|
|
1213
|
-
/* @__PURE__ */
|
|
1214
|
-
/* @__PURE__ */
|
|
1280
|
+
return /* @__PURE__ */ jsxs4("section", { class: "scui-terminal", children: [
|
|
1281
|
+
/* @__PURE__ */ jsxs4("header", { children: [
|
|
1282
|
+
/* @__PURE__ */ jsxs4("span", { "aria-hidden": "true", children: [
|
|
1283
|
+
/* @__PURE__ */ jsx5("i", {}),
|
|
1284
|
+
/* @__PURE__ */ jsx5("i", {}),
|
|
1285
|
+
/* @__PURE__ */ jsx5("i", {})
|
|
1215
1286
|
] }),
|
|
1216
|
-
/* @__PURE__ */
|
|
1287
|
+
/* @__PURE__ */ jsx5("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
|
|
1217
1288
|
] }),
|
|
1218
|
-
presentation.preview ? /* @__PURE__ */
|
|
1219
|
-
/* @__PURE__ */
|
|
1289
|
+
presentation.preview ? /* @__PURE__ */ jsx5("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs4("div", { class: "scui-terminal-wait", children: [
|
|
1290
|
+
/* @__PURE__ */ jsx5("i", {}),
|
|
1220
1291
|
" Waiting for output"
|
|
1221
|
-
] }) : /* @__PURE__ */
|
|
1292
|
+
] }) : /* @__PURE__ */ jsx5("div", { class: "scui-terminal-empty", children: "No output" })
|
|
1222
1293
|
] });
|
|
1223
1294
|
}
|
|
1224
1295
|
function SearchPreview({ presentation }) {
|
|
1225
1296
|
const lines = stripAnsi(presentation.preview).split("\n").filter(Boolean);
|
|
1226
|
-
return /* @__PURE__ */
|
|
1227
|
-
presentation.query ? /* @__PURE__ */
|
|
1228
|
-
/* @__PURE__ */
|
|
1229
|
-
/* @__PURE__ */
|
|
1297
|
+
return /* @__PURE__ */ jsxs4("section", { class: "scui-search-preview", children: [
|
|
1298
|
+
presentation.query ? /* @__PURE__ */ jsxs4("header", { children: [
|
|
1299
|
+
/* @__PURE__ */ jsx5("span", { children: "Search" }),
|
|
1300
|
+
/* @__PURE__ */ jsx5("code", { children: presentation.query })
|
|
1230
1301
|
] }) : null,
|
|
1231
|
-
lines.length ? /* @__PURE__ */
|
|
1302
|
+
lines.length ? /* @__PURE__ */ jsx5("ol", { children: lines.map((line, index) => {
|
|
1232
1303
|
const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
|
|
1233
|
-
return /* @__PURE__ */
|
|
1234
|
-
/* @__PURE__ */
|
|
1235
|
-
/* @__PURE__ */
|
|
1304
|
+
return /* @__PURE__ */ jsx5("li", { children: match ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1305
|
+
/* @__PURE__ */ jsx5("code", { children: match[1] }),
|
|
1306
|
+
/* @__PURE__ */ jsxs4("small", { children: [
|
|
1236
1307
|
match[2],
|
|
1237
1308
|
match[3] ? `:${match[3]}` : ""
|
|
1238
1309
|
] }),
|
|
1239
|
-
/* @__PURE__ */
|
|
1240
|
-
] }) : /* @__PURE__ */
|
|
1241
|
-
}) }) : /* @__PURE__ */
|
|
1310
|
+
/* @__PURE__ */ jsx5("span", { children: match[4] })
|
|
1311
|
+
] }) : /* @__PURE__ */ jsx5("span", { children: line }) }, index);
|
|
1312
|
+
}) }) : /* @__PURE__ */ jsx5("p", { children: "No textual results" })
|
|
1242
1313
|
] });
|
|
1243
1314
|
}
|
|
1244
1315
|
function ToolPreview({ presentation, entry }) {
|
|
1245
1316
|
const pending = entry.status === "pending";
|
|
1246
1317
|
const failed = entry.status === "error";
|
|
1247
|
-
if (presentation.detail === "terminal") return /* @__PURE__ */
|
|
1248
|
-
if (presentation.detail === "diff") return presentation.preview ? /* @__PURE__ */
|
|
1249
|
-
if (presentation.detail === "file") return presentation.preview ? /* @__PURE__ */
|
|
1250
|
-
if (presentation.detail === "matches") return /* @__PURE__ */
|
|
1251
|
-
if (presentation.detail === "web") return /* @__PURE__ */
|
|
1252
|
-
presentation.url ? /* @__PURE__ */
|
|
1253
|
-
presentation.preview ? /* @__PURE__ */
|
|
1318
|
+
if (presentation.detail === "terminal") return /* @__PURE__ */ jsx5(TerminalPreview, { presentation, pending, failed });
|
|
1319
|
+
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" });
|
|
1320
|
+
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" });
|
|
1321
|
+
if (presentation.detail === "matches") return /* @__PURE__ */ jsx5(SearchPreview, { presentation });
|
|
1322
|
+
if (presentation.detail === "web") return /* @__PURE__ */ jsxs4("section", { class: "scui-web-preview", children: [
|
|
1323
|
+
presentation.url ? /* @__PURE__ */ jsx5("code", { children: presentation.url }) : null,
|
|
1324
|
+
presentation.preview ? /* @__PURE__ */ jsx5("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx5("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
|
|
1254
1325
|
] });
|
|
1255
|
-
if (presentation.detail === "agent") return /* @__PURE__ */
|
|
1256
|
-
/* @__PURE__ */
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
] }, `${item.label}:${index}`)) }) : presentation.preview ? /* @__PURE__ */
|
|
1259
|
-
if (presentation.detail === "plan") return /* @__PURE__ */
|
|
1260
|
-
/* @__PURE__ */
|
|
1261
|
-
/* @__PURE__ */
|
|
1326
|
+
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: [
|
|
1327
|
+
/* @__PURE__ */ jsx5("strong", { children: item.label }),
|
|
1328
|
+
/* @__PURE__ */ jsx5("small", { children: item.status })
|
|
1329
|
+
] }, `${item.label}:${index}`)) }) : presentation.preview ? /* @__PURE__ */ jsx5("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx5("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
|
|
1330
|
+
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: [
|
|
1331
|
+
/* @__PURE__ */ jsx5("i", { "aria-hidden": "true" }),
|
|
1332
|
+
/* @__PURE__ */ jsx5("span", { children: item.label })
|
|
1262
1333
|
] }, `${item.label}:${index}`)) });
|
|
1263
|
-
return presentation.preview ? /* @__PURE__ */
|
|
1334
|
+
return presentation.preview ? /* @__PURE__ */ jsx5("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
|
|
1264
1335
|
}
|
|
1265
1336
|
function ToolActions({ presentation, adapter }) {
|
|
1266
1337
|
const [copied, setCopied] = useState2(false);
|
|
@@ -1274,27 +1345,27 @@ function ToolActions({ presentation, adapter }) {
|
|
|
1274
1345
|
clearTimeout(reset.current);
|
|
1275
1346
|
reset.current = setTimeout(() => setCopied(false), 1500);
|
|
1276
1347
|
};
|
|
1277
|
-
return action ? /* @__PURE__ */
|
|
1348
|
+
return action ? /* @__PURE__ */ jsx5("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx5("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
|
|
1278
1349
|
}
|
|
1279
1350
|
function ToolStack({ tools }) {
|
|
1280
1351
|
if (tools.length < 2) return null;
|
|
1281
|
-
return /* @__PURE__ */
|
|
1352
|
+
return /* @__PURE__ */ jsx5("div", { class: "scui-tool-stack", "aria-label": "Coordinated tools", children: tools.map((tool) => /* @__PURE__ */ jsx5("span", { children: tool.replaceAll("__", " \xB7 ").replaceAll("_", " ") }, tool)) });
|
|
1282
1353
|
}
|
|
1283
1354
|
function TechnicalDetails({ entry }) {
|
|
1284
1355
|
if (!entry.arguments && !entry.resultText) return null;
|
|
1285
|
-
return /* @__PURE__ */
|
|
1286
|
-
/* @__PURE__ */
|
|
1287
|
-
/* @__PURE__ */
|
|
1288
|
-
entry.arguments ? /* @__PURE__ */
|
|
1289
|
-
/* @__PURE__ */
|
|
1290
|
-
/* @__PURE__ */
|
|
1291
|
-
/* @__PURE__ */
|
|
1292
|
-
/* @__PURE__ */
|
|
1356
|
+
return /* @__PURE__ */ jsxs4("details", { class: "scui-tool-technical", children: [
|
|
1357
|
+
/* @__PURE__ */ jsx5("summary", { children: "Technical details" }),
|
|
1358
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1359
|
+
entry.arguments ? /* @__PURE__ */ jsxs4("section", { children: [
|
|
1360
|
+
/* @__PURE__ */ jsx5("strong", { children: "Native arguments" }),
|
|
1361
|
+
/* @__PURE__ */ jsx5("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs4("div", { children: [
|
|
1362
|
+
/* @__PURE__ */ jsx5("dt", { children: row.label }),
|
|
1363
|
+
/* @__PURE__ */ jsx5("dd", { children: /* @__PURE__ */ jsx5("pre", { children: row.value }) })
|
|
1293
1364
|
] }, row.key)) })
|
|
1294
1365
|
] }) : null,
|
|
1295
|
-
entry.resultText ? /* @__PURE__ */
|
|
1296
|
-
/* @__PURE__ */
|
|
1297
|
-
/* @__PURE__ */
|
|
1366
|
+
entry.resultText ? /* @__PURE__ */ jsxs4("section", { children: [
|
|
1367
|
+
/* @__PURE__ */ jsx5("strong", { children: "Native result" }),
|
|
1368
|
+
/* @__PURE__ */ jsxs4("pre", { "data-error": entry.status === "error", children: [
|
|
1298
1369
|
entry.resultText,
|
|
1299
1370
|
entry.truncated ? "\n[truncated]" : ""
|
|
1300
1371
|
] })
|
|
@@ -1303,19 +1374,19 @@ function TechnicalDetails({ entry }) {
|
|
|
1303
1374
|
] });
|
|
1304
1375
|
}
|
|
1305
1376
|
function TranscriptEntry({ entry, state, adapter }) {
|
|
1306
|
-
if (entry.role === "request") return /* @__PURE__ */
|
|
1377
|
+
if (entry.role === "request") return /* @__PURE__ */ jsx5(RequestCard, { entry, adapter, canRespond: state.canRespond });
|
|
1307
1378
|
if (entry.role === "reasoning") {
|
|
1308
|
-
return /* @__PURE__ */
|
|
1309
|
-
/* @__PURE__ */
|
|
1310
|
-
/* @__PURE__ */
|
|
1379
|
+
return /* @__PURE__ */ jsxs4("details", { class: "scui-reasoning", open: entry.streaming, children: [
|
|
1380
|
+
/* @__PURE__ */ jsx5("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
|
|
1381
|
+
/* @__PURE__ */ jsx5(Markdown, { value: entry.text, copyText: adapter?.copyText })
|
|
1311
1382
|
] });
|
|
1312
1383
|
}
|
|
1313
|
-
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */
|
|
1314
|
-
return /* @__PURE__ */
|
|
1315
|
-
/* @__PURE__ */
|
|
1316
|
-
/* @__PURE__ */
|
|
1317
|
-
entry.truncated ? /* @__PURE__ */
|
|
1318
|
-
/* @__PURE__ */
|
|
1384
|
+
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx5("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
|
|
1385
|
+
return /* @__PURE__ */ jsxs4("article", { class: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
|
|
1386
|
+
/* @__PURE__ */ jsx5(Markdown, { value: entry.text, copyText: adapter?.copyText }),
|
|
1387
|
+
/* @__PURE__ */ jsx5(ContextDisclosure, { context: entry.context }),
|
|
1388
|
+
entry.truncated ? /* @__PURE__ */ jsx5("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
|
|
1389
|
+
/* @__PURE__ */ jsx5(MessageMeta, { entry, adapter })
|
|
1319
1390
|
] });
|
|
1320
1391
|
}
|
|
1321
1392
|
function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
@@ -1327,102 +1398,102 @@ function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
|
1327
1398
|
const target = compactToolTarget(presentation.target, workspace);
|
|
1328
1399
|
const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
|
|
1329
1400
|
const category = presentation.category ?? toolCategory(entry);
|
|
1330
|
-
const summary = /* @__PURE__ */
|
|
1331
|
-
/* @__PURE__ */
|
|
1332
|
-
/* @__PURE__ */
|
|
1333
|
-
target ? /* @__PURE__ */
|
|
1334
|
-
/* @__PURE__ */
|
|
1335
|
-
entry.status === "pending" ? /* @__PURE__ */
|
|
1336
|
-
/* @__PURE__ */
|
|
1337
|
-
hasDetail ? /* @__PURE__ */
|
|
1401
|
+
const summary = /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1402
|
+
/* @__PURE__ */ jsx5(ToolIcon, { category }),
|
|
1403
|
+
/* @__PURE__ */ jsx5("strong", { children: toolAction2(entry, category, presentation) }),
|
|
1404
|
+
target ? /* @__PURE__ */ jsx5("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
|
|
1405
|
+
/* @__PURE__ */ jsx5("span", { class: "scui-spacer" }),
|
|
1406
|
+
entry.status === "pending" ? /* @__PURE__ */ jsx5(PendingElapsed, { now: adapter?.now }) : null,
|
|
1407
|
+
/* @__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 }) }),
|
|
1408
|
+
hasDetail ? /* @__PURE__ */ jsx5(UiIcon, { name: "chevron", size: 14, class: "scui-tool-chevron" }) : null
|
|
1338
1409
|
] });
|
|
1339
|
-
if (!hasDetail) return /* @__PURE__ */
|
|
1340
|
-
return /* @__PURE__ */
|
|
1341
|
-
/* @__PURE__ */
|
|
1342
|
-
/* @__PURE__ */
|
|
1343
|
-
/* @__PURE__ */
|
|
1344
|
-
/* @__PURE__ */
|
|
1345
|
-
/* @__PURE__ */
|
|
1346
|
-
presentation.fields.length ? /* @__PURE__ */
|
|
1347
|
-
/* @__PURE__ */
|
|
1348
|
-
/* @__PURE__ */
|
|
1410
|
+
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 }) });
|
|
1411
|
+
return /* @__PURE__ */ jsxs4("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
|
|
1412
|
+
/* @__PURE__ */ jsx5("summary", { class: "scui-tool-head", children: summary }),
|
|
1413
|
+
/* @__PURE__ */ jsxs4("div", { class: "scui-tool-detail", children: [
|
|
1414
|
+
/* @__PURE__ */ jsx5(ToolMetrics, { presentation }),
|
|
1415
|
+
/* @__PURE__ */ jsx5(ToolStack, { tools: presentation.tools ?? [] }),
|
|
1416
|
+
/* @__PURE__ */ jsx5(ToolPreview, { presentation, entry }),
|
|
1417
|
+
presentation.fields.length ? /* @__PURE__ */ jsx5("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs4("div", { children: [
|
|
1418
|
+
/* @__PURE__ */ jsx5("dt", { children: field.label }),
|
|
1419
|
+
/* @__PURE__ */ jsx5("dd", { children: field.value })
|
|
1349
1420
|
] }, field.label)) }) : null,
|
|
1350
|
-
/* @__PURE__ */
|
|
1351
|
-
/* @__PURE__ */
|
|
1421
|
+
/* @__PURE__ */ jsx5(ToolActions, { presentation, adapter }),
|
|
1422
|
+
/* @__PURE__ */ jsx5(TechnicalDetails, { entry })
|
|
1352
1423
|
] })
|
|
1353
1424
|
] });
|
|
1354
1425
|
}
|
|
1355
1426
|
function ActivityGroup({ entries, state, adapter }) {
|
|
1356
|
-
if (entries.length === 1) return /* @__PURE__ */
|
|
1427
|
+
if (entries.length === 1) return /* @__PURE__ */ jsx5("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx5(ToolRow, { entry: entries[0], workspace: state.workspace, adapter }) });
|
|
1357
1428
|
const active = entries.some((entry) => entry.status === "pending");
|
|
1358
1429
|
const [open, setOpen] = useState2(active);
|
|
1359
1430
|
const id = useId();
|
|
1360
1431
|
useEffect3(() => {
|
|
1361
1432
|
if (active) setOpen(true);
|
|
1362
1433
|
}, [active]);
|
|
1363
|
-
return /* @__PURE__ */
|
|
1364
|
-
/* @__PURE__ */
|
|
1365
|
-
/* @__PURE__ */
|
|
1366
|
-
/* @__PURE__ */
|
|
1367
|
-
/* @__PURE__ */
|
|
1368
|
-
/* @__PURE__ */
|
|
1434
|
+
return /* @__PURE__ */ jsxs4("section", { class: "scui-activity", children: [
|
|
1435
|
+
/* @__PURE__ */ jsxs4("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
|
|
1436
|
+
/* @__PURE__ */ jsx5("span", { class: "scui-fold", "data-open": open, children: /* @__PURE__ */ jsx5(UiIcon, { name: "chevron", size: 14 }) }),
|
|
1437
|
+
/* @__PURE__ */ jsx5("strong", { children: activitySummary(entries) }),
|
|
1438
|
+
/* @__PURE__ */ jsx5("span", { class: "scui-spacer" }),
|
|
1439
|
+
/* @__PURE__ */ jsxs4("small", { children: [
|
|
1369
1440
|
entries.filter((entry) => entry.status !== "pending").length,
|
|
1370
1441
|
"/",
|
|
1371
1442
|
entries.length
|
|
1372
1443
|
] })
|
|
1373
1444
|
] }),
|
|
1374
|
-
open ? /* @__PURE__ */
|
|
1445
|
+
open ? /* @__PURE__ */ jsx5("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx5(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
|
|
1375
1446
|
] });
|
|
1376
1447
|
}
|
|
1377
1448
|
function TaskPlan({ plan }) {
|
|
1378
1449
|
if (!plan.items.length) return null;
|
|
1379
1450
|
const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
|
|
1380
|
-
return /* @__PURE__ */
|
|
1381
|
-
/* @__PURE__ */
|
|
1382
|
-
/* @__PURE__ */
|
|
1383
|
-
/* @__PURE__ */
|
|
1451
|
+
return /* @__PURE__ */ jsxs4("details", { class: "scui-plan", children: [
|
|
1452
|
+
/* @__PURE__ */ jsxs4("summary", { children: [
|
|
1453
|
+
/* @__PURE__ */ jsx5("span", { children: "Plan" }),
|
|
1454
|
+
/* @__PURE__ */ jsxs4("small", { children: [
|
|
1384
1455
|
complete,
|
|
1385
1456
|
"/",
|
|
1386
1457
|
plan.items.length
|
|
1387
1458
|
] })
|
|
1388
1459
|
] }),
|
|
1389
|
-
/* @__PURE__ */
|
|
1390
|
-
/* @__PURE__ */
|
|
1460
|
+
/* @__PURE__ */ jsx5("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs4("li", { "data-status": item.status, children: [
|
|
1461
|
+
/* @__PURE__ */ jsx5("i", { "aria-hidden": "true" }),
|
|
1391
1462
|
" ",
|
|
1392
|
-
/* @__PURE__ */
|
|
1463
|
+
/* @__PURE__ */ jsx5("span", { children: item.title })
|
|
1393
1464
|
] }, item.id)) })
|
|
1394
1465
|
] });
|
|
1395
1466
|
}
|
|
1396
1467
|
function SessionDetails({ semantics }) {
|
|
1397
1468
|
if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
|
|
1398
|
-
return /* @__PURE__ */
|
|
1399
|
-
/* @__PURE__ */
|
|
1400
|
-
/* @__PURE__ */
|
|
1401
|
-
semantics.fidelity ? /* @__PURE__ */
|
|
1402
|
-
/* @__PURE__ */
|
|
1403
|
-
/* @__PURE__ */
|
|
1469
|
+
return /* @__PURE__ */ jsxs4("details", { class: "scui-details", children: [
|
|
1470
|
+
/* @__PURE__ */ jsx5("summary", { children: "Session details" }),
|
|
1471
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
1472
|
+
semantics.fidelity ? /* @__PURE__ */ jsxs4("p", { children: [
|
|
1473
|
+
/* @__PURE__ */ jsx5("strong", { children: "Fidelity" }),
|
|
1474
|
+
/* @__PURE__ */ jsx5("span", { children: semantics.fidelity.replaceAll("_", " ") })
|
|
1404
1475
|
] }) : null,
|
|
1405
|
-
/* @__PURE__ */
|
|
1406
|
-
/* @__PURE__ */
|
|
1407
|
-
/* @__PURE__ */
|
|
1476
|
+
/* @__PURE__ */ jsxs4("p", { children: [
|
|
1477
|
+
/* @__PURE__ */ jsx5("strong", { children: "Native records" }),
|
|
1478
|
+
/* @__PURE__ */ jsx5("span", { children: semantics.rawRecords })
|
|
1408
1479
|
] }),
|
|
1409
|
-
semantics.residueCount ? /* @__PURE__ */
|
|
1410
|
-
/* @__PURE__ */
|
|
1411
|
-
/* @__PURE__ */
|
|
1480
|
+
semantics.residueCount ? /* @__PURE__ */ jsxs4("p", { children: [
|
|
1481
|
+
/* @__PURE__ */ jsx5("strong", { children: "Residue" }),
|
|
1482
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1412
1483
|
semantics.residueCount,
|
|
1413
1484
|
" retained"
|
|
1414
1485
|
] })
|
|
1415
1486
|
] }) : null,
|
|
1416
|
-
semantics.parseErrors ? /* @__PURE__ */
|
|
1417
|
-
/* @__PURE__ */
|
|
1418
|
-
/* @__PURE__ */
|
|
1487
|
+
semantics.parseErrors ? /* @__PURE__ */ jsxs4("p", { children: [
|
|
1488
|
+
/* @__PURE__ */ jsx5("strong", { children: "Parse diagnostics" }),
|
|
1489
|
+
/* @__PURE__ */ jsx5("span", { children: semantics.parseErrors })
|
|
1419
1490
|
] }) : null,
|
|
1420
|
-
semantics.subagents.map((agent) => /* @__PURE__ */
|
|
1421
|
-
/* @__PURE__ */
|
|
1491
|
+
semantics.subagents.map((agent) => /* @__PURE__ */ jsxs4("p", { children: [
|
|
1492
|
+
/* @__PURE__ */ jsxs4("strong", { children: [
|
|
1422
1493
|
agent.source,
|
|
1423
1494
|
" subagent"
|
|
1424
1495
|
] }),
|
|
1425
|
-
/* @__PURE__ */
|
|
1496
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
1426
1497
|
agent.messages,
|
|
1427
1498
|
" messages \xB7 ",
|
|
1428
1499
|
agent.fidelity.replaceAll("_", " ")
|
|
@@ -1441,7 +1512,7 @@ function ConversationAnnouncements({ state }) {
|
|
|
1441
1512
|
}
|
|
1442
1513
|
previousBusy.current = state.busy;
|
|
1443
1514
|
}, [state.busy, state.error, state.harness]);
|
|
1444
|
-
return /* @__PURE__ */
|
|
1515
|
+
return /* @__PURE__ */ jsx5("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
|
|
1445
1516
|
}
|
|
1446
1517
|
function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null, unreadAfterMessages = null }) {
|
|
1447
1518
|
const scroller = useRef3(null);
|
|
@@ -1473,65 +1544,71 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1473
1544
|
const element = scroller.current;
|
|
1474
1545
|
if (!element) return;
|
|
1475
1546
|
const anchor = earlierAnchor.current;
|
|
1476
|
-
if (anchor
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1547
|
+
if (anchor) {
|
|
1548
|
+
if (state.operation === "loadEarlier") anchor.seenOperation = true;
|
|
1549
|
+
const prepended = state.transcript.length > anchor.entries && state.transcript[0]?.id !== anchor.firstId;
|
|
1550
|
+
if (prepended) {
|
|
1551
|
+
element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
|
|
1552
|
+
earlierAnchor.current = null;
|
|
1553
|
+
remember({ top: element.scrollTop, atBottom: false });
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
if (state.error || anchor.seenOperation && state.operation !== "loadEarlier") earlierAnchor.current = null;
|
|
1481
1557
|
}
|
|
1482
1558
|
if (!restored.current) {
|
|
1483
1559
|
restored.current = true;
|
|
1484
1560
|
if (remembered.top !== null && !remembered.atBottom) element.scrollTop = remembered.top;
|
|
1485
1561
|
else pin();
|
|
1486
1562
|
} else if (atBottom) pin();
|
|
1487
|
-
}, [memoryKey, state.transcript, state.busy, state.operation, pendingMessage?.text, pendingMessage?.status]);
|
|
1488
|
-
return /* @__PURE__ */
|
|
1489
|
-
/* @__PURE__ */
|
|
1490
|
-
/* @__PURE__ */
|
|
1563
|
+
}, [memoryKey, state.transcript, state.busy, state.operation, state.error, pendingMessage?.text, pendingMessage?.status]);
|
|
1564
|
+
return /* @__PURE__ */ jsxs4("div", { class: "scui-conversation-wrap", children: [
|
|
1565
|
+
/* @__PURE__ */ jsx5(ConversationAnnouncements, { state }),
|
|
1566
|
+
/* @__PURE__ */ jsx5("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
|
|
1491
1567
|
const element = event.currentTarget;
|
|
1492
1568
|
const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
|
|
1493
1569
|
setAtBottom(bottom);
|
|
1494
1570
|
remember({ top: element.scrollTop, atBottom: bottom });
|
|
1495
|
-
}, children: /* @__PURE__ */
|
|
1496
|
-
Before ? /* @__PURE__ */
|
|
1497
|
-
/* @__PURE__ */
|
|
1498
|
-
/* @__PURE__ */
|
|
1499
|
-
state.history.hasEarlier ? /* @__PURE__ */
|
|
1571
|
+
}, children: /* @__PURE__ */ jsxs4("div", { children: [
|
|
1572
|
+
Before ? /* @__PURE__ */ jsx5(Before, { state, adapter, value: null }) : null,
|
|
1573
|
+
/* @__PURE__ */ jsx5(Plan, { plan: state.taskPlan, value: state.taskPlan, state, adapter }),
|
|
1574
|
+
/* @__PURE__ */ jsx5(SessionDetails, { semantics: state.semantics }),
|
|
1575
|
+
state.history.hasEarlier ? /* @__PURE__ */ jsx5("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
|
|
1500
1576
|
const element = scroller.current;
|
|
1501
|
-
if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
|
|
1577
|
+
if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length, firstId: state.transcript[0]?.id, seenOperation: false };
|
|
1502
1578
|
setAtBottom(false);
|
|
1503
1579
|
adapter.onIntent({ action: "loadEarlier" });
|
|
1504
1580
|
}, children: "Load earlier messages" }) : null,
|
|
1505
|
-
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */
|
|
1506
|
-
!blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */
|
|
1507
|
-
blocks.map((block, index) => /* @__PURE__ */
|
|
1508
|
-
index === unreadBlock ? /* @__PURE__ */
|
|
1509
|
-
block.kind === "activity" ? /* @__PURE__ */
|
|
1581
|
+
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx5(LoadingStatus, { state }) : null,
|
|
1582
|
+
!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,
|
|
1583
|
+
blocks.map((block, index) => /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
1584
|
+
index === unreadBlock ? /* @__PURE__ */ jsx5("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx5("span", { children: "New" }) }) : null,
|
|
1585
|
+
block.kind === "activity" ? /* @__PURE__ */ jsx5(Group, { value: block.entries, entries: block.entries, state, adapter }) : /* @__PURE__ */ jsx5(Entry, { value: block.entry, entry: block.entry, state, adapter })
|
|
1510
1586
|
] }, block.id)),
|
|
1511
|
-
pendingMessage ? /* @__PURE__ */
|
|
1512
|
-
/* @__PURE__ */
|
|
1513
|
-
/* @__PURE__ */
|
|
1514
|
-
|
|
1515
|
-
pendingMessage.status === "failed" ?
|
|
1516
|
-
|
|
1517
|
-
/* @__PURE__ */
|
|
1587
|
+
pendingMessage ? /* @__PURE__ */ jsxs4("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
|
|
1588
|
+
/* @__PURE__ */ jsx5(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
|
|
1589
|
+
/* @__PURE__ */ jsx5(ContextDisclosure, { context: pendingMessage.context }),
|
|
1590
|
+
/* @__PURE__ */ jsxs4("footer", { children: [
|
|
1591
|
+
/* @__PURE__ */ jsx5("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
|
|
1592
|
+
pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs4("span", { children: [
|
|
1593
|
+
/* @__PURE__ */ jsx5("button", { type: "button", onClick: pendingMessage.onRetry, children: "Retry" }),
|
|
1594
|
+
/* @__PURE__ */ jsx5("button", { type: "button", onClick: pendingMessage.onEdit, children: "Edit" })
|
|
1518
1595
|
] }) : null
|
|
1519
1596
|
] })
|
|
1520
1597
|
] }) : null,
|
|
1521
|
-
state.busy ? /* @__PURE__ */
|
|
1522
|
-
/* @__PURE__ */
|
|
1523
|
-
/* @__PURE__ */
|
|
1524
|
-
/* @__PURE__ */
|
|
1525
|
-
/* @__PURE__ */
|
|
1526
|
-
/* @__PURE__ */
|
|
1598
|
+
state.busy ? /* @__PURE__ */ jsxs4("div", { class: "scui-working", role: "status", children: [
|
|
1599
|
+
/* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
1600
|
+
/* @__PURE__ */ jsx5("i", {}),
|
|
1601
|
+
/* @__PURE__ */ jsx5("i", {}),
|
|
1602
|
+
/* @__PURE__ */ jsx5("i", {}),
|
|
1603
|
+
/* @__PURE__ */ jsxs4("small", { children: [
|
|
1527
1604
|
harnessDisplayName(state.harness),
|
|
1528
1605
|
" is working"
|
|
1529
1606
|
] })
|
|
1530
1607
|
] }) : null,
|
|
1531
|
-
After ? /* @__PURE__ */
|
|
1608
|
+
After ? /* @__PURE__ */ jsx5(After, { state, adapter, value: null }) : null
|
|
1532
1609
|
] }) }),
|
|
1533
|
-
!atBottom ? /* @__PURE__ */
|
|
1534
|
-
/* @__PURE__ */
|
|
1610
|
+
!atBottom ? /* @__PURE__ */ jsxs4("button", { class: "scui-latest", type: "button", onClick: pin, children: [
|
|
1611
|
+
/* @__PURE__ */ jsx5(UiIcon, { name: "down", size: 13 }),
|
|
1535
1612
|
" Latest"
|
|
1536
1613
|
] }) : null
|
|
1537
1614
|
] });
|
|
@@ -1539,7 +1616,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1539
1616
|
|
|
1540
1617
|
// src/logo.jsx
|
|
1541
1618
|
import { useEffect as useEffect4 } from "preact/hooks";
|
|
1542
|
-
import { jsx as
|
|
1619
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
1543
1620
|
var LOGOS = {
|
|
1544
1621
|
"claude-code": {
|
|
1545
1622
|
viewBox: "-1 3.5 26 18",
|
|
@@ -1590,30 +1667,30 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
|
1590
1667
|
if (!logo) onMissingLogo?.(id);
|
|
1591
1668
|
}, [id, logo, onMissingLogo]);
|
|
1592
1669
|
if (!logo) return null;
|
|
1593
|
-
return /* @__PURE__ */
|
|
1594
|
-
/* @__PURE__ */
|
|
1595
|
-
activity && activity !== "idle" ? /* @__PURE__ */
|
|
1670
|
+
return /* @__PURE__ */ jsxs5("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
|
|
1671
|
+
/* @__PURE__ */ jsx6("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx6(Tag, { ...props }, index)) }),
|
|
1672
|
+
activity && activity !== "idle" ? /* @__PURE__ */ jsx6("i", {}) : null
|
|
1596
1673
|
] });
|
|
1597
1674
|
}
|
|
1598
1675
|
|
|
1599
1676
|
// src/sessions.jsx
|
|
1600
1677
|
import { useEffect as useEffect5, useLayoutEffect as useLayoutEffect3, useRef as useRef4, useState as useState3 } from "preact/hooks";
|
|
1601
|
-
import { jsx as
|
|
1678
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
1602
1679
|
var sessionListMemory = /* @__PURE__ */ new Map();
|
|
1603
1680
|
function SessionRow({ row, state, onOpen }) {
|
|
1604
1681
|
const activity = sessionActivity(state, row);
|
|
1605
1682
|
const attentionPreview = state.attention.find((item) => item.key === row.key)?.preview;
|
|
1606
1683
|
const title = sessionDisplayName(row);
|
|
1607
1684
|
const detail = attentionPreview || row.preview || (row.name && row.name !== title ? row.name : row.cwd);
|
|
1608
|
-
return /* @__PURE__ */
|
|
1609
|
-
/* @__PURE__ */
|
|
1610
|
-
/* @__PURE__ */
|
|
1611
|
-
/* @__PURE__ */
|
|
1612
|
-
/* @__PURE__ */
|
|
1613
|
-
/* @__PURE__ */
|
|
1685
|
+
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: [
|
|
1686
|
+
/* @__PURE__ */ jsx7(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
1687
|
+
/* @__PURE__ */ jsxs6("span", { class: "scui-session-copy", children: [
|
|
1688
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1689
|
+
/* @__PURE__ */ jsx7("strong", { children: title }),
|
|
1690
|
+
/* @__PURE__ */ jsx7("small", { children: row.age })
|
|
1614
1691
|
] }),
|
|
1615
|
-
detail ? /* @__PURE__ */
|
|
1616
|
-
state.attachError?.key === row.key ? /* @__PURE__ */
|
|
1692
|
+
detail ? /* @__PURE__ */ jsx7("span", { children: /* @__PURE__ */ jsx7("small", { title: row.cwd, children: detail }) }) : null,
|
|
1693
|
+
state.attachError?.key === row.key ? /* @__PURE__ */ jsx7("em", { children: state.attachError.message }) : null
|
|
1617
1694
|
] })
|
|
1618
1695
|
] });
|
|
1619
1696
|
}
|
|
@@ -1644,48 +1721,48 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
1644
1721
|
Promise.resolve(result).then(() => setLoadingMore(false), () => setLoadingMore(false));
|
|
1645
1722
|
}
|
|
1646
1723
|
};
|
|
1647
|
-
return /* @__PURE__ */
|
|
1648
|
-
/* @__PURE__ */
|
|
1649
|
-
/* @__PURE__ */
|
|
1650
|
-
/* @__PURE__ */
|
|
1651
|
-
/* @__PURE__ */
|
|
1724
|
+
return /* @__PURE__ */ jsxs6("section", { class: "scui-list", ref: root, children: [
|
|
1725
|
+
/* @__PURE__ */ jsxs6("header", { class: "scui-head", children: [
|
|
1726
|
+
/* @__PURE__ */ jsxs6("span", { class: "scui-head-copy", children: [
|
|
1727
|
+
/* @__PURE__ */ jsx7("strong", { children: labels.chats }),
|
|
1728
|
+
/* @__PURE__ */ jsxs6("small", { children: [
|
|
1652
1729
|
state.sessions.length,
|
|
1653
1730
|
" recent conversations"
|
|
1654
1731
|
] })
|
|
1655
1732
|
] }),
|
|
1656
|
-
/* @__PURE__ */
|
|
1657
|
-
onClose ? /* @__PURE__ */
|
|
1733
|
+
/* @__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 }) }),
|
|
1734
|
+
onClose ? /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx7(UiIcon, { name: "close", size: 18 }) }) : null
|
|
1658
1735
|
] }),
|
|
1659
|
-
state.startup !== "ready" ? /* @__PURE__ */
|
|
1660
|
-
state.sessions.length > 4 ? /* @__PURE__ */
|
|
1661
|
-
/* @__PURE__ */
|
|
1662
|
-
/* @__PURE__ */
|
|
1736
|
+
state.startup !== "ready" ? /* @__PURE__ */ jsx7(LoadingStatus, { state, compact: rows.length > 0 }) : null,
|
|
1737
|
+
state.sessions.length > 4 ? /* @__PURE__ */ jsxs6("label", { class: "scui-search", children: [
|
|
1738
|
+
/* @__PURE__ */ jsx7(UiIcon, { name: "search", size: 15 }),
|
|
1739
|
+
/* @__PURE__ */ jsx7("input", { type: "search", "aria-label": labels.searchChats, placeholder: labels.searchChats, value: query, onInput: (event) => {
|
|
1663
1740
|
const value = event.currentTarget.value;
|
|
1664
1741
|
setQuery(value);
|
|
1665
1742
|
boundedSet(sessionListMemory, memoryKey, { query: value, top: 0 });
|
|
1666
1743
|
if (rowScroller.current) rowScroller.current.scrollTop = 0;
|
|
1667
1744
|
} }),
|
|
1668
|
-
/* @__PURE__ */
|
|
1745
|
+
/* @__PURE__ */ jsx7("small", { children: rows.length })
|
|
1669
1746
|
] }) : null,
|
|
1670
|
-
/* @__PURE__ */
|
|
1671
|
-
!rows.length && state.startup === "ready" ? /* @__PURE__ */
|
|
1672
|
-
rows.map((row) => /* @__PURE__ */
|
|
1673
|
-
state.history.hasMoreSessions ? /* @__PURE__ */
|
|
1747
|
+
/* @__PURE__ */ jsxs6("div", { class: "scui-session-rows", ref: rowScroller, onScroll: (event) => boundedSet(sessionListMemory, memoryKey, { query, top: event.currentTarget.scrollTop }), children: [
|
|
1748
|
+
!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,
|
|
1749
|
+
rows.map((row) => /* @__PURE__ */ jsx7(Row, { value: row, row, state, adapter, onOpen }, row.key)),
|
|
1750
|
+
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
1751
|
] })
|
|
1675
1752
|
] });
|
|
1676
1753
|
}
|
|
1677
1754
|
|
|
1678
1755
|
// src/messenger.jsx
|
|
1679
|
-
import { jsx as
|
|
1756
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "preact/jsx-runtime";
|
|
1680
1757
|
var pendingMessageMemory = /* @__PURE__ */ new Map();
|
|
1681
1758
|
var messengerViewMemory = /* @__PURE__ */ new Map();
|
|
1682
1759
|
var newChatMemory = /* @__PURE__ */ new Map();
|
|
1683
1760
|
var TRACKED_ACTIONS = /* @__PURE__ */ new Set(["resume", "join", "detach", "branch", "reduce", "terminal", "export", "interrupt", "respond", "refresh", "loadEarlier", "loadSessions"]);
|
|
1684
1761
|
function Receipt({ state, adapter }) {
|
|
1685
1762
|
const receipt = state.reductionReceipt;
|
|
1686
|
-
if (receipt) return /* @__PURE__ */
|
|
1687
|
-
/* @__PURE__ */
|
|
1688
|
-
/* @__PURE__ */
|
|
1763
|
+
if (receipt) return /* @__PURE__ */ jsx8("div", { class: "scui-receipt", children: /* @__PURE__ */ jsxs7("span", { children: [
|
|
1764
|
+
/* @__PURE__ */ jsx8("strong", { children: "Reduced and verified" }),
|
|
1765
|
+
/* @__PURE__ */ jsxs7("small", { children: [
|
|
1689
1766
|
receipt.sourceTokens.toLocaleString(),
|
|
1690
1767
|
" \u2192 ",
|
|
1691
1768
|
receipt.reducedTokens.toLocaleString(),
|
|
@@ -1694,27 +1771,27 @@ function Receipt({ state, adapter }) {
|
|
|
1694
1771
|
"\xD7 \xB7 reversible"
|
|
1695
1772
|
] })
|
|
1696
1773
|
] }) });
|
|
1697
|
-
if (state.exportReceipt) return /* @__PURE__ */
|
|
1698
|
-
/* @__PURE__ */
|
|
1699
|
-
/* @__PURE__ */
|
|
1774
|
+
if (state.exportReceipt) return /* @__PURE__ */ jsxs7("div", { class: "scui-receipt", children: [
|
|
1775
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
1776
|
+
/* @__PURE__ */ jsxs7("strong", { children: [
|
|
1700
1777
|
"Lossless export ready \xB7 ",
|
|
1701
1778
|
harnessDisplayName(state.exportReceipt.targetHarness)
|
|
1702
1779
|
] }),
|
|
1703
|
-
/* @__PURE__ */
|
|
1780
|
+
/* @__PURE__ */ jsxs7("small", { children: [
|
|
1704
1781
|
state.exportReceipt.path,
|
|
1705
1782
|
" \xB7 ",
|
|
1706
1783
|
state.exportReceipt.files,
|
|
1707
1784
|
" files"
|
|
1708
1785
|
] })
|
|
1709
1786
|
] }),
|
|
1710
|
-
/* @__PURE__ */
|
|
1787
|
+
/* @__PURE__ */ jsx8("button", { type: "button", onClick: () => adapter.copyText?.(state.exportReceipt.path), children: "Copy path" })
|
|
1711
1788
|
] });
|
|
1712
|
-
if (state.terminalHandoff) return /* @__PURE__ */
|
|
1713
|
-
/* @__PURE__ */
|
|
1714
|
-
/* @__PURE__ */
|
|
1715
|
-
/* @__PURE__ */
|
|
1789
|
+
if (state.terminalHandoff) return /* @__PURE__ */ jsxs7("div", { class: "scui-receipt", children: [
|
|
1790
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
1791
|
+
/* @__PURE__ */ jsx8("strong", { children: "Terminal handoff ready" }),
|
|
1792
|
+
/* @__PURE__ */ jsx8("small", { children: state.terminalHandoff.cwd })
|
|
1716
1793
|
] }),
|
|
1717
|
-
/* @__PURE__ */
|
|
1794
|
+
/* @__PURE__ */ jsx8("button", { type: "button", onClick: () => adapter.copyText?.(terminalCommand(state.terminalHandoff)), children: "Copy command" })
|
|
1718
1795
|
] });
|
|
1719
1796
|
return null;
|
|
1720
1797
|
}
|
|
@@ -1782,13 +1859,13 @@ function ConversationActions({ state, adapter, actionPending }) {
|
|
|
1782
1859
|
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
1860
|
items[index].focus({ preventScroll: true });
|
|
1784
1861
|
};
|
|
1785
|
-
return /* @__PURE__ */
|
|
1862
|
+
return /* @__PURE__ */ jsxs7("div", { class: "scui-menu", ref: root, onBlur: (event) => {
|
|
1786
1863
|
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
1787
1864
|
}, children: [
|
|
1788
|
-
/* @__PURE__ */
|
|
1789
|
-
open ? /* @__PURE__ */
|
|
1790
|
-
/* @__PURE__ */
|
|
1791
|
-
group.items.map((item) => /* @__PURE__ */
|
|
1865
|
+
/* @__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 }) }),
|
|
1866
|
+
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: [
|
|
1867
|
+
/* @__PURE__ */ jsx8("strong", { children: group.label }),
|
|
1868
|
+
group.items.map((item) => /* @__PURE__ */ jsx8("button", { role: "menuitem", type: "button", disabled: actionPending, onClick: () => dispatch(item.intent), children: item.label }, item.key))
|
|
1792
1869
|
] }, group.label)) }) : null
|
|
1793
1870
|
] });
|
|
1794
1871
|
}
|
|
@@ -1801,20 +1878,20 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
1801
1878
|
useEffect6(() => {
|
|
1802
1879
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
1803
1880
|
}, []);
|
|
1804
|
-
return /* @__PURE__ */
|
|
1805
|
-
/* @__PURE__ */
|
|
1806
|
-
/* @__PURE__ */
|
|
1807
|
-
/* @__PURE__ */
|
|
1808
|
-
/* @__PURE__ */
|
|
1809
|
-
/* @__PURE__ */
|
|
1881
|
+
return /* @__PURE__ */ jsxs7("header", { class: "scui-head scui-chat-head", children: [
|
|
1882
|
+
/* @__PURE__ */ jsx8("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx8(UiIcon, { name: "back", size: 18 }) }),
|
|
1883
|
+
/* @__PURE__ */ jsx8(HarnessLogo, { id: harness, size: 28 }),
|
|
1884
|
+
/* @__PURE__ */ jsxs7("span", { class: "scui-head-copy", children: [
|
|
1885
|
+
/* @__PURE__ */ jsx8("strong", { children: title }),
|
|
1886
|
+
/* @__PURE__ */ jsxs7("small", { children: [
|
|
1810
1887
|
harnessDisplayName(harness),
|
|
1811
1888
|
" \xB7 ",
|
|
1812
1889
|
status
|
|
1813
1890
|
] })
|
|
1814
1891
|
] }),
|
|
1815
|
-
menu ? /* @__PURE__ */
|
|
1816
|
-
/* @__PURE__ */
|
|
1817
|
-
onClose ? /* @__PURE__ */
|
|
1892
|
+
menu ? /* @__PURE__ */ jsx8(ConversationActions, { state, adapter, actionPending }) : null,
|
|
1893
|
+
/* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: /* @__PURE__ */ jsx8(UiIcon, { name: "plus", size: 18 }) }),
|
|
1894
|
+
onClose ? /* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx8(UiIcon, { name: "close", size: 18 }) }) : null
|
|
1818
1895
|
] });
|
|
1819
1896
|
}
|
|
1820
1897
|
function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
|
|
@@ -1846,8 +1923,9 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
1846
1923
|
if (pending.status === "sending" && state.busy && !pending.seenBusy) setPending({ ...pending, seenBusy: true });
|
|
1847
1924
|
else if (pending.status === "sending" && state.error && !state.busy && !state.operation && (pending.seenBusy || state.error !== pending.initialError)) setPending({ ...pending, status: "failed" });
|
|
1848
1925
|
}, [pending, state.busy, state.error, state.operation, state.transcript]);
|
|
1849
|
-
const beginPending = (text) => setPending({
|
|
1926
|
+
const beginPending = (text, context = []) => setPending({
|
|
1850
1927
|
text,
|
|
1928
|
+
context,
|
|
1851
1929
|
status: "sending",
|
|
1852
1930
|
initialError: state.error,
|
|
1853
1931
|
seenBusy: state.busy,
|
|
@@ -1855,13 +1933,13 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
1855
1933
|
});
|
|
1856
1934
|
const retryPending = () => {
|
|
1857
1935
|
if (!pending) return;
|
|
1858
|
-
adapter.onIntent({ action: "send", text: pending.text });
|
|
1936
|
+
adapter.onIntent({ action: "send", text: pending.text, ...pending.context?.length ? { context: pending.context } : {} });
|
|
1859
1937
|
setPending({ ...pending, status: "sending", initialError: state.error, seenBusy: state.busy });
|
|
1860
1938
|
};
|
|
1861
1939
|
const editPending = () => {
|
|
1862
1940
|
if (!pending) return;
|
|
1863
1941
|
restoreSequence.current += 1;
|
|
1864
|
-
setRestoreDraft({ id: restoreSequence.current, text: pending.text });
|
|
1942
|
+
setRestoreDraft({ id: restoreSequence.current, text: pending.text, context: pending.context });
|
|
1865
1943
|
setPending({ ...pending, status: "editing" });
|
|
1866
1944
|
};
|
|
1867
1945
|
useEffect6(() => {
|
|
@@ -1907,34 +1985,37 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
1907
1985
|
setPendingAction(null);
|
|
1908
1986
|
}
|
|
1909
1987
|
}, [pendingAction, state.error, state.operation]);
|
|
1910
|
-
const pendingMessage = pending && pending.status !== "editing" ? { text: pending.text, status: pending.status, onRetry: retryPending, onEdit: editPending } : null;
|
|
1988
|
+
const pendingMessage = pending && pending.status !== "editing" ? { text: pending.text, context: pending.context, status: pending.status, onRetry: retryPending, onEdit: editPending } : null;
|
|
1911
1989
|
const action = state.operation || pendingAction?.action || null;
|
|
1912
1990
|
const actionLabel = operationLabel(action);
|
|
1913
1991
|
const actionState = action ? { ...state, operation: action, canInterrupt: false, canRespond: false } : state;
|
|
1914
1992
|
const unreadAfterMessages = state.attention.find((item) => item.key === state.attached?.key)?.afterMessages ?? null;
|
|
1915
|
-
return /* @__PURE__ */
|
|
1916
|
-
Header ? /* @__PURE__ */
|
|
1917
|
-
actionLabel ? /* @__PURE__ */
|
|
1918
|
-
/* @__PURE__ */
|
|
1993
|
+
return /* @__PURE__ */ jsxs7("section", { class: "scui-chat", children: [
|
|
1994
|
+
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 }),
|
|
1995
|
+
actionLabel ? /* @__PURE__ */ jsxs7("div", { class: "scui-operation", role: "status", children: [
|
|
1996
|
+
/* @__PURE__ */ jsx8("i", {}),
|
|
1919
1997
|
actionLabel
|
|
1920
1998
|
] }) : null,
|
|
1921
|
-
state.error ? /* @__PURE__ */
|
|
1922
|
-
/* @__PURE__ */
|
|
1923
|
-
state.recoverable ? /* @__PURE__ */
|
|
1999
|
+
state.error ? /* @__PURE__ */ jsxs7("div", { class: "scui-error", role: "alert", children: [
|
|
2000
|
+
/* @__PURE__ */ jsx8("span", { children: state.error }),
|
|
2001
|
+
state.recoverable ? /* @__PURE__ */ jsx8("button", { type: "button", disabled: Boolean(action), onClick: () => trackedAdapter.onIntent({ action: "refresh" }), children: "Retry" }) : null
|
|
1924
2002
|
] }) : null,
|
|
1925
|
-
/* @__PURE__ */
|
|
1926
|
-
/* @__PURE__ */
|
|
1927
|
-
/* @__PURE__ */
|
|
1928
|
-
state.mode !== "mirror" || state.canSend ? /* @__PURE__ */
|
|
2003
|
+
/* @__PURE__ */ jsx8(Receipt, { state, adapter }),
|
|
2004
|
+
/* @__PURE__ */ jsx8(Conversation, { state: actionState, adapter: trackedAdapter, components, slots, memoryKey, pending: pendingMessage, unreadAfterMessages }, memoryKey),
|
|
2005
|
+
/* @__PURE__ */ jsx8(ContinuationBar, { state: actionState, adapter: trackedAdapter, labels }),
|
|
2006
|
+
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
2007
|
] });
|
|
1930
2008
|
}
|
|
1931
2009
|
function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey }) {
|
|
1932
2010
|
const startable = state.harnesses.filter((item) => item.startable);
|
|
1933
2011
|
const startableKey = startable.map((item) => item.id).join("\0");
|
|
1934
|
-
const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "" };
|
|
2012
|
+
const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "", context: [] };
|
|
1935
2013
|
const [harness, setHarness] = useState4(remembered.harness);
|
|
1936
2014
|
const [draft, setDraft] = useState4(remembered.draft);
|
|
2015
|
+
const [context, setContext] = useState4(remembered.context);
|
|
1937
2016
|
const [starting, setStarting] = useState4(null);
|
|
2017
|
+
const [picking, setPicking] = useState4(false);
|
|
2018
|
+
const [pickerError, setPickerError] = useState4(null);
|
|
1938
2019
|
const startSequence = useRef5(0);
|
|
1939
2020
|
const textarea = useRef5(null);
|
|
1940
2021
|
useAutosizeTextarea(textarea, draft);
|
|
@@ -1942,7 +2023,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
1942
2023
|
if (startable.some((item) => item.id === harness)) return;
|
|
1943
2024
|
const next = startable[0]?.id ?? "";
|
|
1944
2025
|
setHarness(next);
|
|
1945
|
-
boundedSet(newChatMemory, memoryKey, { harness: next, draft });
|
|
2026
|
+
boundedSet(newChatMemory, memoryKey, { harness: next, draft, context });
|
|
1946
2027
|
}, [harness, startableKey]);
|
|
1947
2028
|
useEffect6(() => {
|
|
1948
2029
|
if (!starting) return;
|
|
@@ -1958,60 +2039,79 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
1958
2039
|
useEffect6(() => {
|
|
1959
2040
|
textarea.current?.focus({ preventScroll: true });
|
|
1960
2041
|
}, []);
|
|
2042
|
+
const pickContext = () => {
|
|
2043
|
+
if (!adapter.pickContext || picking || context.length >= MAX_CONTEXT_ITEMS) return;
|
|
2044
|
+
setPicking(true);
|
|
2045
|
+
setPickerError(null);
|
|
2046
|
+
Promise.resolve().then(() => adapter.pickContext()).then((picked) => {
|
|
2047
|
+
setContext((current) => {
|
|
2048
|
+
const next = mergeContext(current, picked);
|
|
2049
|
+
boundedSet(newChatMemory, memoryKey, { harness, draft, context: next });
|
|
2050
|
+
return next;
|
|
2051
|
+
});
|
|
2052
|
+
}, (error) => setPickerError(error instanceof Error ? error.message : "Could not attach context.")).finally(() => setPicking(false));
|
|
2053
|
+
};
|
|
1961
2054
|
const send = () => {
|
|
1962
2055
|
const text = draft.trim();
|
|
1963
2056
|
if (!text || !harness || starting) return;
|
|
1964
2057
|
const id = startSequence.current + 1;
|
|
1965
2058
|
startSequence.current = id;
|
|
1966
2059
|
setStarting({ id, attachedKey: state.attached?.key ?? null, busy: state.busy, initialError: state.error });
|
|
1967
|
-
const result = adapter.onIntent({ action: "new", harness, text });
|
|
2060
|
+
const result = adapter.onIntent({ action: "new", harness, text, ...context.length ? { context } : {} });
|
|
1968
2061
|
if (result && typeof result.then === "function") {
|
|
1969
2062
|
Promise.resolve(result).catch(() => setStarting((current) => current?.id === id ? null : current));
|
|
1970
2063
|
}
|
|
1971
2064
|
};
|
|
1972
|
-
return /* @__PURE__ */
|
|
1973
|
-
/* @__PURE__ */
|
|
1974
|
-
/* @__PURE__ */
|
|
1975
|
-
/* @__PURE__ */
|
|
1976
|
-
/* @__PURE__ */
|
|
1977
|
-
/* @__PURE__ */
|
|
2065
|
+
return /* @__PURE__ */ jsxs7("section", { class: "scui-chat", children: [
|
|
2066
|
+
/* @__PURE__ */ jsxs7("header", { class: "scui-head", children: [
|
|
2067
|
+
/* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "Back", onClick: onBack, children: /* @__PURE__ */ jsx8(UiIcon, { name: "back", size: 18 }) }),
|
|
2068
|
+
/* @__PURE__ */ jsxs7("span", { class: "scui-head-copy", children: [
|
|
2069
|
+
/* @__PURE__ */ jsx8("strong", { children: labels.newChat }),
|
|
2070
|
+
/* @__PURE__ */ jsx8("small", { children: "No session is created until you send" })
|
|
1978
2071
|
] }),
|
|
1979
|
-
onClose ? /* @__PURE__ */
|
|
2072
|
+
onClose ? /* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx8(UiIcon, { name: "close", size: 18 }) }) : null
|
|
1980
2073
|
] }),
|
|
1981
|
-
starting ? /* @__PURE__ */
|
|
1982
|
-
/* @__PURE__ */
|
|
2074
|
+
starting ? /* @__PURE__ */ jsxs7("div", { class: "scui-operation", role: "status", children: [
|
|
2075
|
+
/* @__PURE__ */ jsx8("i", {}),
|
|
1983
2076
|
operationLabel("start")
|
|
1984
2077
|
] }) : null,
|
|
1985
|
-
/* @__PURE__ */
|
|
1986
|
-
/* @__PURE__ */
|
|
1987
|
-
/* @__PURE__ */
|
|
1988
|
-
/* @__PURE__ */
|
|
2078
|
+
/* @__PURE__ */ jsxs7("div", { class: "scui-new", children: [
|
|
2079
|
+
/* @__PURE__ */ jsx8("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
2080
|
+
/* @__PURE__ */ jsx8("strong", { children: "What should the agent build or fix?" }),
|
|
2081
|
+
/* @__PURE__ */ jsx8("small", { children: "Choose a coding harness and send the first message." })
|
|
1989
2082
|
] }),
|
|
1990
|
-
/* @__PURE__ */
|
|
1991
|
-
/* @__PURE__ */
|
|
1992
|
-
/* @__PURE__ */
|
|
1993
|
-
/* @__PURE__ */
|
|
1994
|
-
/* @__PURE__ */
|
|
2083
|
+
/* @__PURE__ */ jsxs7("div", { class: "scui-compose", children: [
|
|
2084
|
+
/* @__PURE__ */ jsxs7("label", { class: "scui-harness-picker", children: [
|
|
2085
|
+
/* @__PURE__ */ jsx8(HarnessLogo, { id: harness, size: 24 }),
|
|
2086
|
+
/* @__PURE__ */ jsx8("span", { children: "Coding harness" }),
|
|
2087
|
+
/* @__PURE__ */ jsx8("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
|
|
1995
2088
|
const value = event.currentTarget.value;
|
|
1996
2089
|
setHarness(value);
|
|
1997
|
-
boundedSet(newChatMemory, memoryKey, { harness: value, draft });
|
|
1998
|
-
}, children: state.harnesses.map((item) => /* @__PURE__ */
|
|
2090
|
+
boundedSet(newChatMemory, memoryKey, { harness: value, draft, context });
|
|
2091
|
+
}, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs7("option", { value: item.id, disabled: !item.startable, children: [
|
|
1999
2092
|
item.label,
|
|
2000
2093
|
item.startable ? "" : " \xB7 unavailable"
|
|
2001
2094
|
] }, item.id)) })
|
|
2002
2095
|
] }),
|
|
2003
|
-
/* @__PURE__ */
|
|
2004
|
-
|
|
2096
|
+
/* @__PURE__ */ jsx8(ContextTray, { items: context, onRemove: (index) => setContext((items) => {
|
|
2097
|
+
const next = items.filter((_, itemIndex) => itemIndex !== index);
|
|
2098
|
+
boundedSet(newChatMemory, memoryKey, { harness, draft, context: next });
|
|
2099
|
+
return next;
|
|
2100
|
+
}) }),
|
|
2101
|
+
pickerError ? /* @__PURE__ */ jsx8("small", { class: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
2102
|
+
/* @__PURE__ */ jsxs7("div", { class: "scui-envelope", children: [
|
|
2103
|
+
adapter.pickContext ? /* @__PURE__ */ jsx8("button", { class: "scui-attach", type: "button", "aria-label": "Attach context", disabled: picking || context.length >= MAX_CONTEXT_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx8("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx8(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2104
|
+
/* @__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), onInput: (event) => {
|
|
2005
2105
|
const value = event.currentTarget.value;
|
|
2006
2106
|
setDraft(value);
|
|
2007
|
-
boundedSet(newChatMemory, memoryKey, { harness, draft: value });
|
|
2107
|
+
boundedSet(newChatMemory, memoryKey, { harness, draft: value, context });
|
|
2008
2108
|
}, onKeyDown: (event) => {
|
|
2009
2109
|
if (isSendKey(event)) {
|
|
2010
2110
|
event.preventDefault();
|
|
2011
2111
|
send();
|
|
2012
2112
|
}
|
|
2013
2113
|
} }),
|
|
2014
|
-
/* @__PURE__ */
|
|
2114
|
+
/* @__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
2115
|
] })
|
|
2016
2116
|
] })
|
|
2017
2117
|
] });
|
|
@@ -2043,40 +2143,40 @@ function SupercodeMessenger({ state: stateInput, adapter, class: className = "",
|
|
|
2043
2143
|
};
|
|
2044
2144
|
const close = () => adapter.onClose?.();
|
|
2045
2145
|
const Footer = slots.footer;
|
|
2046
|
-
return /* @__PURE__ */
|
|
2047
|
-
view === "list" ? /* @__PURE__ */
|
|
2146
|
+
return /* @__PURE__ */ jsxs7("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
|
|
2147
|
+
view === "list" ? /* @__PURE__ */ jsx8(SessionList, { state, adapter, focusKey: listFocus, onOpen: open, onNew: () => {
|
|
2048
2148
|
setListFocus("@new");
|
|
2049
2149
|
setView("new");
|
|
2050
2150
|
}, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey }) : null,
|
|
2051
|
-
view === "new" ? /* @__PURE__ */
|
|
2052
|
-
view === "chat" ? /* @__PURE__ */
|
|
2151
|
+
view === "new" ? /* @__PURE__ */ jsx8(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: () => setView("chat"), labels: copy, memoryKey }) : null,
|
|
2152
|
+
view === "chat" ? /* @__PURE__ */ jsx8(Chat, { state, adapter, onBack: () => {
|
|
2053
2153
|
setListFocus(state.attached?.key ?? listFocus);
|
|
2054
2154
|
setView("list");
|
|
2055
2155
|
}, onNew: () => {
|
|
2056
2156
|
setListFocus("@new");
|
|
2057
2157
|
setView("new");
|
|
2058
2158
|
}, onClose: adapter.onClose ? close : void 0, components, slots, labels: copy }) : null,
|
|
2059
|
-
opening ? /* @__PURE__ */
|
|
2060
|
-
/* @__PURE__ */
|
|
2061
|
-
/* @__PURE__ */
|
|
2062
|
-
/* @__PURE__ */
|
|
2159
|
+
opening ? /* @__PURE__ */ jsxs7("div", { class: "scui-opening", role: "status", "aria-busy": "true", children: [
|
|
2160
|
+
/* @__PURE__ */ jsx8(HarnessLogo, { id: opening.harness, size: 34 }),
|
|
2161
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2162
|
+
/* @__PURE__ */ jsxs7("strong", { children: [
|
|
2063
2163
|
"Opening ",
|
|
2064
2164
|
sessionDisplayName(opening)
|
|
2065
2165
|
] }),
|
|
2066
|
-
/* @__PURE__ */
|
|
2166
|
+
/* @__PURE__ */ jsx8("small", { children: "Loading the latest transcript window\u2026" })
|
|
2067
2167
|
] }),
|
|
2068
|
-
/* @__PURE__ */
|
|
2168
|
+
/* @__PURE__ */ jsx8("i", {})
|
|
2069
2169
|
] }) : null,
|
|
2070
|
-
Footer ? /* @__PURE__ */
|
|
2170
|
+
Footer ? /* @__PURE__ */ jsx8(Footer, { state, adapter, value: copy }) : null
|
|
2071
2171
|
] });
|
|
2072
2172
|
}
|
|
2073
2173
|
|
|
2074
2174
|
// src/embed.jsx
|
|
2075
|
-
import { jsx as
|
|
2175
|
+
import { jsx as jsx9 } from "preact/jsx-runtime";
|
|
2076
2176
|
function mountSupercodeMessenger(element, options) {
|
|
2077
2177
|
if (!(element instanceof Element)) throw new TypeError("mountSupercodeMessenger requires an Element");
|
|
2078
2178
|
let state = options.state;
|
|
2079
|
-
const draw = () => render(/* @__PURE__ */
|
|
2179
|
+
const draw = () => render(/* @__PURE__ */ jsx9(SupercodeMessenger, { ...options, state }), element);
|
|
2080
2180
|
options.adapter.onIntent({ action: "mounted" });
|
|
2081
2181
|
draw();
|
|
2082
2182
|
return {
|