@volter-ai-dev/supercode-ui 0.1.33 → 0.1.34

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 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?.runtimeStatus !== "running" && row?.runtimeStatus !== "busy" && row?.runtimeStatus !== "idle";
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,7 +2410,7 @@ 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";
@@ -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?.runtimeStatus !== "running" && row?.runtimeStatus !== "busy" && row?.runtimeStatus !== "idle";
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?.runtimeStatus !== 'running' && row?.runtimeStatus !== 'busy' && row?.runtimeStatus !== 'idle';
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?.runtimeStatus !== "running" && row?.runtimeStatus !== "busy" && row?.runtimeStatus !== "idle";
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,7 +2389,7 @@ 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";
@@ -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?.runtimeStatus !== "running" && row?.runtimeStatus !== "busy" && row?.runtimeStatus !== "idle";
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,7 +2386,7 @@ 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";
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter-ai-dev/supercode-ui",
3
- "version": "0.1.33",
3
+ "version": "0.1.34",
4
4
  "type": "module",
5
5
  "description": "Composable default UI kit for Supercode-powered coding-agent experiences",
6
6
  "exports": {
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
  ] }),