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