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