@volter-ai-dev/supercode-ui 0.1.13 → 0.1.14
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 +1 -1
- package/components.d.ts +1 -0
- package/components.mjs +711 -361
- package/composer.mjs +77 -19
- package/controller.mjs +5 -2
- package/conversation.mjs +364 -196
- package/core.mjs +3 -2
- package/embed.mjs +712 -363
- package/icon.d.ts +2 -0
- package/icon.mjs +45 -0
- package/index.d.ts +9 -3
- package/messenger.mjs +710 -361
- package/package.json +8 -2
- package/sessions.mjs +160 -48
- package/styles.css +35 -18
package/messenger.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/messenger.jsx
|
|
2
|
-
import { useEffect as
|
|
2
|
+
import { useEffect as useEffect6, useId as useId2, useMemo as useMemo2, useRef as useRef5, useState as useState4 } from "preact/hooks";
|
|
3
3
|
|
|
4
4
|
// core.mjs
|
|
5
5
|
var HARNESS_NAMES = Object.freeze({
|
|
@@ -292,7 +292,8 @@ function readTranscript(value) {
|
|
|
292
292
|
role: item.role,
|
|
293
293
|
text: item.text,
|
|
294
294
|
ts: nullableNumber(item.ts),
|
|
295
|
-
truncated: item.truncated === true
|
|
295
|
+
truncated: item.truncated === true,
|
|
296
|
+
...Number.isSafeInteger(item.messageIndex) && item.messageIndex > 0 ? { messageIndex: item.messageIndex } : {}
|
|
296
297
|
};
|
|
297
298
|
for (const key of ["label", "arguments", "resultText", "code"]) {
|
|
298
299
|
if (typeof item[key] === "string") entry[key] = item[key];
|
|
@@ -463,7 +464,7 @@ function normalizeUiState(value) {
|
|
|
463
464
|
savedDraft: string(raw.savedDraft),
|
|
464
465
|
attention: Array.isArray(raw.attention) ? raw.attention.flatMap((candidate) => {
|
|
465
466
|
const item = record(candidate);
|
|
466
|
-
return item && typeof item.key === "string" && ["unseen", "finished", "failed"].includes(item.kind) ? [{ key: item.key, kind: item.kind, ...typeof item.preview === "string" ? { preview: item.preview } : {} }] : [];
|
|
467
|
+
return item && typeof item.key === "string" && ["unseen", "finished", "failed"].includes(item.kind) ? [{ key: item.key, kind: item.kind, ...typeof item.preview === "string" ? { preview: item.preview } : {}, ...Number.isSafeInteger(item.afterMessages) && item.afterMessages >= 0 ? { afterMessages: item.afterMessages } : {} }] : [];
|
|
467
468
|
}) : [],
|
|
468
469
|
sessions: readSessions(raw.sessions),
|
|
469
470
|
attached: readAttached(raw.attached),
|
|
@@ -545,7 +546,7 @@ function canContinueHere(state) {
|
|
|
545
546
|
}
|
|
546
547
|
function operationLabel(operation) {
|
|
547
548
|
if (!operation) return "";
|
|
548
|
-
const labels = { discover: "Refreshing chats\u2026", observe: "Loading recent messages\u2026", attach: "Opening chat\u2026", resume: "Continuing here\u2026", branch: "Starting continuation\u2026", reduce: "Reducing context and verifying reversibility\u2026", terminal: "Preparing terminal handoff\u2026", export: "Exporting losslessly\u2026", refresh: "Retrying\u2026" };
|
|
549
|
+
const labels = { discover: "Refreshing chats\u2026", observe: "Loading recent messages\u2026", attach: "Opening chat\u2026", start: "Starting new chat\u2026", resume: "Continuing here\u2026", join: "Joining live session\u2026", detach: "Detaching to read-only\u2026", branch: "Starting continuation\u2026", reduce: "Reducing context and verifying reversibility\u2026", terminal: "Preparing terminal handoff\u2026", export: "Exporting losslessly\u2026", interrupt: "Stopping agent\u2026", respond: "Sending response\u2026", loadEarlier: "Loading earlier messages\u2026", loadSessions: "Loading more chats\u2026", refresh: "Retrying\u2026" };
|
|
549
550
|
return labels[operation] ?? `${operation.replaceAll("_", " ")}\u2026`;
|
|
550
551
|
}
|
|
551
552
|
function terminalCommand(handoff) {
|
|
@@ -567,8 +568,65 @@ function boundedSet(map, key, value) {
|
|
|
567
568
|
while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
|
|
568
569
|
}
|
|
569
570
|
|
|
571
|
+
// src/icon.jsx
|
|
572
|
+
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
573
|
+
var ICONS = {
|
|
574
|
+
back: () => /* @__PURE__ */ jsx("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
|
|
575
|
+
check: () => /* @__PURE__ */ jsx("path", { d: "m4 9 3.25 3.25L14 5.5" }),
|
|
576
|
+
chevron: () => /* @__PURE__ */ jsx("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
|
|
577
|
+
close: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
578
|
+
/* @__PURE__ */ jsx("path", { d: "m4.75 4.75 8.5 8.5" }),
|
|
579
|
+
/* @__PURE__ */ jsx("path", { d: "m13.25 4.75-8.5 8.5" })
|
|
580
|
+
] }),
|
|
581
|
+
copy: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
582
|
+
/* @__PURE__ */ jsx("rect", { x: "5", y: "5", width: "8", height: "8", rx: "1.5" }),
|
|
583
|
+
/* @__PURE__ */ jsx("path", { d: "M3 10.5V4.25C3 3.56 3.56 3 4.25 3h6.25" })
|
|
584
|
+
] }),
|
|
585
|
+
down: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
586
|
+
/* @__PURE__ */ jsx("path", { d: "M9 3.5v10" }),
|
|
587
|
+
/* @__PURE__ */ jsx("path", { d: "m4.75 9.5 4.25 4 4.25-4" })
|
|
588
|
+
] }),
|
|
589
|
+
menu: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
590
|
+
/* @__PURE__ */ jsx("circle", { cx: "4", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
|
|
591
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
|
|
592
|
+
/* @__PURE__ */ jsx("circle", { cx: "14", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" })
|
|
593
|
+
] }),
|
|
594
|
+
plus: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
595
|
+
/* @__PURE__ */ jsx("path", { d: "M9 3.5v11" }),
|
|
596
|
+
/* @__PURE__ */ jsx("path", { d: "M3.5 9h11" })
|
|
597
|
+
] }),
|
|
598
|
+
search: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
599
|
+
/* @__PURE__ */ jsx("circle", { cx: "7.75", cy: "7.75", r: "4.25" }),
|
|
600
|
+
/* @__PURE__ */ jsx("path", { d: "m11 11 3.5 3.5" })
|
|
601
|
+
] }),
|
|
602
|
+
send: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
603
|
+
/* @__PURE__ */ jsx("path", { d: "M9 14.5v-11" }),
|
|
604
|
+
/* @__PURE__ */ jsx("path", { d: "m4.75 7.75 4.25-4.25 4.25 4.25" })
|
|
605
|
+
] }),
|
|
606
|
+
stop: () => /* @__PURE__ */ jsx("rect", { x: "4.5", y: "4.5", width: "9", height: "9", rx: "1.5", fill: "currentColor", stroke: "none" })
|
|
607
|
+
};
|
|
608
|
+
function UiIcon({ name, size = 16, class: className = "" }) {
|
|
609
|
+
const Glyph = ICONS[name];
|
|
610
|
+
if (!Glyph) return null;
|
|
611
|
+
return /* @__PURE__ */ jsx("svg", { class: `scui-icon ${className}`, style: { "--scui-icon-size": `${size}px` }, viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Glyph, {}) });
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// src/textarea.js
|
|
615
|
+
import { useLayoutEffect } from "preact/hooks";
|
|
616
|
+
function useAutosizeTextarea(ref, value) {
|
|
617
|
+
useLayoutEffect(() => {
|
|
618
|
+
const element = ref.current;
|
|
619
|
+
if (!element) return;
|
|
620
|
+
element.style.height = "auto";
|
|
621
|
+
const maxHeight = Number.parseFloat(getComputedStyle(element).maxHeight) || 150;
|
|
622
|
+
const height = Math.min(element.scrollHeight, maxHeight);
|
|
623
|
+
element.style.height = `${height}px`;
|
|
624
|
+
element.style.overflowY = element.scrollHeight > maxHeight ? "auto" : "hidden";
|
|
625
|
+
}, [ref, value]);
|
|
626
|
+
}
|
|
627
|
+
|
|
570
628
|
// src/composer.jsx
|
|
571
|
-
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
629
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
572
630
|
var composerMemory = /* @__PURE__ */ new Map();
|
|
573
631
|
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
574
632
|
if (state.mode !== "mirror" || state.canSend) return null;
|
|
@@ -578,16 +636,16 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
578
636
|
const resume = canContinueHere(state);
|
|
579
637
|
const join = state.canAttach;
|
|
580
638
|
const branch = state.canBranch;
|
|
581
|
-
if (!resume && !join && !branch) return /* @__PURE__ */
|
|
582
|
-
/* @__PURE__ */
|
|
583
|
-
/* @__PURE__ */
|
|
639
|
+
if (!resume && !join && !branch) return /* @__PURE__ */ jsx2("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs2("span", { children: [
|
|
640
|
+
/* @__PURE__ */ jsx2("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
641
|
+
/* @__PURE__ */ jsx2("small", { children: "This session cannot be continued by an available harness." })
|
|
584
642
|
] }) });
|
|
585
|
-
return /* @__PURE__ */
|
|
586
|
-
/* @__PURE__ */
|
|
587
|
-
/* @__PURE__ */
|
|
588
|
-
/* @__PURE__ */
|
|
643
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-continuation", children: [
|
|
644
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
645
|
+
/* @__PURE__ */ jsx2("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
646
|
+
/* @__PURE__ */ jsx2("small", { children: join ? "Join the proven live runtime without taking it over." : resume ? `Resume this ${harnessDisplayName(state.harness)} session here.` : "Start an independent continuation." })
|
|
589
647
|
] }),
|
|
590
|
-
/* @__PURE__ */
|
|
648
|
+
/* @__PURE__ */ jsx2("button", { type: "button", disabled: Boolean(state.operation), onClick: () => adapter.onIntent(join ? { action: "join" } : resume ? { action: "resume" } : { action: "branch" }), children: join ? labels.joinLive : resume ? labels.continueHere : labels.forkHere })
|
|
591
649
|
] });
|
|
592
650
|
}
|
|
593
651
|
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
|
|
@@ -596,6 +654,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
596
654
|
const [queue, setQueue] = useState(remembered.queue);
|
|
597
655
|
const [dispatching, setDispatching] = useState(false);
|
|
598
656
|
const textarea = useRef(null);
|
|
657
|
+
useAutosizeTextarea(textarea, draft);
|
|
599
658
|
const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
|
|
600
659
|
const updateQueue = (update) => setQueue((items) => {
|
|
601
660
|
const next = update(items);
|
|
@@ -643,19 +702,19 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
643
702
|
setDraft("");
|
|
644
703
|
remember("", queuesNewMessage ? [...queue, text] : queue);
|
|
645
704
|
};
|
|
646
|
-
return /* @__PURE__ */
|
|
647
|
-
queue.length ? /* @__PURE__ */
|
|
648
|
-
/* @__PURE__ */
|
|
705
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-compose", children: [
|
|
706
|
+
queue.length ? /* @__PURE__ */ jsxs2("div", { class: "scui-queue", children: [
|
|
707
|
+
/* @__PURE__ */ jsxs2("strong", { children: [
|
|
649
708
|
queue.length,
|
|
650
709
|
" queued"
|
|
651
710
|
] }),
|
|
652
|
-
queue.map((item, index) => /* @__PURE__ */
|
|
711
|
+
queue.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
|
|
653
712
|
item,
|
|
654
|
-
/* @__PURE__ */
|
|
713
|
+
/* @__PURE__ */ jsx2("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 13 }) })
|
|
655
714
|
] }, `${index}:${item}`))
|
|
656
715
|
] }) : null,
|
|
657
|
-
/* @__PURE__ */
|
|
658
|
-
/* @__PURE__ */
|
|
716
|
+
/* @__PURE__ */ jsxs2("div", { class: "scui-envelope", children: [
|
|
717
|
+
/* @__PURE__ */ jsx2("textarea", { ref: textarea, rows: 1, "aria-label": `Message ${harnessDisplayName(state.harness) || "agent"}`, placeholder: state.startup !== "ready" ? "Connecting\u2026" : pendingStatus === "failed" ? "Retry or edit the unsent message\u2026" : pendingStatus === "editing" ? "Edit and resend\u2026" : queueBlocked ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onInput: (event) => {
|
|
659
718
|
const value = event.currentTarget.value;
|
|
660
719
|
setDraft(value);
|
|
661
720
|
remember(value, queue);
|
|
@@ -665,35 +724,113 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
665
724
|
send();
|
|
666
725
|
}
|
|
667
726
|
} }),
|
|
668
|
-
/* @__PURE__ */
|
|
669
|
-
state.busy ? /* @__PURE__ */
|
|
670
|
-
/* @__PURE__ */
|
|
727
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
728
|
+
state.busy ? /* @__PURE__ */ jsx2("button", { class: "scui-stop", type: "button", "aria-label": "Stop agent", disabled: !state.canInterrupt, onClick: () => adapter.onIntent({ action: "interrupt" }), children: /* @__PURE__ */ jsx2(UiIcon, { name: "stop", size: 15 }) }) : null,
|
|
729
|
+
/* @__PURE__ */ jsx2("button", { class: "scui-send", type: "button", "aria-label": queuesNewMessage ? "Queue message" : "Send message", disabled: !draft.trim() || !queuesNewMessage && !state.canSend, onClick: send, children: /* @__PURE__ */ jsx2(UiIcon, { name: queuesNewMessage ? "plus" : "send", size: 17 }) })
|
|
671
730
|
] })
|
|
672
731
|
] })
|
|
673
732
|
] });
|
|
674
733
|
}
|
|
675
734
|
|
|
676
735
|
// src/conversation.jsx
|
|
677
|
-
import {
|
|
736
|
+
import { Fragment as Fragment2 } from "preact";
|
|
737
|
+
import { useEffect as useEffect3, useId, useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState2 } from "preact/hooks";
|
|
678
738
|
|
|
679
739
|
// src/markdown.jsx
|
|
680
740
|
import MarkdownIt from "markdown-it";
|
|
681
|
-
import { useMemo } from "preact/hooks";
|
|
682
|
-
import { jsx as
|
|
741
|
+
import { useEffect as useEffect2, useMemo, useRef as useRef2 } from "preact/hooks";
|
|
742
|
+
import { jsx as jsx3 } from "preact/jsx-runtime";
|
|
683
743
|
var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
|
|
744
|
+
var LANGUAGE_LABELS = {
|
|
745
|
+
bash: "Shell",
|
|
746
|
+
css: "CSS",
|
|
747
|
+
html: "HTML",
|
|
748
|
+
js: "JavaScript",
|
|
749
|
+
javascript: "JavaScript",
|
|
750
|
+
jsx: "JSX",
|
|
751
|
+
md: "Markdown",
|
|
752
|
+
markdown: "Markdown",
|
|
753
|
+
py: "Python",
|
|
754
|
+
python: "Python",
|
|
755
|
+
rs: "Rust",
|
|
756
|
+
rust: "Rust",
|
|
757
|
+
sh: "Shell",
|
|
758
|
+
shell: "Shell",
|
|
759
|
+
ts: "TypeScript",
|
|
760
|
+
tsx: "TSX",
|
|
761
|
+
yaml: "YAML",
|
|
762
|
+
yml: "YAML",
|
|
763
|
+
json: "JSON",
|
|
764
|
+
jsonc: "JSONC",
|
|
765
|
+
sql: "SQL",
|
|
766
|
+
xml: "XML"
|
|
767
|
+
};
|
|
768
|
+
var COPY_ICON = '<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="5" width="8" height="8" rx="1.5"></rect><path d="M3 10.5V4.25C3 3.56 3.56 3 4.25 3h6.25"></path></svg>';
|
|
769
|
+
function languageLabel(info) {
|
|
770
|
+
const language = info.trim().split(/\s+/, 1)[0]?.toLocaleLowerCase() ?? "";
|
|
771
|
+
if (!language) return "Code";
|
|
772
|
+
return LANGUAGE_LABELS[language] ?? language.toLocaleUpperCase();
|
|
773
|
+
}
|
|
774
|
+
function frameCode(render, tokens, index, options, env, self) {
|
|
775
|
+
const label = markdown.utils.escapeHtml(languageLabel(tokens[index]?.info ?? ""));
|
|
776
|
+
return `<div class="scui-code-block"><div class="scui-code-head"><span>${label}</span><button class="scui-code-copy" type="button" aria-label="Copy code" title="Copy code">${COPY_ICON}<span>Copy</span></button></div>${render(tokens, index, options, env, self)}</div>`;
|
|
777
|
+
}
|
|
778
|
+
for (const kind of ["fence", "code_block"]) {
|
|
779
|
+
const render = markdown.renderer.rules[kind];
|
|
780
|
+
markdown.renderer.rules[kind] = (tokens, index, options, env, self) => frameCode(render, tokens, index, options, env, self);
|
|
781
|
+
}
|
|
684
782
|
var defaultLinkOpen = markdown.renderer.rules.link_open;
|
|
685
783
|
markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
|
|
686
784
|
tokens[index]?.attrSet("target", "_blank");
|
|
687
785
|
tokens[index]?.attrSet("rel", "noreferrer noopener");
|
|
688
786
|
return defaultLinkOpen ? defaultLinkOpen(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
|
|
689
787
|
};
|
|
690
|
-
function
|
|
788
|
+
function setCopyState(button, status) {
|
|
789
|
+
const labels = {
|
|
790
|
+
idle: ["Copy code", "Copy"],
|
|
791
|
+
copied: ["Code copied", "Copied"],
|
|
792
|
+
failed: ["Copy failed \xB7 retry", "Retry"]
|
|
793
|
+
};
|
|
794
|
+
const [label, visible] = labels[status];
|
|
795
|
+
button.dataset.status = status;
|
|
796
|
+
button.setAttribute("aria-label", label);
|
|
797
|
+
button.setAttribute("title", label);
|
|
798
|
+
const text = button.querySelector("span");
|
|
799
|
+
if (text) text.textContent = visible;
|
|
800
|
+
}
|
|
801
|
+
function Markdown({ value, copyText }) {
|
|
691
802
|
const html = useMemo(() => markdown.render(value), [value]);
|
|
692
|
-
|
|
803
|
+
const resets = useRef2(/* @__PURE__ */ new Map());
|
|
804
|
+
useEffect2(() => () => {
|
|
805
|
+
for (const timer of resets.current.values()) clearTimeout(timer);
|
|
806
|
+
resets.current.clear();
|
|
807
|
+
}, []);
|
|
808
|
+
const copyCode = async (event) => {
|
|
809
|
+
const button = event.target.closest?.(".scui-code-copy");
|
|
810
|
+
if (!button || !event.currentTarget.contains(button) || !copyText) return;
|
|
811
|
+
const code = button.closest(".scui-code-block")?.querySelector("pre code");
|
|
812
|
+
if (!code) return;
|
|
813
|
+
button.disabled = true;
|
|
814
|
+
try {
|
|
815
|
+
await copyText(code.textContent ?? "");
|
|
816
|
+
setCopyState(button, "copied");
|
|
817
|
+
} catch {
|
|
818
|
+
setCopyState(button, "failed");
|
|
819
|
+
} finally {
|
|
820
|
+
button.disabled = false;
|
|
821
|
+
}
|
|
822
|
+
clearTimeout(resets.current.get(button));
|
|
823
|
+
const timer = setTimeout(() => {
|
|
824
|
+
if (button.isConnected) setCopyState(button, "idle");
|
|
825
|
+
resets.current.delete(button);
|
|
826
|
+
}, 1500);
|
|
827
|
+
resets.current.set(button, timer);
|
|
828
|
+
};
|
|
829
|
+
return /* @__PURE__ */ jsx3("div", { class: "scui-markdown", "data-copyable": Boolean(copyText), onClick: copyCode, dangerouslySetInnerHTML: { __html: html } });
|
|
693
830
|
}
|
|
694
831
|
|
|
695
832
|
// src/conversation.jsx
|
|
696
|
-
import { Fragment, jsx as
|
|
833
|
+
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
697
834
|
function LoadingStatus({ state, compact = false }) {
|
|
698
835
|
const copy = {
|
|
699
836
|
connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
|
|
@@ -701,81 +838,104 @@ function LoadingStatus({ state, compact = false }) {
|
|
|
701
838
|
discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
|
|
702
839
|
ready: ["Ready", "Coding sessions are up to date.", 3]
|
|
703
840
|
}[state.startup];
|
|
704
|
-
return /* @__PURE__ */
|
|
705
|
-
/* @__PURE__ */
|
|
706
|
-
/* @__PURE__ */
|
|
707
|
-
/* @__PURE__ */
|
|
708
|
-
/* @__PURE__ */
|
|
841
|
+
return /* @__PURE__ */ jsxs3("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
|
|
842
|
+
/* @__PURE__ */ jsx4("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("i", {}) }),
|
|
843
|
+
/* @__PURE__ */ jsxs3("span", { class: "scui-loading-copy", children: [
|
|
844
|
+
/* @__PURE__ */ jsx4("strong", { children: copy[0] }),
|
|
845
|
+
/* @__PURE__ */ jsx4("small", { children: copy[1] })
|
|
709
846
|
] }),
|
|
710
|
-
/* @__PURE__ */
|
|
847
|
+
/* @__PURE__ */ jsx4("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx4("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
|
|
711
848
|
] });
|
|
712
849
|
}
|
|
713
850
|
function RequestCard({ entry, adapter, canRespond }) {
|
|
714
851
|
const request = entry.request;
|
|
715
852
|
if (!request) return null;
|
|
716
853
|
if (request.status === "responded") {
|
|
717
|
-
return /* @__PURE__ */
|
|
854
|
+
return /* @__PURE__ */ jsxs3("div", { class: "scui-request-done", children: [
|
|
718
855
|
"\u2713 Request answered \xB7 ",
|
|
719
856
|
request.resolution?.name ?? request.requestKind
|
|
720
857
|
] });
|
|
721
858
|
}
|
|
722
|
-
return /* @__PURE__ */
|
|
723
|
-
/* @__PURE__ */
|
|
724
|
-
/* @__PURE__ */
|
|
725
|
-
/* @__PURE__ */
|
|
726
|
-
request.options.map((option) => /* @__PURE__ */
|
|
727
|
-
request.cancellable ? /* @__PURE__ */
|
|
859
|
+
return /* @__PURE__ */ jsxs3("section", { class: "scui-request", role: "alert", "aria-label": `${request.requestKind} needs input`, children: [
|
|
860
|
+
/* @__PURE__ */ jsx4("strong", { children: "Agent needs input" }),
|
|
861
|
+
/* @__PURE__ */ jsx4(Markdown, { value: request.payloadText || entry.text, copyText: adapter?.copyText }),
|
|
862
|
+
/* @__PURE__ */ jsxs3("div", { class: "scui-request-actions", children: [
|
|
863
|
+
request.options.map((option) => /* @__PURE__ */ jsx4("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: option.optionId }), children: option.name }, option.optionId)),
|
|
864
|
+
request.cancellable ? /* @__PURE__ */ jsx4("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
|
|
728
865
|
] })
|
|
729
866
|
] });
|
|
730
867
|
}
|
|
731
868
|
function ContextDisclosure({ context }) {
|
|
732
869
|
if (!context?.length) return null;
|
|
733
|
-
return /* @__PURE__ */
|
|
734
|
-
/* @__PURE__ */
|
|
870
|
+
return /* @__PURE__ */ jsxs3("details", { class: "scui-context", children: [
|
|
871
|
+
/* @__PURE__ */ jsxs3("summary", { children: [
|
|
735
872
|
"Context \xB7 ",
|
|
736
873
|
context.length
|
|
737
874
|
] }),
|
|
738
|
-
/* @__PURE__ */
|
|
739
|
-
/* @__PURE__ */
|
|
740
|
-
/* @__PURE__ */
|
|
875
|
+
/* @__PURE__ */ jsx4("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs3("p", { children: [
|
|
876
|
+
/* @__PURE__ */ jsx4("strong", { children: item.label }),
|
|
877
|
+
/* @__PURE__ */ jsx4("span", { children: item.detail })
|
|
741
878
|
] }, item.id ?? index)) })
|
|
742
879
|
] });
|
|
743
880
|
}
|
|
881
|
+
function MessageMeta({ entry, adapter }) {
|
|
882
|
+
const [copyState, setCopyState2] = useState2("idle");
|
|
883
|
+
const reset = useRef3(null);
|
|
884
|
+
useEffect3(() => () => clearTimeout(reset.current), []);
|
|
885
|
+
const date = entry.ts === null ? null : new Date(entry.ts);
|
|
886
|
+
const validDate = date && Number.isFinite(date.valueOf()) ? date : null;
|
|
887
|
+
if (!validDate && (!adapter?.copyText || !entry.text)) return null;
|
|
888
|
+
const copy = async () => {
|
|
889
|
+
try {
|
|
890
|
+
await adapter.copyText(entry.text);
|
|
891
|
+
setCopyState2("copied");
|
|
892
|
+
} catch {
|
|
893
|
+
setCopyState2("failed");
|
|
894
|
+
}
|
|
895
|
+
clearTimeout(reset.current);
|
|
896
|
+
reset.current = setTimeout(() => setCopyState2("idle"), 1500);
|
|
897
|
+
};
|
|
898
|
+
const copyLabel = copyState === "copied" ? "Message copied" : copyState === "failed" ? "Copy failed \xB7 retry" : "Copy message";
|
|
899
|
+
return /* @__PURE__ */ jsxs3("footer", { class: "scui-message-meta", children: [
|
|
900
|
+
validDate ? /* @__PURE__ */ jsx4("time", { dateTime: validDate.toISOString(), title: validDate.toLocaleString(), children: validDate.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }) : null,
|
|
901
|
+
adapter?.copyText && entry.text ? /* @__PURE__ */ jsx4("button", { type: "button", "aria-label": copyLabel, title: copyLabel, onClick: copy, "data-status": copyState, children: /* @__PURE__ */ jsx4(UiIcon, { name: "copy", size: 13 }) }) : null
|
|
902
|
+
] });
|
|
903
|
+
}
|
|
744
904
|
var TOOL_ICONS = {
|
|
745
|
-
read: () => /* @__PURE__ */
|
|
746
|
-
/* @__PURE__ */
|
|
747
|
-
/* @__PURE__ */
|
|
905
|
+
read: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
906
|
+
/* @__PURE__ */ jsx4("path", { d: "M5 2.75h7.25L15 5.5v7.75A1.75 1.75 0 0 1 13.25 15h-8.5A1.75 1.75 0 0 1 3 13.25v-8.5A2 2 0 0 1 5 2.75Z" }),
|
|
907
|
+
/* @__PURE__ */ jsx4("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
|
|
748
908
|
] }),
|
|
749
|
-
search: () => /* @__PURE__ */
|
|
750
|
-
/* @__PURE__ */
|
|
751
|
-
/* @__PURE__ */
|
|
909
|
+
search: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
910
|
+
/* @__PURE__ */ jsx4("circle", { cx: "8", cy: "8", r: "4.5" }),
|
|
911
|
+
/* @__PURE__ */ jsx4("path", { d: "m11.5 11.5 3 3" })
|
|
752
912
|
] }),
|
|
753
|
-
edit: () => /* @__PURE__ */
|
|
754
|
-
/* @__PURE__ */
|
|
755
|
-
/* @__PURE__ */
|
|
913
|
+
edit: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
914
|
+
/* @__PURE__ */ jsx4("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
|
|
915
|
+
/* @__PURE__ */ jsx4("path", { d: "m10 5 3 3" })
|
|
756
916
|
] }),
|
|
757
|
-
command: () => /* @__PURE__ */
|
|
758
|
-
test: () => /* @__PURE__ */
|
|
759
|
-
/* @__PURE__ */
|
|
760
|
-
/* @__PURE__ */
|
|
917
|
+
command: () => /* @__PURE__ */ jsx4(Fragment3, { children: /* @__PURE__ */ jsx4("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
|
|
918
|
+
test: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
919
|
+
/* @__PURE__ */ jsx4("path", { d: "M6 2.5v3L3 12a2 2 0 0 0 1.8 3h8.4a2 2 0 0 0 1.8-3l-3-6.5v-3M5 9h8" }),
|
|
920
|
+
/* @__PURE__ */ jsx4("path", { d: "M5 2.5h8" })
|
|
761
921
|
] }),
|
|
762
|
-
web: () => /* @__PURE__ */
|
|
763
|
-
/* @__PURE__ */
|
|
764
|
-
/* @__PURE__ */
|
|
922
|
+
web: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
923
|
+
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "6.5" }),
|
|
924
|
+
/* @__PURE__ */ jsx4("path", { d: "M2.75 9h12.5M9 2.5c2 1.8 3 4 3 6.5s-1 4.7-3 6.5c-2-1.8-3-4-3-6.5s1-4.7 3-6.5Z" })
|
|
765
925
|
] }),
|
|
766
|
-
agent: () => /* @__PURE__ */
|
|
767
|
-
/* @__PURE__ */
|
|
768
|
-
/* @__PURE__ */
|
|
926
|
+
agent: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
927
|
+
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "6", r: "2.5" }),
|
|
928
|
+
/* @__PURE__ */ jsx4("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
|
|
769
929
|
] }),
|
|
770
|
-
plan: () => /* @__PURE__ */
|
|
771
|
-
other: () => /* @__PURE__ */
|
|
772
|
-
/* @__PURE__ */
|
|
773
|
-
/* @__PURE__ */
|
|
930
|
+
plan: () => /* @__PURE__ */ jsx4(Fragment3, { children: /* @__PURE__ */ jsx4("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
|
|
931
|
+
other: () => /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
932
|
+
/* @__PURE__ */ jsx4("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
|
|
933
|
+
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "3.5" })
|
|
774
934
|
] })
|
|
775
935
|
};
|
|
776
936
|
function ToolIcon({ category }) {
|
|
777
937
|
const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
|
|
778
|
-
return /* @__PURE__ */
|
|
938
|
+
return /* @__PURE__ */ jsx4("svg", { class: "scui-tool-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.35", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(Glyph, {}) });
|
|
779
939
|
}
|
|
780
940
|
function toolAction2(entry, category, presentation) {
|
|
781
941
|
if (presentation?.action) return presentation.action;
|
|
@@ -830,86 +990,86 @@ function ToolMetrics({ presentation }) {
|
|
|
830
990
|
presentation.exitCode === null ? "" : `exit ${presentation.exitCode}`,
|
|
831
991
|
formatDuration(presentation.durationMs)
|
|
832
992
|
].filter(Boolean);
|
|
833
|
-
return metrics.length ? /* @__PURE__ */
|
|
993
|
+
return metrics.length ? /* @__PURE__ */ jsx4("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx4("span", { children: metric }, metric)) }) : null;
|
|
834
994
|
}
|
|
835
995
|
function PendingElapsed({ now }) {
|
|
836
996
|
const clock = now ?? Date.now;
|
|
837
|
-
const started =
|
|
997
|
+
const started = useRef3(clock());
|
|
838
998
|
const [elapsed, setElapsed] = useState2(0);
|
|
839
|
-
|
|
999
|
+
useEffect3(() => {
|
|
840
1000
|
const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
|
|
841
1001
|
return () => clearInterval(timer);
|
|
842
1002
|
}, [clock]);
|
|
843
|
-
return /* @__PURE__ */
|
|
1003
|
+
return /* @__PURE__ */ jsx4("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
|
|
844
1004
|
}
|
|
845
1005
|
function LinePreview({ value, kind }) {
|
|
846
1006
|
if (!value) return null;
|
|
847
|
-
return /* @__PURE__ */
|
|
1007
|
+
return /* @__PURE__ */ jsx4("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
|
|
848
1008
|
const tone = kind === "diff" ? line.startsWith("+") && !line.startsWith("+++") ? "add" : line.startsWith("-") && !line.startsWith("---") ? "remove" : line.startsWith("@@") ? "hunk" : "plain" : "plain";
|
|
849
|
-
return /* @__PURE__ */
|
|
850
|
-
/* @__PURE__ */
|
|
851
|
-
/* @__PURE__ */
|
|
1009
|
+
return /* @__PURE__ */ jsxs3("li", { "data-tone": tone, children: [
|
|
1010
|
+
/* @__PURE__ */ jsx4("span", { children: index + 1 }),
|
|
1011
|
+
/* @__PURE__ */ jsx4("code", { children: line || " " })
|
|
852
1012
|
] }, index);
|
|
853
1013
|
}) });
|
|
854
1014
|
}
|
|
855
1015
|
function TerminalPreview({ presentation, pending, failed }) {
|
|
856
|
-
return /* @__PURE__ */
|
|
857
|
-
/* @__PURE__ */
|
|
858
|
-
/* @__PURE__ */
|
|
859
|
-
/* @__PURE__ */
|
|
860
|
-
/* @__PURE__ */
|
|
861
|
-
/* @__PURE__ */
|
|
1016
|
+
return /* @__PURE__ */ jsxs3("section", { class: "scui-terminal", children: [
|
|
1017
|
+
/* @__PURE__ */ jsxs3("header", { children: [
|
|
1018
|
+
/* @__PURE__ */ jsxs3("span", { "aria-hidden": "true", children: [
|
|
1019
|
+
/* @__PURE__ */ jsx4("i", {}),
|
|
1020
|
+
/* @__PURE__ */ jsx4("i", {}),
|
|
1021
|
+
/* @__PURE__ */ jsx4("i", {})
|
|
862
1022
|
] }),
|
|
863
|
-
/* @__PURE__ */
|
|
1023
|
+
/* @__PURE__ */ jsx4("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
|
|
864
1024
|
] }),
|
|
865
|
-
presentation.preview ? /* @__PURE__ */
|
|
866
|
-
/* @__PURE__ */
|
|
1025
|
+
presentation.preview ? /* @__PURE__ */ jsx4("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs3("div", { class: "scui-terminal-wait", children: [
|
|
1026
|
+
/* @__PURE__ */ jsx4("i", {}),
|
|
867
1027
|
" Waiting for output"
|
|
868
|
-
] }) : /* @__PURE__ */
|
|
1028
|
+
] }) : /* @__PURE__ */ jsx4("div", { class: "scui-terminal-empty", children: "No output" })
|
|
869
1029
|
] });
|
|
870
1030
|
}
|
|
871
1031
|
function SearchPreview({ presentation }) {
|
|
872
1032
|
const lines = stripAnsi(presentation.preview).split("\n").filter(Boolean);
|
|
873
|
-
return /* @__PURE__ */
|
|
874
|
-
presentation.query ? /* @__PURE__ */
|
|
875
|
-
/* @__PURE__ */
|
|
876
|
-
/* @__PURE__ */
|
|
1033
|
+
return /* @__PURE__ */ jsxs3("section", { class: "scui-search-preview", children: [
|
|
1034
|
+
presentation.query ? /* @__PURE__ */ jsxs3("header", { children: [
|
|
1035
|
+
/* @__PURE__ */ jsx4("span", { children: "Search" }),
|
|
1036
|
+
/* @__PURE__ */ jsx4("code", { children: presentation.query })
|
|
877
1037
|
] }) : null,
|
|
878
|
-
lines.length ? /* @__PURE__ */
|
|
1038
|
+
lines.length ? /* @__PURE__ */ jsx4("ol", { children: lines.map((line, index) => {
|
|
879
1039
|
const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
|
|
880
|
-
return /* @__PURE__ */
|
|
881
|
-
/* @__PURE__ */
|
|
882
|
-
/* @__PURE__ */
|
|
1040
|
+
return /* @__PURE__ */ jsx4("li", { children: match ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
1041
|
+
/* @__PURE__ */ jsx4("code", { children: match[1] }),
|
|
1042
|
+
/* @__PURE__ */ jsxs3("small", { children: [
|
|
883
1043
|
match[2],
|
|
884
1044
|
match[3] ? `:${match[3]}` : ""
|
|
885
1045
|
] }),
|
|
886
|
-
/* @__PURE__ */
|
|
887
|
-
] }) : /* @__PURE__ */
|
|
888
|
-
}) }) : /* @__PURE__ */
|
|
1046
|
+
/* @__PURE__ */ jsx4("span", { children: match[4] })
|
|
1047
|
+
] }) : /* @__PURE__ */ jsx4("span", { children: line }) }, index);
|
|
1048
|
+
}) }) : /* @__PURE__ */ jsx4("p", { children: "No textual results" })
|
|
889
1049
|
] });
|
|
890
1050
|
}
|
|
891
1051
|
function ToolPreview({ presentation, entry }) {
|
|
892
1052
|
const pending = entry.status === "pending";
|
|
893
1053
|
const failed = entry.status === "error";
|
|
894
|
-
if (presentation.detail === "terminal") return /* @__PURE__ */
|
|
895
|
-
if (presentation.detail === "diff") return presentation.preview ? /* @__PURE__ */
|
|
896
|
-
if (presentation.detail === "file") return presentation.preview ? /* @__PURE__ */
|
|
897
|
-
if (presentation.detail === "matches") return /* @__PURE__ */
|
|
898
|
-
if (presentation.detail === "web") return /* @__PURE__ */
|
|
899
|
-
presentation.url ? /* @__PURE__ */
|
|
900
|
-
presentation.preview ? /* @__PURE__ */
|
|
1054
|
+
if (presentation.detail === "terminal") return /* @__PURE__ */ jsx4(TerminalPreview, { presentation, pending, failed });
|
|
1055
|
+
if (presentation.detail === "diff") return presentation.preview ? /* @__PURE__ */ jsx4(LinePreview, { value: presentation.preview, kind: "diff" }) : /* @__PURE__ */ jsx4("div", { class: "scui-tool-empty", children: "Edit completed without a textual diff" });
|
|
1056
|
+
if (presentation.detail === "file") return presentation.preview ? /* @__PURE__ */ jsx4(LinePreview, { value: presentation.preview, kind: "file" }) : /* @__PURE__ */ jsx4("div", { class: "scui-tool-empty", children: "File contents were not included in this event" });
|
|
1057
|
+
if (presentation.detail === "matches") return /* @__PURE__ */ jsx4(SearchPreview, { presentation });
|
|
1058
|
+
if (presentation.detail === "web") return /* @__PURE__ */ jsxs3("section", { class: "scui-web-preview", children: [
|
|
1059
|
+
presentation.url ? /* @__PURE__ */ jsx4("code", { children: presentation.url }) : null,
|
|
1060
|
+
presentation.preview ? /* @__PURE__ */ jsx4("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx4("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
|
|
901
1061
|
] });
|
|
902
|
-
if (presentation.detail === "agent") return /* @__PURE__ */
|
|
903
|
-
if (presentation.detail === "plan") return /* @__PURE__ */
|
|
904
|
-
/* @__PURE__ */
|
|
905
|
-
/* @__PURE__ */
|
|
1062
|
+
if (presentation.detail === "agent") return /* @__PURE__ */ jsx4("section", { class: "scui-agent-preview", children: presentation.preview ? /* @__PURE__ */ jsx4("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx4("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
|
|
1063
|
+
if (presentation.detail === "plan") return /* @__PURE__ */ jsx4("ol", { class: "scui-plan-preview", children: presentation.items?.map((item, index) => /* @__PURE__ */ jsxs3("li", { "data-status": item.status, children: [
|
|
1064
|
+
/* @__PURE__ */ jsx4("i", { "aria-hidden": "true" }),
|
|
1065
|
+
/* @__PURE__ */ jsx4("span", { children: item.label })
|
|
906
1066
|
] }, `${item.label}:${index}`)) });
|
|
907
|
-
return presentation.preview ? /* @__PURE__ */
|
|
1067
|
+
return presentation.preview ? /* @__PURE__ */ jsx4("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
|
|
908
1068
|
}
|
|
909
1069
|
function ToolActions({ presentation, adapter }) {
|
|
910
1070
|
const [copied, setCopied] = useState2(false);
|
|
911
|
-
const reset =
|
|
912
|
-
|
|
1071
|
+
const reset = useRef3(null);
|
|
1072
|
+
useEffect3(() => () => clearTimeout(reset.current), []);
|
|
913
1073
|
if (!adapter?.copyText) return null;
|
|
914
1074
|
const action = presentation.command ? ["Copy command", presentation.command] : presentation.path ? ["Copy path", presentation.path] : presentation.url ? ["Copy URL", presentation.url] : presentation.query ? ["Copy query", presentation.query] : null;
|
|
915
1075
|
const copy = async () => {
|
|
@@ -918,27 +1078,27 @@ function ToolActions({ presentation, adapter }) {
|
|
|
918
1078
|
clearTimeout(reset.current);
|
|
919
1079
|
reset.current = setTimeout(() => setCopied(false), 1500);
|
|
920
1080
|
};
|
|
921
|
-
return action ? /* @__PURE__ */
|
|
1081
|
+
return action ? /* @__PURE__ */ jsx4("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx4("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
|
|
922
1082
|
}
|
|
923
1083
|
function ToolStack({ tools }) {
|
|
924
1084
|
if (tools.length < 2) return null;
|
|
925
|
-
return /* @__PURE__ */
|
|
1085
|
+
return /* @__PURE__ */ jsx4("div", { class: "scui-tool-stack", "aria-label": "Coordinated tools", children: tools.map((tool) => /* @__PURE__ */ jsx4("span", { children: tool.replaceAll("__", " \xB7 ").replaceAll("_", " ") }, tool)) });
|
|
926
1086
|
}
|
|
927
1087
|
function TechnicalDetails({ entry }) {
|
|
928
1088
|
if (!entry.arguments && !entry.resultText) return null;
|
|
929
|
-
return /* @__PURE__ */
|
|
930
|
-
/* @__PURE__ */
|
|
931
|
-
/* @__PURE__ */
|
|
932
|
-
entry.arguments ? /* @__PURE__ */
|
|
933
|
-
/* @__PURE__ */
|
|
934
|
-
/* @__PURE__ */
|
|
935
|
-
/* @__PURE__ */
|
|
936
|
-
/* @__PURE__ */
|
|
1089
|
+
return /* @__PURE__ */ jsxs3("details", { class: "scui-tool-technical", children: [
|
|
1090
|
+
/* @__PURE__ */ jsx4("summary", { children: "Technical details" }),
|
|
1091
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1092
|
+
entry.arguments ? /* @__PURE__ */ jsxs3("section", { children: [
|
|
1093
|
+
/* @__PURE__ */ jsx4("strong", { children: "Native arguments" }),
|
|
1094
|
+
/* @__PURE__ */ jsx4("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs3("div", { children: [
|
|
1095
|
+
/* @__PURE__ */ jsx4("dt", { children: row.label }),
|
|
1096
|
+
/* @__PURE__ */ jsx4("dd", { children: /* @__PURE__ */ jsx4("pre", { children: row.value }) })
|
|
937
1097
|
] }, row.key)) })
|
|
938
1098
|
] }) : null,
|
|
939
|
-
entry.resultText ? /* @__PURE__ */
|
|
940
|
-
/* @__PURE__ */
|
|
941
|
-
/* @__PURE__ */
|
|
1099
|
+
entry.resultText ? /* @__PURE__ */ jsxs3("section", { children: [
|
|
1100
|
+
/* @__PURE__ */ jsx4("strong", { children: "Native result" }),
|
|
1101
|
+
/* @__PURE__ */ jsxs3("pre", { "data-error": entry.status === "error", children: [
|
|
942
1102
|
entry.resultText,
|
|
943
1103
|
entry.truncated ? "\n[truncated]" : ""
|
|
944
1104
|
] })
|
|
@@ -947,125 +1107,126 @@ function TechnicalDetails({ entry }) {
|
|
|
947
1107
|
] });
|
|
948
1108
|
}
|
|
949
1109
|
function TranscriptEntry({ entry, state, adapter }) {
|
|
950
|
-
if (entry.role === "request") return /* @__PURE__ */
|
|
1110
|
+
if (entry.role === "request") return /* @__PURE__ */ jsx4(RequestCard, { entry, adapter, canRespond: state.canRespond });
|
|
951
1111
|
if (entry.role === "reasoning") {
|
|
952
|
-
return /* @__PURE__ */
|
|
953
|
-
/* @__PURE__ */
|
|
954
|
-
/* @__PURE__ */
|
|
1112
|
+
return /* @__PURE__ */ jsxs3("details", { class: "scui-reasoning", open: entry.streaming, children: [
|
|
1113
|
+
/* @__PURE__ */ jsx4("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
|
|
1114
|
+
/* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText })
|
|
955
1115
|
] });
|
|
956
1116
|
}
|
|
957
|
-
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */
|
|
958
|
-
return /* @__PURE__ */
|
|
959
|
-
/* @__PURE__ */
|
|
960
|
-
/* @__PURE__ */
|
|
961
|
-
entry.truncated ? /* @__PURE__ */
|
|
1117
|
+
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx4("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
|
|
1118
|
+
return /* @__PURE__ */ jsxs3("article", { class: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
|
|
1119
|
+
/* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText }),
|
|
1120
|
+
/* @__PURE__ */ jsx4(ContextDisclosure, { context: entry.context }),
|
|
1121
|
+
entry.truncated ? /* @__PURE__ */ jsx4("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
|
|
1122
|
+
/* @__PURE__ */ jsx4(MessageMeta, { entry, adapter })
|
|
962
1123
|
] });
|
|
963
1124
|
}
|
|
964
1125
|
function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
965
1126
|
const presentation = entry.presentation ?? createToolPresentation(entry);
|
|
966
1127
|
const [expanded, setExpanded] = useState2(open || entry.status === "pending");
|
|
967
|
-
|
|
1128
|
+
useEffect3(() => {
|
|
968
1129
|
if (entry.status === "pending") setExpanded(true);
|
|
969
1130
|
}, [entry.status]);
|
|
970
1131
|
const target = compactToolTarget(presentation.target, workspace);
|
|
971
1132
|
const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
|
|
972
1133
|
const category = presentation.category ?? toolCategory(entry);
|
|
973
|
-
const summary = /* @__PURE__ */
|
|
974
|
-
/* @__PURE__ */
|
|
975
|
-
/* @__PURE__ */
|
|
976
|
-
target ? /* @__PURE__ */
|
|
977
|
-
/* @__PURE__ */
|
|
978
|
-
entry.status === "pending" ? /* @__PURE__ */
|
|
979
|
-
/* @__PURE__ */
|
|
980
|
-
hasDetail ? /* @__PURE__ */
|
|
1134
|
+
const summary = /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
1135
|
+
/* @__PURE__ */ jsx4(ToolIcon, { category }),
|
|
1136
|
+
/* @__PURE__ */ jsx4("strong", { children: toolAction2(entry, category, presentation) }),
|
|
1137
|
+
target ? /* @__PURE__ */ jsx4("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
|
|
1138
|
+
/* @__PURE__ */ jsx4("span", { class: "scui-spacer" }),
|
|
1139
|
+
entry.status === "pending" ? /* @__PURE__ */ jsx4(PendingElapsed, { now: adapter?.now }) : null,
|
|
1140
|
+
/* @__PURE__ */ jsx4("span", { class: "scui-tool-status", role: "status", "data-status": entry.status ?? "completed", "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? /* @__PURE__ */ jsx4("i", {}) : /* @__PURE__ */ jsx4(UiIcon, { name: entry.status === "error" ? "close" : "check", size: 12 }) }),
|
|
1141
|
+
hasDetail ? /* @__PURE__ */ jsx4(UiIcon, { name: "chevron", size: 14, class: "scui-tool-chevron" }) : null
|
|
981
1142
|
] });
|
|
982
|
-
if (!hasDetail) return /* @__PURE__ */
|
|
983
|
-
return /* @__PURE__ */
|
|
984
|
-
/* @__PURE__ */
|
|
985
|
-
/* @__PURE__ */
|
|
986
|
-
/* @__PURE__ */
|
|
987
|
-
/* @__PURE__ */
|
|
988
|
-
/* @__PURE__ */
|
|
989
|
-
presentation.fields.length ? /* @__PURE__ */
|
|
990
|
-
/* @__PURE__ */
|
|
991
|
-
/* @__PURE__ */
|
|
1143
|
+
if (!hasDetail) return /* @__PURE__ */ jsx4("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: /* @__PURE__ */ jsx4("div", { class: "scui-tool-head", children: summary }) });
|
|
1144
|
+
return /* @__PURE__ */ jsxs3("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
|
|
1145
|
+
/* @__PURE__ */ jsx4("summary", { class: "scui-tool-head", children: summary }),
|
|
1146
|
+
/* @__PURE__ */ jsxs3("div", { class: "scui-tool-detail", children: [
|
|
1147
|
+
/* @__PURE__ */ jsx4(ToolMetrics, { presentation }),
|
|
1148
|
+
/* @__PURE__ */ jsx4(ToolStack, { tools: presentation.tools ?? [] }),
|
|
1149
|
+
/* @__PURE__ */ jsx4(ToolPreview, { presentation, entry }),
|
|
1150
|
+
presentation.fields.length ? /* @__PURE__ */ jsx4("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs3("div", { children: [
|
|
1151
|
+
/* @__PURE__ */ jsx4("dt", { children: field.label }),
|
|
1152
|
+
/* @__PURE__ */ jsx4("dd", { children: field.value })
|
|
992
1153
|
] }, field.label)) }) : null,
|
|
993
|
-
/* @__PURE__ */
|
|
994
|
-
/* @__PURE__ */
|
|
1154
|
+
/* @__PURE__ */ jsx4(ToolActions, { presentation, adapter }),
|
|
1155
|
+
/* @__PURE__ */ jsx4(TechnicalDetails, { entry })
|
|
995
1156
|
] })
|
|
996
1157
|
] });
|
|
997
1158
|
}
|
|
998
1159
|
function ActivityGroup({ entries, state, adapter }) {
|
|
999
|
-
if (entries.length === 1) return /* @__PURE__ */
|
|
1160
|
+
if (entries.length === 1) return /* @__PURE__ */ jsx4("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx4(ToolRow, { entry: entries[0], workspace: state.workspace, adapter }) });
|
|
1000
1161
|
const active = entries.some((entry) => entry.status === "pending");
|
|
1001
1162
|
const [open, setOpen] = useState2(active);
|
|
1002
1163
|
const id = useId();
|
|
1003
|
-
|
|
1164
|
+
useEffect3(() => {
|
|
1004
1165
|
if (active) setOpen(true);
|
|
1005
1166
|
}, [active]);
|
|
1006
|
-
return /* @__PURE__ */
|
|
1007
|
-
/* @__PURE__ */
|
|
1008
|
-
/* @__PURE__ */
|
|
1009
|
-
/* @__PURE__ */
|
|
1010
|
-
/* @__PURE__ */
|
|
1011
|
-
/* @__PURE__ */
|
|
1167
|
+
return /* @__PURE__ */ jsxs3("section", { class: "scui-activity", children: [
|
|
1168
|
+
/* @__PURE__ */ jsxs3("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
|
|
1169
|
+
/* @__PURE__ */ jsx4("span", { class: "scui-fold", "data-open": open, children: /* @__PURE__ */ jsx4(UiIcon, { name: "chevron", size: 14 }) }),
|
|
1170
|
+
/* @__PURE__ */ jsx4("strong", { children: activitySummary(entries) }),
|
|
1171
|
+
/* @__PURE__ */ jsx4("span", { class: "scui-spacer" }),
|
|
1172
|
+
/* @__PURE__ */ jsxs3("small", { children: [
|
|
1012
1173
|
entries.filter((entry) => entry.status !== "pending").length,
|
|
1013
1174
|
"/",
|
|
1014
1175
|
entries.length
|
|
1015
1176
|
] })
|
|
1016
1177
|
] }),
|
|
1017
|
-
open ? /* @__PURE__ */
|
|
1178
|
+
open ? /* @__PURE__ */ jsx4("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx4(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
|
|
1018
1179
|
] });
|
|
1019
1180
|
}
|
|
1020
1181
|
function TaskPlan({ plan }) {
|
|
1021
1182
|
if (!plan.items.length) return null;
|
|
1022
1183
|
const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
|
|
1023
|
-
return /* @__PURE__ */
|
|
1024
|
-
/* @__PURE__ */
|
|
1025
|
-
/* @__PURE__ */
|
|
1026
|
-
/* @__PURE__ */
|
|
1184
|
+
return /* @__PURE__ */ jsxs3("details", { class: "scui-plan", children: [
|
|
1185
|
+
/* @__PURE__ */ jsxs3("summary", { children: [
|
|
1186
|
+
/* @__PURE__ */ jsx4("span", { children: "Plan" }),
|
|
1187
|
+
/* @__PURE__ */ jsxs3("small", { children: [
|
|
1027
1188
|
complete,
|
|
1028
1189
|
"/",
|
|
1029
1190
|
plan.items.length
|
|
1030
1191
|
] })
|
|
1031
1192
|
] }),
|
|
1032
|
-
/* @__PURE__ */
|
|
1033
|
-
/* @__PURE__ */
|
|
1193
|
+
/* @__PURE__ */ jsx4("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs3("li", { "data-status": item.status, children: [
|
|
1194
|
+
/* @__PURE__ */ jsx4("i", { "aria-hidden": "true" }),
|
|
1034
1195
|
" ",
|
|
1035
|
-
/* @__PURE__ */
|
|
1196
|
+
/* @__PURE__ */ jsx4("span", { children: item.title })
|
|
1036
1197
|
] }, item.id)) })
|
|
1037
1198
|
] });
|
|
1038
1199
|
}
|
|
1039
1200
|
function SessionDetails({ semantics }) {
|
|
1040
1201
|
if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
|
|
1041
|
-
return /* @__PURE__ */
|
|
1042
|
-
/* @__PURE__ */
|
|
1043
|
-
/* @__PURE__ */
|
|
1044
|
-
semantics.fidelity ? /* @__PURE__ */
|
|
1045
|
-
/* @__PURE__ */
|
|
1046
|
-
/* @__PURE__ */
|
|
1202
|
+
return /* @__PURE__ */ jsxs3("details", { class: "scui-details", children: [
|
|
1203
|
+
/* @__PURE__ */ jsx4("summary", { children: "Session details" }),
|
|
1204
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
1205
|
+
semantics.fidelity ? /* @__PURE__ */ jsxs3("p", { children: [
|
|
1206
|
+
/* @__PURE__ */ jsx4("strong", { children: "Fidelity" }),
|
|
1207
|
+
/* @__PURE__ */ jsx4("span", { children: semantics.fidelity.replaceAll("_", " ") })
|
|
1047
1208
|
] }) : null,
|
|
1048
|
-
/* @__PURE__ */
|
|
1049
|
-
/* @__PURE__ */
|
|
1050
|
-
/* @__PURE__ */
|
|
1209
|
+
/* @__PURE__ */ jsxs3("p", { children: [
|
|
1210
|
+
/* @__PURE__ */ jsx4("strong", { children: "Native records" }),
|
|
1211
|
+
/* @__PURE__ */ jsx4("span", { children: semantics.rawRecords })
|
|
1051
1212
|
] }),
|
|
1052
|
-
semantics.residueCount ? /* @__PURE__ */
|
|
1053
|
-
/* @__PURE__ */
|
|
1054
|
-
/* @__PURE__ */
|
|
1213
|
+
semantics.residueCount ? /* @__PURE__ */ jsxs3("p", { children: [
|
|
1214
|
+
/* @__PURE__ */ jsx4("strong", { children: "Residue" }),
|
|
1215
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1055
1216
|
semantics.residueCount,
|
|
1056
1217
|
" retained"
|
|
1057
1218
|
] })
|
|
1058
1219
|
] }) : null,
|
|
1059
|
-
semantics.parseErrors ? /* @__PURE__ */
|
|
1060
|
-
/* @__PURE__ */
|
|
1061
|
-
/* @__PURE__ */
|
|
1220
|
+
semantics.parseErrors ? /* @__PURE__ */ jsxs3("p", { children: [
|
|
1221
|
+
/* @__PURE__ */ jsx4("strong", { children: "Parse diagnostics" }),
|
|
1222
|
+
/* @__PURE__ */ jsx4("span", { children: semantics.parseErrors })
|
|
1062
1223
|
] }) : null,
|
|
1063
|
-
semantics.subagents.map((agent) => /* @__PURE__ */
|
|
1064
|
-
/* @__PURE__ */
|
|
1224
|
+
semantics.subagents.map((agent) => /* @__PURE__ */ jsxs3("p", { children: [
|
|
1225
|
+
/* @__PURE__ */ jsxs3("strong", { children: [
|
|
1065
1226
|
agent.source,
|
|
1066
1227
|
" subagent"
|
|
1067
1228
|
] }),
|
|
1068
|
-
/* @__PURE__ */
|
|
1229
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1069
1230
|
agent.messages,
|
|
1070
1231
|
" messages \xB7 ",
|
|
1071
1232
|
agent.fidelity.replaceAll("_", " ")
|
|
@@ -1075,13 +1236,29 @@ function SessionDetails({ semantics }) {
|
|
|
1075
1236
|
] });
|
|
1076
1237
|
}
|
|
1077
1238
|
var conversationMemory = /* @__PURE__ */ new Map();
|
|
1078
|
-
function
|
|
1079
|
-
const
|
|
1239
|
+
function ConversationAnnouncements({ state }) {
|
|
1240
|
+
const previousBusy = useRef3(state.busy);
|
|
1241
|
+
const [announcement, setAnnouncement] = useState2("");
|
|
1242
|
+
useEffect3(() => {
|
|
1243
|
+
if (previousBusy.current && !state.busy && !state.error) {
|
|
1244
|
+
setAnnouncement(`${harnessDisplayName(state.harness) || "Coding agent"} finished working`);
|
|
1245
|
+
}
|
|
1246
|
+
previousBusy.current = state.busy;
|
|
1247
|
+
}, [state.busy, state.error, state.harness]);
|
|
1248
|
+
return /* @__PURE__ */ jsx4("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
|
|
1249
|
+
}
|
|
1250
|
+
function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null, unreadAfterMessages = null }) {
|
|
1251
|
+
const scroller = useRef3(null);
|
|
1080
1252
|
const remembered = conversationMemory.get(memoryKey) ?? { top: null, atBottom: true };
|
|
1081
1253
|
const [atBottom, setAtBottom] = useState2(remembered.atBottom);
|
|
1082
|
-
const earlierAnchor =
|
|
1083
|
-
const restored =
|
|
1254
|
+
const earlierAnchor = useRef3(null);
|
|
1255
|
+
const restored = useRef3(false);
|
|
1084
1256
|
const blocks = groupConversation(state.transcript);
|
|
1257
|
+
const unreadBoundary = useRef3(Number.isSafeInteger(unreadAfterMessages) && unreadAfterMessages >= 0 ? unreadAfterMessages : null);
|
|
1258
|
+
const unreadBlock = unreadBoundary.current === null ? -1 : blocks.findIndex((block) => {
|
|
1259
|
+
const entries = block.kind === "activity" ? block.entries : [block.entry];
|
|
1260
|
+
return entries.some((entry) => Number.isSafeInteger(entry.messageIndex) && entry.messageIndex > unreadBoundary.current);
|
|
1261
|
+
});
|
|
1085
1262
|
const Entry = components.TranscriptEntry ?? TranscriptEntry;
|
|
1086
1263
|
const Group = components.ActivityGroup ?? ActivityGroup;
|
|
1087
1264
|
const Plan = components.TaskPlan ?? TaskPlan;
|
|
@@ -1096,7 +1273,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1096
1273
|
setAtBottom(true);
|
|
1097
1274
|
remember({ top: scroller.current.scrollTop, atBottom: true });
|
|
1098
1275
|
};
|
|
1099
|
-
|
|
1276
|
+
useLayoutEffect2(() => {
|
|
1100
1277
|
const element = scroller.current;
|
|
1101
1278
|
if (!element) return;
|
|
1102
1279
|
const anchor = earlierAnchor.current;
|
|
@@ -1112,54 +1289,61 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
1112
1289
|
else pin();
|
|
1113
1290
|
} else if (atBottom) pin();
|
|
1114
1291
|
}, [memoryKey, state.transcript, state.busy, state.operation, pendingMessage?.text, pendingMessage?.status]);
|
|
1115
|
-
return /* @__PURE__ */
|
|
1116
|
-
/* @__PURE__ */
|
|
1292
|
+
return /* @__PURE__ */ jsxs3("div", { class: "scui-conversation-wrap", children: [
|
|
1293
|
+
/* @__PURE__ */ jsx4(ConversationAnnouncements, { state }),
|
|
1294
|
+
/* @__PURE__ */ jsx4("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
|
|
1117
1295
|
const element = event.currentTarget;
|
|
1118
1296
|
const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
|
|
1119
1297
|
setAtBottom(bottom);
|
|
1120
1298
|
remember({ top: element.scrollTop, atBottom: bottom });
|
|
1121
|
-
}, children: /* @__PURE__ */
|
|
1122
|
-
Before ? /* @__PURE__ */
|
|
1123
|
-
/* @__PURE__ */
|
|
1124
|
-
/* @__PURE__ */
|
|
1125
|
-
state.history.hasEarlier ? /* @__PURE__ */
|
|
1299
|
+
}, children: /* @__PURE__ */ jsxs3("div", { children: [
|
|
1300
|
+
Before ? /* @__PURE__ */ jsx4(Before, { state, adapter, value: null }) : null,
|
|
1301
|
+
/* @__PURE__ */ jsx4(Plan, { plan: state.taskPlan, value: state.taskPlan, state, adapter }),
|
|
1302
|
+
/* @__PURE__ */ jsx4(SessionDetails, { semantics: state.semantics }),
|
|
1303
|
+
state.history.hasEarlier ? /* @__PURE__ */ jsx4("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
|
|
1126
1304
|
const element = scroller.current;
|
|
1127
1305
|
if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
|
|
1128
1306
|
setAtBottom(false);
|
|
1129
1307
|
adapter.onIntent({ action: "loadEarlier" });
|
|
1130
1308
|
}, children: "Load earlier messages" }) : null,
|
|
1131
|
-
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */
|
|
1132
|
-
!blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */
|
|
1133
|
-
blocks.map((block
|
|
1134
|
-
|
|
1135
|
-
/* @__PURE__ */
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1309
|
+
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx4(LoadingStatus, { state }) : null,
|
|
1310
|
+
!blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx4(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx4("div", { class: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
|
|
1311
|
+
blocks.map((block, index) => /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1312
|
+
index === unreadBlock ? /* @__PURE__ */ jsx4("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx4("span", { children: "New" }) }) : null,
|
|
1313
|
+
block.kind === "activity" ? /* @__PURE__ */ jsx4(Group, { value: block.entries, entries: block.entries, state, adapter }) : /* @__PURE__ */ jsx4(Entry, { value: block.entry, entry: block.entry, state, adapter })
|
|
1314
|
+
] }, block.id)),
|
|
1315
|
+
pendingMessage ? /* @__PURE__ */ jsxs3("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
|
|
1316
|
+
/* @__PURE__ */ jsx4(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
|
|
1317
|
+
/* @__PURE__ */ jsxs3("footer", { children: [
|
|
1318
|
+
/* @__PURE__ */ jsx4("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
|
|
1319
|
+
pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs3("span", { children: [
|
|
1320
|
+
/* @__PURE__ */ jsx4("button", { type: "button", onClick: pendingMessage.onRetry, children: "Retry" }),
|
|
1321
|
+
/* @__PURE__ */ jsx4("button", { type: "button", onClick: pendingMessage.onEdit, children: "Edit" })
|
|
1141
1322
|
] }) : null
|
|
1142
1323
|
] })
|
|
1143
1324
|
] }) : null,
|
|
1144
|
-
state.busy ? /* @__PURE__ */
|
|
1145
|
-
/* @__PURE__ */
|
|
1146
|
-
/* @__PURE__ */
|
|
1147
|
-
/* @__PURE__ */
|
|
1148
|
-
/* @__PURE__ */
|
|
1149
|
-
/* @__PURE__ */
|
|
1325
|
+
state.busy ? /* @__PURE__ */ jsxs3("div", { class: "scui-working", role: "status", children: [
|
|
1326
|
+
/* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
1327
|
+
/* @__PURE__ */ jsx4("i", {}),
|
|
1328
|
+
/* @__PURE__ */ jsx4("i", {}),
|
|
1329
|
+
/* @__PURE__ */ jsx4("i", {}),
|
|
1330
|
+
/* @__PURE__ */ jsxs3("small", { children: [
|
|
1150
1331
|
harnessDisplayName(state.harness),
|
|
1151
1332
|
" is working"
|
|
1152
1333
|
] })
|
|
1153
1334
|
] }) : null,
|
|
1154
|
-
After ? /* @__PURE__ */
|
|
1335
|
+
After ? /* @__PURE__ */ jsx4(After, { state, adapter, value: null }) : null
|
|
1155
1336
|
] }) }),
|
|
1156
|
-
!atBottom ? /* @__PURE__ */
|
|
1337
|
+
!atBottom ? /* @__PURE__ */ jsxs3("button", { class: "scui-latest", type: "button", onClick: pin, children: [
|
|
1338
|
+
/* @__PURE__ */ jsx4(UiIcon, { name: "down", size: 13 }),
|
|
1339
|
+
" Latest"
|
|
1340
|
+
] }) : null
|
|
1157
1341
|
] });
|
|
1158
1342
|
}
|
|
1159
1343
|
|
|
1160
1344
|
// src/logo.jsx
|
|
1161
|
-
import { useEffect as
|
|
1162
|
-
import { jsx as
|
|
1345
|
+
import { useEffect as useEffect4 } from "preact/hooks";
|
|
1346
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
1163
1347
|
var LOGOS = {
|
|
1164
1348
|
"claude-code": {
|
|
1165
1349
|
viewBox: "-1 3.5 26 18",
|
|
@@ -1206,81 +1390,106 @@ var LOGOS = {
|
|
|
1206
1390
|
};
|
|
1207
1391
|
function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
1208
1392
|
const logo = LOGOS[id];
|
|
1209
|
-
|
|
1393
|
+
useEffect4(() => {
|
|
1210
1394
|
if (!logo) onMissingLogo?.(id);
|
|
1211
1395
|
}, [id, logo, onMissingLogo]);
|
|
1212
1396
|
if (!logo) return null;
|
|
1213
|
-
return /* @__PURE__ */
|
|
1214
|
-
/* @__PURE__ */
|
|
1215
|
-
activity && activity !== "idle" ? /* @__PURE__ */
|
|
1397
|
+
return /* @__PURE__ */ jsxs4("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
|
|
1398
|
+
/* @__PURE__ */ jsx5("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx5(Tag, { ...props }, index)) }),
|
|
1399
|
+
activity && activity !== "idle" ? /* @__PURE__ */ jsx5("i", {}) : null
|
|
1216
1400
|
] });
|
|
1217
1401
|
}
|
|
1218
1402
|
|
|
1219
1403
|
// src/sessions.jsx
|
|
1220
|
-
import { useEffect as
|
|
1221
|
-
import { jsx as
|
|
1404
|
+
import { useEffect as useEffect5, useLayoutEffect as useLayoutEffect3, useRef as useRef4, useState as useState3 } from "preact/hooks";
|
|
1405
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
1406
|
+
var sessionListMemory = /* @__PURE__ */ new Map();
|
|
1222
1407
|
function SessionRow({ row, state, onOpen }) {
|
|
1223
1408
|
const activity = sessionActivity(state, row);
|
|
1224
1409
|
const preview = state.attention.find((item) => item.key === row.key)?.preview;
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
/* @__PURE__ */ jsx5("b", { children: harnessDisplayName(row.harness) }),
|
|
1234
|
-
/* @__PURE__ */ jsx5("small", { children: preview || row.cwd || row.name })
|
|
1410
|
+
const title = sessionDisplayName(row);
|
|
1411
|
+
const detail = preview || (row.name && row.name !== title ? row.name : row.cwd);
|
|
1412
|
+
return /* @__PURE__ */ jsxs5("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, "data-session-key": row.key, type: "button", "aria-label": `${title} \xB7 ${harnessDisplayName(row.harness)}${row.age ? ` \xB7 ${row.age}` : ""}`, "aria-current": row.active ? "true" : void 0, onClick: () => onOpen(row), children: [
|
|
1413
|
+
/* @__PURE__ */ jsx6(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
1414
|
+
/* @__PURE__ */ jsxs5("span", { class: "scui-session-copy", children: [
|
|
1415
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
1416
|
+
/* @__PURE__ */ jsx6("strong", { children: title }),
|
|
1417
|
+
/* @__PURE__ */ jsx6("small", { children: row.age })
|
|
1235
1418
|
] }),
|
|
1236
|
-
|
|
1419
|
+
detail ? /* @__PURE__ */ jsx6("span", { children: /* @__PURE__ */ jsx6("small", { title: row.cwd, children: detail }) }) : null,
|
|
1420
|
+
state.attachError?.key === row.key ? /* @__PURE__ */ jsx6("em", { children: state.attachError.message }) : null
|
|
1237
1421
|
] })
|
|
1238
1422
|
] });
|
|
1239
1423
|
}
|
|
1240
|
-
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null }) {
|
|
1241
|
-
const
|
|
1242
|
-
const
|
|
1424
|
+
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS, focusKey = null, memoryKey = state.workspace || "@default" }) {
|
|
1425
|
+
const remembered = sessionListMemory.get(memoryKey) ?? { query: "", top: 0 };
|
|
1426
|
+
const [query, setQuery] = useState3(remembered.query);
|
|
1427
|
+
const [loadingMore, setLoadingMore] = useState3(false);
|
|
1428
|
+
const root = useRef4(null);
|
|
1429
|
+
const rowScroller = useRef4(null);
|
|
1243
1430
|
const rows = filterSessions(state.sessions, query);
|
|
1244
1431
|
const Row = components.SessionRow ?? SessionRow;
|
|
1245
|
-
|
|
1432
|
+
useLayoutEffect3(() => {
|
|
1433
|
+
if (rowScroller.current) rowScroller.current.scrollTop = remembered.top;
|
|
1434
|
+
}, [memoryKey]);
|
|
1435
|
+
useEffect5(() => {
|
|
1246
1436
|
if (!focusKey || !root.current) return;
|
|
1247
1437
|
const target = focusKey === "@new" ? root.current.querySelector('[data-list-focus="new"]') : [...root.current.querySelectorAll("[data-session-key]")].find((element) => element.dataset.sessionKey === focusKey);
|
|
1248
1438
|
(target ?? root.current.querySelector("input,button"))?.focus({ preventScroll: true });
|
|
1249
1439
|
}, [focusKey, rows.length]);
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1440
|
+
useEffect5(() => {
|
|
1441
|
+
if (loadingMore) setLoadingMore(false);
|
|
1442
|
+
}, [state.error, state.history.hasMoreSessions, state.sessions.length]);
|
|
1443
|
+
const loadMore = () => {
|
|
1444
|
+
if (loadingMore) return;
|
|
1445
|
+
setLoadingMore(true);
|
|
1446
|
+
const result = adapter.onIntent({ action: "loadSessions" });
|
|
1447
|
+
if (result && typeof result.then === "function") {
|
|
1448
|
+
Promise.resolve(result).then(() => setLoadingMore(false), () => setLoadingMore(false));
|
|
1449
|
+
}
|
|
1450
|
+
};
|
|
1451
|
+
return /* @__PURE__ */ jsxs5("section", { class: "scui-list", ref: root, children: [
|
|
1452
|
+
/* @__PURE__ */ jsxs5("header", { class: "scui-head", children: [
|
|
1453
|
+
/* @__PURE__ */ jsxs5("span", { class: "scui-head-copy", children: [
|
|
1454
|
+
/* @__PURE__ */ jsx6("strong", { children: labels.chats }),
|
|
1455
|
+
/* @__PURE__ */ jsxs5("small", { children: [
|
|
1255
1456
|
state.sessions.length,
|
|
1256
1457
|
" recent conversations"
|
|
1257
1458
|
] })
|
|
1258
1459
|
] }),
|
|
1259
|
-
/* @__PURE__ */
|
|
1260
|
-
onClose ? /* @__PURE__ */
|
|
1460
|
+
/* @__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 }) }),
|
|
1461
|
+
onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx6(UiIcon, { name: "close", size: 18 }) }) : null
|
|
1261
1462
|
] }),
|
|
1262
|
-
state.startup !== "ready" ? /* @__PURE__ */
|
|
1263
|
-
state.sessions.length > 4 ? /* @__PURE__ */
|
|
1264
|
-
/* @__PURE__ */
|
|
1265
|
-
/* @__PURE__ */
|
|
1266
|
-
|
|
1463
|
+
state.startup !== "ready" ? /* @__PURE__ */ jsx6(LoadingStatus, { state, compact: rows.length > 0 }) : null,
|
|
1464
|
+
state.sessions.length > 4 ? /* @__PURE__ */ jsxs5("label", { class: "scui-search", children: [
|
|
1465
|
+
/* @__PURE__ */ jsx6(UiIcon, { name: "search", size: 15 }),
|
|
1466
|
+
/* @__PURE__ */ jsx6("input", { type: "search", "aria-label": labels.searchChats, placeholder: labels.searchChats, value: query, onInput: (event) => {
|
|
1467
|
+
const value = event.currentTarget.value;
|
|
1468
|
+
setQuery(value);
|
|
1469
|
+
boundedSet(sessionListMemory, memoryKey, { query: value, top: 0 });
|
|
1470
|
+
if (rowScroller.current) rowScroller.current.scrollTop = 0;
|
|
1471
|
+
} }),
|
|
1472
|
+
/* @__PURE__ */ jsx6("small", { children: rows.length })
|
|
1267
1473
|
] }) : null,
|
|
1268
|
-
/* @__PURE__ */
|
|
1269
|
-
!rows.length && state.startup === "ready" ? /* @__PURE__ */
|
|
1270
|
-
rows.map((row) => /* @__PURE__ */
|
|
1271
|
-
state.history.hasMoreSessions ? /* @__PURE__ */
|
|
1474
|
+
/* @__PURE__ */ jsxs5("div", { class: "scui-session-rows", ref: rowScroller, onScroll: (event) => boundedSet(sessionListMemory, memoryKey, { query, top: event.currentTarget.scrollTop }), children: [
|
|
1475
|
+
!rows.length && state.startup === "ready" ? /* @__PURE__ */ jsx6("div", { class: "scui-empty", children: query ? "No chats match your search." : state.error ?? "No coding chats found." }) : null,
|
|
1476
|
+
rows.map((row) => /* @__PURE__ */ jsx6(Row, { value: row, row, state, adapter, onOpen }, row.key)),
|
|
1477
|
+
state.history.hasMoreSessions ? /* @__PURE__ */ jsx6("button", { class: "scui-load", type: "button", disabled: loadingMore, onClick: loadMore, children: loadingMore ? "Loading older chats\u2026" : "Load older chats" }) : null
|
|
1272
1478
|
] })
|
|
1273
1479
|
] });
|
|
1274
1480
|
}
|
|
1275
1481
|
|
|
1276
1482
|
// src/messenger.jsx
|
|
1277
|
-
import { jsx as
|
|
1483
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
1278
1484
|
var pendingMessageMemory = /* @__PURE__ */ new Map();
|
|
1485
|
+
var messengerViewMemory = /* @__PURE__ */ new Map();
|
|
1486
|
+
var newChatMemory = /* @__PURE__ */ new Map();
|
|
1487
|
+
var TRACKED_ACTIONS = /* @__PURE__ */ new Set(["resume", "join", "detach", "branch", "reduce", "terminal", "export", "interrupt", "respond", "refresh", "loadEarlier", "loadSessions"]);
|
|
1279
1488
|
function Receipt({ state, adapter }) {
|
|
1280
1489
|
const receipt = state.reductionReceipt;
|
|
1281
|
-
if (receipt) return /* @__PURE__ */
|
|
1282
|
-
/* @__PURE__ */
|
|
1283
|
-
/* @__PURE__ */
|
|
1490
|
+
if (receipt) return /* @__PURE__ */ jsx7("div", { class: "scui-receipt", children: /* @__PURE__ */ jsxs6("span", { children: [
|
|
1491
|
+
/* @__PURE__ */ jsx7("strong", { children: "Reduced and verified" }),
|
|
1492
|
+
/* @__PURE__ */ jsxs6("small", { children: [
|
|
1284
1493
|
receipt.sourceTokens.toLocaleString(),
|
|
1285
1494
|
" \u2192 ",
|
|
1286
1495
|
receipt.reducedTokens.toLocaleString(),
|
|
@@ -1289,82 +1498,150 @@ function Receipt({ state, adapter }) {
|
|
|
1289
1498
|
"\xD7 \xB7 reversible"
|
|
1290
1499
|
] })
|
|
1291
1500
|
] }) });
|
|
1292
|
-
if (state.exportReceipt) return /* @__PURE__ */
|
|
1293
|
-
/* @__PURE__ */
|
|
1294
|
-
/* @__PURE__ */
|
|
1501
|
+
if (state.exportReceipt) return /* @__PURE__ */ jsxs6("div", { class: "scui-receipt", children: [
|
|
1502
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1503
|
+
/* @__PURE__ */ jsxs6("strong", { children: [
|
|
1295
1504
|
"Lossless export ready \xB7 ",
|
|
1296
1505
|
harnessDisplayName(state.exportReceipt.targetHarness)
|
|
1297
1506
|
] }),
|
|
1298
|
-
/* @__PURE__ */
|
|
1507
|
+
/* @__PURE__ */ jsxs6("small", { children: [
|
|
1299
1508
|
state.exportReceipt.path,
|
|
1300
1509
|
" \xB7 ",
|
|
1301
1510
|
state.exportReceipt.files,
|
|
1302
1511
|
" files"
|
|
1303
1512
|
] })
|
|
1304
1513
|
] }),
|
|
1305
|
-
/* @__PURE__ */
|
|
1514
|
+
/* @__PURE__ */ jsx7("button", { type: "button", onClick: () => adapter.copyText?.(state.exportReceipt.path), children: "Copy path" })
|
|
1306
1515
|
] });
|
|
1307
|
-
if (state.terminalHandoff) return /* @__PURE__ */
|
|
1308
|
-
/* @__PURE__ */
|
|
1309
|
-
/* @__PURE__ */
|
|
1310
|
-
/* @__PURE__ */
|
|
1516
|
+
if (state.terminalHandoff) return /* @__PURE__ */ jsxs6("div", { class: "scui-receipt", children: [
|
|
1517
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1518
|
+
/* @__PURE__ */ jsx7("strong", { children: "Terminal handoff ready" }),
|
|
1519
|
+
/* @__PURE__ */ jsx7("small", { children: state.terminalHandoff.cwd })
|
|
1311
1520
|
] }),
|
|
1312
|
-
/* @__PURE__ */
|
|
1521
|
+
/* @__PURE__ */ jsx7("button", { type: "button", onClick: () => adapter.copyText?.(terminalCommand(state.terminalHandoff)), children: "Copy command" })
|
|
1313
1522
|
] });
|
|
1314
1523
|
return null;
|
|
1315
1524
|
}
|
|
1316
|
-
function
|
|
1317
|
-
const
|
|
1525
|
+
function ConversationActions({ state, adapter, actionPending }) {
|
|
1526
|
+
const [open, setOpen] = useState4(false);
|
|
1527
|
+
const root = useRef5(null);
|
|
1528
|
+
const panel = useRef5(null);
|
|
1529
|
+
const trigger = useRef5(null);
|
|
1530
|
+
const menuId = useId2();
|
|
1318
1531
|
const targets = state.harnesses.filter((item) => item.startable);
|
|
1532
|
+
const groups = [
|
|
1533
|
+
{
|
|
1534
|
+
label: "Session",
|
|
1535
|
+
items: [
|
|
1536
|
+
state.canDetach ? { key: "detach", label: "Detach to read-only", intent: { action: "detach" } } : null,
|
|
1537
|
+
state.canOpenTerminal ? { key: "terminal", label: "Prepare terminal handoff", intent: { action: "terminal" } } : null,
|
|
1538
|
+
state.canExport && state.exportBackTarget ? { key: "export", label: `Export back to ${harnessDisplayName(state.exportBackTarget)}`, intent: { action: "export", targetHarness: state.exportBackTarget } } : null
|
|
1539
|
+
].filter(Boolean)
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
label: "Lower-cost continuation",
|
|
1543
|
+
items: state.canReduce ? targets.map((target) => ({ key: `reduce:${target.id}`, label: target.id === state.harness ? `Reduce and continue in ${target.label}` : `Reduce and switch to ${target.label}`, intent: { action: "reduce", targetHarness: target.id } })) : []
|
|
1544
|
+
},
|
|
1545
|
+
{
|
|
1546
|
+
label: "Independent continuation",
|
|
1547
|
+
items: state.canBranch ? targets.map((target) => ({ key: `branch:${target.id}`, label: target.id === state.harness ? `Fork in ${target.label}` : `Continue with ${target.label}`, intent: { action: "branch", targetHarness: target.id } })) : []
|
|
1548
|
+
}
|
|
1549
|
+
].filter((group) => group.items.length);
|
|
1550
|
+
useEffect6(() => {
|
|
1551
|
+
if (!open) return;
|
|
1552
|
+
panel.current?.querySelector("button:not(:disabled)")?.focus({ preventScroll: true });
|
|
1553
|
+
const dismiss = (event) => {
|
|
1554
|
+
if (event.type === "keydown" && event.key === "Escape") {
|
|
1555
|
+
event.preventDefault();
|
|
1556
|
+
setOpen(false);
|
|
1557
|
+
trigger.current?.focus({ preventScroll: true });
|
|
1558
|
+
} else if (event.type === "pointerdown" && !root.current?.contains(event.target)) {
|
|
1559
|
+
setOpen(false);
|
|
1560
|
+
}
|
|
1561
|
+
};
|
|
1562
|
+
document.addEventListener("keydown", dismiss);
|
|
1563
|
+
document.addEventListener("pointerdown", dismiss, true);
|
|
1564
|
+
return () => {
|
|
1565
|
+
document.removeEventListener("keydown", dismiss);
|
|
1566
|
+
document.removeEventListener("pointerdown", dismiss, true);
|
|
1567
|
+
};
|
|
1568
|
+
}, [open]);
|
|
1569
|
+
const dispatch = (intent) => {
|
|
1570
|
+
setOpen(false);
|
|
1571
|
+
adapter.onIntent(intent);
|
|
1572
|
+
};
|
|
1573
|
+
const navigate = (event) => {
|
|
1574
|
+
if (event.key === "Escape") {
|
|
1575
|
+
event.preventDefault();
|
|
1576
|
+
event.stopPropagation();
|
|
1577
|
+
setOpen(false);
|
|
1578
|
+
trigger.current?.focus({ preventScroll: true });
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1581
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) return;
|
|
1582
|
+
const items = [...panel.current.querySelectorAll("button:not(:disabled)")];
|
|
1583
|
+
if (!items.length) return;
|
|
1584
|
+
event.preventDefault();
|
|
1585
|
+
const current = items.indexOf(document.activeElement);
|
|
1586
|
+
const index = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : event.key === "ArrowDown" ? (current + 1) % items.length : (current <= 0 ? items.length : current) - 1;
|
|
1587
|
+
items[index].focus({ preventScroll: true });
|
|
1588
|
+
};
|
|
1589
|
+
return /* @__PURE__ */ jsxs6("div", { class: "scui-menu", ref: root, onBlur: (event) => {
|
|
1590
|
+
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
1591
|
+
}, children: [
|
|
1592
|
+
/* @__PURE__ */ jsx7("button", { ref: trigger, class: "scui-menu-trigger", type: "button", "aria-label": "Conversation actions", "aria-haspopup": "menu", "aria-expanded": open, "aria-controls": open ? menuId : void 0, onClick: () => setOpen((value) => !value), children: /* @__PURE__ */ jsx7(UiIcon, { name: "menu", size: 18 }) }),
|
|
1593
|
+
open ? /* @__PURE__ */ jsx7("div", { ref: panel, id: menuId, class: "scui-menu-panel", role: "menu", "aria-label": "Conversation actions", onKeyDown: navigate, children: groups.map((group) => /* @__PURE__ */ jsxs6("section", { role: "group", "aria-label": group.label, children: [
|
|
1594
|
+
/* @__PURE__ */ jsx7("strong", { children: group.label }),
|
|
1595
|
+
group.items.map((item) => /* @__PURE__ */ jsx7("button", { role: "menuitem", type: "button", disabled: actionPending, onClick: () => dispatch(item.intent), children: item.label }, item.key))
|
|
1596
|
+
] }, group.label)) }) : null
|
|
1597
|
+
] });
|
|
1598
|
+
}
|
|
1599
|
+
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose }) {
|
|
1600
|
+
const back = useRef5(null);
|
|
1601
|
+
const harness = state.attached?.harness ?? state.harness;
|
|
1319
1602
|
const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
|
|
1320
1603
|
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";
|
|
1321
1604
|
const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce;
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1605
|
+
useEffect6(() => {
|
|
1606
|
+
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
1607
|
+
}, []);
|
|
1608
|
+
return /* @__PURE__ */ jsxs6("header", { class: "scui-head scui-chat-head", children: [
|
|
1609
|
+
/* @__PURE__ */ jsx7("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx7(UiIcon, { name: "back", size: 18 }) }),
|
|
1610
|
+
/* @__PURE__ */ jsx7(HarnessLogo, { id: harness, size: 28 }),
|
|
1611
|
+
/* @__PURE__ */ jsxs6("span", { class: "scui-head-copy", children: [
|
|
1612
|
+
/* @__PURE__ */ jsx7("strong", { children: title }),
|
|
1613
|
+
/* @__PURE__ */ jsxs6("small", { children: [
|
|
1328
1614
|
harnessDisplayName(harness),
|
|
1329
1615
|
" \xB7 ",
|
|
1330
1616
|
status
|
|
1331
1617
|
] })
|
|
1332
1618
|
] }),
|
|
1333
|
-
menu ? /* @__PURE__ */
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
state.canDetach ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "detach" }), children: "Detach to read-only" }) : null,
|
|
1337
|
-
state.canOpenTerminal ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "terminal" }), children: "Prepare terminal handoff" }) : null,
|
|
1338
|
-
state.canReduce ? targets.map((target) => /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "reduce", targetHarness: target.id }), children: target.id === state.harness ? `Reduce and continue in ${target.label}` : `Reduce and switch to ${target.label}` }, `reduce:${target.id}`)) : null,
|
|
1339
|
-
state.canBranch ? targets.map((target) => /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "branch", targetHarness: target.id }), children: target.id === state.harness ? `Fork in ${target.label}` : `Continue with ${target.label}` }, `branch:${target.id}`)) : null,
|
|
1340
|
-
state.canExport && state.exportBackTarget ? /* @__PURE__ */ jsxs5("button", { type: "button", onClick: () => adapter.onIntent({ action: "export", targetHarness: state.exportBackTarget }), children: [
|
|
1341
|
-
"Export back to ",
|
|
1342
|
-
harnessDisplayName(state.exportBackTarget)
|
|
1343
|
-
] }) : null
|
|
1344
|
-
] })
|
|
1345
|
-
] }) : null,
|
|
1346
|
-
/* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: "\uFF0B" }),
|
|
1347
|
-
onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
|
|
1619
|
+
menu ? /* @__PURE__ */ jsx7(ConversationActions, { state, adapter, actionPending }) : null,
|
|
1620
|
+
/* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: /* @__PURE__ */ jsx7(UiIcon, { name: "plus", size: 18 }) }),
|
|
1621
|
+
onClose ? /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx7(UiIcon, { name: "close", size: 18 }) }) : null
|
|
1348
1622
|
] });
|
|
1349
1623
|
}
|
|
1350
1624
|
function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
|
|
1351
1625
|
const Header = slots.header;
|
|
1352
1626
|
const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
|
|
1353
1627
|
const [pending, setPendingState] = useState4(() => pendingMessageMemory.get(memoryKey) ?? null);
|
|
1628
|
+
const [pendingAction, setPendingAction] = useState4(null);
|
|
1354
1629
|
const [restoreDraft, setRestoreDraft] = useState4(null);
|
|
1355
|
-
const restoreSequence =
|
|
1356
|
-
const
|
|
1630
|
+
const restoreSequence = useRef5(0);
|
|
1631
|
+
const actionSequence = useRef5(0);
|
|
1632
|
+
const acknowledged = useRef5(/* @__PURE__ */ new Set());
|
|
1357
1633
|
const setPending = (update) => setPendingState((current) => {
|
|
1358
1634
|
const next = typeof update === "function" ? update(current) : update;
|
|
1359
1635
|
if (next) boundedSet(pendingMessageMemory, memoryKey, next);
|
|
1360
1636
|
else pendingMessageMemory.delete(memoryKey);
|
|
1361
1637
|
return next;
|
|
1362
1638
|
});
|
|
1363
|
-
|
|
1639
|
+
useEffect6(() => {
|
|
1364
1640
|
setPendingState(pendingMessageMemory.get(memoryKey) ?? null);
|
|
1641
|
+
setPendingAction(null);
|
|
1365
1642
|
setRestoreDraft(null);
|
|
1366
1643
|
}, [memoryKey]);
|
|
1367
|
-
|
|
1644
|
+
useEffect6(() => {
|
|
1368
1645
|
if (!pending) return;
|
|
1369
1646
|
if (state.transcript.some((entry) => entry.role === "user" && entry.text.trim() === pending.text.trim() && !pending.baselineIds.includes(entry.id))) {
|
|
1370
1647
|
setPending(null);
|
|
@@ -1391,7 +1668,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
1391
1668
|
setRestoreDraft({ id: restoreSequence.current, text: pending.text });
|
|
1392
1669
|
setPending({ ...pending, status: "editing" });
|
|
1393
1670
|
};
|
|
1394
|
-
|
|
1671
|
+
useEffect6(() => {
|
|
1395
1672
|
const key = state.attached?.key;
|
|
1396
1673
|
if (!key || !state.attention.some((item) => item.key === key)) {
|
|
1397
1674
|
if (key) acknowledged.current.delete(key);
|
|
@@ -1402,75 +1679,143 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
1402
1679
|
adapter.onIntent({ action: "ack", key });
|
|
1403
1680
|
}
|
|
1404
1681
|
}, [adapter, state.attached?.key, state.attention]);
|
|
1682
|
+
const trackedAdapter = useMemo2(() => ({
|
|
1683
|
+
...adapter,
|
|
1684
|
+
onIntent(intent) {
|
|
1685
|
+
if (!TRACKED_ACTIONS.has(intent.action)) return adapter.onIntent(intent);
|
|
1686
|
+
const id = actionSequence.current + 1;
|
|
1687
|
+
actionSequence.current = id;
|
|
1688
|
+
const action2 = intent.action;
|
|
1689
|
+
setPendingAction({ id, action: action2, initialError: state.error, seenOperation: false });
|
|
1690
|
+
let result;
|
|
1691
|
+
try {
|
|
1692
|
+
result = adapter.onIntent(intent);
|
|
1693
|
+
} catch (error) {
|
|
1694
|
+
setPendingAction((current) => current?.id === id ? null : current);
|
|
1695
|
+
throw error;
|
|
1696
|
+
}
|
|
1697
|
+
if (result && typeof result.then === "function") {
|
|
1698
|
+
Promise.resolve(result).then(
|
|
1699
|
+
() => setPendingAction((current) => current?.id === id ? null : current),
|
|
1700
|
+
() => setPendingAction((current) => current?.id === id ? null : current)
|
|
1701
|
+
);
|
|
1702
|
+
}
|
|
1703
|
+
return result;
|
|
1704
|
+
}
|
|
1705
|
+
}), [adapter, state.error]);
|
|
1706
|
+
useEffect6(() => {
|
|
1707
|
+
if (!pendingAction) return;
|
|
1708
|
+
if (state.operation && !pendingAction.seenOperation) {
|
|
1709
|
+
setPendingAction({ ...pendingAction, seenOperation: true });
|
|
1710
|
+
} else if (!state.operation && (pendingAction.seenOperation || state.error !== pendingAction.initialError)) {
|
|
1711
|
+
setPendingAction(null);
|
|
1712
|
+
}
|
|
1713
|
+
}, [pendingAction, state.error, state.operation]);
|
|
1405
1714
|
const pendingMessage = pending && pending.status !== "editing" ? { text: pending.text, status: pending.status, onRetry: retryPending, onEdit: editPending } : null;
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1715
|
+
const action = state.operation || pendingAction?.action || null;
|
|
1716
|
+
const actionLabel = operationLabel(action);
|
|
1717
|
+
const actionState = action ? { ...state, operation: action, canInterrupt: false, canRespond: false } : state;
|
|
1718
|
+
const unreadAfterMessages = state.attention.find((item) => item.key === state.attached?.key)?.afterMessages ?? null;
|
|
1719
|
+
return /* @__PURE__ */ jsxs6("section", { class: "scui-chat", children: [
|
|
1720
|
+
Header ? /* @__PURE__ */ jsx7(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx7(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose }),
|
|
1721
|
+
actionLabel ? /* @__PURE__ */ jsxs6("div", { class: "scui-operation", role: "status", children: [
|
|
1722
|
+
/* @__PURE__ */ jsx7("i", {}),
|
|
1723
|
+
actionLabel
|
|
1411
1724
|
] }) : null,
|
|
1412
|
-
state.error ? /* @__PURE__ */
|
|
1413
|
-
/* @__PURE__ */
|
|
1414
|
-
state.recoverable ? /* @__PURE__ */
|
|
1725
|
+
state.error ? /* @__PURE__ */ jsxs6("div", { class: "scui-error", role: "alert", children: [
|
|
1726
|
+
/* @__PURE__ */ jsx7("span", { children: state.error }),
|
|
1727
|
+
state.recoverable ? /* @__PURE__ */ jsx7("button", { type: "button", disabled: Boolean(action), onClick: () => trackedAdapter.onIntent({ action: "refresh" }), children: "Retry" }) : null
|
|
1415
1728
|
] }) : null,
|
|
1416
|
-
/* @__PURE__ */
|
|
1417
|
-
/* @__PURE__ */
|
|
1418
|
-
/* @__PURE__ */
|
|
1419
|
-
state.mode !== "mirror" || state.canSend ? /* @__PURE__ */
|
|
1729
|
+
/* @__PURE__ */ jsx7(Receipt, { state, adapter }),
|
|
1730
|
+
/* @__PURE__ */ jsx7(Conversation, { state: actionState, adapter: trackedAdapter, components, slots, memoryKey, pending: pendingMessage, unreadAfterMessages }, memoryKey),
|
|
1731
|
+
/* @__PURE__ */ jsx7(ContinuationBar, { state: actionState, adapter: trackedAdapter, labels }),
|
|
1732
|
+
state.mode !== "mirror" || state.canSend ? /* @__PURE__ */ jsx7(Composer, { state: actionState, adapter: trackedAdapter, labels, memoryKey, pendingStatus: pending?.status ?? null, restoreDraft, onDraftRestored: (id) => setRestoreDraft((value) => value?.id === id ? null : value), onPending: beginPending }, memoryKey) : null
|
|
1420
1733
|
] });
|
|
1421
1734
|
}
|
|
1422
|
-
function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
|
|
1735
|
+
function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey }) {
|
|
1423
1736
|
const startable = state.harnesses.filter((item) => item.startable);
|
|
1424
1737
|
const startableKey = startable.map((item) => item.id).join("\0");
|
|
1425
|
-
const
|
|
1426
|
-
const [
|
|
1427
|
-
const [
|
|
1428
|
-
|
|
1429
|
-
|
|
1738
|
+
const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "" };
|
|
1739
|
+
const [harness, setHarness] = useState4(remembered.harness);
|
|
1740
|
+
const [draft, setDraft] = useState4(remembered.draft);
|
|
1741
|
+
const [starting, setStarting] = useState4(null);
|
|
1742
|
+
const startSequence = useRef5(0);
|
|
1743
|
+
const textarea = useRef5(null);
|
|
1744
|
+
useAutosizeTextarea(textarea, draft);
|
|
1745
|
+
useEffect6(() => {
|
|
1746
|
+
if (startable.some((item) => item.id === harness)) return;
|
|
1747
|
+
const next = startable[0]?.id ?? "";
|
|
1748
|
+
setHarness(next);
|
|
1749
|
+
boundedSet(newChatMemory, memoryKey, { harness: next, draft });
|
|
1430
1750
|
}, [harness, startableKey]);
|
|
1431
|
-
|
|
1432
|
-
if (starting
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
if (
|
|
1751
|
+
useEffect6(() => {
|
|
1752
|
+
if (!starting) return;
|
|
1753
|
+
const sessionChanged = (state.attached?.key ?? null) !== starting.attachedKey;
|
|
1754
|
+
const beganWorking = !starting.busy && state.busy;
|
|
1755
|
+
if (!sessionChanged && !beganWorking) return;
|
|
1756
|
+
newChatMemory.delete(memoryKey);
|
|
1757
|
+
onStarted();
|
|
1758
|
+
}, [memoryKey, onStarted, starting, state.attached?.key, state.busy]);
|
|
1759
|
+
useEffect6(() => {
|
|
1760
|
+
if (starting && state.error !== starting.initialError && !state.busy && !state.operation) setStarting(null);
|
|
1436
1761
|
}, [starting, state.busy, state.error, state.operation]);
|
|
1762
|
+
useEffect6(() => {
|
|
1763
|
+
textarea.current?.focus({ preventScroll: true });
|
|
1764
|
+
}, []);
|
|
1437
1765
|
const send = () => {
|
|
1438
1766
|
const text = draft.trim();
|
|
1439
1767
|
if (!text || !harness || starting) return;
|
|
1440
|
-
|
|
1441
|
-
|
|
1768
|
+
const id = startSequence.current + 1;
|
|
1769
|
+
startSequence.current = id;
|
|
1770
|
+
setStarting({ id, attachedKey: state.attached?.key ?? null, busy: state.busy, initialError: state.error });
|
|
1771
|
+
const result = adapter.onIntent({ action: "new", harness, text });
|
|
1772
|
+
if (result && typeof result.then === "function") {
|
|
1773
|
+
Promise.resolve(result).catch(() => setStarting((current) => current?.id === id ? null : current));
|
|
1774
|
+
}
|
|
1442
1775
|
};
|
|
1443
|
-
return /* @__PURE__ */
|
|
1444
|
-
/* @__PURE__ */
|
|
1445
|
-
/* @__PURE__ */
|
|
1446
|
-
/* @__PURE__ */
|
|
1447
|
-
/* @__PURE__ */
|
|
1448
|
-
/* @__PURE__ */
|
|
1776
|
+
return /* @__PURE__ */ jsxs6("section", { class: "scui-chat", children: [
|
|
1777
|
+
/* @__PURE__ */ jsxs6("header", { class: "scui-head", children: [
|
|
1778
|
+
/* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Back", onClick: onBack, children: /* @__PURE__ */ jsx7(UiIcon, { name: "back", size: 18 }) }),
|
|
1779
|
+
/* @__PURE__ */ jsxs6("span", { class: "scui-head-copy", children: [
|
|
1780
|
+
/* @__PURE__ */ jsx7("strong", { children: labels.newChat }),
|
|
1781
|
+
/* @__PURE__ */ jsx7("small", { children: "No session is created until you send" })
|
|
1449
1782
|
] }),
|
|
1450
|
-
onClose ? /* @__PURE__ */
|
|
1783
|
+
onClose ? /* @__PURE__ */ jsx7("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx7(UiIcon, { name: "close", size: 18 }) }) : null
|
|
1451
1784
|
] }),
|
|
1452
|
-
/* @__PURE__ */
|
|
1453
|
-
/* @__PURE__ */
|
|
1454
|
-
|
|
1455
|
-
|
|
1785
|
+
starting ? /* @__PURE__ */ jsxs6("div", { class: "scui-operation", role: "status", children: [
|
|
1786
|
+
/* @__PURE__ */ jsx7("i", {}),
|
|
1787
|
+
operationLabel("start")
|
|
1788
|
+
] }) : null,
|
|
1789
|
+
/* @__PURE__ */ jsxs6("div", { class: "scui-new", children: [
|
|
1790
|
+
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
1791
|
+
/* @__PURE__ */ jsx7("strong", { children: "What should the agent build or fix?" }),
|
|
1792
|
+
/* @__PURE__ */ jsx7("small", { children: "Choose a coding harness and send the first message." })
|
|
1456
1793
|
] }),
|
|
1457
|
-
/* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1459
|
-
/* @__PURE__ */
|
|
1460
|
-
/* @__PURE__ */
|
|
1461
|
-
/* @__PURE__ */
|
|
1794
|
+
/* @__PURE__ */ jsxs6("div", { class: "scui-compose", children: [
|
|
1795
|
+
/* @__PURE__ */ jsxs6("label", { class: "scui-harness-picker", children: [
|
|
1796
|
+
/* @__PURE__ */ jsx7(HarnessLogo, { id: harness, size: 24 }),
|
|
1797
|
+
/* @__PURE__ */ jsx7("span", { children: "Coding harness" }),
|
|
1798
|
+
/* @__PURE__ */ jsx7("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
|
|
1799
|
+
const value = event.currentTarget.value;
|
|
1800
|
+
setHarness(value);
|
|
1801
|
+
boundedSet(newChatMemory, memoryKey, { harness: value, draft });
|
|
1802
|
+
}, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs6("option", { value: item.id, disabled: !item.startable, children: [
|
|
1462
1803
|
item.label,
|
|
1463
1804
|
item.startable ? "" : " \xB7 unavailable"
|
|
1464
1805
|
] }, item.id)) })
|
|
1465
1806
|
] }),
|
|
1466
|
-
/* @__PURE__ */
|
|
1467
|
-
/* @__PURE__ */
|
|
1807
|
+
/* @__PURE__ */ jsxs6("div", { class: "scui-envelope", children: [
|
|
1808
|
+
/* @__PURE__ */ jsx7("textarea", { ref: textarea, rows: 3, "aria-label": "Message coding agent", placeholder: startable.length ? "What should the agent do?" : "No coding harness is available", value: draft, disabled: !startable.length || Boolean(starting), onInput: (event) => {
|
|
1809
|
+
const value = event.currentTarget.value;
|
|
1810
|
+
setDraft(value);
|
|
1811
|
+
boundedSet(newChatMemory, memoryKey, { harness, draft: value });
|
|
1812
|
+
}, onKeyDown: (event) => {
|
|
1468
1813
|
if (isSendKey(event)) {
|
|
1469
1814
|
event.preventDefault();
|
|
1470
1815
|
send();
|
|
1471
1816
|
}
|
|
1472
1817
|
} }),
|
|
1473
|
-
/* @__PURE__ */
|
|
1818
|
+
/* @__PURE__ */ jsx7("span", { children: /* @__PURE__ */ jsx7("button", { type: "button", class: "scui-send", "aria-label": "Start chat", disabled: !draft.trim() || !harness || Boolean(starting), onClick: send, children: starting ? /* @__PURE__ */ jsx7("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx7(UiIcon, { name: "send", size: 17 }) }) })
|
|
1474
1819
|
] })
|
|
1475
1820
|
] })
|
|
1476
1821
|
] });
|
|
@@ -1478,10 +1823,15 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
|
|
|
1478
1823
|
function SupercodeMessenger({ state: stateInput, adapter, class: className = "", initialView, labels, components = {}, slots = {} }) {
|
|
1479
1824
|
const state = useMemo2(() => normalizeUiState(stateInput), [stateInput]);
|
|
1480
1825
|
const copy = { ...DEFAULT_LABELS, ...labels };
|
|
1481
|
-
const
|
|
1826
|
+
const memoryKey = state.workspace || "@default";
|
|
1827
|
+
const [view, setViewState] = useState4(initialView ?? (state.attention.length ? "list" : messengerViewMemory.get(memoryKey) ?? (state.attached || state.transcript.length ? "chat" : "list")));
|
|
1482
1828
|
const [opening, setOpening] = useState4(null);
|
|
1483
1829
|
const [listFocus, setListFocus] = useState4(null);
|
|
1484
|
-
|
|
1830
|
+
const setView = (next) => {
|
|
1831
|
+
boundedSet(messengerViewMemory, memoryKey, next);
|
|
1832
|
+
setViewState(next);
|
|
1833
|
+
};
|
|
1834
|
+
useEffect6(() => {
|
|
1485
1835
|
if (!opening) return;
|
|
1486
1836
|
if (state.attached?.key === opening.key) {
|
|
1487
1837
|
setOpening(null);
|
|
@@ -1493,36 +1843,35 @@ function SupercodeMessenger({ state: stateInput, adapter, class: className = "",
|
|
|
1493
1843
|
const open = (row) => {
|
|
1494
1844
|
setListFocus(row.key);
|
|
1495
1845
|
setOpening(row);
|
|
1496
|
-
adapter.onIntent({ action: "ack", key: row.key });
|
|
1497
1846
|
adapter.onIntent({ action: "attach", key: row.key });
|
|
1498
1847
|
};
|
|
1499
1848
|
const close = () => adapter.onClose?.();
|
|
1500
1849
|
const Footer = slots.footer;
|
|
1501
|
-
return /* @__PURE__ */
|
|
1502
|
-
view === "list" ? /* @__PURE__ */
|
|
1850
|
+
return /* @__PURE__ */ jsxs6("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
|
|
1851
|
+
view === "list" ? /* @__PURE__ */ jsx7(SessionList, { state, adapter, focusKey: listFocus, onOpen: open, onNew: () => {
|
|
1503
1852
|
setListFocus("@new");
|
|
1504
1853
|
setView("new");
|
|
1505
|
-
}, onClose: adapter.onClose ? close : void 0, components, labels: copy }) : null,
|
|
1506
|
-
view === "new" ? /* @__PURE__ */
|
|
1507
|
-
view === "chat" ? /* @__PURE__ */
|
|
1854
|
+
}, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey }) : null,
|
|
1855
|
+
view === "new" ? /* @__PURE__ */ jsx7(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: () => setView("chat"), labels: copy, memoryKey }) : null,
|
|
1856
|
+
view === "chat" ? /* @__PURE__ */ jsx7(Chat, { state, adapter, onBack: () => {
|
|
1508
1857
|
setListFocus(state.attached?.key ?? listFocus);
|
|
1509
1858
|
setView("list");
|
|
1510
1859
|
}, onNew: () => {
|
|
1511
1860
|
setListFocus("@new");
|
|
1512
1861
|
setView("new");
|
|
1513
1862
|
}, onClose: adapter.onClose ? close : void 0, components, slots, labels: copy }) : null,
|
|
1514
|
-
opening ? /* @__PURE__ */
|
|
1515
|
-
/* @__PURE__ */
|
|
1516
|
-
/* @__PURE__ */
|
|
1517
|
-
/* @__PURE__ */
|
|
1863
|
+
opening ? /* @__PURE__ */ jsxs6("div", { class: "scui-opening", role: "status", "aria-busy": "true", children: [
|
|
1864
|
+
/* @__PURE__ */ jsx7(HarnessLogo, { id: opening.harness, size: 34 }),
|
|
1865
|
+
/* @__PURE__ */ jsxs6("span", { children: [
|
|
1866
|
+
/* @__PURE__ */ jsxs6("strong", { children: [
|
|
1518
1867
|
"Opening ",
|
|
1519
1868
|
sessionDisplayName(opening)
|
|
1520
1869
|
] }),
|
|
1521
|
-
/* @__PURE__ */
|
|
1870
|
+
/* @__PURE__ */ jsx7("small", { children: "Loading the latest transcript window\u2026" })
|
|
1522
1871
|
] }),
|
|
1523
|
-
/* @__PURE__ */
|
|
1872
|
+
/* @__PURE__ */ jsx7("i", {})
|
|
1524
1873
|
] }) : null,
|
|
1525
|
-
Footer ? /* @__PURE__ */
|
|
1874
|
+
Footer ? /* @__PURE__ */ jsx7(Footer, { state, adapter, value: copy }) : null
|
|
1526
1875
|
] });
|
|
1527
1876
|
}
|
|
1528
1877
|
export {
|