@volter-ai-dev/supercode-ui 0.1.1 → 0.1.2
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 +7 -5
- package/components.d.ts +17 -0
- package/components.mjs +416 -346
- package/composer.d.ts +2 -0
- package/composer.mjs +23 -20
- package/conversation.d.ts +20 -0
- package/conversation.mjs +79 -65
- package/core.d.ts +41 -0
- package/core.mjs +71 -4
- package/embed.d.ts +2 -0
- package/embed.mjs +415 -345
- package/logo.d.ts +2 -0
- package/logo.mjs +7 -70
- package/messenger.d.ts +10 -0
- package/messenger.mjs +413 -343
- package/package.json +23 -12
- package/sessions.d.ts +9 -0
- package/sessions.mjs +71 -53
- package/styles.css +5 -4
package/composer.d.ts
ADDED
package/composer.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import
|
|
3
|
-
import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
|
1
|
+
// src/composer.jsx
|
|
2
|
+
import { useEffect, useRef, useState } from "preact/hooks";
|
|
4
3
|
|
|
5
4
|
// core.mjs
|
|
6
5
|
var HARNESS_NAMES = Object.freeze({
|
|
7
6
|
"claude-code": "Claude Code",
|
|
8
7
|
codex: "Codex",
|
|
8
|
+
gemini: "Gemini CLI",
|
|
9
9
|
opencode: "OpenCode",
|
|
10
10
|
pi: "Pi",
|
|
11
11
|
grok: "Grok"
|
|
@@ -70,15 +70,16 @@ function isSendKey(event) {
|
|
|
70
70
|
return event.key === "Enter" && !event.shiftKey && !event.isComposing;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
// src/
|
|
73
|
+
// src/memory.js
|
|
74
|
+
var MEMORY_LIMIT = 100;
|
|
75
|
+
function boundedSet(map, key, value) {
|
|
76
|
+
map.delete(key);
|
|
77
|
+
map.set(key, value);
|
|
78
|
+
while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/composer.jsx
|
|
74
82
|
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
75
|
-
var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
|
|
76
|
-
var defaultLinkOpen = markdown.renderer.rules.link_open;
|
|
77
|
-
markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
|
|
78
|
-
tokens[index]?.attrSet("target", "_blank");
|
|
79
|
-
tokens[index]?.attrSet("rel", "noreferrer noopener");
|
|
80
|
-
return defaultLinkOpen ? defaultLinkOpen(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
|
|
81
|
-
};
|
|
82
83
|
var composerMemory = /* @__PURE__ */ new Map();
|
|
83
84
|
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
84
85
|
if (state.mode !== "mirror" || state.canSend) return null;
|
|
@@ -105,11 +106,17 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
105
106
|
const [draft, setDraft] = useState(remembered.draft);
|
|
106
107
|
const [queue, setQueue] = useState(remembered.queue);
|
|
107
108
|
const textarea = useRef(null);
|
|
109
|
+
const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
|
|
110
|
+
const updateQueue = (update) => setQueue((items) => {
|
|
111
|
+
const next = update(items);
|
|
112
|
+
remember(draft, next);
|
|
113
|
+
return next;
|
|
114
|
+
});
|
|
108
115
|
useEffect(() => {
|
|
109
116
|
if (!state.busy && state.canSend && queue.length) {
|
|
110
117
|
const [next, ...rest] = queue;
|
|
111
118
|
setQueue(rest);
|
|
112
|
-
|
|
119
|
+
remember(draft, rest);
|
|
113
120
|
onPending?.(next);
|
|
114
121
|
adapter.onIntent({ action: "send", text: next });
|
|
115
122
|
}
|
|
@@ -121,17 +128,13 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
121
128
|
const send = () => {
|
|
122
129
|
const text = draft.trim();
|
|
123
130
|
if (!text) return;
|
|
124
|
-
if (state.busy)
|
|
125
|
-
const next = [...items, text];
|
|
126
|
-
composerMemory.set(memoryKey, { draft: "", queue: next });
|
|
127
|
-
return next;
|
|
128
|
-
});
|
|
131
|
+
if (state.busy) updateQueue((items) => [...items, text]);
|
|
129
132
|
else if (state.canSend) {
|
|
130
133
|
onPending?.(text);
|
|
131
134
|
adapter.onIntent({ action: "send", text });
|
|
132
135
|
} else return;
|
|
133
136
|
setDraft("");
|
|
134
|
-
|
|
137
|
+
remember("", state.busy ? [...queue, text] : queue);
|
|
135
138
|
};
|
|
136
139
|
return /* @__PURE__ */ jsxs("div", { class: "scui-compose", children: [
|
|
137
140
|
queue.length ? /* @__PURE__ */ jsxs("div", { class: "scui-queue", children: [
|
|
@@ -141,14 +144,14 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
141
144
|
] }),
|
|
142
145
|
queue.map((item, index) => /* @__PURE__ */ jsxs("span", { children: [
|
|
143
146
|
item,
|
|
144
|
-
/* @__PURE__ */ jsx("button", { "aria-label": `Remove queued message ${index + 1}`, onClick: () =>
|
|
147
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: "\xD7" })
|
|
145
148
|
] }, `${index}:${item}`))
|
|
146
149
|
] }) : null,
|
|
147
150
|
/* @__PURE__ */ jsxs("div", { class: "scui-envelope", children: [
|
|
148
151
|
/* @__PURE__ */ jsx("textarea", { ref: textarea, rows: 1, "aria-label": `Message ${harnessDisplayName(state.harness) || "agent"}`, placeholder: state.startup !== "ready" ? "Connecting\u2026" : state.busy ? "Queue a follow-up\u2026" : labels.askAgent, value: draft, disabled: state.mode !== "control" && !state.canSend, onInput: (event) => {
|
|
149
152
|
const value = event.currentTarget.value;
|
|
150
153
|
setDraft(value);
|
|
151
|
-
|
|
154
|
+
remember(value, queue);
|
|
152
155
|
}, onKeyDown: (event) => {
|
|
153
156
|
if (isSendKey(event)) {
|
|
154
157
|
event.preventDefault();
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
ActivityGroupProps,
|
|
3
|
+
MessengerComponents,
|
|
4
|
+
MessengerSlots,
|
|
5
|
+
SessionSemanticsModel,
|
|
6
|
+
SupercodeUiState,
|
|
7
|
+
TaskPlanModel,
|
|
8
|
+
TranscriptEntryModel,
|
|
9
|
+
TranscriptEntryProps,
|
|
10
|
+
UiAdapter,
|
|
11
|
+
} from './index.js';
|
|
12
|
+
export {
|
|
13
|
+
ActivityGroup,
|
|
14
|
+
Conversation,
|
|
15
|
+
LoadingStatus,
|
|
16
|
+
RequestCard,
|
|
17
|
+
SessionDetails,
|
|
18
|
+
TaskPlan,
|
|
19
|
+
TranscriptEntry,
|
|
20
|
+
} from './index.js';
|
package/conversation.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import
|
|
3
|
-
import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
|
1
|
+
// src/conversation.jsx
|
|
2
|
+
import { useEffect, useId, useLayoutEffect, useRef, useState } from "preact/hooks";
|
|
4
3
|
|
|
5
4
|
// core.mjs
|
|
6
5
|
var HARNESS_NAMES = Object.freeze({
|
|
7
6
|
"claude-code": "Claude Code",
|
|
8
7
|
codex: "Codex",
|
|
8
|
+
gemini: "Gemini CLI",
|
|
9
9
|
opencode: "OpenCode",
|
|
10
10
|
pi: "Pi",
|
|
11
11
|
grok: "Grok"
|
|
@@ -109,8 +109,10 @@ function activitySummary(entries) {
|
|
|
109
109
|
return `Activity \xB7 ${Object.entries(labels).flatMap(([key, label]) => counts.has(key) ? [`${counts.get(key)} ${label}`] : []).join(" \xB7 ")}`;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
// src/
|
|
113
|
-
import
|
|
112
|
+
// src/markdown.jsx
|
|
113
|
+
import MarkdownIt from "markdown-it";
|
|
114
|
+
import { useMemo } from "preact/hooks";
|
|
115
|
+
import { jsx } from "preact/jsx-runtime";
|
|
114
116
|
var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
|
|
115
117
|
var defaultLinkOpen = markdown.renderer.rules.link_open;
|
|
116
118
|
markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
|
|
@@ -122,6 +124,17 @@ function Markdown({ value }) {
|
|
|
122
124
|
const html = useMemo(() => markdown.render(value), [value]);
|
|
123
125
|
return /* @__PURE__ */ jsx("div", { class: "scui-markdown", dangerouslySetInnerHTML: { __html: html } });
|
|
124
126
|
}
|
|
127
|
+
|
|
128
|
+
// src/memory.js
|
|
129
|
+
var MEMORY_LIMIT = 100;
|
|
130
|
+
function boundedSet(map, key, value) {
|
|
131
|
+
map.delete(key);
|
|
132
|
+
map.set(key, value);
|
|
133
|
+
while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/conversation.jsx
|
|
137
|
+
import { jsx as jsx2, jsxs } from "preact/jsx-runtime";
|
|
125
138
|
function LoadingStatus({ state, compact = false }) {
|
|
126
139
|
const copy = {
|
|
127
140
|
connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
|
|
@@ -130,12 +143,12 @@ function LoadingStatus({ state, compact = false }) {
|
|
|
130
143
|
ready: ["Ready", "Coding sessions are up to date.", 3]
|
|
131
144
|
}[state.startup];
|
|
132
145
|
return /* @__PURE__ */ jsxs("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
|
|
133
|
-
/* @__PURE__ */
|
|
146
|
+
/* @__PURE__ */ jsx2("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx2("i", {}) }),
|
|
134
147
|
/* @__PURE__ */ jsxs("span", { class: "scui-loading-copy", children: [
|
|
135
|
-
/* @__PURE__ */
|
|
136
|
-
/* @__PURE__ */
|
|
148
|
+
/* @__PURE__ */ jsx2("strong", { children: copy[0] }),
|
|
149
|
+
/* @__PURE__ */ jsx2("small", { children: copy[1] })
|
|
137
150
|
] }),
|
|
138
|
-
/* @__PURE__ */
|
|
151
|
+
/* @__PURE__ */ jsx2("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx2("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
|
|
139
152
|
] });
|
|
140
153
|
}
|
|
141
154
|
function RequestCard({ entry, adapter, canRespond }) {
|
|
@@ -148,11 +161,11 @@ function RequestCard({ entry, adapter, canRespond }) {
|
|
|
148
161
|
] });
|
|
149
162
|
}
|
|
150
163
|
return /* @__PURE__ */ jsxs("section", { class: "scui-request", "aria-label": `${request.requestKind} needs input`, children: [
|
|
151
|
-
/* @__PURE__ */
|
|
152
|
-
/* @__PURE__ */
|
|
164
|
+
/* @__PURE__ */ jsx2("strong", { children: "Agent needs input" }),
|
|
165
|
+
/* @__PURE__ */ jsx2(Markdown, { value: request.payloadText || entry.text }),
|
|
153
166
|
/* @__PURE__ */ jsxs("div", { class: "scui-request-actions", children: [
|
|
154
|
-
request.options.map((option) => /* @__PURE__ */
|
|
155
|
-
request.cancellable ? /* @__PURE__ */
|
|
167
|
+
request.options.map((option) => /* @__PURE__ */ jsx2("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: option.optionId }), children: option.name }, option.optionId)),
|
|
168
|
+
request.cancellable ? /* @__PURE__ */ jsx2("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
|
|
156
169
|
] })
|
|
157
170
|
] });
|
|
158
171
|
}
|
|
@@ -163,25 +176,25 @@ function ContextDisclosure({ context }) {
|
|
|
163
176
|
"Context \xB7 ",
|
|
164
177
|
context.length
|
|
165
178
|
] }),
|
|
166
|
-
/* @__PURE__ */
|
|
167
|
-
/* @__PURE__ */
|
|
168
|
-
/* @__PURE__ */
|
|
179
|
+
/* @__PURE__ */ jsx2("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs("p", { children: [
|
|
180
|
+
/* @__PURE__ */ jsx2("strong", { children: item.label }),
|
|
181
|
+
/* @__PURE__ */ jsx2("span", { children: item.detail })
|
|
169
182
|
] }, item.id ?? index)) })
|
|
170
183
|
] });
|
|
171
184
|
}
|
|
172
185
|
function TranscriptEntry({ entry, state, adapter }) {
|
|
173
|
-
if (entry.role === "request") return /* @__PURE__ */
|
|
186
|
+
if (entry.role === "request") return /* @__PURE__ */ jsx2(RequestCard, { entry, adapter, canRespond: state.canRespond });
|
|
174
187
|
if (entry.role === "reasoning") {
|
|
175
188
|
return /* @__PURE__ */ jsxs("details", { class: "scui-reasoning", open: entry.streaming, children: [
|
|
176
|
-
/* @__PURE__ */
|
|
177
|
-
/* @__PURE__ */
|
|
189
|
+
/* @__PURE__ */ jsx2("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
|
|
190
|
+
/* @__PURE__ */ jsx2(Markdown, { value: entry.text })
|
|
178
191
|
] });
|
|
179
192
|
}
|
|
180
|
-
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */
|
|
193
|
+
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx2("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
|
|
181
194
|
return /* @__PURE__ */ jsxs("article", { class: "scui-message", "data-role": entry.role, children: [
|
|
182
|
-
/* @__PURE__ */
|
|
183
|
-
/* @__PURE__ */
|
|
184
|
-
entry.truncated ? /* @__PURE__ */
|
|
195
|
+
/* @__PURE__ */ jsx2(Markdown, { value: entry.text }),
|
|
196
|
+
/* @__PURE__ */ jsx2(ContextDisclosure, { context: entry.context }),
|
|
197
|
+
entry.truncated ? /* @__PURE__ */ jsx2("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
|
|
185
198
|
] });
|
|
186
199
|
}
|
|
187
200
|
function ToolRow({ entry, workspace }) {
|
|
@@ -192,20 +205,20 @@ function ToolRow({ entry, workspace }) {
|
|
|
192
205
|
const category = toolCategory(entry);
|
|
193
206
|
return /* @__PURE__ */ jsxs("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
|
|
194
207
|
/* @__PURE__ */ jsxs("button", { type: "button", class: "scui-tool-head", disabled: !hasDetail, "aria-expanded": hasDetail ? open : void 0, "aria-controls": hasDetail ? detailId : void 0, onClick: () => hasDetail && setOpen((value) => !value), children: [
|
|
195
|
-
/* @__PURE__ */
|
|
196
|
-
/* @__PURE__ */
|
|
197
|
-
target ? /* @__PURE__ */
|
|
198
|
-
/* @__PURE__ */
|
|
199
|
-
/* @__PURE__ */
|
|
208
|
+
/* @__PURE__ */ jsx2("span", { class: "scui-tool-glyph", "aria-hidden": "true", children: { read: "\u25A4", search: "\u2315", edit: "\u270E", command: ">_", test: "\u25C7", web: "\u25CE", agent: "\u2659", other: "\u25C6" }[category] }),
|
|
209
|
+
/* @__PURE__ */ jsx2("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
|
|
210
|
+
target ? /* @__PURE__ */ jsx2("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
|
|
211
|
+
/* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
|
|
212
|
+
/* @__PURE__ */ jsx2("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
|
|
200
213
|
] }),
|
|
201
214
|
hasDetail && open ? /* @__PURE__ */ jsxs("div", { id: detailId, class: "scui-tool-detail", children: [
|
|
202
215
|
entry.arguments ? /* @__PURE__ */ jsxs("pre", { children: [
|
|
203
|
-
/* @__PURE__ */
|
|
216
|
+
/* @__PURE__ */ jsx2("b", { children: "Input" }),
|
|
204
217
|
"\n",
|
|
205
218
|
entry.arguments
|
|
206
219
|
] }) : null,
|
|
207
220
|
entry.resultText ? /* @__PURE__ */ jsxs("pre", { "data-error": entry.status === "error", children: [
|
|
208
|
-
/* @__PURE__ */
|
|
221
|
+
/* @__PURE__ */ jsx2("b", { children: "Output" }),
|
|
209
222
|
"\n",
|
|
210
223
|
entry.resultText,
|
|
211
224
|
entry.truncated ? "\n[truncated]" : ""
|
|
@@ -222,16 +235,16 @@ function ActivityGroup({ entries, state }) {
|
|
|
222
235
|
}, [active]);
|
|
223
236
|
return /* @__PURE__ */ jsxs("section", { class: "scui-activity", children: [
|
|
224
237
|
/* @__PURE__ */ jsxs("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
|
|
225
|
-
/* @__PURE__ */
|
|
226
|
-
/* @__PURE__ */
|
|
227
|
-
/* @__PURE__ */
|
|
238
|
+
/* @__PURE__ */ jsx2("span", { class: "scui-fold", "data-open": open, children: "\u203A" }),
|
|
239
|
+
/* @__PURE__ */ jsx2("strong", { children: activitySummary(entries) }),
|
|
240
|
+
/* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
|
|
228
241
|
/* @__PURE__ */ jsxs("small", { children: [
|
|
229
242
|
entries.filter((entry) => entry.status === "completed").length,
|
|
230
243
|
"/",
|
|
231
244
|
entries.length
|
|
232
245
|
] })
|
|
233
246
|
] }),
|
|
234
|
-
open ? /* @__PURE__ */
|
|
247
|
+
open ? /* @__PURE__ */ jsx2("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx2(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
|
|
235
248
|
] });
|
|
236
249
|
}
|
|
237
250
|
function TaskPlan({ plan }) {
|
|
@@ -239,43 +252,43 @@ function TaskPlan({ plan }) {
|
|
|
239
252
|
const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
|
|
240
253
|
return /* @__PURE__ */ jsxs("details", { class: "scui-plan", children: [
|
|
241
254
|
/* @__PURE__ */ jsxs("summary", { children: [
|
|
242
|
-
/* @__PURE__ */
|
|
255
|
+
/* @__PURE__ */ jsx2("span", { children: "Plan" }),
|
|
243
256
|
/* @__PURE__ */ jsxs("small", { children: [
|
|
244
257
|
complete,
|
|
245
258
|
"/",
|
|
246
259
|
plan.items.length
|
|
247
260
|
] })
|
|
248
261
|
] }),
|
|
249
|
-
/* @__PURE__ */
|
|
250
|
-
/* @__PURE__ */
|
|
262
|
+
/* @__PURE__ */ jsx2("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs("li", { "data-status": item.status, children: [
|
|
263
|
+
/* @__PURE__ */ jsx2("i", { "aria-hidden": "true" }),
|
|
251
264
|
" ",
|
|
252
|
-
/* @__PURE__ */
|
|
265
|
+
/* @__PURE__ */ jsx2("span", { children: item.title })
|
|
253
266
|
] }, item.id)) })
|
|
254
267
|
] });
|
|
255
268
|
}
|
|
256
269
|
function SessionDetails({ semantics }) {
|
|
257
270
|
if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
|
|
258
271
|
return /* @__PURE__ */ jsxs("details", { class: "scui-details", children: [
|
|
259
|
-
/* @__PURE__ */
|
|
272
|
+
/* @__PURE__ */ jsx2("summary", { children: "Session details" }),
|
|
260
273
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
261
274
|
semantics.fidelity ? /* @__PURE__ */ jsxs("p", { children: [
|
|
262
|
-
/* @__PURE__ */
|
|
263
|
-
/* @__PURE__ */
|
|
275
|
+
/* @__PURE__ */ jsx2("strong", { children: "Fidelity" }),
|
|
276
|
+
/* @__PURE__ */ jsx2("span", { children: semantics.fidelity.replaceAll("_", " ") })
|
|
264
277
|
] }) : null,
|
|
265
278
|
/* @__PURE__ */ jsxs("p", { children: [
|
|
266
|
-
/* @__PURE__ */
|
|
267
|
-
/* @__PURE__ */
|
|
279
|
+
/* @__PURE__ */ jsx2("strong", { children: "Native records" }),
|
|
280
|
+
/* @__PURE__ */ jsx2("span", { children: semantics.rawRecords })
|
|
268
281
|
] }),
|
|
269
282
|
semantics.residueCount ? /* @__PURE__ */ jsxs("p", { children: [
|
|
270
|
-
/* @__PURE__ */
|
|
283
|
+
/* @__PURE__ */ jsx2("strong", { children: "Residue" }),
|
|
271
284
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
272
285
|
semantics.residueCount,
|
|
273
286
|
" retained"
|
|
274
287
|
] })
|
|
275
288
|
] }) : null,
|
|
276
289
|
semantics.parseErrors ? /* @__PURE__ */ jsxs("p", { children: [
|
|
277
|
-
/* @__PURE__ */
|
|
278
|
-
/* @__PURE__ */
|
|
290
|
+
/* @__PURE__ */ jsx2("strong", { children: "Parse diagnostics" }),
|
|
291
|
+
/* @__PURE__ */ jsx2("span", { children: semantics.parseErrors })
|
|
279
292
|
] }) : null,
|
|
280
293
|
semantics.subagents.map((agent) => /* @__PURE__ */ jsxs("p", { children: [
|
|
281
294
|
/* @__PURE__ */ jsxs("strong", { children: [
|
|
@@ -304,11 +317,12 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
304
317
|
const Before = slots.beforeConversation;
|
|
305
318
|
const After = slots.afterConversation;
|
|
306
319
|
const Empty = slots.emptyConversation;
|
|
320
|
+
const remember = (value) => boundedSet(conversationMemory, memoryKey, value);
|
|
307
321
|
const pin = () => {
|
|
308
322
|
if (!scroller.current) return;
|
|
309
323
|
scroller.current.scrollTop = scroller.current.scrollHeight;
|
|
310
324
|
setAtBottom(true);
|
|
311
|
-
|
|
325
|
+
remember({ top: scroller.current.scrollTop, atBottom: true });
|
|
312
326
|
};
|
|
313
327
|
useLayoutEffect(() => {
|
|
314
328
|
const element = scroller.current;
|
|
@@ -317,7 +331,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
317
331
|
if (anchor && state.transcript.length > anchor.entries) {
|
|
318
332
|
element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
|
|
319
333
|
earlierAnchor.current = null;
|
|
320
|
-
|
|
334
|
+
remember({ top: element.scrollTop, atBottom: false });
|
|
321
335
|
return;
|
|
322
336
|
}
|
|
323
337
|
if (!restored.current) {
|
|
@@ -327,41 +341,41 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
327
341
|
} else if (atBottom) pin();
|
|
328
342
|
}, [memoryKey, state.transcript.length, state.busy]);
|
|
329
343
|
return /* @__PURE__ */ jsxs("div", { class: "scui-conversation-wrap", children: [
|
|
330
|
-
/* @__PURE__ */
|
|
344
|
+
/* @__PURE__ */ jsx2("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
|
|
331
345
|
const element = event.currentTarget;
|
|
332
346
|
const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
|
|
333
347
|
setAtBottom(bottom);
|
|
334
|
-
|
|
348
|
+
remember({ top: element.scrollTop, atBottom: bottom });
|
|
335
349
|
}, children: /* @__PURE__ */ jsxs("div", { children: [
|
|
336
|
-
Before ? /* @__PURE__ */
|
|
337
|
-
/* @__PURE__ */
|
|
338
|
-
/* @__PURE__ */
|
|
339
|
-
state.history.hasEarlier ? /* @__PURE__ */
|
|
350
|
+
Before ? /* @__PURE__ */ jsx2(Before, { state, adapter, value: null }) : null,
|
|
351
|
+
/* @__PURE__ */ jsx2(TaskPlan, { plan: state.taskPlan }),
|
|
352
|
+
/* @__PURE__ */ jsx2(SessionDetails, { semantics: state.semantics }),
|
|
353
|
+
state.history.hasEarlier ? /* @__PURE__ */ jsx2("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
|
|
340
354
|
const element = scroller.current;
|
|
341
355
|
if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
|
|
342
356
|
setAtBottom(false);
|
|
343
357
|
adapter.onIntent({ action: "loadEarlier" });
|
|
344
358
|
}, children: "Load earlier messages" }) : null,
|
|
345
|
-
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */
|
|
346
|
-
!blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */
|
|
347
|
-
blocks.map((block) => block.kind === "activity" ? /* @__PURE__ */
|
|
359
|
+
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx2(LoadingStatus, { state }) : null,
|
|
360
|
+
!blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx2(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx2("div", { class: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
|
|
361
|
+
blocks.map((block) => block.kind === "activity" ? /* @__PURE__ */ jsx2(Group, { value: block.entries, entries: block.entries, state, adapter }, block.id) : /* @__PURE__ */ jsx2(Entry, { value: block.entry, entry: block.entry, state, adapter }, block.id)),
|
|
348
362
|
pending ? /* @__PURE__ */ jsxs("article", { class: "scui-message scui-pending", "data-role": "user", children: [
|
|
349
|
-
/* @__PURE__ */
|
|
350
|
-
/* @__PURE__ */
|
|
363
|
+
/* @__PURE__ */ jsx2(Markdown, { value: pending }),
|
|
364
|
+
/* @__PURE__ */ jsx2("small", { children: state.error && !state.busy ? "Not sent" : "Sending\u2026" })
|
|
351
365
|
] }) : null,
|
|
352
366
|
state.busy ? /* @__PURE__ */ jsxs("div", { class: "scui-working", role: "status", children: [
|
|
353
|
-
/* @__PURE__ */
|
|
354
|
-
/* @__PURE__ */
|
|
355
|
-
/* @__PURE__ */
|
|
356
|
-
/* @__PURE__ */
|
|
367
|
+
/* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
368
|
+
/* @__PURE__ */ jsx2("i", {}),
|
|
369
|
+
/* @__PURE__ */ jsx2("i", {}),
|
|
370
|
+
/* @__PURE__ */ jsx2("i", {}),
|
|
357
371
|
/* @__PURE__ */ jsxs("small", { children: [
|
|
358
372
|
harnessDisplayName(state.harness),
|
|
359
373
|
" is working"
|
|
360
374
|
] })
|
|
361
375
|
] }) : null,
|
|
362
|
-
After ? /* @__PURE__ */
|
|
376
|
+
After ? /* @__PURE__ */ jsx2(After, { state, adapter, value: null }) : null
|
|
363
377
|
] }) }),
|
|
364
|
-
!atBottom ? /* @__PURE__ */
|
|
378
|
+
!atBottom ? /* @__PURE__ */ jsx2("button", { class: "scui-latest", type: "button", onClick: pin, children: "\u2193 Latest" }) : null
|
|
365
379
|
] });
|
|
366
380
|
}
|
|
367
381
|
export {
|
package/core.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
AttachedSessionModel,
|
|
3
|
+
ControlStrategy,
|
|
4
|
+
HarnessId,
|
|
5
|
+
HarnessOption,
|
|
6
|
+
MessengerLabels,
|
|
7
|
+
ReductionReceiptModel,
|
|
8
|
+
RequestOption,
|
|
9
|
+
SessionActivity,
|
|
10
|
+
SessionAttention,
|
|
11
|
+
SessionMode,
|
|
12
|
+
SessionRowModel,
|
|
13
|
+
SessionSemanticsModel,
|
|
14
|
+
StartupPhase,
|
|
15
|
+
SupercodeUiIntent,
|
|
16
|
+
SupercodeUiState,
|
|
17
|
+
TaskPlanItem,
|
|
18
|
+
TaskPlanModel,
|
|
19
|
+
TranscriptContext,
|
|
20
|
+
TranscriptEntryModel,
|
|
21
|
+
TranscriptRequest,
|
|
22
|
+
UiTone,
|
|
23
|
+
} from './index.js';
|
|
24
|
+
export {
|
|
25
|
+
DEFAULT_LABELS,
|
|
26
|
+
EMPTY_UI_STATE,
|
|
27
|
+
activitySummary,
|
|
28
|
+
canContinueHere,
|
|
29
|
+
compactToolTarget,
|
|
30
|
+
filterSessions,
|
|
31
|
+
groupConversation,
|
|
32
|
+
harnessDisplayName,
|
|
33
|
+
isSendKey,
|
|
34
|
+
normalizeUiState,
|
|
35
|
+
operationLabel,
|
|
36
|
+
sessionActivity,
|
|
37
|
+
sessionDisplayName,
|
|
38
|
+
terminalCommand,
|
|
39
|
+
toolCategory,
|
|
40
|
+
toolTarget,
|
|
41
|
+
} from './index.js';
|
package/core.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const HARNESS_NAMES = Object.freeze({
|
|
2
2
|
'claude-code': 'Claude Code',
|
|
3
3
|
codex: 'Codex',
|
|
4
|
+
gemini: 'Gemini CLI',
|
|
4
5
|
opencode: 'OpenCode',
|
|
5
6
|
pi: 'Pi',
|
|
6
7
|
grok: 'Grok',
|
|
@@ -58,7 +59,7 @@ export const EMPTY_UI_STATE = Object.freeze({
|
|
|
58
59
|
|
|
59
60
|
const ROLES = new Set(['system', 'user', 'assistant', 'tool', 'reasoning', 'request', 'notice']);
|
|
60
61
|
const MODES = new Set(['none', 'control', 'mirror']);
|
|
61
|
-
const STRATEGIES = new Set(['start', 'resume', 'attach', 'branch']);
|
|
62
|
+
const STRATEGIES = new Set(['start', 'resume', 'attach', 'branch', 'reduce']);
|
|
62
63
|
const STARTUP = new Set(['connecting', 'starting', 'discovering', 'ready']);
|
|
63
64
|
const FIDELITY = new Set(['byte_lossless', 'value_lossless', 'semantic']);
|
|
64
65
|
|
|
@@ -196,6 +197,72 @@ function readSemantics(value) {
|
|
|
196
197
|
};
|
|
197
198
|
}
|
|
198
199
|
|
|
200
|
+
function readTerminalHandoff(value) {
|
|
201
|
+
const handoff = record(value);
|
|
202
|
+
if (
|
|
203
|
+
!handoff ||
|
|
204
|
+
typeof handoff.program !== 'string' ||
|
|
205
|
+
!handoff.program.trim() ||
|
|
206
|
+
!Array.isArray(handoff.arguments) ||
|
|
207
|
+
!handoff.arguments.every((argument) => typeof argument === 'string') ||
|
|
208
|
+
typeof handoff.cwd !== 'string'
|
|
209
|
+
) return null;
|
|
210
|
+
return { program: handoff.program, arguments: [...handoff.arguments], cwd: handoff.cwd };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function readExportReceipt(value) {
|
|
214
|
+
const receipt = record(value);
|
|
215
|
+
if (
|
|
216
|
+
!receipt ||
|
|
217
|
+
typeof receipt.targetHarness !== 'string' ||
|
|
218
|
+
!['byte_lossless', 'value_lossless'].includes(receipt.fidelity) ||
|
|
219
|
+
typeof receipt.path !== 'string' ||
|
|
220
|
+
!receipt.path.trim() ||
|
|
221
|
+
!Number.isInteger(receipt.files) ||
|
|
222
|
+
receipt.files < 1 ||
|
|
223
|
+
!Number.isInteger(receipt.residueCount) ||
|
|
224
|
+
receipt.residueCount < 0
|
|
225
|
+
) return null;
|
|
226
|
+
return {
|
|
227
|
+
targetHarness: receipt.targetHarness,
|
|
228
|
+
fidelity: receipt.fidelity,
|
|
229
|
+
path: receipt.path,
|
|
230
|
+
files: receipt.files,
|
|
231
|
+
residueCount: receipt.residueCount,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function readReductionReceipt(value) {
|
|
236
|
+
const receipt = record(value);
|
|
237
|
+
if (
|
|
238
|
+
!receipt ||
|
|
239
|
+
typeof receipt.sourceTokens !== 'number' ||
|
|
240
|
+
!Number.isFinite(receipt.sourceTokens) ||
|
|
241
|
+
typeof receipt.reducedTokens !== 'number' ||
|
|
242
|
+
!Number.isFinite(receipt.reducedTokens) ||
|
|
243
|
+
receipt.sourceTokens <= receipt.reducedTokens ||
|
|
244
|
+
receipt.reducedTokens < 0 ||
|
|
245
|
+
typeof receipt.ratio !== 'number' ||
|
|
246
|
+
!Number.isFinite(receipt.ratio) ||
|
|
247
|
+
receipt.ratio <= 1 ||
|
|
248
|
+
typeof receipt.sidecarId !== 'string' ||
|
|
249
|
+
!receipt.sidecarId.trim() ||
|
|
250
|
+
receipt.verified !== true ||
|
|
251
|
+
receipt.reversible !== true ||
|
|
252
|
+
typeof receipt.targetHarness !== 'string' ||
|
|
253
|
+
!receipt.targetHarness.trim()
|
|
254
|
+
) return null;
|
|
255
|
+
return {
|
|
256
|
+
sourceTokens: receipt.sourceTokens,
|
|
257
|
+
reducedTokens: receipt.reducedTokens,
|
|
258
|
+
ratio: receipt.ratio,
|
|
259
|
+
sidecarId: receipt.sidecarId,
|
|
260
|
+
verified: true,
|
|
261
|
+
reversible: true,
|
|
262
|
+
targetHarness: receipt.targetHarness,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
199
266
|
export function normalizeUiState(value) {
|
|
200
267
|
const raw = record(value) ?? {};
|
|
201
268
|
const pill = record(raw.pill);
|
|
@@ -225,10 +292,10 @@ export function normalizeUiState(value) {
|
|
|
225
292
|
workspace: string(raw.workspace),
|
|
226
293
|
taskPlan: readTaskPlan(raw.taskPlan),
|
|
227
294
|
semantics: readSemantics(raw.semantics),
|
|
228
|
-
terminalHandoff:
|
|
295
|
+
terminalHandoff: readTerminalHandoff(raw.terminalHandoff),
|
|
229
296
|
exportBackTarget: typeof raw.exportBackTarget === 'string' ? raw.exportBackTarget : null,
|
|
230
|
-
exportReceipt:
|
|
231
|
-
reductionReceipt:
|
|
297
|
+
exportReceipt: readExportReceipt(raw.exportReceipt),
|
|
298
|
+
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
232
299
|
error: typeof raw.error === 'string' ? raw.error : null,
|
|
233
300
|
recoverable: raw.recoverable === true,
|
|
234
301
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
package/embed.d.ts
ADDED