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