@volter-ai-dev/supercode-ui 0.1.33 → 0.1.35
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 +2 -0
- package/components.mjs +13 -8
- package/composer.mjs +1 -1
- package/core.mjs +1 -1
- package/embed.mjs +13 -8
- package/index.d.ts +3 -1
- package/messenger.mjs +13 -8
- package/package.json +1 -1
- package/sessions.mjs +2 -1
package/README.md
CHANGED
|
@@ -123,6 +123,8 @@ errors, and owned/attached identities without reimplementing transcript or capab
|
|
|
123
123
|
- Every component accepts data and callbacks. No component reaches into a global controller.
|
|
124
124
|
- The complete messenger accepts `slots` for high-level replacement and `components` for row-level
|
|
125
125
|
replacement. Replacements receive the same typed, capability-filtered props as defaults.
|
|
126
|
+
- `slots.headerActions` adds compact product controls to the default list, chat, and new-chat
|
|
127
|
+
headers without replacing their navigation, status, or accessibility behavior.
|
|
126
128
|
- Stable `scui-*` classes and `data-*` attributes support additive styling; CSS custom properties
|
|
127
129
|
are the supported theme API.
|
|
128
130
|
- `styles.css` contains both neutral tokens and default component rules. Teams may load it whole,
|
package/components.mjs
CHANGED
|
@@ -833,7 +833,7 @@ function activitySummary(entries) {
|
|
|
833
833
|
function canContinueHere(state) {
|
|
834
834
|
if (state.mode !== "mirror" || state.canSend) return false;
|
|
835
835
|
const row = state.attached?.key ? state.sessions.find((item) => item.key === state.attached.key) : null;
|
|
836
|
-
return state.canResume && row
|
|
836
|
+
return Boolean(row) && state.canResume && row.runtimeStatus !== "running" && row.runtimeStatus !== "busy" && row.runtimeStatus !== "idle";
|
|
837
837
|
}
|
|
838
838
|
function operationLabel(operation) {
|
|
839
839
|
if (!operation) return "";
|
|
@@ -2130,7 +2130,7 @@ function SessionRow({ row, state, onOpen, now = Date.now() }) {
|
|
|
2130
2130
|
] })
|
|
2131
2131
|
] });
|
|
2132
2132
|
}
|
|
2133
|
-
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default" }) {
|
|
2133
|
+
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default", headerActions: HeaderActions }) {
|
|
2134
2134
|
const remembered = sessionListMemory.get(memoryKey) ?? { query: "", top: 0 };
|
|
2135
2135
|
const [query, setQuery] = useState4(remembered.query);
|
|
2136
2136
|
const [loadingMore, setLoadingMore] = useState4(false);
|
|
@@ -2171,6 +2171,7 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
2171
2171
|
" recent conversations"
|
|
2172
2172
|
] })
|
|
2173
2173
|
] }),
|
|
2174
|
+
HeaderActions ? /* @__PURE__ */ jsx7(HeaderActions, { state, adapter, value: "list" }) : null,
|
|
2174
2175
|
/* @__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 }) }),
|
|
2175
2176
|
onClose ? /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx7(UiIcon, { name: "close", size: 18 }) }) : null
|
|
2176
2177
|
] }),
|
|
@@ -2409,11 +2410,11 @@ function ConversationActions({ state, adapter, actionPending, onSettings }) {
|
|
|
2409
2410
|
] }, group.label)) }) : null
|
|
2410
2411
|
] });
|
|
2411
2412
|
}
|
|
2412
|
-
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose, onSettings }) {
|
|
2413
|
+
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose, onSettings, headerActions: HeaderActions }) {
|
|
2413
2414
|
const back = useRef7(null);
|
|
2414
2415
|
const harness = state.attached?.harness ?? state.harness;
|
|
2415
2416
|
const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
|
|
2416
|
-
const status = state.needsInput ? "Needs input" : pendingStatus === "failed" ? "Send failed" : state.busy ? "Working" : pendingStatus === "sending" ? "Sending" : pendingStatus === "editing" ? "Editing message" : state.mode === "mirror" ? "Read-only" : "Ready";
|
|
2417
|
+
const status = state.needsInput ? "Needs input" : pendingStatus === "failed" ? "Send failed" : state.busy ? "Working" : pendingStatus === "sending" ? "Sending" : pendingStatus === "editing" ? "Editing message" : state.messaging === "live_peer" ? "Live" : state.mode === "mirror" ? "Read-only" : "Ready";
|
|
2417
2418
|
const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce || state.interopSettings || state.interopSettingsError;
|
|
2418
2419
|
useEffect8(() => {
|
|
2419
2420
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
@@ -2429,6 +2430,7 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2429
2430
|
status
|
|
2430
2431
|
] })
|
|
2431
2432
|
] }),
|
|
2433
|
+
HeaderActions ? /* @__PURE__ */ jsx9(HeaderActions, { state, adapter, value: "chat" }) : null,
|
|
2432
2434
|
menu ? /* @__PURE__ */ jsx9(ConversationActions, { state, adapter, actionPending, onSettings }) : null,
|
|
2433
2435
|
/* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: /* @__PURE__ */ jsx9(UiIcon, { name: "plus", size: 18 }) }),
|
|
2434
2436
|
onClose ? /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx9(UiIcon, { name: "close", size: 18 }) }) : null
|
|
@@ -2436,6 +2438,7 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2436
2438
|
}
|
|
2437
2439
|
function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
|
|
2438
2440
|
const Header = slots.header;
|
|
2441
|
+
const HeaderActions = slots.headerActions;
|
|
2439
2442
|
const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
|
|
2440
2443
|
const [pending, setPendingState] = useState6(() => pendingMessageMemory.get(memoryKey) ?? null);
|
|
2441
2444
|
const [pendingAction, setPendingAction] = useState6(null);
|
|
@@ -2535,7 +2538,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2535
2538
|
const Advisory = components.HarnessAdvisory ?? HarnessAdvisory;
|
|
2536
2539
|
const SettingsPanel = components.HarnessSettingsPanel ?? HarnessSettingsPanel;
|
|
2537
2540
|
return /* @__PURE__ */ jsxs8("section", { class: "scui-chat", children: [
|
|
2538
|
-
Header ? /* @__PURE__ */ jsx9(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx9(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose, onSettings: () => setSettings({ recommendedChange: null }) }),
|
|
2541
|
+
Header ? /* @__PURE__ */ jsx9(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx9(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose, onSettings: () => setSettings({ recommendedChange: null }), headerActions: HeaderActions }),
|
|
2539
2542
|
actionLabel ? /* @__PURE__ */ jsxs8("div", { class: "scui-operation", role: "status", children: [
|
|
2540
2543
|
/* @__PURE__ */ jsx9("i", {}),
|
|
2541
2544
|
actionLabel
|
|
@@ -2552,7 +2555,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2552
2555
|
settings ? /* @__PURE__ */ jsx9(SettingsPanel, { state: actionState, adapter: trackedAdapter, value: state.interopSettings, recommendedChange: settings.recommendedChange, onClose: () => setSettings(null) }) : null
|
|
2553
2556
|
] });
|
|
2554
2557
|
}
|
|
2555
|
-
function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey }) {
|
|
2558
|
+
function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey, headerActions: HeaderActions }) {
|
|
2556
2559
|
const startable = state.harnesses.filter((item) => item.startable);
|
|
2557
2560
|
const startableKey = startable.map((item) => `${item.id}:${item.launchModes?.join(",")}:${item.preferredLaunchMode ?? ""}`).join("\0");
|
|
2558
2561
|
const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "", context: [], images: [], modes: {} };
|
|
@@ -2669,6 +2672,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2669
2672
|
/* @__PURE__ */ jsx9("strong", { children: labels.newChat }),
|
|
2670
2673
|
/* @__PURE__ */ jsx9("small", { children: "No session is created until you send" })
|
|
2671
2674
|
] }),
|
|
2675
|
+
HeaderActions ? /* @__PURE__ */ jsx9(HeaderActions, { state, adapter, value: "new" }) : null,
|
|
2672
2676
|
onClose ? /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx9(UiIcon, { name: "close", size: 18 }) }) : null
|
|
2673
2677
|
] }),
|
|
2674
2678
|
starting ? /* @__PURE__ */ jsxs8("div", { class: "scui-operation", role: "status", children: [
|
|
@@ -2772,12 +2776,13 @@ function SupercodeMessenger({ state: stateInput, adapter, class: className = "",
|
|
|
2772
2776
|
};
|
|
2773
2777
|
const close = () => adapter.onClose?.();
|
|
2774
2778
|
const Footer = slots.footer;
|
|
2779
|
+
const HeaderActions = slots.headerActions;
|
|
2775
2780
|
return /* @__PURE__ */ jsxs8("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
|
|
2776
2781
|
view === "list" ? /* @__PURE__ */ jsx9(SessionList, { state, adapter, focusKey: listFocus, onOpen: open, onNew: () => {
|
|
2777
2782
|
setListFocus("@new");
|
|
2778
2783
|
setView("new");
|
|
2779
|
-
}, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey }) : null,
|
|
2780
|
-
view === "new" ? /* @__PURE__ */ jsx9(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: (mode) => setView(mode === "terminal" ? "list" : "chat"), labels: copy, memoryKey }) : null,
|
|
2784
|
+
}, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey, headerActions: HeaderActions }) : null,
|
|
2785
|
+
view === "new" ? /* @__PURE__ */ jsx9(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: (mode) => setView(mode === "terminal" ? "list" : "chat"), labels: copy, memoryKey, headerActions: HeaderActions }) : null,
|
|
2781
2786
|
view === "chat" ? /* @__PURE__ */ jsx9(Chat, { state, adapter, onBack: () => {
|
|
2782
2787
|
setListFocus(state.attached?.key ?? listFocus);
|
|
2783
2788
|
setView("list");
|
package/composer.mjs
CHANGED
|
@@ -70,7 +70,7 @@ function harnessDisplayName(id) {
|
|
|
70
70
|
function canContinueHere(state) {
|
|
71
71
|
if (state.mode !== "mirror" || state.canSend) return false;
|
|
72
72
|
const row = state.attached?.key ? state.sessions.find((item) => item.key === state.attached.key) : null;
|
|
73
|
-
return state.canResume && row
|
|
73
|
+
return Boolean(row) && state.canResume && row.runtimeStatus !== "running" && row.runtimeStatus !== "busy" && row.runtimeStatus !== "idle";
|
|
74
74
|
}
|
|
75
75
|
function isSendKey(event) {
|
|
76
76
|
return event.key === "Enter" && !event.shiftKey && !event.isComposing;
|
package/core.mjs
CHANGED
|
@@ -903,7 +903,7 @@ export function activitySummary(entries) {
|
|
|
903
903
|
export function canContinueHere(state) {
|
|
904
904
|
if (state.mode !== 'mirror' || state.canSend) return false;
|
|
905
905
|
const row = state.attached?.key ? state.sessions.find((item) => item.key === state.attached.key) : null;
|
|
906
|
-
return state.canResume && row
|
|
906
|
+
return Boolean(row) && state.canResume && row.runtimeStatus !== 'running' && row.runtimeStatus !== 'busy' && row.runtimeStatus !== 'idle';
|
|
907
907
|
}
|
|
908
908
|
|
|
909
909
|
export function operationLabel(operation) {
|
package/embed.mjs
CHANGED
|
@@ -836,7 +836,7 @@ function activitySummary(entries) {
|
|
|
836
836
|
function canContinueHere(state) {
|
|
837
837
|
if (state.mode !== "mirror" || state.canSend) return false;
|
|
838
838
|
const row = state.attached?.key ? state.sessions.find((item) => item.key === state.attached.key) : null;
|
|
839
|
-
return state.canResume && row
|
|
839
|
+
return Boolean(row) && state.canResume && row.runtimeStatus !== "running" && row.runtimeStatus !== "busy" && row.runtimeStatus !== "idle";
|
|
840
840
|
}
|
|
841
841
|
function operationLabel(operation) {
|
|
842
842
|
if (!operation) return "";
|
|
@@ -2109,7 +2109,7 @@ function SessionRow({ row, state, onOpen, now = Date.now() }) {
|
|
|
2109
2109
|
] })
|
|
2110
2110
|
] });
|
|
2111
2111
|
}
|
|
2112
|
-
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default" }) {
|
|
2112
|
+
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default", headerActions: HeaderActions }) {
|
|
2113
2113
|
const remembered = sessionListMemory.get(memoryKey) ?? { query: "", top: 0 };
|
|
2114
2114
|
const [query, setQuery] = useState4(remembered.query);
|
|
2115
2115
|
const [loadingMore, setLoadingMore] = useState4(false);
|
|
@@ -2150,6 +2150,7 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
2150
2150
|
" recent conversations"
|
|
2151
2151
|
] })
|
|
2152
2152
|
] }),
|
|
2153
|
+
HeaderActions ? /* @__PURE__ */ jsx7(HeaderActions, { state, adapter, value: "list" }) : null,
|
|
2153
2154
|
/* @__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 }) }),
|
|
2154
2155
|
onClose ? /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx7(UiIcon, { name: "close", size: 18 }) }) : null
|
|
2155
2156
|
] }),
|
|
@@ -2388,11 +2389,11 @@ function ConversationActions({ state, adapter, actionPending, onSettings }) {
|
|
|
2388
2389
|
] }, group.label)) }) : null
|
|
2389
2390
|
] });
|
|
2390
2391
|
}
|
|
2391
|
-
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose, onSettings }) {
|
|
2392
|
+
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose, onSettings, headerActions: HeaderActions }) {
|
|
2392
2393
|
const back = useRef7(null);
|
|
2393
2394
|
const harness = state.attached?.harness ?? state.harness;
|
|
2394
2395
|
const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
|
|
2395
|
-
const status = state.needsInput ? "Needs input" : pendingStatus === "failed" ? "Send failed" : state.busy ? "Working" : pendingStatus === "sending" ? "Sending" : pendingStatus === "editing" ? "Editing message" : state.mode === "mirror" ? "Read-only" : "Ready";
|
|
2396
|
+
const status = state.needsInput ? "Needs input" : pendingStatus === "failed" ? "Send failed" : state.busy ? "Working" : pendingStatus === "sending" ? "Sending" : pendingStatus === "editing" ? "Editing message" : state.messaging === "live_peer" ? "Live" : state.mode === "mirror" ? "Read-only" : "Ready";
|
|
2396
2397
|
const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce || state.interopSettings || state.interopSettingsError;
|
|
2397
2398
|
useEffect8(() => {
|
|
2398
2399
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
@@ -2408,6 +2409,7 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2408
2409
|
status
|
|
2409
2410
|
] })
|
|
2410
2411
|
] }),
|
|
2412
|
+
HeaderActions ? /* @__PURE__ */ jsx9(HeaderActions, { state, adapter, value: "chat" }) : null,
|
|
2411
2413
|
menu ? /* @__PURE__ */ jsx9(ConversationActions, { state, adapter, actionPending, onSettings }) : null,
|
|
2412
2414
|
/* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: /* @__PURE__ */ jsx9(UiIcon, { name: "plus", size: 18 }) }),
|
|
2413
2415
|
onClose ? /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx9(UiIcon, { name: "close", size: 18 }) }) : null
|
|
@@ -2415,6 +2417,7 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2415
2417
|
}
|
|
2416
2418
|
function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
|
|
2417
2419
|
const Header = slots.header;
|
|
2420
|
+
const HeaderActions = slots.headerActions;
|
|
2418
2421
|
const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
|
|
2419
2422
|
const [pending, setPendingState] = useState6(() => pendingMessageMemory.get(memoryKey) ?? null);
|
|
2420
2423
|
const [pendingAction, setPendingAction] = useState6(null);
|
|
@@ -2514,7 +2517,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2514
2517
|
const Advisory = components.HarnessAdvisory ?? HarnessAdvisory;
|
|
2515
2518
|
const SettingsPanel = components.HarnessSettingsPanel ?? HarnessSettingsPanel;
|
|
2516
2519
|
return /* @__PURE__ */ jsxs8("section", { class: "scui-chat", children: [
|
|
2517
|
-
Header ? /* @__PURE__ */ jsx9(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx9(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose, onSettings: () => setSettings({ recommendedChange: null }) }),
|
|
2520
|
+
Header ? /* @__PURE__ */ jsx9(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx9(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose, onSettings: () => setSettings({ recommendedChange: null }), headerActions: HeaderActions }),
|
|
2518
2521
|
actionLabel ? /* @__PURE__ */ jsxs8("div", { class: "scui-operation", role: "status", children: [
|
|
2519
2522
|
/* @__PURE__ */ jsx9("i", {}),
|
|
2520
2523
|
actionLabel
|
|
@@ -2531,7 +2534,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2531
2534
|
settings ? /* @__PURE__ */ jsx9(SettingsPanel, { state: actionState, adapter: trackedAdapter, value: state.interopSettings, recommendedChange: settings.recommendedChange, onClose: () => setSettings(null) }) : null
|
|
2532
2535
|
] });
|
|
2533
2536
|
}
|
|
2534
|
-
function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey }) {
|
|
2537
|
+
function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey, headerActions: HeaderActions }) {
|
|
2535
2538
|
const startable = state.harnesses.filter((item) => item.startable);
|
|
2536
2539
|
const startableKey = startable.map((item) => `${item.id}:${item.launchModes?.join(",")}:${item.preferredLaunchMode ?? ""}`).join("\0");
|
|
2537
2540
|
const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "", context: [], images: [], modes: {} };
|
|
@@ -2648,6 +2651,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2648
2651
|
/* @__PURE__ */ jsx9("strong", { children: labels.newChat }),
|
|
2649
2652
|
/* @__PURE__ */ jsx9("small", { children: "No session is created until you send" })
|
|
2650
2653
|
] }),
|
|
2654
|
+
HeaderActions ? /* @__PURE__ */ jsx9(HeaderActions, { state, adapter, value: "new" }) : null,
|
|
2651
2655
|
onClose ? /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx9(UiIcon, { name: "close", size: 18 }) }) : null
|
|
2652
2656
|
] }),
|
|
2653
2657
|
starting ? /* @__PURE__ */ jsxs8("div", { class: "scui-operation", role: "status", children: [
|
|
@@ -2751,12 +2755,13 @@ function SupercodeMessenger({ state: stateInput, adapter, class: className = "",
|
|
|
2751
2755
|
};
|
|
2752
2756
|
const close = () => adapter.onClose?.();
|
|
2753
2757
|
const Footer = slots.footer;
|
|
2758
|
+
const HeaderActions = slots.headerActions;
|
|
2754
2759
|
return /* @__PURE__ */ jsxs8("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
|
|
2755
2760
|
view === "list" ? /* @__PURE__ */ jsx9(SessionList, { state, adapter, focusKey: listFocus, onOpen: open, onNew: () => {
|
|
2756
2761
|
setListFocus("@new");
|
|
2757
2762
|
setView("new");
|
|
2758
|
-
}, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey }) : null,
|
|
2759
|
-
view === "new" ? /* @__PURE__ */ jsx9(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: (mode) => setView(mode === "terminal" ? "list" : "chat"), labels: copy, memoryKey }) : null,
|
|
2763
|
+
}, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey, headerActions: HeaderActions }) : null,
|
|
2764
|
+
view === "new" ? /* @__PURE__ */ jsx9(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: (mode) => setView(mode === "terminal" ? "list" : "chat"), labels: copy, memoryKey, headerActions: HeaderActions }) : null,
|
|
2760
2765
|
view === "chat" ? /* @__PURE__ */ jsx9(Chat, { state, adapter, onBack: () => {
|
|
2761
2766
|
setListFocus(state.attached?.key ?? listFocus);
|
|
2762
2767
|
setView("list");
|
package/index.d.ts
CHANGED
|
@@ -409,6 +409,8 @@ export interface MessengerComponents {
|
|
|
409
409
|
|
|
410
410
|
export interface MessengerSlots {
|
|
411
411
|
header?: ComponentType<ComponentOverrideProps>;
|
|
412
|
+
/** Add a compact consumer control to every default messenger header. `value` is the current view. */
|
|
413
|
+
headerActions?: ComponentType<ComponentOverrideProps<'list' | 'chat' | 'new'>>;
|
|
412
414
|
emptyConversation?: ComponentType<ComponentOverrideProps>;
|
|
413
415
|
beforeConversation?: ComponentType<ComponentOverrideProps>;
|
|
414
416
|
afterConversation?: ComponentType<ComponentOverrideProps>;
|
|
@@ -466,7 +468,7 @@ export function HarnessSettingsPanel(props: HarnessSettingsPanelProps): VNode;
|
|
|
466
468
|
export function SessionDetails(props: { semantics: SessionSemanticsModel }): VNode | null;
|
|
467
469
|
export function Conversation(props: { state: SupercodeUiState; adapter: UiAdapter; components?: MessengerComponents; slots?: MessengerSlots; memoryKey?: string; pending?: string | PendingMessageModel | null; unreadAfterMessages?: number | null }): VNode;
|
|
468
470
|
export function SessionRow(props: { row: SessionRowModel; state: SupercodeUiState; adapter: UiAdapter; now?: number; onOpen(row: SessionRowModel): void }): VNode;
|
|
469
|
-
export function SessionList(props: { state: SupercodeUiState; adapter: UiAdapter; onOpen(row: SessionRowModel): void; onNew?(): void; onClose?(): void; components?: MessengerComponents; labels?: MessengerLabels; focusKey?: string | null; memoryKey?: string }): VNode;
|
|
471
|
+
export function SessionList(props: { state: SupercodeUiState; adapter: UiAdapter; onOpen(row: SessionRowModel): void; onNew?(): void; onClose?(): void; components?: MessengerComponents; labels?: MessengerLabels; focusKey?: string | null; memoryKey?: string; headerActions?: MessengerSlots['headerActions'] }): VNode;
|
|
470
472
|
export function ContinuationBar(props: { state: SupercodeUiState; adapter: UiAdapter; labels?: MessengerLabels }): VNode | null;
|
|
471
473
|
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; onPending?(text: string, context?: TranscriptContext[], images?: TranscriptImage[]): void; onDraftRestored?(id: string | number): void }): VNode;
|
|
472
474
|
export function SupercodeMessenger(props: MessengerProps): VNode;
|
package/messenger.mjs
CHANGED
|
@@ -833,7 +833,7 @@ function activitySummary(entries) {
|
|
|
833
833
|
function canContinueHere(state) {
|
|
834
834
|
if (state.mode !== "mirror" || state.canSend) return false;
|
|
835
835
|
const row = state.attached?.key ? state.sessions.find((item) => item.key === state.attached.key) : null;
|
|
836
|
-
return state.canResume && row
|
|
836
|
+
return Boolean(row) && state.canResume && row.runtimeStatus !== "running" && row.runtimeStatus !== "busy" && row.runtimeStatus !== "idle";
|
|
837
837
|
}
|
|
838
838
|
function operationLabel(operation) {
|
|
839
839
|
if (!operation) return "";
|
|
@@ -2106,7 +2106,7 @@ function SessionRow({ row, state, onOpen, now = Date.now() }) {
|
|
|
2106
2106
|
] })
|
|
2107
2107
|
] });
|
|
2108
2108
|
}
|
|
2109
|
-
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default" }) {
|
|
2109
|
+
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default", headerActions: HeaderActions }) {
|
|
2110
2110
|
const remembered = sessionListMemory.get(memoryKey) ?? { query: "", top: 0 };
|
|
2111
2111
|
const [query, setQuery] = useState4(remembered.query);
|
|
2112
2112
|
const [loadingMore, setLoadingMore] = useState4(false);
|
|
@@ -2147,6 +2147,7 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
2147
2147
|
" recent conversations"
|
|
2148
2148
|
] })
|
|
2149
2149
|
] }),
|
|
2150
|
+
HeaderActions ? /* @__PURE__ */ jsx7(HeaderActions, { state, adapter, value: "list" }) : null,
|
|
2150
2151
|
/* @__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 }) }),
|
|
2151
2152
|
onClose ? /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx7(UiIcon, { name: "close", size: 18 }) }) : null
|
|
2152
2153
|
] }),
|
|
@@ -2385,11 +2386,11 @@ function ConversationActions({ state, adapter, actionPending, onSettings }) {
|
|
|
2385
2386
|
] }, group.label)) }) : null
|
|
2386
2387
|
] });
|
|
2387
2388
|
}
|
|
2388
|
-
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose, onSettings }) {
|
|
2389
|
+
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose, onSettings, headerActions: HeaderActions }) {
|
|
2389
2390
|
const back = useRef7(null);
|
|
2390
2391
|
const harness = state.attached?.harness ?? state.harness;
|
|
2391
2392
|
const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
|
|
2392
|
-
const status = state.needsInput ? "Needs input" : pendingStatus === "failed" ? "Send failed" : state.busy ? "Working" : pendingStatus === "sending" ? "Sending" : pendingStatus === "editing" ? "Editing message" : state.mode === "mirror" ? "Read-only" : "Ready";
|
|
2393
|
+
const status = state.needsInput ? "Needs input" : pendingStatus === "failed" ? "Send failed" : state.busy ? "Working" : pendingStatus === "sending" ? "Sending" : pendingStatus === "editing" ? "Editing message" : state.messaging === "live_peer" ? "Live" : state.mode === "mirror" ? "Read-only" : "Ready";
|
|
2393
2394
|
const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce || state.interopSettings || state.interopSettingsError;
|
|
2394
2395
|
useEffect8(() => {
|
|
2395
2396
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
@@ -2405,6 +2406,7 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2405
2406
|
status
|
|
2406
2407
|
] })
|
|
2407
2408
|
] }),
|
|
2409
|
+
HeaderActions ? /* @__PURE__ */ jsx9(HeaderActions, { state, adapter, value: "chat" }) : null,
|
|
2408
2410
|
menu ? /* @__PURE__ */ jsx9(ConversationActions, { state, adapter, actionPending, onSettings }) : null,
|
|
2409
2411
|
/* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: /* @__PURE__ */ jsx9(UiIcon, { name: "plus", size: 18 }) }),
|
|
2410
2412
|
onClose ? /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx9(UiIcon, { name: "close", size: 18 }) }) : null
|
|
@@ -2412,6 +2414,7 @@ function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNe
|
|
|
2412
2414
|
}
|
|
2413
2415
|
function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
|
|
2414
2416
|
const Header = slots.header;
|
|
2417
|
+
const HeaderActions = slots.headerActions;
|
|
2415
2418
|
const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
|
|
2416
2419
|
const [pending, setPendingState] = useState6(() => pendingMessageMemory.get(memoryKey) ?? null);
|
|
2417
2420
|
const [pendingAction, setPendingAction] = useState6(null);
|
|
@@ -2511,7 +2514,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2511
2514
|
const Advisory = components.HarnessAdvisory ?? HarnessAdvisory;
|
|
2512
2515
|
const SettingsPanel = components.HarnessSettingsPanel ?? HarnessSettingsPanel;
|
|
2513
2516
|
return /* @__PURE__ */ jsxs8("section", { class: "scui-chat", children: [
|
|
2514
|
-
Header ? /* @__PURE__ */ jsx9(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx9(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose, onSettings: () => setSettings({ recommendedChange: null }) }),
|
|
2517
|
+
Header ? /* @__PURE__ */ jsx9(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx9(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose, onSettings: () => setSettings({ recommendedChange: null }), headerActions: HeaderActions }),
|
|
2515
2518
|
actionLabel ? /* @__PURE__ */ jsxs8("div", { class: "scui-operation", role: "status", children: [
|
|
2516
2519
|
/* @__PURE__ */ jsx9("i", {}),
|
|
2517
2520
|
actionLabel
|
|
@@ -2528,7 +2531,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2528
2531
|
settings ? /* @__PURE__ */ jsx9(SettingsPanel, { state: actionState, adapter: trackedAdapter, value: state.interopSettings, recommendedChange: settings.recommendedChange, onClose: () => setSettings(null) }) : null
|
|
2529
2532
|
] });
|
|
2530
2533
|
}
|
|
2531
|
-
function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey }) {
|
|
2534
|
+
function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey, headerActions: HeaderActions }) {
|
|
2532
2535
|
const startable = state.harnesses.filter((item) => item.startable);
|
|
2533
2536
|
const startableKey = startable.map((item) => `${item.id}:${item.launchModes?.join(",")}:${item.preferredLaunchMode ?? ""}`).join("\0");
|
|
2534
2537
|
const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "", context: [], images: [], modes: {} };
|
|
@@ -2645,6 +2648,7 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2645
2648
|
/* @__PURE__ */ jsx9("strong", { children: labels.newChat }),
|
|
2646
2649
|
/* @__PURE__ */ jsx9("small", { children: "No session is created until you send" })
|
|
2647
2650
|
] }),
|
|
2651
|
+
HeaderActions ? /* @__PURE__ */ jsx9(HeaderActions, { state, adapter, value: "new" }) : null,
|
|
2648
2652
|
onClose ? /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx9(UiIcon, { name: "close", size: 18 }) }) : null
|
|
2649
2653
|
] }),
|
|
2650
2654
|
starting ? /* @__PURE__ */ jsxs8("div", { class: "scui-operation", role: "status", children: [
|
|
@@ -2748,12 +2752,13 @@ function SupercodeMessenger({ state: stateInput, adapter, class: className = "",
|
|
|
2748
2752
|
};
|
|
2749
2753
|
const close = () => adapter.onClose?.();
|
|
2750
2754
|
const Footer = slots.footer;
|
|
2755
|
+
const HeaderActions = slots.headerActions;
|
|
2751
2756
|
return /* @__PURE__ */ jsxs8("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
|
|
2752
2757
|
view === "list" ? /* @__PURE__ */ jsx9(SessionList, { state, adapter, focusKey: listFocus, onOpen: open, onNew: () => {
|
|
2753
2758
|
setListFocus("@new");
|
|
2754
2759
|
setView("new");
|
|
2755
|
-
}, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey }) : null,
|
|
2756
|
-
view === "new" ? /* @__PURE__ */ jsx9(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: (mode) => setView(mode === "terminal" ? "list" : "chat"), labels: copy, memoryKey }) : null,
|
|
2760
|
+
}, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey, headerActions: HeaderActions }) : null,
|
|
2761
|
+
view === "new" ? /* @__PURE__ */ jsx9(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: (mode) => setView(mode === "terminal" ? "list" : "chat"), labels: copy, memoryKey, headerActions: HeaderActions }) : null,
|
|
2757
2762
|
view === "chat" ? /* @__PURE__ */ jsx9(Chat, { state, adapter, onBack: () => {
|
|
2758
2763
|
setListFocus(state.attached?.key ?? listFocus);
|
|
2759
2764
|
setView("list");
|
package/package.json
CHANGED
package/sessions.mjs
CHANGED
|
@@ -340,7 +340,7 @@ function SessionRow({ row, state, onOpen, now = Date.now() }) {
|
|
|
340
340
|
] })
|
|
341
341
|
] });
|
|
342
342
|
}
|
|
343
|
-
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default" }) {
|
|
343
|
+
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default", headerActions: HeaderActions }) {
|
|
344
344
|
const remembered = sessionListMemory.get(memoryKey) ?? { query: "", top: 0 };
|
|
345
345
|
const [query, setQuery] = useState3(remembered.query);
|
|
346
346
|
const [loadingMore, setLoadingMore] = useState3(false);
|
|
@@ -381,6 +381,7 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
381
381
|
" recent conversations"
|
|
382
382
|
] })
|
|
383
383
|
] }),
|
|
384
|
+
HeaderActions ? /* @__PURE__ */ jsx6(HeaderActions, { state, adapter, value: "list" }) : null,
|
|
384
385
|
/* @__PURE__ */ jsx6("button", { type: "button", "data-list-focus": "new", "aria-label": labels.newChat, disabled: !state.harnesses.some((item) => item.startable), onClick: onNew, children: /* @__PURE__ */ jsx6(UiIcon, { name: "plus", size: 18 }) }),
|
|
385
386
|
onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx6(UiIcon, { name: "close", size: 18 }) }) : null
|
|
386
387
|
] }),
|