@volter-ai-dev/supercode-ui 0.1.29 → 0.1.31
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 +10 -2
- package/components.mjs +326 -130
- package/composer.mjs +3 -0
- package/controller.mjs +10 -11
- package/conversation.mjs +4 -1
- package/core.d.ts +1 -0
- package/core.mjs +94 -2
- package/embed.mjs +326 -132
- package/index.d.ts +80 -1
- package/messenger.mjs +324 -130
- package/package.json +8 -2
- package/sessions.mjs +30 -6
- package/settings.d.ts +2 -0
- package/settings.mjs +216 -0
- package/styles.css +12 -3
package/messenger.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/messenger.jsx
|
|
2
|
-
import { useEffect as
|
|
2
|
+
import { useEffect as useEffect8, useId as useId3, useMemo as useMemo3, useRef as useRef7, useState as useState6 } from "preact/hooks";
|
|
3
3
|
|
|
4
4
|
// core.mjs
|
|
5
5
|
var HARNESS_NAMES = Object.freeze({
|
|
@@ -40,6 +40,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
40
40
|
canReduce: false,
|
|
41
41
|
canInterrupt: false,
|
|
42
42
|
canRespond: false,
|
|
43
|
+
canConfigureSettings: false,
|
|
43
44
|
messaging: null,
|
|
44
45
|
workspace: "",
|
|
45
46
|
taskPlan: Object.freeze({ source: "none", items: Object.freeze([]), residueCount: 0, observedAt: null }),
|
|
@@ -48,6 +49,8 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
48
49
|
exportBackTarget: null,
|
|
49
50
|
exportReceipt: null,
|
|
50
51
|
reductionReceipt: null,
|
|
52
|
+
interopSettings: null,
|
|
53
|
+
interopSettingsError: null,
|
|
51
54
|
error: null,
|
|
52
55
|
recoverable: false,
|
|
53
56
|
harnesses: Object.freeze([]),
|
|
@@ -81,7 +84,16 @@ function number(value, fallback = 0) {
|
|
|
81
84
|
function nullableNumber(value) {
|
|
82
85
|
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
83
86
|
}
|
|
84
|
-
function
|
|
87
|
+
function relativeAge(updatedAt, now = Date.now()) {
|
|
88
|
+
if (typeof updatedAt !== "number" || !Number.isFinite(updatedAt) || updatedAt <= 0) return "";
|
|
89
|
+
const delta = Math.max(0, now - updatedAt);
|
|
90
|
+
if (delta < 6e4) return "now";
|
|
91
|
+
if (delta < 36e5) return `${Math.floor(delta / 6e4)}m ago`;
|
|
92
|
+
if (delta < 864e5) return `${Math.floor(delta / 36e5)}h ago`;
|
|
93
|
+
if (delta < 6048e5) return `${Math.floor(delta / 864e5)}d ago`;
|
|
94
|
+
return `${Math.floor(delta / 6048e5)}w ago`;
|
|
95
|
+
}
|
|
96
|
+
function boundedString(value, max = 2e3) {
|
|
85
97
|
if (typeof value !== "string") return "";
|
|
86
98
|
return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
|
|
87
99
|
}
|
|
@@ -546,6 +558,7 @@ function readSessions(value) {
|
|
|
546
558
|
title: string(row.title),
|
|
547
559
|
preview: string(row.preview),
|
|
548
560
|
age: string(row.age),
|
|
561
|
+
previewUpdatedAt: nullableNumber(row.previewUpdatedAt),
|
|
549
562
|
updatedAt: nullableNumber(row.updatedAt),
|
|
550
563
|
messages: nullableNumber(row.messages),
|
|
551
564
|
active: row.active === true,
|
|
@@ -624,6 +637,68 @@ function readReductionReceipt(value) {
|
|
|
624
637
|
targetHarness: receipt.targetHarness
|
|
625
638
|
};
|
|
626
639
|
}
|
|
640
|
+
function readInteropSettings(value) {
|
|
641
|
+
const report = record(value);
|
|
642
|
+
if (report?.schema !== "supercode.harness-interop-settings.v1" || typeof report.harness !== "string" || typeof report.revision !== "string" || !Array.isArray(report.controls) || !Array.isArray(report.advisories)) return null;
|
|
643
|
+
const controls = report.controls.slice(0, 20).flatMap((raw) => {
|
|
644
|
+
const control = record(raw);
|
|
645
|
+
if (!control || typeof control.key !== "string" || typeof control.label !== "string") return [];
|
|
646
|
+
return [{
|
|
647
|
+
key: boundedString(control.key, 200),
|
|
648
|
+
nativeKey: boundedString(control.native_key ?? control.nativeKey, 200),
|
|
649
|
+
label: boundedString(control.label, 300),
|
|
650
|
+
description: boundedString(control.description),
|
|
651
|
+
scope: ["user", "project", "managed", "command_line"].includes(control.scope) ? control.scope : "user",
|
|
652
|
+
sourcePath: boundedString(control.source_path ?? control.sourcePath, 4e3),
|
|
653
|
+
configuredValue: typeof (control.configured_value ?? control.configuredValue) === "string" ? boundedString(control.configured_value ?? control.configuredValue, 500) : null,
|
|
654
|
+
effectiveValue: typeof (control.effective_value ?? control.effectiveValue) === "string" ? boundedString(control.effective_value ?? control.effectiveValue, 500) : null,
|
|
655
|
+
effectiveKnown: (control.effective_known ?? control.effectiveKnown) === true,
|
|
656
|
+
effectiveNote: boundedString(control.effective_note ?? control.effectiveNote),
|
|
657
|
+
choices: Array.isArray(control.choices) ? control.choices.slice(0, 20).flatMap((candidate) => {
|
|
658
|
+
const choice = record(candidate);
|
|
659
|
+
return choice && typeof choice.value === "string" && typeof choice.label === "string" ? [{
|
|
660
|
+
value: boundedString(choice.value, 500),
|
|
661
|
+
label: boundedString(choice.label, 300),
|
|
662
|
+
description: boundedString(choice.description),
|
|
663
|
+
...typeof choice.risk === "string" ? { risk: boundedString(choice.risk) } : {}
|
|
664
|
+
}] : [];
|
|
665
|
+
}) : [],
|
|
666
|
+
writable: control.writable === true,
|
|
667
|
+
resettable: control.resettable === true,
|
|
668
|
+
requiresRestart: (control.requires_restart ?? control.requiresRestart) === true
|
|
669
|
+
}];
|
|
670
|
+
});
|
|
671
|
+
const advisories = report.advisories.slice(0, 20).flatMap((raw) => {
|
|
672
|
+
const advisory = record(raw);
|
|
673
|
+
const recommendation = record(advisory?.recommendation);
|
|
674
|
+
const change = record(recommendation?.change);
|
|
675
|
+
if (!advisory || !recommendation || !change || typeof advisory.code !== "string" || typeof advisory.title !== "string" || typeof advisory.setting !== "string" || typeof change.key !== "string") return [];
|
|
676
|
+
return [{
|
|
677
|
+
code: boundedString(advisory.code, 200),
|
|
678
|
+
severity: ["info", "warning", "error"].includes(advisory.severity) ? advisory.severity : "warning",
|
|
679
|
+
title: boundedString(advisory.title, 500),
|
|
680
|
+
message: boundedString(advisory.message),
|
|
681
|
+
setting: boundedString(advisory.setting, 200),
|
|
682
|
+
recommendation: {
|
|
683
|
+
label: boundedString(recommendation.label, 500),
|
|
684
|
+
description: boundedString(recommendation.description),
|
|
685
|
+
consequence: boundedString(recommendation.consequence),
|
|
686
|
+
change: {
|
|
687
|
+
key: boundedString(change.key, 200),
|
|
688
|
+
value: typeof change.value === "string" ? boundedString(change.value, 500) : null
|
|
689
|
+
},
|
|
690
|
+
command: boundedString(recommendation.command, 4e3)
|
|
691
|
+
}
|
|
692
|
+
}];
|
|
693
|
+
});
|
|
694
|
+
return {
|
|
695
|
+
schema: "supercode.harness-interop-settings.v1",
|
|
696
|
+
harness: report.harness,
|
|
697
|
+
revision: boundedString(report.revision, 500),
|
|
698
|
+
controls,
|
|
699
|
+
advisories
|
|
700
|
+
};
|
|
701
|
+
}
|
|
627
702
|
function normalizeUiState(value) {
|
|
628
703
|
const raw = record(value) ?? {};
|
|
629
704
|
const pill = record(raw.pill);
|
|
@@ -649,6 +724,7 @@ function normalizeUiState(value) {
|
|
|
649
724
|
canReduce: raw.canReduce === true,
|
|
650
725
|
canInterrupt: raw.canInterrupt === true,
|
|
651
726
|
canRespond: raw.canRespond === true,
|
|
727
|
+
canConfigureSettings: raw.canConfigureSettings === true,
|
|
652
728
|
messaging: raw.messaging === "live_peer" ? "live_peer" : null,
|
|
653
729
|
workspace: string(raw.workspace),
|
|
654
730
|
taskPlan: readTaskPlan(raw.taskPlan),
|
|
@@ -657,6 +733,8 @@ function normalizeUiState(value) {
|
|
|
657
733
|
exportBackTarget: typeof raw.exportBackTarget === "string" ? raw.exportBackTarget : null,
|
|
658
734
|
exportReceipt: readExportReceipt(raw.exportReceipt),
|
|
659
735
|
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
736
|
+
interopSettings: readInteropSettings(raw.interopSettings),
|
|
737
|
+
interopSettingsError: typeof raw.interopSettingsError === "string" ? boundedString(raw.interopSettingsError) : null,
|
|
660
738
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
661
739
|
recoverable: raw.recoverable === true,
|
|
662
740
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
@@ -750,7 +828,7 @@ function canContinueHere(state) {
|
|
|
750
828
|
}
|
|
751
829
|
function operationLabel(operation) {
|
|
752
830
|
if (!operation) return "";
|
|
753
|
-
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" };
|
|
831
|
+
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", configureHarness: "Updating harness settings\u2026", loadEarlier: "Loading earlier messages\u2026", loadSessions: "Loading more chats\u2026", refresh: "Retrying\u2026" };
|
|
754
832
|
return labels[operation] ?? `${operation.replaceAll("_", " ")}\u2026`;
|
|
755
833
|
}
|
|
756
834
|
function terminalCommand(handoff) {
|
|
@@ -1980,28 +2058,35 @@ function sessionPathParts(value) {
|
|
|
1980
2058
|
trailing: complete.slice(boundary + 1)
|
|
1981
2059
|
};
|
|
1982
2060
|
}
|
|
1983
|
-
function SessionRow({ row, state, onOpen }) {
|
|
2061
|
+
function SessionRow({ row, state, onOpen, now = Date.now() }) {
|
|
1984
2062
|
const activity = sessionActivity(state, row);
|
|
2063
|
+
const working = activity === "working";
|
|
1985
2064
|
const attention = state.attention.find((item) => item.key === row.key);
|
|
1986
2065
|
const title = sessionDisplayName(row);
|
|
1987
2066
|
const path = sessionPathParts(row.cwd);
|
|
1988
2067
|
const preview = row.preview || attention?.preview || "";
|
|
1989
2068
|
const unreadCount = attention?.unreadCount ?? 0;
|
|
1990
2069
|
const unreadLabel = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
1991
|
-
|
|
2070
|
+
const age = relativeAge(row.previewUpdatedAt ?? row.updatedAt, now) || row.age;
|
|
2071
|
+
return /* @__PURE__ */ jsxs6("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)}${working ? " \xB7 Working" : ""}${path.complete ? ` \xB7 ${path.complete}` : ""}${preview ? ` \xB7 ${preview}` : ""}${unreadCount ? ` \xB7 ${unreadCount} unread` : ""}${age ? ` \xB7 ${age}` : ""}`, "aria-current": row.active ? "true" : void 0, onClick: () => onOpen(row), children: [
|
|
1992
2072
|
/* @__PURE__ */ jsx7(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
1993
2073
|
/* @__PURE__ */ jsxs6("span", { class: "scui-session-copy", children: [
|
|
1994
2074
|
/* @__PURE__ */ jsxs6("span", { class: "scui-session-title", children: [
|
|
1995
2075
|
/* @__PURE__ */ jsx7("strong", { children: title }),
|
|
1996
|
-
|
|
2076
|
+
/* @__PURE__ */ jsx7("span", { class: "scui-session-meta", children: age ? /* @__PURE__ */ jsx7("time", { children: age }) : null })
|
|
1997
2077
|
] }),
|
|
1998
2078
|
path.complete ? /* @__PURE__ */ jsxs6("small", { class: "scui-session-path", title: row.cwd, children: [
|
|
1999
2079
|
/* @__PURE__ */ jsx7("span", { class: "scui-session-path-leading", children: path.leading }),
|
|
2000
2080
|
path.separator ? /* @__PURE__ */ jsx7("span", { class: "scui-session-path-separator", children: path.separator }) : null,
|
|
2001
2081
|
path.trailing ? /* @__PURE__ */ jsx7("span", { class: "scui-session-path-trailing", children: path.trailing }) : null
|
|
2002
2082
|
] }) : null,
|
|
2003
|
-
preview || unreadCount ? /* @__PURE__ */ jsxs6("span", { class: "scui-session-preview", children: [
|
|
2004
|
-
|
|
2083
|
+
working || preview || unreadCount ? /* @__PURE__ */ jsxs6("span", { class: "scui-session-preview", children: [
|
|
2084
|
+
working ? /* @__PURE__ */ jsxs6("span", { class: "scui-session-working", "aria-hidden": "true", children: [
|
|
2085
|
+
/* @__PURE__ */ jsx7("i", {}),
|
|
2086
|
+
/* @__PURE__ */ jsx7("i", {}),
|
|
2087
|
+
/* @__PURE__ */ jsx7("i", {})
|
|
2088
|
+
] }) : null,
|
|
2089
|
+
preview || working ? /* @__PURE__ */ jsx7("small", { children: preview || "Working\u2026" }) : null,
|
|
2005
2090
|
unreadCount ? /* @__PURE__ */ jsx7("b", { "aria-label": `${unreadCount} unread messages`, children: unreadLabel }) : null
|
|
2006
2091
|
] }) : null,
|
|
2007
2092
|
state.attachError?.key === row.key ? /* @__PURE__ */ jsx7("em", { children: state.attachError.message }) : null
|
|
@@ -2012,6 +2097,7 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
2012
2097
|
const remembered = sessionListMemory.get(memoryKey) ?? { query: "", top: 0 };
|
|
2013
2098
|
const [query, setQuery] = useState4(remembered.query);
|
|
2014
2099
|
const [loadingMore, setLoadingMore] = useState4(false);
|
|
2100
|
+
const [now, setNow] = useState4(() => Date.now());
|
|
2015
2101
|
const root = useRef5(null);
|
|
2016
2102
|
const rowScroller = useRef5(null);
|
|
2017
2103
|
const rows = filterSessions(state.sessions, query);
|
|
@@ -2027,6 +2113,10 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
2027
2113
|
useEffect6(() => {
|
|
2028
2114
|
if (loadingMore) setLoadingMore(false);
|
|
2029
2115
|
}, [state.error, state.history.hasMoreSessions, state.sessions.length]);
|
|
2116
|
+
useEffect6(() => {
|
|
2117
|
+
const timer = setInterval(() => setNow(Date.now()), 1e4);
|
|
2118
|
+
return () => clearInterval(timer);
|
|
2119
|
+
}, []);
|
|
2030
2120
|
const loadMore = () => {
|
|
2031
2121
|
if (loadingMore) return;
|
|
2032
2122
|
setLoadingMore(true);
|
|
@@ -2060,23 +2150,120 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
2060
2150
|
] }) : null,
|
|
2061
2151
|
/* @__PURE__ */ jsxs6("div", { class: "scui-session-rows", ref: rowScroller, onScroll: (event) => boundedSet(sessionListMemory, memoryKey, { query, top: event.currentTarget.scrollTop }), children: [
|
|
2062
2152
|
!rows.length && state.startup === "ready" ? /* @__PURE__ */ jsx7("div", { class: "scui-empty", children: query ? "No chats match your search." : state.error ?? "No coding chats found." }) : null,
|
|
2063
|
-
rows.map((row) => /* @__PURE__ */ jsx7(Row, { value: row, row, state, adapter, onOpen }, row.key)),
|
|
2153
|
+
rows.map((row) => /* @__PURE__ */ jsx7(Row, { value: row, row, state, adapter, onOpen, now }, row.key)),
|
|
2064
2154
|
state.history.hasMoreSessions ? /* @__PURE__ */ jsx7("button", { class: "scui-load", type: "button", disabled: loadingMore, onClick: loadMore, children: loadingMore ? "Loading older chats\u2026" : "Load older chats" }) : null
|
|
2065
2155
|
] })
|
|
2066
2156
|
] });
|
|
2067
2157
|
}
|
|
2068
2158
|
|
|
2069
|
-
// src/
|
|
2159
|
+
// src/settings.jsx
|
|
2160
|
+
import { useEffect as useEffect7, useId as useId2, useMemo as useMemo2, useRef as useRef6, useState as useState5 } from "preact/hooks";
|
|
2070
2161
|
import { jsx as jsx8, jsxs as jsxs7 } from "preact/jsx-runtime";
|
|
2162
|
+
function HarnessAdvisory({ state, onReview }) {
|
|
2163
|
+
const advisory = state.interopSettings?.advisories[0];
|
|
2164
|
+
if (!advisory && !state.interopSettingsError) return null;
|
|
2165
|
+
return /* @__PURE__ */ jsxs7("div", { class: "scui-advisory", "data-severity": advisory?.severity ?? "error", role: advisory?.severity === "error" || !advisory ? "alert" : "status", children: [
|
|
2166
|
+
/* @__PURE__ */ jsx8("span", { "aria-hidden": "true", children: "!" }),
|
|
2167
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2168
|
+
/* @__PURE__ */ jsx8("strong", { children: advisory?.title ?? "Could not inspect harness settings" }),
|
|
2169
|
+
/* @__PURE__ */ jsx8("small", { children: advisory?.message ?? state.interopSettingsError })
|
|
2170
|
+
] }),
|
|
2171
|
+
advisory && state.canConfigureSettings ? /* @__PURE__ */ jsx8("button", { type: "button", onClick: () => onReview(advisory.recommendation.change), children: "Review" }) : null
|
|
2172
|
+
] });
|
|
2173
|
+
}
|
|
2174
|
+
function initialValues(report, recommendedChange) {
|
|
2175
|
+
return Object.fromEntries(report.controls.map((control) => [
|
|
2176
|
+
control.key,
|
|
2177
|
+
recommendedChange?.key === control.key ? recommendedChange.value : control.configuredValue ?? control.effectiveValue ?? control.choices[0]?.value ?? null
|
|
2178
|
+
]));
|
|
2179
|
+
}
|
|
2180
|
+
function HarnessSettingsPanel({ state, adapter, onClose, recommendedChange = null }) {
|
|
2181
|
+
const report = state.interopSettings;
|
|
2182
|
+
const titleId = useId2();
|
|
2183
|
+
const panel = useRef6(null);
|
|
2184
|
+
const valuesKey = `${report?.revision ?? ""}:${recommendedChange?.key ?? ""}:${recommendedChange?.value ?? ""}`;
|
|
2185
|
+
const defaults = useMemo2(() => report ? initialValues(report, recommendedChange) : {}, [valuesKey]);
|
|
2186
|
+
const [values, setValues] = useState5(defaults);
|
|
2187
|
+
useEffect7(() => setValues(defaults), [defaults]);
|
|
2188
|
+
useEffect7(() => {
|
|
2189
|
+
panel.current?.querySelector("select, button")?.focus({ preventScroll: true });
|
|
2190
|
+
const dismiss = (event) => {
|
|
2191
|
+
if (event.key === "Escape") {
|
|
2192
|
+
event.preventDefault();
|
|
2193
|
+
onClose();
|
|
2194
|
+
}
|
|
2195
|
+
};
|
|
2196
|
+
document.addEventListener("keydown", dismiss);
|
|
2197
|
+
return () => document.removeEventListener("keydown", dismiss);
|
|
2198
|
+
}, [onClose]);
|
|
2199
|
+
if (!report) return /* @__PURE__ */ jsx8("section", { ref: panel, class: "scui-settings", role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: /* @__PURE__ */ jsxs7("header", { children: [
|
|
2200
|
+
/* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "Close settings", onClick: onClose, children: /* @__PURE__ */ jsx8(UiIcon, { name: "close", size: 18 }) }),
|
|
2201
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2202
|
+
/* @__PURE__ */ jsx8("strong", { id: titleId, children: "Harness settings" }),
|
|
2203
|
+
/* @__PURE__ */ jsx8("small", { children: state.interopSettingsError ?? "No interoperability controls are available." })
|
|
2204
|
+
] })
|
|
2205
|
+
] }) });
|
|
2206
|
+
const changed = report.controls.flatMap((control) => values[control.key] !== (control.configuredValue ?? control.effectiveValue ?? control.choices[0]?.value ?? null) ? [{ key: control.key, value: values[control.key] ?? null }] : []);
|
|
2207
|
+
const submit = (event) => {
|
|
2208
|
+
event.preventDefault();
|
|
2209
|
+
if (!changed.length || !state.canConfigureSettings) return;
|
|
2210
|
+
adapter.onIntent({ action: "configureHarness", harness: report.harness, changes: changed, expectedRevision: report.revision });
|
|
2211
|
+
};
|
|
2212
|
+
return /* @__PURE__ */ jsxs7("section", { ref: panel, class: "scui-settings", role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: [
|
|
2213
|
+
/* @__PURE__ */ jsxs7("header", { children: [
|
|
2214
|
+
/* @__PURE__ */ jsx8("button", { type: "button", "aria-label": "Close settings", onClick: onClose, children: /* @__PURE__ */ jsx8(UiIcon, { name: "close", size: 18 }) }),
|
|
2215
|
+
/* @__PURE__ */ jsxs7("span", { children: [
|
|
2216
|
+
/* @__PURE__ */ jsxs7("strong", { id: titleId, children: [
|
|
2217
|
+
harnessDisplayName(report.harness),
|
|
2218
|
+
" interoperability"
|
|
2219
|
+
] }),
|
|
2220
|
+
/* @__PURE__ */ jsx8("small", { children: "Native harness settings used by Supercode" })
|
|
2221
|
+
] })
|
|
2222
|
+
] }),
|
|
2223
|
+
/* @__PURE__ */ jsxs7("form", { onSubmit: submit, children: [
|
|
2224
|
+
report.controls.map((control) => {
|
|
2225
|
+
const choice = control.choices.find((item) => item.value === values[control.key]);
|
|
2226
|
+
const recommendation = report.advisories.map((advisory) => advisory.recommendation).find((item) => item.change.key === control.key && item.change.value === values[control.key]);
|
|
2227
|
+
const consequence = choice?.risk ?? recommendation?.consequence;
|
|
2228
|
+
return /* @__PURE__ */ jsxs7("fieldset", { disabled: !control.writable || Boolean(state.operation), children: [
|
|
2229
|
+
/* @__PURE__ */ jsxs7("label", { for: `scui-setting-${control.key}`, children: [
|
|
2230
|
+
/* @__PURE__ */ jsx8("strong", { children: control.label }),
|
|
2231
|
+
/* @__PURE__ */ jsx8("small", { children: control.description })
|
|
2232
|
+
] }),
|
|
2233
|
+
/* @__PURE__ */ jsxs7("select", { id: `scui-setting-${control.key}`, value: values[control.key] ?? "@default", onChange: (event) => setValues((current) => ({ ...current, [control.key]: event.currentTarget.value === "@default" ? null : event.currentTarget.value })), children: [
|
|
2234
|
+
control.resettable ? /* @__PURE__ */ jsx8("option", { value: "@default", children: "Use harness default" }) : null,
|
|
2235
|
+
control.choices.map((item) => /* @__PURE__ */ jsx8("option", { value: item.value, children: item.label }, item.value))
|
|
2236
|
+
] }),
|
|
2237
|
+
choice ? /* @__PURE__ */ jsx8("p", { children: choice.description }) : null,
|
|
2238
|
+
consequence ? /* @__PURE__ */ jsxs7("p", { class: "scui-setting-risk", children: [
|
|
2239
|
+
/* @__PURE__ */ jsx8("strong", { children: "Security consequence" }),
|
|
2240
|
+
consequence
|
|
2241
|
+
] }) : null,
|
|
2242
|
+
/* @__PURE__ */ jsxs7("small", { class: "scui-setting-source", children: [
|
|
2243
|
+
control.effectiveNote,
|
|
2244
|
+
control.sourcePath ? ` Source: ${control.sourcePath}` : ""
|
|
2245
|
+
] })
|
|
2246
|
+
] }, control.key);
|
|
2247
|
+
}),
|
|
2248
|
+
/* @__PURE__ */ jsxs7("footer", { children: [
|
|
2249
|
+
/* @__PURE__ */ jsx8("button", { type: "button", onClick: onClose, children: "Cancel" }),
|
|
2250
|
+
/* @__PURE__ */ jsx8("button", { type: "submit", disabled: !changed.length || !state.canConfigureSettings || Boolean(state.operation), children: state.operation === "configureHarness" ? "Applying\u2026" : "Apply changes" })
|
|
2251
|
+
] })
|
|
2252
|
+
] })
|
|
2253
|
+
] });
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
// src/messenger.jsx
|
|
2257
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
2071
2258
|
var pendingMessageMemory = /* @__PURE__ */ new Map();
|
|
2072
2259
|
var messengerViewMemory = /* @__PURE__ */ new Map();
|
|
2073
2260
|
var newChatMemory = /* @__PURE__ */ new Map();
|
|
2074
|
-
var TRACKED_ACTIONS = /* @__PURE__ */ new Set(["resume", "join", "detach", "branch", "reduce", "terminal", "export", "interrupt", "respond", "refresh", "loadEarlier", "loadSessions"]);
|
|
2261
|
+
var TRACKED_ACTIONS = /* @__PURE__ */ new Set(["resume", "join", "detach", "branch", "reduce", "terminal", "export", "interrupt", "respond", "configureHarness", "refresh", "loadEarlier", "loadSessions"]);
|
|
2075
2262
|
function Receipt({ state, adapter }) {
|
|
2076
2263
|
const receipt = state.reductionReceipt;
|
|
2077
|
-
if (receipt) return /* @__PURE__ */
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2264
|
+
if (receipt) return /* @__PURE__ */ jsx9("div", { class: "scui-receipt", children: /* @__PURE__ */ jsxs8("span", { children: [
|
|
2265
|
+
/* @__PURE__ */ jsx9("strong", { children: "Reduced and verified" }),
|
|
2266
|
+
/* @__PURE__ */ jsxs8("small", { children: [
|
|
2080
2267
|
receipt.sourceTokens.toLocaleString(),
|
|
2081
2268
|
" \u2192 ",
|
|
2082
2269
|
receipt.reducedTokens.toLocaleString(),
|
|
@@ -2085,36 +2272,36 @@ function Receipt({ state, adapter }) {
|
|
|
2085
2272
|
"\xD7 \xB7 reversible"
|
|
2086
2273
|
] })
|
|
2087
2274
|
] }) });
|
|
2088
|
-
if (state.exportReceipt) return /* @__PURE__ */
|
|
2089
|
-
/* @__PURE__ */
|
|
2090
|
-
/* @__PURE__ */
|
|
2275
|
+
if (state.exportReceipt) return /* @__PURE__ */ jsxs8("div", { class: "scui-receipt", children: [
|
|
2276
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2277
|
+
/* @__PURE__ */ jsxs8("strong", { children: [
|
|
2091
2278
|
"Lossless export ready \xB7 ",
|
|
2092
2279
|
harnessDisplayName(state.exportReceipt.targetHarness)
|
|
2093
2280
|
] }),
|
|
2094
|
-
/* @__PURE__ */
|
|
2281
|
+
/* @__PURE__ */ jsxs8("small", { children: [
|
|
2095
2282
|
state.exportReceipt.path,
|
|
2096
2283
|
" \xB7 ",
|
|
2097
2284
|
state.exportReceipt.files,
|
|
2098
2285
|
" files"
|
|
2099
2286
|
] })
|
|
2100
2287
|
] }),
|
|
2101
|
-
/* @__PURE__ */
|
|
2288
|
+
/* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.copyText?.(state.exportReceipt.path), children: "Copy path" })
|
|
2102
2289
|
] });
|
|
2103
|
-
if (state.terminalHandoff) return /* @__PURE__ */
|
|
2104
|
-
/* @__PURE__ */
|
|
2105
|
-
/* @__PURE__ */
|
|
2106
|
-
/* @__PURE__ */
|
|
2290
|
+
if (state.terminalHandoff) return /* @__PURE__ */ jsxs8("div", { class: "scui-receipt", children: [
|
|
2291
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2292
|
+
/* @__PURE__ */ jsx9("strong", { children: "Terminal handoff ready" }),
|
|
2293
|
+
/* @__PURE__ */ jsx9("small", { children: state.terminalHandoff.cwd })
|
|
2107
2294
|
] }),
|
|
2108
|
-
/* @__PURE__ */
|
|
2295
|
+
/* @__PURE__ */ jsx9("button", { type: "button", onClick: () => adapter.copyText?.(terminalCommand(state.terminalHandoff)), children: "Copy command" })
|
|
2109
2296
|
] });
|
|
2110
2297
|
return null;
|
|
2111
2298
|
}
|
|
2112
|
-
function ConversationActions({ state, adapter, actionPending }) {
|
|
2113
|
-
const [open, setOpen] =
|
|
2114
|
-
const root =
|
|
2115
|
-
const panel =
|
|
2116
|
-
const trigger =
|
|
2117
|
-
const menuId =
|
|
2299
|
+
function ConversationActions({ state, adapter, actionPending, onSettings }) {
|
|
2300
|
+
const [open, setOpen] = useState6(false);
|
|
2301
|
+
const root = useRef7(null);
|
|
2302
|
+
const panel = useRef7(null);
|
|
2303
|
+
const trigger = useRef7(null);
|
|
2304
|
+
const menuId = useId3();
|
|
2118
2305
|
const targets = state.harnesses.filter((item) => item.startable);
|
|
2119
2306
|
const groups = [
|
|
2120
2307
|
{
|
|
@@ -2122,7 +2309,8 @@ function ConversationActions({ state, adapter, actionPending }) {
|
|
|
2122
2309
|
items: [
|
|
2123
2310
|
state.canDetach ? { key: "detach", label: "Detach to read-only", intent: { action: "detach" } } : null,
|
|
2124
2311
|
state.canOpenTerminal ? { key: "terminal", label: "Prepare terminal handoff", intent: { action: "terminal" } } : null,
|
|
2125
|
-
state.canExport && state.exportBackTarget ? { key: "export", label: `Export back to ${harnessDisplayName(state.exportBackTarget)}`, intent: { action: "export", targetHarness: state.exportBackTarget } } : null
|
|
2312
|
+
state.canExport && state.exportBackTarget ? { key: "export", label: `Export back to ${harnessDisplayName(state.exportBackTarget)}`, intent: { action: "export", targetHarness: state.exportBackTarget } } : null,
|
|
2313
|
+
state.interopSettings || state.interopSettingsError ? { key: "settings", label: "Interoperability settings", onSelect: onSettings } : null
|
|
2126
2314
|
].filter(Boolean)
|
|
2127
2315
|
},
|
|
2128
2316
|
{
|
|
@@ -2134,7 +2322,7 @@ function ConversationActions({ state, adapter, actionPending }) {
|
|
|
2134
2322
|
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 } })) : []
|
|
2135
2323
|
}
|
|
2136
2324
|
].filter((group) => group.items.length);
|
|
2137
|
-
|
|
2325
|
+
useEffect8(() => {
|
|
2138
2326
|
if (!open) return;
|
|
2139
2327
|
panel.current?.querySelector("button:not(:disabled)")?.focus({ preventScroll: true });
|
|
2140
2328
|
const dismiss = (event) => {
|
|
@@ -2153,9 +2341,10 @@ function ConversationActions({ state, adapter, actionPending }) {
|
|
|
2153
2341
|
document.removeEventListener("pointerdown", dismiss, true);
|
|
2154
2342
|
};
|
|
2155
2343
|
}, [open]);
|
|
2156
|
-
const dispatch = (
|
|
2344
|
+
const dispatch = (item) => {
|
|
2157
2345
|
setOpen(false);
|
|
2158
|
-
|
|
2346
|
+
if (item.onSelect) item.onSelect();
|
|
2347
|
+
else adapter.onIntent(item.intent);
|
|
2159
2348
|
};
|
|
2160
2349
|
const navigate = (event) => {
|
|
2161
2350
|
if (event.key === "Escape") {
|
|
@@ -2173,62 +2362,63 @@ function ConversationActions({ state, adapter, actionPending }) {
|
|
|
2173
2362
|
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;
|
|
2174
2363
|
items[index].focus({ preventScroll: true });
|
|
2175
2364
|
};
|
|
2176
|
-
return /* @__PURE__ */
|
|
2365
|
+
return /* @__PURE__ */ jsxs8("div", { class: "scui-menu", ref: root, onBlur: (event) => {
|
|
2177
2366
|
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
2178
2367
|
}, children: [
|
|
2179
|
-
/* @__PURE__ */
|
|
2180
|
-
open ? /* @__PURE__ */
|
|
2181
|
-
/* @__PURE__ */
|
|
2182
|
-
group.items.map((item) => /* @__PURE__ */
|
|
2368
|
+
/* @__PURE__ */ jsx9("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__ */ jsx9(UiIcon, { name: "menu", size: 18 }) }),
|
|
2369
|
+
open ? /* @__PURE__ */ jsx9("div", { ref: panel, id: menuId, class: "scui-menu-panel", role: "menu", "aria-label": "Conversation actions", onKeyDown: navigate, children: groups.map((group) => /* @__PURE__ */ jsxs8("section", { role: "group", "aria-label": group.label, children: [
|
|
2370
|
+
/* @__PURE__ */ jsx9("strong", { children: group.label }),
|
|
2371
|
+
group.items.map((item) => /* @__PURE__ */ jsx9("button", { role: "menuitem", type: "button", disabled: actionPending, onClick: () => dispatch(item), children: item.label }, item.key))
|
|
2183
2372
|
] }, group.label)) }) : null
|
|
2184
2373
|
] });
|
|
2185
2374
|
}
|
|
2186
|
-
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose }) {
|
|
2187
|
-
const back =
|
|
2375
|
+
function ChatHeader({ state, adapter, pendingStatus, actionPending, onBack, onNew, onClose, onSettings }) {
|
|
2376
|
+
const back = useRef7(null);
|
|
2188
2377
|
const harness = state.attached?.harness ?? state.harness;
|
|
2189
2378
|
const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
|
|
2190
2379
|
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";
|
|
2191
|
-
const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce;
|
|
2192
|
-
|
|
2380
|
+
const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce || state.interopSettings || state.interopSettingsError;
|
|
2381
|
+
useEffect8(() => {
|
|
2193
2382
|
if (state.mode === "mirror" && !state.canSend) back.current?.focus({ preventScroll: true });
|
|
2194
2383
|
}, []);
|
|
2195
|
-
return /* @__PURE__ */
|
|
2196
|
-
/* @__PURE__ */
|
|
2197
|
-
/* @__PURE__ */
|
|
2198
|
-
/* @__PURE__ */
|
|
2199
|
-
/* @__PURE__ */
|
|
2200
|
-
/* @__PURE__ */
|
|
2384
|
+
return /* @__PURE__ */ jsxs8("header", { class: "scui-head scui-chat-head", children: [
|
|
2385
|
+
/* @__PURE__ */ jsx9("button", { ref: back, type: "button", "aria-label": "Back to chats", onClick: onBack, children: /* @__PURE__ */ jsx9(UiIcon, { name: "back", size: 18 }) }),
|
|
2386
|
+
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size: 28 }),
|
|
2387
|
+
/* @__PURE__ */ jsxs8("span", { class: "scui-head-copy", children: [
|
|
2388
|
+
/* @__PURE__ */ jsx9("strong", { children: title }),
|
|
2389
|
+
/* @__PURE__ */ jsxs8("small", { children: [
|
|
2201
2390
|
harnessDisplayName(harness),
|
|
2202
2391
|
" \xB7 ",
|
|
2203
2392
|
status
|
|
2204
2393
|
] })
|
|
2205
2394
|
] }),
|
|
2206
|
-
menu ? /* @__PURE__ */
|
|
2207
|
-
/* @__PURE__ */
|
|
2208
|
-
onClose ? /* @__PURE__ */
|
|
2395
|
+
menu ? /* @__PURE__ */ jsx9(ConversationActions, { state, adapter, actionPending, onSettings }) : null,
|
|
2396
|
+
/* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: /* @__PURE__ */ jsx9(UiIcon, { name: "plus", size: 18 }) }),
|
|
2397
|
+
onClose ? /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx9(UiIcon, { name: "close", size: 18 }) }) : null
|
|
2209
2398
|
] });
|
|
2210
2399
|
}
|
|
2211
2400
|
function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
|
|
2212
2401
|
const Header = slots.header;
|
|
2213
2402
|
const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
|
|
2214
|
-
const [pending, setPendingState] =
|
|
2215
|
-
const [pendingAction, setPendingAction] =
|
|
2216
|
-
const [restoreDraft, setRestoreDraft] =
|
|
2217
|
-
const
|
|
2218
|
-
const
|
|
2219
|
-
const
|
|
2403
|
+
const [pending, setPendingState] = useState6(() => pendingMessageMemory.get(memoryKey) ?? null);
|
|
2404
|
+
const [pendingAction, setPendingAction] = useState6(null);
|
|
2405
|
+
const [restoreDraft, setRestoreDraft] = useState6(null);
|
|
2406
|
+
const [settings, setSettings] = useState6(null);
|
|
2407
|
+
const restoreSequence = useRef7(0);
|
|
2408
|
+
const actionSequence = useRef7(0);
|
|
2409
|
+
const acknowledged = useRef7(/* @__PURE__ */ new Set());
|
|
2220
2410
|
const setPending = (update) => setPendingState((current) => {
|
|
2221
2411
|
const next = typeof update === "function" ? update(current) : update;
|
|
2222
2412
|
if (next) boundedSet(pendingMessageMemory, memoryKey, next);
|
|
2223
2413
|
else pendingMessageMemory.delete(memoryKey);
|
|
2224
2414
|
return next;
|
|
2225
2415
|
});
|
|
2226
|
-
|
|
2416
|
+
useEffect8(() => {
|
|
2227
2417
|
setPendingState(pendingMessageMemory.get(memoryKey) ?? null);
|
|
2228
2418
|
setPendingAction(null);
|
|
2229
2419
|
setRestoreDraft(null);
|
|
2230
2420
|
}, [memoryKey]);
|
|
2231
|
-
|
|
2421
|
+
useEffect8(() => {
|
|
2232
2422
|
if (!pending) return;
|
|
2233
2423
|
if (state.transcript.some((entry) => entry.role === "user" && entry.text.trim() === pending.text.trim() && !pending.baselineIds.includes(entry.id))) {
|
|
2234
2424
|
setPending(null);
|
|
@@ -2257,7 +2447,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2257
2447
|
setRestoreDraft({ id: restoreSequence.current, text: pending.text, context: pending.context, images: pending.images });
|
|
2258
2448
|
setPending({ ...pending, status: "editing" });
|
|
2259
2449
|
};
|
|
2260
|
-
|
|
2450
|
+
useEffect8(() => {
|
|
2261
2451
|
const key = state.attached?.key;
|
|
2262
2452
|
if (!key || !state.attention.some((item) => item.key === key)) {
|
|
2263
2453
|
if (key) acknowledged.current.delete(key);
|
|
@@ -2268,7 +2458,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2268
2458
|
adapter.onIntent({ action: "ack", key });
|
|
2269
2459
|
}
|
|
2270
2460
|
}, [adapter, state.attached?.key, state.attention]);
|
|
2271
|
-
const trackedAdapter =
|
|
2461
|
+
const trackedAdapter = useMemo3(() => ({
|
|
2272
2462
|
...adapter,
|
|
2273
2463
|
onIntent(intent) {
|
|
2274
2464
|
if (!TRACKED_ACTIONS.has(intent.action)) return adapter.onIntent(intent);
|
|
@@ -2292,7 +2482,7 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2292
2482
|
return result;
|
|
2293
2483
|
}
|
|
2294
2484
|
}), [adapter, state.error]);
|
|
2295
|
-
|
|
2485
|
+
useEffect8(() => {
|
|
2296
2486
|
if (!pendingAction) return;
|
|
2297
2487
|
if (state.operation && !pendingAction.seenOperation) {
|
|
2298
2488
|
setPendingAction({ ...pendingAction, seenOperation: true });
|
|
@@ -2305,44 +2495,48 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
2305
2495
|
const actionLabel = operationLabel(action);
|
|
2306
2496
|
const actionState = action ? { ...state, operation: action, canInterrupt: false, canRespond: false } : state;
|
|
2307
2497
|
const unreadAfterMessages = state.attention.find((item) => item.key === state.attached?.key)?.afterMessages ?? null;
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2498
|
+
const Advisory = components.HarnessAdvisory ?? HarnessAdvisory;
|
|
2499
|
+
const SettingsPanel = components.HarnessSettingsPanel ?? HarnessSettingsPanel;
|
|
2500
|
+
return /* @__PURE__ */ jsxs8("section", { class: "scui-chat", children: [
|
|
2501
|
+
Header ? /* @__PURE__ */ jsx9(Header, { state: actionState, adapter: trackedAdapter, value: null }) : /* @__PURE__ */ jsx9(ChatHeader, { state: actionState, adapter: trackedAdapter, pendingStatus: pending?.status ?? null, actionPending: Boolean(action), onBack, onNew, onClose, onSettings: () => setSettings({ recommendedChange: null }) }),
|
|
2502
|
+
actionLabel ? /* @__PURE__ */ jsxs8("div", { class: "scui-operation", role: "status", children: [
|
|
2503
|
+
/* @__PURE__ */ jsx9("i", {}),
|
|
2312
2504
|
actionLabel
|
|
2313
2505
|
] }) : null,
|
|
2314
|
-
state.error ? /* @__PURE__ */
|
|
2315
|
-
/* @__PURE__ */
|
|
2316
|
-
state.recoverable ? /* @__PURE__ */
|
|
2506
|
+
state.error ? /* @__PURE__ */ jsxs8("div", { class: "scui-error", role: "alert", children: [
|
|
2507
|
+
/* @__PURE__ */ jsx9("span", { children: state.error }),
|
|
2508
|
+
state.recoverable ? /* @__PURE__ */ jsx9("button", { type: "button", disabled: Boolean(action), onClick: () => trackedAdapter.onIntent({ action: "refresh" }), children: "Retry" }) : null
|
|
2317
2509
|
] }) : null,
|
|
2318
|
-
/* @__PURE__ */
|
|
2319
|
-
/* @__PURE__ */
|
|
2320
|
-
/* @__PURE__ */
|
|
2321
|
-
|
|
2510
|
+
/* @__PURE__ */ jsx9(Receipt, { state, adapter }),
|
|
2511
|
+
/* @__PURE__ */ jsx9(Conversation, { state: actionState, adapter: trackedAdapter, components, slots, memoryKey, pending: pendingMessage, unreadAfterMessages }, memoryKey),
|
|
2512
|
+
/* @__PURE__ */ jsx9(ContinuationBar, { state: actionState, adapter: trackedAdapter, labels }),
|
|
2513
|
+
/* @__PURE__ */ jsx9(Advisory, { state: actionState, adapter: trackedAdapter, value: state.interopSettings?.advisories[0] ?? null, onReview: (recommendedChange) => setSettings({ recommendedChange }) }),
|
|
2514
|
+
state.mode !== "mirror" || state.canSend ? /* @__PURE__ */ jsx9(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,
|
|
2515
|
+
settings ? /* @__PURE__ */ jsx9(SettingsPanel, { state: actionState, adapter: trackedAdapter, value: state.interopSettings, recommendedChange: settings.recommendedChange, onClose: () => setSettings(null) }) : null
|
|
2322
2516
|
] });
|
|
2323
2517
|
}
|
|
2324
2518
|
function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey }) {
|
|
2325
2519
|
const startable = state.harnesses.filter((item) => item.startable);
|
|
2326
2520
|
const startableKey = startable.map((item) => item.id).join("\0");
|
|
2327
2521
|
const remembered = newChatMemory.get(memoryKey) ?? { harness: startable[0]?.id ?? "", draft: "", context: [], images: [] };
|
|
2328
|
-
const [harness, setHarness] =
|
|
2329
|
-
const [draft, setDraft] =
|
|
2330
|
-
const [context, setContext] =
|
|
2331
|
-
const [images, setImages] =
|
|
2332
|
-
const [starting, setStarting] =
|
|
2333
|
-
const [picking, setPicking] =
|
|
2334
|
-
const [dragging, setDragging] =
|
|
2335
|
-
const [pickerError, setPickerError] =
|
|
2336
|
-
const startSequence =
|
|
2337
|
-
const textarea =
|
|
2522
|
+
const [harness, setHarness] = useState6(remembered.harness);
|
|
2523
|
+
const [draft, setDraft] = useState6(remembered.draft);
|
|
2524
|
+
const [context, setContext] = useState6(remembered.context);
|
|
2525
|
+
const [images, setImages] = useState6(remembered.images ?? []);
|
|
2526
|
+
const [starting, setStarting] = useState6(null);
|
|
2527
|
+
const [picking, setPicking] = useState6(false);
|
|
2528
|
+
const [dragging, setDragging] = useState6(false);
|
|
2529
|
+
const [pickerError, setPickerError] = useState6(null);
|
|
2530
|
+
const startSequence = useRef7(0);
|
|
2531
|
+
const textarea = useRef7(null);
|
|
2338
2532
|
useAutosizeTextarea(textarea, draft);
|
|
2339
|
-
|
|
2533
|
+
useEffect8(() => {
|
|
2340
2534
|
if (startable.some((item) => item.id === harness)) return;
|
|
2341
2535
|
const next = startable[0]?.id ?? "";
|
|
2342
2536
|
setHarness(next);
|
|
2343
2537
|
boundedSet(newChatMemory, memoryKey, { harness: next, draft, context, images });
|
|
2344
2538
|
}, [harness, startableKey]);
|
|
2345
|
-
|
|
2539
|
+
useEffect8(() => {
|
|
2346
2540
|
if (!starting) return;
|
|
2347
2541
|
const sessionChanged = (state.attached?.key ?? null) !== starting.attachedKey;
|
|
2348
2542
|
const beganWorking = !starting.busy && state.busy;
|
|
@@ -2350,10 +2544,10 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2350
2544
|
newChatMemory.delete(memoryKey);
|
|
2351
2545
|
onStarted();
|
|
2352
2546
|
}, [memoryKey, onStarted, starting, state.attached?.key, state.busy]);
|
|
2353
|
-
|
|
2547
|
+
useEffect8(() => {
|
|
2354
2548
|
if (starting && state.error !== starting.initialError && !state.busy && !state.operation) setStarting(null);
|
|
2355
2549
|
}, [starting, state.busy, state.error, state.operation]);
|
|
2356
|
-
|
|
2550
|
+
useEffect8(() => {
|
|
2357
2551
|
textarea.current?.focus({ preventScroll: true });
|
|
2358
2552
|
}, []);
|
|
2359
2553
|
const pickContext = () => {
|
|
@@ -2415,49 +2609,49 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2415
2609
|
Promise.resolve(result).catch(() => setStarting((current) => current?.id === id ? null : current));
|
|
2416
2610
|
}
|
|
2417
2611
|
};
|
|
2418
|
-
return /* @__PURE__ */
|
|
2419
|
-
/* @__PURE__ */
|
|
2420
|
-
/* @__PURE__ */
|
|
2421
|
-
/* @__PURE__ */
|
|
2422
|
-
/* @__PURE__ */
|
|
2423
|
-
/* @__PURE__ */
|
|
2612
|
+
return /* @__PURE__ */ jsxs8("section", { class: "scui-chat", children: [
|
|
2613
|
+
/* @__PURE__ */ jsxs8("header", { class: "scui-head", children: [
|
|
2614
|
+
/* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Back", onClick: onBack, children: /* @__PURE__ */ jsx9(UiIcon, { name: "back", size: 18 }) }),
|
|
2615
|
+
/* @__PURE__ */ jsxs8("span", { class: "scui-head-copy", children: [
|
|
2616
|
+
/* @__PURE__ */ jsx9("strong", { children: labels.newChat }),
|
|
2617
|
+
/* @__PURE__ */ jsx9("small", { children: "No session is created until you send" })
|
|
2424
2618
|
] }),
|
|
2425
|
-
onClose ? /* @__PURE__ */
|
|
2619
|
+
onClose ? /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx9(UiIcon, { name: "close", size: 18 }) }) : null
|
|
2426
2620
|
] }),
|
|
2427
|
-
starting ? /* @__PURE__ */
|
|
2428
|
-
/* @__PURE__ */
|
|
2621
|
+
starting ? /* @__PURE__ */ jsxs8("div", { class: "scui-operation", role: "status", children: [
|
|
2622
|
+
/* @__PURE__ */ jsx9("i", {}),
|
|
2429
2623
|
operationLabel("start")
|
|
2430
2624
|
] }) : null,
|
|
2431
|
-
/* @__PURE__ */
|
|
2432
|
-
/* @__PURE__ */
|
|
2433
|
-
/* @__PURE__ */
|
|
2434
|
-
/* @__PURE__ */
|
|
2625
|
+
/* @__PURE__ */ jsxs8("div", { class: "scui-new", children: [
|
|
2626
|
+
/* @__PURE__ */ jsx9("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
2627
|
+
/* @__PURE__ */ jsx9("strong", { children: "What should the agent build or fix?" }),
|
|
2628
|
+
/* @__PURE__ */ jsx9("small", { children: "Choose a coding harness and send the first message." })
|
|
2435
2629
|
] }),
|
|
2436
|
-
/* @__PURE__ */
|
|
2437
|
-
/* @__PURE__ */
|
|
2438
|
-
/* @__PURE__ */
|
|
2439
|
-
/* @__PURE__ */
|
|
2440
|
-
/* @__PURE__ */
|
|
2630
|
+
/* @__PURE__ */ jsxs8("div", { class: "scui-compose", children: [
|
|
2631
|
+
/* @__PURE__ */ jsxs8("label", { class: "scui-harness-picker", children: [
|
|
2632
|
+
/* @__PURE__ */ jsx9(HarnessLogo, { id: harness, size: 24 }),
|
|
2633
|
+
/* @__PURE__ */ jsx9("span", { children: "Coding harness" }),
|
|
2634
|
+
/* @__PURE__ */ jsx9("select", { value: harness, disabled: Boolean(starting), onChange: (event) => {
|
|
2441
2635
|
const value = event.currentTarget.value;
|
|
2442
2636
|
setHarness(value);
|
|
2443
2637
|
boundedSet(newChatMemory, memoryKey, { harness: value, draft, context, images });
|
|
2444
|
-
}, children: state.harnesses.map((item) => /* @__PURE__ */
|
|
2638
|
+
}, children: state.harnesses.map((item) => /* @__PURE__ */ jsxs8("option", { value: item.id, disabled: !item.startable, children: [
|
|
2445
2639
|
item.label,
|
|
2446
2640
|
item.startable ? "" : " \xB7 unavailable"
|
|
2447
2641
|
] }, item.id)) })
|
|
2448
2642
|
] }),
|
|
2449
|
-
/* @__PURE__ */
|
|
2643
|
+
/* @__PURE__ */ jsx9(ImageTray, { items: images, onRemove: (index) => setImages((items) => {
|
|
2450
2644
|
const next = items.filter((_, itemIndex) => itemIndex !== index);
|
|
2451
2645
|
boundedSet(newChatMemory, memoryKey, { harness, draft, context, images: next });
|
|
2452
2646
|
return next;
|
|
2453
2647
|
}) }),
|
|
2454
|
-
/* @__PURE__ */
|
|
2648
|
+
/* @__PURE__ */ jsx9(ContextTray, { items: context, onRemove: (index) => setContext((items) => {
|
|
2455
2649
|
const next = items.filter((_, itemIndex) => itemIndex !== index);
|
|
2456
2650
|
boundedSet(newChatMemory, memoryKey, { harness, draft, context: next, images });
|
|
2457
2651
|
return next;
|
|
2458
2652
|
}) }),
|
|
2459
|
-
pickerError ? /* @__PURE__ */
|
|
2460
|
-
/* @__PURE__ */
|
|
2653
|
+
pickerError ? /* @__PURE__ */ jsx9("small", { class: "scui-context-error", role: "alert", children: pickerError }) : null,
|
|
2654
|
+
/* @__PURE__ */ jsxs8("div", { class: `scui-envelope${dragging ? " scui-drop-target" : ""}`, onDragEnter: (event) => {
|
|
2461
2655
|
if (Array.from(event.dataTransfer?.types ?? []).includes("Files")) {
|
|
2462
2656
|
event.preventDefault();
|
|
2463
2657
|
setDragging(true);
|
|
@@ -2467,8 +2661,8 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2467
2661
|
}, onDragLeave: (event) => {
|
|
2468
2662
|
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
2469
2663
|
}, onDrop: dropImages, children: [
|
|
2470
|
-
adapter.pickContext ? /* @__PURE__ */
|
|
2471
|
-
/* @__PURE__ */
|
|
2664
|
+
adapter.pickContext ? /* @__PURE__ */ jsx9("button", { class: "scui-attach", type: "button", "aria-label": "Attach files or images", disabled: picking || context.length >= MAX_CONTEXT_ITEMS && images.length >= MAX_IMAGE_ITEMS || Boolean(starting), onClick: pickContext, children: picking ? /* @__PURE__ */ jsx9("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "attach", size: 17 }) }) : null,
|
|
2665
|
+
/* @__PURE__ */ jsx9("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), onPaste: pasteImages, onInput: (event) => {
|
|
2472
2666
|
const value = event.currentTarget.value;
|
|
2473
2667
|
setDraft(value);
|
|
2474
2668
|
boundedSet(newChatMemory, memoryKey, { harness, draft: value, context, images });
|
|
@@ -2478,23 +2672,23 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels, memoryKey
|
|
|
2478
2672
|
send();
|
|
2479
2673
|
}
|
|
2480
2674
|
} }),
|
|
2481
|
-
/* @__PURE__ */
|
|
2675
|
+
/* @__PURE__ */ jsx9("span", { children: /* @__PURE__ */ jsx9("button", { type: "button", class: "scui-send", "aria-label": "Start chat", disabled: !draft.trim() && !images.length || !harness || Boolean(starting), onClick: send, children: starting ? /* @__PURE__ */ jsx9("i", { class: "scui-control-spinner" }) : /* @__PURE__ */ jsx9(UiIcon, { name: "send", size: 17 }) }) })
|
|
2482
2676
|
] })
|
|
2483
2677
|
] })
|
|
2484
2678
|
] });
|
|
2485
2679
|
}
|
|
2486
2680
|
function SupercodeMessenger({ state: stateInput, adapter, class: className = "", initialView, labels, components = {}, slots = {} }) {
|
|
2487
|
-
const state =
|
|
2681
|
+
const state = useMemo3(() => normalizeUiState(stateInput), [stateInput]);
|
|
2488
2682
|
const copy = { ...DEFAULT_LABELS, ...labels };
|
|
2489
2683
|
const memoryKey = state.workspace || "@default";
|
|
2490
|
-
const [view, setViewState] =
|
|
2491
|
-
const [opening, setOpening] =
|
|
2492
|
-
const [listFocus, setListFocus] =
|
|
2684
|
+
const [view, setViewState] = useState6(initialView ?? (state.attention.length ? "list" : messengerViewMemory.get(memoryKey) ?? (state.attached || state.transcript.length ? "chat" : "list")));
|
|
2685
|
+
const [opening, setOpening] = useState6(null);
|
|
2686
|
+
const [listFocus, setListFocus] = useState6(null);
|
|
2493
2687
|
const setView = (next) => {
|
|
2494
2688
|
boundedSet(messengerViewMemory, memoryKey, next);
|
|
2495
2689
|
setViewState(next);
|
|
2496
2690
|
};
|
|
2497
|
-
|
|
2691
|
+
useEffect8(() => {
|
|
2498
2692
|
if (!opening) return;
|
|
2499
2693
|
if (state.attached?.key === opening.key) {
|
|
2500
2694
|
setOpening(null);
|
|
@@ -2510,31 +2704,31 @@ function SupercodeMessenger({ state: stateInput, adapter, class: className = "",
|
|
|
2510
2704
|
};
|
|
2511
2705
|
const close = () => adapter.onClose?.();
|
|
2512
2706
|
const Footer = slots.footer;
|
|
2513
|
-
return /* @__PURE__ */
|
|
2514
|
-
view === "list" ? /* @__PURE__ */
|
|
2707
|
+
return /* @__PURE__ */ jsxs8("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
|
|
2708
|
+
view === "list" ? /* @__PURE__ */ jsx9(SessionList, { state, adapter, focusKey: listFocus, onOpen: open, onNew: () => {
|
|
2515
2709
|
setListFocus("@new");
|
|
2516
2710
|
setView("new");
|
|
2517
2711
|
}, onClose: adapter.onClose ? close : void 0, components, labels: copy, memoryKey }) : null,
|
|
2518
|
-
view === "new" ? /* @__PURE__ */
|
|
2519
|
-
view === "chat" ? /* @__PURE__ */
|
|
2712
|
+
view === "new" ? /* @__PURE__ */ jsx9(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: () => setView("chat"), labels: copy, memoryKey }) : null,
|
|
2713
|
+
view === "chat" ? /* @__PURE__ */ jsx9(Chat, { state, adapter, onBack: () => {
|
|
2520
2714
|
setListFocus(state.attached?.key ?? listFocus);
|
|
2521
2715
|
setView("list");
|
|
2522
2716
|
}, onNew: () => {
|
|
2523
2717
|
setListFocus("@new");
|
|
2524
2718
|
setView("new");
|
|
2525
2719
|
}, onClose: adapter.onClose ? close : void 0, components, slots, labels: copy }) : null,
|
|
2526
|
-
opening ? /* @__PURE__ */
|
|
2527
|
-
/* @__PURE__ */
|
|
2528
|
-
/* @__PURE__ */
|
|
2529
|
-
/* @__PURE__ */
|
|
2720
|
+
opening ? /* @__PURE__ */ jsxs8("div", { class: "scui-opening", role: "status", "aria-busy": "true", children: [
|
|
2721
|
+
/* @__PURE__ */ jsx9(HarnessLogo, { id: opening.harness, size: 34 }),
|
|
2722
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
2723
|
+
/* @__PURE__ */ jsxs8("strong", { children: [
|
|
2530
2724
|
"Opening ",
|
|
2531
2725
|
sessionDisplayName(opening)
|
|
2532
2726
|
] }),
|
|
2533
|
-
/* @__PURE__ */
|
|
2727
|
+
/* @__PURE__ */ jsx9("small", { children: "Loading the latest transcript window\u2026" })
|
|
2534
2728
|
] }),
|
|
2535
|
-
/* @__PURE__ */
|
|
2729
|
+
/* @__PURE__ */ jsx9("i", {})
|
|
2536
2730
|
] }) : null,
|
|
2537
|
-
Footer ? /* @__PURE__ */
|
|
2731
|
+
Footer ? /* @__PURE__ */ jsx9(Footer, { state, adapter, value: copy }) : null
|
|
2538
2732
|
] });
|
|
2539
2733
|
}
|
|
2540
2734
|
export {
|