@volter-ai-dev/supercode-ui 0.1.43 → 0.1.45
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 +8 -7
- package/activity.mjs +2 -1
- package/components.d.ts +1 -0
- package/components.mjs +31 -29
- package/composer.d.ts +1 -1
- package/composer.mjs +17 -5
- package/conversation.mjs +1 -0
- package/core.mjs +4 -1
- package/embed.mjs +30 -29
- package/index.d.ts +4 -2
- package/messenger.mjs +30 -29
- package/package.json +1 -1
- package/react/activity.mjs +2 -1
- package/react/components.mjs +31 -29
- package/react/composer.mjs +17 -5
- package/react/conversation.mjs +1 -0
- package/react/messenger.mjs +30 -29
- package/react/sessions.mjs +1 -0
- package/react/settings.mjs +1 -0
- package/sessions.mjs +1 -0
- package/settings.mjs +1 -0
- package/styles.css +2 -2
package/README.md
CHANGED
|
@@ -183,15 +183,16 @@ drafts, and artifact materialization remain explicit callbacks. A
|
|
|
183
183
|
browser should receive projected state from a trusted host rather than instantiate a local
|
|
184
184
|
controller or gain filesystem authority.
|
|
185
185
|
|
|
186
|
-
Native continuation
|
|
187
|
-
`terminal` to `continuationModes` and handle `onResumeTerminal`;
|
|
188
|
-
|
|
189
|
-
handoff, and never presents a terminal
|
|
186
|
+
Native continuation exposes one action and a quiet execution-transport selector. A host with a real
|
|
187
|
+
terminal provider can add `terminal` to `continuationModes` and handle `onResumeTerminal`; Terminal
|
|
188
|
+
is then the initial choice and Headless remains available from the selector. The UI never infers
|
|
189
|
+
terminal support from a generic runtime handoff, and never presents a terminal transport when the
|
|
190
|
+
host cannot create one.
|
|
190
191
|
|
|
191
192
|
New-session execution is advertised per harness. Set `launchModes: ['headless', 'terminal']` and
|
|
192
|
-
`preferredLaunchMode` on a `HarnessOption`; the complete messenger renders
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
`preferredLaunchMode` on a `HarnessOption`; the complete messenger renders the same compact Terminal
|
|
194
|
+
versus Headless selector in the composer footer and emits that `mode` on the `new` intent. Direct
|
|
195
|
+
controller bindings delegate Terminal only through `onStartTerminal`, so a terminal selection can
|
|
195
196
|
never accidentally create a second headless runtime. Hosts may remember the preference per harness;
|
|
196
197
|
the messenger also retains the current browser draft choice while its New Chat view is open.
|
|
197
198
|
|
package/activity.mjs
CHANGED
|
@@ -13,6 +13,7 @@ var DEFAULT_LABELS = Object.freeze({
|
|
|
13
13
|
newChat: "New chat",
|
|
14
14
|
searchChats: "Search chats",
|
|
15
15
|
askAgent: "Ask your agent\u2026",
|
|
16
|
+
attachContext: "Attach files or images",
|
|
16
17
|
continueHere: "Continue here",
|
|
17
18
|
continueWithTerminal: "Continue with terminal",
|
|
18
19
|
joinLive: "Join live",
|
|
@@ -737,7 +738,7 @@ function normalizeUiState(value) {
|
|
|
737
738
|
if (!item || typeof item.id !== "string") return [];
|
|
738
739
|
const startable = item.startable === true;
|
|
739
740
|
const launchModes = Array.isArray(item.launchModes) ? [...new Set(item.launchModes.filter((mode) => mode === "headless" || mode === "terminal"))] : startable ? ["headless"] : [];
|
|
740
|
-
const preferredLaunchMode = launchModes.includes(item.preferredLaunchMode) ? item.preferredLaunchMode : launchModes[0] ?? null;
|
|
741
|
+
const preferredLaunchMode = launchModes.includes(item.preferredLaunchMode) ? item.preferredLaunchMode : launchModes.includes("terminal") ? "terminal" : launchModes[0] ?? null;
|
|
741
742
|
const capabilities = record(item.capabilities);
|
|
742
743
|
return [{
|
|
743
744
|
id: item.id,
|
package/components.d.ts
CHANGED
package/components.mjs
CHANGED
|
@@ -16,6 +16,7 @@ var DEFAULT_LABELS = Object.freeze({
|
|
|
16
16
|
newChat: "New chat",
|
|
17
17
|
searchChats: "Search chats",
|
|
18
18
|
askAgent: "Ask your agent\u2026",
|
|
19
|
+
attachContext: "Attach files or images",
|
|
19
20
|
continueHere: "Continue here",
|
|
20
21
|
continueWithTerminal: "Continue with terminal",
|
|
21
22
|
joinLive: "Join live",
|
|
@@ -749,7 +750,7 @@ function normalizeUiState(value) {
|
|
|
749
750
|
if (!item || typeof item.id !== "string") return [];
|
|
750
751
|
const startable = item.startable === true;
|
|
751
752
|
const launchModes = Array.isArray(item.launchModes) ? [...new Set(item.launchModes.filter((mode) => mode === "headless" || mode === "terminal"))] : startable ? ["headless"] : [];
|
|
752
|
-
const preferredLaunchMode = launchModes.includes(item.preferredLaunchMode) ? item.preferredLaunchMode : launchModes[0] ?? null;
|
|
753
|
+
const preferredLaunchMode = launchModes.includes(item.preferredLaunchMode) ? item.preferredLaunchMode : launchModes.includes("terminal") ? "terminal" : launchModes[0] ?? null;
|
|
753
754
|
const capabilities = record(item.capabilities);
|
|
754
755
|
return [{
|
|
755
756
|
id: item.id,
|
|
@@ -1293,13 +1294,23 @@ function useAutosizeTextarea(ref, value) {
|
|
|
1293
1294
|
// src/composer.jsx
|
|
1294
1295
|
import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
1295
1296
|
var composerMemory = /* @__PURE__ */ new Map();
|
|
1297
|
+
function ExecutionModeSelect({ modes = [], value, onChange, disabled = false, label = "Run in" }) {
|
|
1298
|
+
if (modes.length < 2) return null;
|
|
1299
|
+
return /* @__PURE__ */ jsxs3("label", { className: "scui-execution-mode", title: disabled ? void 0 : `${label}: ${value}`, children: [
|
|
1300
|
+
/* @__PURE__ */ jsx3("span", { children: label }),
|
|
1301
|
+
/* @__PURE__ */ jsx3("select", { "aria-label": label, value, disabled, onChange: (event) => onChange?.(event.currentTarget.value), children: modes.map((mode) => /* @__PURE__ */ jsx3("option", { value: mode, children: mode === "terminal" ? "Terminal" : "Headless" }, mode)) })
|
|
1302
|
+
] });
|
|
1303
|
+
}
|
|
1296
1304
|
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
1305
|
+
const continuationModes = state.continuationModes?.length ? state.continuationModes : ["headless"];
|
|
1306
|
+
const [selection, setSelection] = useState2({ key: null, mode: null });
|
|
1307
|
+
const requestedMode = selection.key === state.attached?.key ? selection.mode : null;
|
|
1308
|
+
const executionMode = continuationModes.includes(requestedMode) ? requestedMode : continuationModes.includes("terminal") ? "terminal" : continuationModes[0];
|
|
1297
1309
|
if (state.mode !== "mirror" || state.canSend) return null;
|
|
1298
1310
|
const attached = state.attached;
|
|
1299
1311
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
1300
1312
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
1301
1313
|
const resume = canContinueHere(state);
|
|
1302
|
-
const terminal = resume && state.continuationModes?.includes("terminal");
|
|
1303
1314
|
const join = state.canAttach;
|
|
1304
1315
|
const branch = state.canBranch;
|
|
1305
1316
|
if (!resume && !join && !branch) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
@@ -1312,8 +1323,8 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
1312
1323
|
/* @__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." })
|
|
1313
1324
|
] }),
|
|
1314
1325
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
1315
|
-
/* @__PURE__ */ jsx3(
|
|
1316
|
-
|
|
1326
|
+
!join && resume ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation), onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
1327
|
+
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
1317
1328
|
] })
|
|
1318
1329
|
] });
|
|
1319
1330
|
}
|
|
@@ -1513,7 +1524,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
1513
1524
|
}, onDragLeave: (event) => {
|
|
1514
1525
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
1515
1526
|
}, onDrop: dropImages, children: [
|
|
1516
|
-
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { className: "scui-attach", type: "button", "aria-label":
|
|
1527
|
+
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, disabled: picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS, onClick: pickContext, children: picking ? /* @__PURE__ */ jsx3("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx3(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
1517
1528
|
/* @__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" : steerAvailable && context.length === 0 && images.length === 0 ? "Redirect the current turn\u2026" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onPaste: pasteImages, onInput: (event) => {
|
|
1518
1529
|
const value = event.currentTarget.value;
|
|
1519
1530
|
setDraft(value);
|
|
@@ -2869,7 +2880,8 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2869
2880
|
const Readiness = components.HarnessReadiness ?? HarnessReadiness;
|
|
2870
2881
|
const launchModes = selectedHarness?.launchModes?.length ? selectedHarness.launchModes : ["headless"];
|
|
2871
2882
|
const rememberedMode = modes[harness];
|
|
2872
|
-
const
|
|
2883
|
+
const requestedMode = launchModes.includes(rememberedMode) ? rememberedMode : launchModes.includes(selectedHarness?.preferredLaunchMode) ? selectedHarness.preferredLaunchMode : launchModes[0];
|
|
2884
|
+
const mode = (context.length > 0 || images.length > 0) && launchModes.includes("headless") ? "headless" : requestedMode;
|
|
2873
2885
|
const terminalAttachments = mode === "terminal" && (context.length > 0 || images.length > 0);
|
|
2874
2886
|
const remember = (overrides = {}) => boundedSet(newChatMemory, memoryKey, { harness, draft, context, images, modes, ...overrides });
|
|
2875
2887
|
useAutosizeTextarea(textarea, draft);
|
|
@@ -2911,7 +2923,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2911
2923
|
lastComposerCommand.current = composerCommand.id;
|
|
2912
2924
|
if (composerCommand.action === "attach") {
|
|
2913
2925
|
if (mode === "terminal" && !launchModes.includes("headless")) {
|
|
2914
|
-
setPickerError("Terminal starts currently accept text only. Choose
|
|
2926
|
+
setPickerError("Terminal starts currently accept text only. Choose Headless to attach context or images.");
|
|
2915
2927
|
} else {
|
|
2916
2928
|
try {
|
|
2917
2929
|
const attachments = partitionAttachments(composerCommand.attachments);
|
|
@@ -2919,12 +2931,10 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2919
2931
|
if (images.length + attachments.images.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
|
|
2920
2932
|
const nextContext = mergeContext(context, attachments.context);
|
|
2921
2933
|
const nextImages = mergeImages(images, attachments.images);
|
|
2922
|
-
const nextModes = mode === "terminal" ? { ...modes, [harness]: "headless" } : modes;
|
|
2923
|
-
if (nextModes !== modes) setModes(nextModes);
|
|
2924
2934
|
setContext(nextContext);
|
|
2925
2935
|
setImages(nextImages);
|
|
2926
2936
|
setPickerError(null);
|
|
2927
|
-
remember({ context: nextContext, images: nextImages
|
|
2937
|
+
remember({ context: nextContext, images: nextImages });
|
|
2928
2938
|
} catch (error) {
|
|
2929
2939
|
setPickerError(error instanceof Error ? error.message : "Could not attach context.");
|
|
2930
2940
|
}
|
|
@@ -2965,7 +2975,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2965
2975
|
const allFiles = Array.from(value ?? []);
|
|
2966
2976
|
if (!allFiles.length) return false;
|
|
2967
2977
|
if (mode === "terminal") {
|
|
2968
|
-
setPickerError("Terminal starts currently accept text only. Choose
|
|
2978
|
+
setPickerError("Terminal starts currently accept text only. Choose Headless to attach context or images.");
|
|
2969
2979
|
return true;
|
|
2970
2980
|
}
|
|
2971
2981
|
const files = allFiles.filter((file) => file.type.startsWith("image/"));
|
|
@@ -3030,21 +3040,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
3030
3040
|
] }),
|
|
3031
3041
|
/* @__PURE__ */ jsxs9("div", { className: "scui-compose", children: [
|
|
3032
3042
|
/* @__PURE__ */ jsx10(Readiness, { harnesses: state.harnesses, state, adapter }),
|
|
3033
|
-
launchModes.length > 1 ? /* @__PURE__ */ jsxs9("fieldset", { className: "scui-launch-modes", disabled: Boolean(starting), children: [
|
|
3034
|
-
/* @__PURE__ */ jsx10("legend", { children: "Run as" }),
|
|
3035
|
-
launchModes.map((item) => /* @__PURE__ */ jsxs9("label", { children: [
|
|
3036
|
-
/* @__PURE__ */ jsx10("input", { type: "radio", name: `launch-mode-${memoryKey}`, value: item, checked: mode === item, onChange: () => {
|
|
3037
|
-
const next = { ...modes, [harness]: item };
|
|
3038
|
-
setModes(next);
|
|
3039
|
-
setPickerError(null);
|
|
3040
|
-
remember({ modes: next });
|
|
3041
|
-
} }),
|
|
3042
|
-
/* @__PURE__ */ jsxs9("span", { children: [
|
|
3043
|
-
/* @__PURE__ */ jsx10("strong", { children: item === "terminal" ? "Terminal" : "Chat" }),
|
|
3044
|
-
/* @__PURE__ */ jsx10("small", { children: item === "terminal" ? "Interactive tmux session" : "Managed here" })
|
|
3045
|
-
] })
|
|
3046
|
-
] }, item))
|
|
3047
|
-
] }) : null,
|
|
3048
3043
|
mode !== "terminal" ? /* @__PURE__ */ jsx10(ContextCandidates, { items: contextCandidates, context, images, state, adapter, onAttach: attachCandidate, component: components.ContextCandidate }) : null,
|
|
3049
3044
|
/* @__PURE__ */ jsx10(ImageTray, { items: images, onRemove: (index) => setImages((items) => {
|
|
3050
3045
|
const next = items.filter((_, itemIndex) => itemIndex !== index);
|
|
@@ -3056,7 +3051,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
3056
3051
|
remember({ context: next });
|
|
3057
3052
|
return next;
|
|
3058
3053
|
}) }),
|
|
3059
|
-
terminalAttachments ? /* @__PURE__ */ jsx10("small", { className: "scui-context-error", role: "alert", children: "Terminal starts currently accept text only. Remove attachments or choose
|
|
3054
|
+
terminalAttachments ? /* @__PURE__ */ jsx10("small", { className: "scui-context-error", role: "alert", children: "Terminal starts currently accept text only. Remove attachments or choose Headless." }) : pickerError ? /* @__PURE__ */ jsx10("small", { className: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
3060
3055
|
/* @__PURE__ */ jsxs9("div", { className: `scui-envelope scui-new-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
3061
3056
|
if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
|
|
3062
3057
|
event.preventDefault();
|
|
@@ -3078,12 +3073,18 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
3078
3073
|
}
|
|
3079
3074
|
} }),
|
|
3080
3075
|
/* @__PURE__ */ jsxs9("footer", { className: "scui-new-envelope-controls", children: [
|
|
3081
|
-
adapter.pickContext ? /* @__PURE__ */ jsx10("button", { className: "scui-attach", type: "button", "aria-label":
|
|
3076
|
+
adapter.pickContext ? /* @__PURE__ */ jsx10("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx10("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx10(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
3082
3077
|
/* @__PURE__ */ jsx10(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3083
3078
|
setHarness(value);
|
|
3084
3079
|
remember({ harness: value });
|
|
3085
3080
|
} }),
|
|
3086
|
-
/* @__PURE__ */ jsx10(
|
|
3081
|
+
/* @__PURE__ */ jsx10(ExecutionModeSelect, { modes: launchModes, value: mode, disabled: Boolean(starting) || mode !== requestedMode, onChange: (item) => {
|
|
3082
|
+
const next = { ...modes, [harness]: item };
|
|
3083
|
+
setModes(next);
|
|
3084
|
+
setPickerError(null);
|
|
3085
|
+
remember({ modes: next });
|
|
3086
|
+
} }),
|
|
3087
|
+
/* @__PURE__ */ jsx10("span", { children: /* @__PURE__ */ jsx10("button", { type: "button", className: "scui-send", "aria-label": mode === "terminal" ? "Start terminal session" : "Start headless session", disabled: !draft.trim() && !images.length || !harness || Boolean(starting) || terminalAttachments || mode === "terminal" && !draft.trim(), onClick: send, children: starting ? /* @__PURE__ */ jsx10("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx10(UiIcon, { name: "send", size: 17 }) }) })
|
|
3087
3088
|
] })
|
|
3088
3089
|
] })
|
|
3089
3090
|
] })
|
|
@@ -3192,6 +3193,7 @@ export {
|
|
|
3192
3193
|
ContextCandidates,
|
|
3193
3194
|
ContinuationBar,
|
|
3194
3195
|
Conversation,
|
|
3196
|
+
ExecutionModeSelect,
|
|
3195
3197
|
HarnessAdvisory,
|
|
3196
3198
|
HarnessLogo,
|
|
3197
3199
|
HarnessPicker,
|
package/composer.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export type { MessengerLabels, PendingMessageModel, SupercodeUiState, UiAdapter } from './index.js';
|
|
2
|
-
export { Composer, ContinuationBar } from './index.js';
|
|
2
|
+
export { Composer, ContinuationBar, ExecutionModeSelect } from './index.js';
|
package/composer.mjs
CHANGED
|
@@ -16,6 +16,7 @@ var DEFAULT_LABELS = Object.freeze({
|
|
|
16
16
|
newChat: "New chat",
|
|
17
17
|
searchChats: "Search chats",
|
|
18
18
|
askAgent: "Ask your agent\u2026",
|
|
19
|
+
attachContext: "Attach files or images",
|
|
19
20
|
continueHere: "Continue here",
|
|
20
21
|
continueWithTerminal: "Continue with terminal",
|
|
21
22
|
joinLive: "Join live",
|
|
@@ -294,13 +295,23 @@ function useAutosizeTextarea(ref, value) {
|
|
|
294
295
|
// src/composer.jsx
|
|
295
296
|
import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
296
297
|
var composerMemory = /* @__PURE__ */ new Map();
|
|
298
|
+
function ExecutionModeSelect({ modes = [], value, onChange, disabled = false, label = "Run in" }) {
|
|
299
|
+
if (modes.length < 2) return null;
|
|
300
|
+
return /* @__PURE__ */ jsxs3("label", { className: "scui-execution-mode", title: disabled ? void 0 : `${label}: ${value}`, children: [
|
|
301
|
+
/* @__PURE__ */ jsx3("span", { children: label }),
|
|
302
|
+
/* @__PURE__ */ jsx3("select", { "aria-label": label, value, disabled, onChange: (event) => onChange?.(event.currentTarget.value), children: modes.map((mode) => /* @__PURE__ */ jsx3("option", { value: mode, children: mode === "terminal" ? "Terminal" : "Headless" }, mode)) })
|
|
303
|
+
] });
|
|
304
|
+
}
|
|
297
305
|
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
306
|
+
const continuationModes = state.continuationModes?.length ? state.continuationModes : ["headless"];
|
|
307
|
+
const [selection, setSelection] = useState2({ key: null, mode: null });
|
|
308
|
+
const requestedMode = selection.key === state.attached?.key ? selection.mode : null;
|
|
309
|
+
const executionMode = continuationModes.includes(requestedMode) ? requestedMode : continuationModes.includes("terminal") ? "terminal" : continuationModes[0];
|
|
298
310
|
if (state.mode !== "mirror" || state.canSend) return null;
|
|
299
311
|
const attached = state.attached;
|
|
300
312
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
301
313
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
302
314
|
const resume = canContinueHere(state);
|
|
303
|
-
const terminal = resume && state.continuationModes?.includes("terminal");
|
|
304
315
|
const join = state.canAttach;
|
|
305
316
|
const branch = state.canBranch;
|
|
306
317
|
if (!resume && !join && !branch) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
@@ -313,8 +324,8 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
313
324
|
/* @__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." })
|
|
314
325
|
] }),
|
|
315
326
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
316
|
-
/* @__PURE__ */ jsx3(
|
|
317
|
-
|
|
327
|
+
!join && resume ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation), onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
328
|
+
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
318
329
|
] })
|
|
319
330
|
] });
|
|
320
331
|
}
|
|
@@ -514,7 +525,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
514
525
|
}, onDragLeave: (event) => {
|
|
515
526
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
516
527
|
}, onDrop: dropImages, children: [
|
|
517
|
-
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { className: "scui-attach", type: "button", "aria-label":
|
|
528
|
+
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, disabled: picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS, onClick: pickContext, children: picking ? /* @__PURE__ */ jsx3("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx3(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
518
529
|
/* @__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" : steerAvailable && context.length === 0 && images.length === 0 ? "Redirect the current turn\u2026" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onPaste: pasteImages, onInput: (event) => {
|
|
519
530
|
const value = event.currentTarget.value;
|
|
520
531
|
setDraft(value);
|
|
@@ -535,5 +546,6 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
535
546
|
}
|
|
536
547
|
export {
|
|
537
548
|
Composer,
|
|
538
|
-
ContinuationBar
|
|
549
|
+
ContinuationBar,
|
|
550
|
+
ExecutionModeSelect
|
|
539
551
|
};
|
package/conversation.mjs
CHANGED
|
@@ -17,6 +17,7 @@ var DEFAULT_LABELS = Object.freeze({
|
|
|
17
17
|
newChat: "New chat",
|
|
18
18
|
searchChats: "Search chats",
|
|
19
19
|
askAgent: "Ask your agent\u2026",
|
|
20
|
+
attachContext: "Attach files or images",
|
|
20
21
|
continueHere: "Continue here",
|
|
21
22
|
continueWithTerminal: "Continue with terminal",
|
|
22
23
|
joinLive: "Join live",
|
package/core.mjs
CHANGED
|
@@ -13,6 +13,7 @@ export const DEFAULT_LABELS = Object.freeze({
|
|
|
13
13
|
newChat: 'New chat',
|
|
14
14
|
searchChats: 'Search chats',
|
|
15
15
|
askAgent: 'Ask your agent…',
|
|
16
|
+
attachContext: 'Attach files or images',
|
|
16
17
|
continueHere: 'Continue here',
|
|
17
18
|
continueWithTerminal: 'Continue with terminal',
|
|
18
19
|
joinLive: 'Join live',
|
|
@@ -805,7 +806,9 @@ export function normalizeUiState(value) {
|
|
|
805
806
|
: startable ? ['headless'] : [];
|
|
806
807
|
const preferredLaunchMode = launchModes.includes(item.preferredLaunchMode)
|
|
807
808
|
? item.preferredLaunchMode
|
|
808
|
-
: launchModes
|
|
809
|
+
: launchModes.includes('terminal')
|
|
810
|
+
? 'terminal'
|
|
811
|
+
: launchModes[0] ?? null;
|
|
809
812
|
const capabilities = record(item.capabilities);
|
|
810
813
|
return [{
|
|
811
814
|
id: item.id,
|
package/embed.mjs
CHANGED
|
@@ -19,6 +19,7 @@ var DEFAULT_LABELS = Object.freeze({
|
|
|
19
19
|
newChat: "New chat",
|
|
20
20
|
searchChats: "Search chats",
|
|
21
21
|
askAgent: "Ask your agent\u2026",
|
|
22
|
+
attachContext: "Attach files or images",
|
|
22
23
|
continueHere: "Continue here",
|
|
23
24
|
continueWithTerminal: "Continue with terminal",
|
|
24
25
|
joinLive: "Join live",
|
|
@@ -752,7 +753,7 @@ function normalizeUiState(value) {
|
|
|
752
753
|
if (!item || typeof item.id !== "string") return [];
|
|
753
754
|
const startable = item.startable === true;
|
|
754
755
|
const launchModes = Array.isArray(item.launchModes) ? [...new Set(item.launchModes.filter((mode) => mode === "headless" || mode === "terminal"))] : startable ? ["headless"] : [];
|
|
755
|
-
const preferredLaunchMode = launchModes.includes(item.preferredLaunchMode) ? item.preferredLaunchMode : launchModes[0] ?? null;
|
|
756
|
+
const preferredLaunchMode = launchModes.includes(item.preferredLaunchMode) ? item.preferredLaunchMode : launchModes.includes("terminal") ? "terminal" : launchModes[0] ?? null;
|
|
756
757
|
const capabilities = record(item.capabilities);
|
|
757
758
|
return [{
|
|
758
759
|
id: item.id,
|
|
@@ -1259,13 +1260,23 @@ function useAutosizeTextarea(ref, value) {
|
|
|
1259
1260
|
// src/composer.jsx
|
|
1260
1261
|
import { jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
1261
1262
|
var composerMemory = /* @__PURE__ */ new Map();
|
|
1263
|
+
function ExecutionModeSelect({ modes = [], value, onChange, disabled = false, label = "Run in" }) {
|
|
1264
|
+
if (modes.length < 2) return null;
|
|
1265
|
+
return /* @__PURE__ */ jsxs3("label", { className: "scui-execution-mode", title: disabled ? void 0 : `${label}: ${value}`, children: [
|
|
1266
|
+
/* @__PURE__ */ jsx3("span", { children: label }),
|
|
1267
|
+
/* @__PURE__ */ jsx3("select", { "aria-label": label, value, disabled, onChange: (event) => onChange?.(event.currentTarget.value), children: modes.map((mode) => /* @__PURE__ */ jsx3("option", { value: mode, children: mode === "terminal" ? "Terminal" : "Headless" }, mode)) })
|
|
1268
|
+
] });
|
|
1269
|
+
}
|
|
1262
1270
|
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
1271
|
+
const continuationModes = state.continuationModes?.length ? state.continuationModes : ["headless"];
|
|
1272
|
+
const [selection, setSelection] = useState2({ key: null, mode: null });
|
|
1273
|
+
const requestedMode = selection.key === state.attached?.key ? selection.mode : null;
|
|
1274
|
+
const executionMode = continuationModes.includes(requestedMode) ? requestedMode : continuationModes.includes("terminal") ? "terminal" : continuationModes[0];
|
|
1263
1275
|
if (state.mode !== "mirror" || state.canSend) return null;
|
|
1264
1276
|
const attached = state.attached;
|
|
1265
1277
|
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
1266
1278
|
const activeElsewhere = row?.runtimeStatus === "running" || row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
1267
1279
|
const resume = canContinueHere(state);
|
|
1268
|
-
const terminal = resume && state.continuationModes?.includes("terminal");
|
|
1269
1280
|
const join = state.canAttach;
|
|
1270
1281
|
const branch = state.canBranch;
|
|
1271
1282
|
if (!resume && !join && !branch) return /* @__PURE__ */ jsx3("div", { className: "scui-continuation", children: /* @__PURE__ */ jsxs3("span", { children: [
|
|
@@ -1278,8 +1289,8 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
1278
1289
|
/* @__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." })
|
|
1279
1290
|
] }),
|
|
1280
1291
|
/* @__PURE__ */ jsxs3("span", { className: "scui-continuation-actions", children: [
|
|
1281
|
-
/* @__PURE__ */ jsx3(
|
|
1282
|
-
|
|
1292
|
+
!join && resume ? /* @__PURE__ */ jsx3(ExecutionModeSelect, { modes: continuationModes, value: executionMode, disabled: Boolean(state.operation), onChange: (mode) => setSelection({ key: state.attached?.key ?? null, mode }) }) : null,
|
|
1293
|
+
/* @__PURE__ */ jsx3("button", { type: "button", disabled: Boolean(state.operation), onClick: () => dispatchConfirmedIntent(adapter, join ? { action: "join" } : resume ? { action: "resume", mode: executionMode } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
1283
1294
|
] })
|
|
1284
1295
|
] });
|
|
1285
1296
|
}
|
|
@@ -1479,7 +1490,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
1479
1490
|
}, onDragLeave: (event) => {
|
|
1480
1491
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
1481
1492
|
}, onDrop: dropImages, children: [
|
|
1482
|
-
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { className: "scui-attach", type: "button", "aria-label":
|
|
1493
|
+
adapter.pickContext && state.mode === "control" ? /* @__PURE__ */ jsx3("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, disabled: picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS, onClick: pickContext, children: picking ? /* @__PURE__ */ jsx3("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx3(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
1483
1494
|
/* @__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" : steerAvailable && context.length === 0 && images.length === 0 ? "Redirect the current turn\u2026" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onPaste: pasteImages, onInput: (event) => {
|
|
1484
1495
|
const value = event.currentTarget.value;
|
|
1485
1496
|
setDraft(value);
|
|
@@ -2789,7 +2800,8 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2789
2800
|
const Readiness = components.HarnessReadiness ?? HarnessReadiness;
|
|
2790
2801
|
const launchModes = selectedHarness?.launchModes?.length ? selectedHarness.launchModes : ["headless"];
|
|
2791
2802
|
const rememberedMode = modes[harness];
|
|
2792
|
-
const
|
|
2803
|
+
const requestedMode = launchModes.includes(rememberedMode) ? rememberedMode : launchModes.includes(selectedHarness?.preferredLaunchMode) ? selectedHarness.preferredLaunchMode : launchModes[0];
|
|
2804
|
+
const mode = (context.length > 0 || images.length > 0) && launchModes.includes("headless") ? "headless" : requestedMode;
|
|
2793
2805
|
const terminalAttachments = mode === "terminal" && (context.length > 0 || images.length > 0);
|
|
2794
2806
|
const remember = (overrides = {}) => boundedSet(newChatMemory, memoryKey, { harness, draft, context, images, modes, ...overrides });
|
|
2795
2807
|
useAutosizeTextarea(textarea, draft);
|
|
@@ -2831,7 +2843,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2831
2843
|
lastComposerCommand.current = composerCommand.id;
|
|
2832
2844
|
if (composerCommand.action === "attach") {
|
|
2833
2845
|
if (mode === "terminal" && !launchModes.includes("headless")) {
|
|
2834
|
-
setPickerError("Terminal starts currently accept text only. Choose
|
|
2846
|
+
setPickerError("Terminal starts currently accept text only. Choose Headless to attach context or images.");
|
|
2835
2847
|
} else {
|
|
2836
2848
|
try {
|
|
2837
2849
|
const attachments = partitionAttachments(composerCommand.attachments);
|
|
@@ -2839,12 +2851,10 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2839
2851
|
if (images.length + attachments.images.length > MAX_IMAGE_ITEMS) throw new Error(`Attach at most ${MAX_IMAGE_ITEMS} images.`);
|
|
2840
2852
|
const nextContext = mergeContext(context, attachments.context);
|
|
2841
2853
|
const nextImages = mergeImages(images, attachments.images);
|
|
2842
|
-
const nextModes = mode === "terminal" ? { ...modes, [harness]: "headless" } : modes;
|
|
2843
|
-
if (nextModes !== modes) setModes(nextModes);
|
|
2844
2854
|
setContext(nextContext);
|
|
2845
2855
|
setImages(nextImages);
|
|
2846
2856
|
setPickerError(null);
|
|
2847
|
-
remember({ context: nextContext, images: nextImages
|
|
2857
|
+
remember({ context: nextContext, images: nextImages });
|
|
2848
2858
|
} catch (error) {
|
|
2849
2859
|
setPickerError(error instanceof Error ? error.message : "Could not attach context.");
|
|
2850
2860
|
}
|
|
@@ -2885,7 +2895,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2885
2895
|
const allFiles = Array.from(value ?? []);
|
|
2886
2896
|
if (!allFiles.length) return false;
|
|
2887
2897
|
if (mode === "terminal") {
|
|
2888
|
-
setPickerError("Terminal starts currently accept text only. Choose
|
|
2898
|
+
setPickerError("Terminal starts currently accept text only. Choose Headless to attach context or images.");
|
|
2889
2899
|
return true;
|
|
2890
2900
|
}
|
|
2891
2901
|
const files = allFiles.filter((file) => file.type.startsWith("image/"));
|
|
@@ -2950,21 +2960,6 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2950
2960
|
] }),
|
|
2951
2961
|
/* @__PURE__ */ jsxs8("div", { className: "scui-compose", children: [
|
|
2952
2962
|
/* @__PURE__ */ jsx9(Readiness, { harnesses: state.harnesses, state, adapter }),
|
|
2953
|
-
launchModes.length > 1 ? /* @__PURE__ */ jsxs8("fieldset", { className: "scui-launch-modes", disabled: Boolean(starting), children: [
|
|
2954
|
-
/* @__PURE__ */ jsx9("legend", { children: "Run as" }),
|
|
2955
|
-
launchModes.map((item) => /* @__PURE__ */ jsxs8("label", { children: [
|
|
2956
|
-
/* @__PURE__ */ jsx9("input", { type: "radio", name: `launch-mode-${memoryKey}`, value: item, checked: mode === item, onChange: () => {
|
|
2957
|
-
const next = { ...modes, [harness]: item };
|
|
2958
|
-
setModes(next);
|
|
2959
|
-
setPickerError(null);
|
|
2960
|
-
remember({ modes: next });
|
|
2961
|
-
} }),
|
|
2962
|
-
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2963
|
-
/* @__PURE__ */ jsx9("strong", { children: item === "terminal" ? "Terminal" : "Chat" }),
|
|
2964
|
-
/* @__PURE__ */ jsx9("small", { children: item === "terminal" ? "Interactive tmux session" : "Managed here" })
|
|
2965
|
-
] })
|
|
2966
|
-
] }, item))
|
|
2967
|
-
] }) : null,
|
|
2968
2963
|
mode !== "terminal" ? /* @__PURE__ */ jsx9(ContextCandidates, { items: contextCandidates, context, images, state, adapter, onAttach: attachCandidate, component: components.ContextCandidate }) : null,
|
|
2969
2964
|
/* @__PURE__ */ jsx9(ImageTray, { items: images, onRemove: (index) => setImages((items) => {
|
|
2970
2965
|
const next = items.filter((_, itemIndex) => itemIndex !== index);
|
|
@@ -2976,7 +2971,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2976
2971
|
remember({ context: next });
|
|
2977
2972
|
return next;
|
|
2978
2973
|
}) }),
|
|
2979
|
-
terminalAttachments ? /* @__PURE__ */ jsx9("small", { className: "scui-context-error", role: "alert", children: "Terminal starts currently accept text only. Remove attachments or choose
|
|
2974
|
+
terminalAttachments ? /* @__PURE__ */ jsx9("small", { className: "scui-context-error", role: "alert", children: "Terminal starts currently accept text only. Remove attachments or choose Headless." }) : pickerError ? /* @__PURE__ */ jsx9("small", { className: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
2980
2975
|
/* @__PURE__ */ jsxs8("div", { className: `scui-envelope scui-new-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2981
2976
|
if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
|
|
2982
2977
|
event.preventDefault();
|
|
@@ -2998,12 +2993,18 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2998
2993
|
}
|
|
2999
2994
|
} }),
|
|
3000
2995
|
/* @__PURE__ */ jsxs8("footer", { className: "scui-new-envelope-controls", children: [
|
|
3001
|
-
adapter.pickContext ? /* @__PURE__ */ jsx9("button", { className: "scui-attach", type: "button", "aria-label":
|
|
2996
|
+
adapter.pickContext ? /* @__PURE__ */ jsx9("button", { className: "scui-attach", type: "button", "aria-label": labels.attachContext ?? DEFAULT_LABELS.attachContext, disabled: mode === "terminal" || picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
3002
2997
|
/* @__PURE__ */ jsx9(Picker, { harnesses: state.harnesses, value: harness, disabled: Boolean(starting), adapter, logo: components.HarnessLogo, onChange: (value) => {
|
|
3003
2998
|
setHarness(value);
|
|
3004
2999
|
remember({ harness: value });
|
|
3005
3000
|
} }),
|
|
3006
|
-
/* @__PURE__ */ jsx9(
|
|
3001
|
+
/* @__PURE__ */ jsx9(ExecutionModeSelect, { modes: launchModes, value: mode, disabled: Boolean(starting) || mode !== requestedMode, onChange: (item) => {
|
|
3002
|
+
const next = { ...modes, [harness]: item };
|
|
3003
|
+
setModes(next);
|
|
3004
|
+
setPickerError(null);
|
|
3005
|
+
remember({ modes: next });
|
|
3006
|
+
} }),
|
|
3007
|
+
/* @__PURE__ */ jsx9("span", { children: /* @__PURE__ */ jsx9("button", { type: "button", className: "scui-send", "aria-label": mode === "terminal" ? "Start terminal session" : "Start headless session", disabled: !draft.trim() && !images.length || !harness || Boolean(starting) || terminalAttachments || mode === "terminal" && !draft.trim(), onClick: send, children: starting ? /* @__PURE__ */ jsx9("i", { className: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "send", size: 17 }) }) })
|
|
3007
3008
|
] })
|
|
3008
3009
|
] })
|
|
3009
3010
|
] })
|
package/index.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export interface HarnessOption {
|
|
|
40
40
|
};
|
|
41
41
|
/** Host-supported ways to start this harness. Omitted means headless when startable. */
|
|
42
42
|
launchModes?: ExecutionMode[];
|
|
43
|
-
/** Host preference, used unless this browser has a remembered choice
|
|
43
|
+
/** Host preference, used unless this browser has a remembered choice. Defaults to terminal when advertised. */
|
|
44
44
|
preferredLaunchMode?: ExecutionMode | null;
|
|
45
45
|
}
|
|
46
46
|
|
|
@@ -264,7 +264,7 @@ export interface SupercodeUiState {
|
|
|
264
264
|
canSend: boolean;
|
|
265
265
|
canSteer: boolean;
|
|
266
266
|
canResume: boolean;
|
|
267
|
-
/** Execution
|
|
267
|
+
/** Execution transports the current host can actually provide. */
|
|
268
268
|
continuationModes: ContinuationMode[];
|
|
269
269
|
canBranch: boolean;
|
|
270
270
|
canAttach: boolean;
|
|
@@ -350,6 +350,7 @@ export interface MessengerLabels {
|
|
|
350
350
|
newChat: string;
|
|
351
351
|
searchChats: string;
|
|
352
352
|
askAgent: string;
|
|
353
|
+
attachContext?: string;
|
|
353
354
|
continueHere: string;
|
|
354
355
|
continueWithTerminal?: string;
|
|
355
356
|
joinLive: string;
|
|
@@ -556,6 +557,7 @@ export function Conversation(props: { state: SupercodeUiState; adapter: UiAdapte
|
|
|
556
557
|
export function SessionRow(props: { row: SessionRowModel; state: SupercodeUiState; adapter: UiAdapter; now?: number; onOpen(row: SessionRowModel): void }): VNode;
|
|
557
558
|
export function SessionList(props: { state: SupercodeUiState; adapter: UiAdapter; onOpen(row: SessionRowModel): void; onNew?(): void; onClose?(): void; components?: MessengerComponents; slots?: MessengerSlots; labels?: MessengerLabels; focusKey?: string | null; memoryKey?: string; headerActions?: MessengerSlots['headerActions'] }): VNode;
|
|
558
559
|
export function ContinuationBar(props: { state: SupercodeUiState; adapter: UiAdapter; labels?: MessengerLabels }): VNode | null;
|
|
560
|
+
export function ExecutionModeSelect(props: { modes?: ExecutionMode[]; value: ExecutionMode; onChange?(mode: ExecutionMode): void; disabled?: boolean; label?: string }): VNode | null;
|
|
559
561
|
export function Composer(props: { state: SupercodeUiState; adapter: UiAdapter; labels?: MessengerLabels; memoryKey?: string; pendingStatus?: PendingMessageModel['status'] | 'editing' | null; restoreDraft?: { id: string | number; text: string; context?: TranscriptContext[]; images?: TranscriptImage[] } | null; command?: MessengerComposerCommand | null; contextCandidates?: TranscriptAttachment[]; components?: Pick<MessengerComponents, 'ContextCandidate'>; onPending?(text: string, context?: TranscriptContext[], images?: TranscriptImage[]): void; onDraftRestored?(id: string | number): void }): VNode;
|
|
560
562
|
export function SupercodeMessenger(props: MessengerProps): VNode;
|
|
561
563
|
|