@volter-ai-dev/supercode-ui 0.1.13 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/components.d.ts +1 -0
- package/components.mjs +711 -361
- package/composer.mjs +77 -19
- package/controller.mjs +5 -2
- package/conversation.mjs +364 -196
- package/core.mjs +3 -2
- package/embed.mjs +712 -363
- package/icon.d.ts +2 -0
- package/icon.mjs +45 -0
- package/index.d.ts +9 -3
- package/messenger.mjs +710 -361
- package/package.json +8 -2
- package/sessions.mjs +160 -48
- package/styles.css +35 -18
package/composer.mjs
CHANGED
|
@@ -79,8 +79,65 @@ function boundedSet(map, key, value) {
|
|
|
79
79
|
while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// src/icon.jsx
|
|
83
|
+
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
84
|
+
var ICONS = {
|
|
85
|
+
back: () => /* @__PURE__ */ jsx("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
|
|
86
|
+
check: () => /* @__PURE__ */ jsx("path", { d: "m4 9 3.25 3.25L14 5.5" }),
|
|
87
|
+
chevron: () => /* @__PURE__ */ jsx("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
|
|
88
|
+
close: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
89
|
+
/* @__PURE__ */ jsx("path", { d: "m4.75 4.75 8.5 8.5" }),
|
|
90
|
+
/* @__PURE__ */ jsx("path", { d: "m13.25 4.75-8.5 8.5" })
|
|
91
|
+
] }),
|
|
92
|
+
copy: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
93
|
+
/* @__PURE__ */ jsx("rect", { x: "5", y: "5", width: "8", height: "8", rx: "1.5" }),
|
|
94
|
+
/* @__PURE__ */ jsx("path", { d: "M3 10.5V4.25C3 3.56 3.56 3 4.25 3h6.25" })
|
|
95
|
+
] }),
|
|
96
|
+
down: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
97
|
+
/* @__PURE__ */ jsx("path", { d: "M9 3.5v10" }),
|
|
98
|
+
/* @__PURE__ */ jsx("path", { d: "m4.75 9.5 4.25 4 4.25-4" })
|
|
99
|
+
] }),
|
|
100
|
+
menu: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
101
|
+
/* @__PURE__ */ jsx("circle", { cx: "4", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
|
|
102
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
|
|
103
|
+
/* @__PURE__ */ jsx("circle", { cx: "14", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" })
|
|
104
|
+
] }),
|
|
105
|
+
plus: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
106
|
+
/* @__PURE__ */ jsx("path", { d: "M9 3.5v11" }),
|
|
107
|
+
/* @__PURE__ */ jsx("path", { d: "M3.5 9h11" })
|
|
108
|
+
] }),
|
|
109
|
+
search: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
110
|
+
/* @__PURE__ */ jsx("circle", { cx: "7.75", cy: "7.75", r: "4.25" }),
|
|
111
|
+
/* @__PURE__ */ jsx("path", { d: "m11 11 3.5 3.5" })
|
|
112
|
+
] }),
|
|
113
|
+
send: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
114
|
+
/* @__PURE__ */ jsx("path", { d: "M9 14.5v-11" }),
|
|
115
|
+
/* @__PURE__ */ jsx("path", { d: "m4.75 7.75 4.25-4.25 4.25 4.25" })
|
|
116
|
+
] }),
|
|
117
|
+
stop: () => /* @__PURE__ */ jsx("rect", { x: "4.5", y: "4.5", width: "9", height: "9", rx: "1.5", fill: "currentColor", stroke: "none" })
|
|
118
|
+
};
|
|
119
|
+
function UiIcon({ name, size = 16, class: className = "" }) {
|
|
120
|
+
const Glyph = ICONS[name];
|
|
121
|
+
if (!Glyph) return null;
|
|
122
|
+
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, {}) });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/textarea.js
|
|
126
|
+
import { useLayoutEffect } from "preact/hooks";
|
|
127
|
+
function useAutosizeTextarea(ref, value) {
|
|
128
|
+
useLayoutEffect(() => {
|
|
129
|
+
const element = ref.current;
|
|
130
|
+
if (!element) return;
|
|
131
|
+
element.style.height = "auto";
|
|
132
|
+
const maxHeight = Number.parseFloat(getComputedStyle(element).maxHeight) || 150;
|
|
133
|
+
const height = Math.min(element.scrollHeight, maxHeight);
|
|
134
|
+
element.style.height = `${height}px`;
|
|
135
|
+
element.style.overflowY = element.scrollHeight > maxHeight ? "auto" : "hidden";
|
|
136
|
+
}, [ref, value]);
|
|
137
|
+
}
|
|
138
|
+
|
|
82
139
|
// src/composer.jsx
|
|
83
|
-
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
140
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
84
141
|
var composerMemory = /* @__PURE__ */ new Map();
|
|
85
142
|
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
86
143
|
if (state.mode !== "mirror" || state.canSend) return null;
|
|
@@ -90,16 +147,16 @@ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
|
90
147
|
const resume = canContinueHere(state);
|
|
91
148
|
const join = state.canAttach;
|
|
92
149
|
const branch = state.canBranch;
|
|
93
|
-
if (!resume && !join && !branch) return /* @__PURE__ */
|
|
94
|
-
/* @__PURE__ */
|
|
95
|
-
/* @__PURE__ */
|
|
150
|
+
if (!resume && !join && !branch) return /* @__PURE__ */ jsx2("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs2("span", { children: [
|
|
151
|
+
/* @__PURE__ */ jsx2("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
152
|
+
/* @__PURE__ */ jsx2("small", { children: "This session cannot be continued by an available harness." })
|
|
96
153
|
] }) });
|
|
97
|
-
return /* @__PURE__ */
|
|
98
|
-
/* @__PURE__ */
|
|
99
|
-
/* @__PURE__ */
|
|
100
|
-
/* @__PURE__ */
|
|
154
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-continuation", children: [
|
|
155
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
156
|
+
/* @__PURE__ */ jsx2("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
157
|
+
/* @__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." })
|
|
101
158
|
] }),
|
|
102
|
-
/* @__PURE__ */
|
|
159
|
+
/* @__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 })
|
|
103
160
|
] });
|
|
104
161
|
}
|
|
105
162
|
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pendingStatus = null, restoreDraft = null, onPending, onDraftRestored }) {
|
|
@@ -108,6 +165,7 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
108
165
|
const [queue, setQueue] = useState(remembered.queue);
|
|
109
166
|
const [dispatching, setDispatching] = useState(false);
|
|
110
167
|
const textarea = useRef(null);
|
|
168
|
+
useAutosizeTextarea(textarea, draft);
|
|
111
169
|
const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
|
|
112
170
|
const updateQueue = (update) => setQueue((items) => {
|
|
113
171
|
const next = update(items);
|
|
@@ -155,19 +213,19 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
155
213
|
setDraft("");
|
|
156
214
|
remember("", queuesNewMessage ? [...queue, text] : queue);
|
|
157
215
|
};
|
|
158
|
-
return /* @__PURE__ */
|
|
159
|
-
queue.length ? /* @__PURE__ */
|
|
160
|
-
/* @__PURE__ */
|
|
216
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-compose", children: [
|
|
217
|
+
queue.length ? /* @__PURE__ */ jsxs2("div", { class: "scui-queue", children: [
|
|
218
|
+
/* @__PURE__ */ jsxs2("strong", { children: [
|
|
161
219
|
queue.length,
|
|
162
220
|
" queued"
|
|
163
221
|
] }),
|
|
164
|
-
queue.map((item, index) => /* @__PURE__ */
|
|
222
|
+
queue.map((item, index) => /* @__PURE__ */ jsxs2("span", { children: [
|
|
165
223
|
item,
|
|
166
|
-
/* @__PURE__ */
|
|
224
|
+
/* @__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 }) })
|
|
167
225
|
] }, `${index}:${item}`))
|
|
168
226
|
] }) : null,
|
|
169
|
-
/* @__PURE__ */
|
|
170
|
-
/* @__PURE__ */
|
|
227
|
+
/* @__PURE__ */ jsxs2("div", { class: "scui-envelope", children: [
|
|
228
|
+
/* @__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) => {
|
|
171
229
|
const value = event.currentTarget.value;
|
|
172
230
|
setDraft(value);
|
|
173
231
|
remember(value, queue);
|
|
@@ -177,9 +235,9 @@ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.a
|
|
|
177
235
|
send();
|
|
178
236
|
}
|
|
179
237
|
} }),
|
|
180
|
-
/* @__PURE__ */
|
|
181
|
-
state.busy ? /* @__PURE__ */
|
|
182
|
-
/* @__PURE__ */
|
|
238
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
239
|
+
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,
|
|
240
|
+
/* @__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 }) })
|
|
183
241
|
] })
|
|
184
242
|
] })
|
|
185
243
|
] });
|
package/controller.mjs
CHANGED
|
@@ -116,6 +116,7 @@ function projectConversationEntry(entry, maxEntryChars) {
|
|
|
116
116
|
return {
|
|
117
117
|
id: entry.id,
|
|
118
118
|
role: entry.role,
|
|
119
|
+
...(Number.isSafeInteger(entry.messageIndex) && entry.messageIndex > 0 ? { messageIndex: entry.messageIndex } : {}),
|
|
119
120
|
text: body.text,
|
|
120
121
|
ts: timestampFromMetadata(entry.metadata),
|
|
121
122
|
truncated: body.truncated,
|
|
@@ -129,6 +130,7 @@ function projectConversationEntry(entry, maxEntryChars) {
|
|
|
129
130
|
const projected = {
|
|
130
131
|
id: entry.id,
|
|
131
132
|
role: 'tool',
|
|
133
|
+
...(Number.isSafeInteger(entry.messageIndex) && entry.messageIndex > 0 ? { messageIndex: entry.messageIndex } : {}),
|
|
132
134
|
text: primary.text,
|
|
133
135
|
ts: timestampFromMetadata(entry.metadata),
|
|
134
136
|
truncated: argumentsText.truncated || result.truncated,
|
|
@@ -401,9 +403,10 @@ export function createControllerBinding(controller, options = {}) {
|
|
|
401
403
|
const getState = () => projectClientSnapshot(controller.getSnapshot(), options.projection?.() ?? {});
|
|
402
404
|
const adapter = {
|
|
403
405
|
onIntent(intent) {
|
|
404
|
-
|
|
406
|
+
return Promise.resolve(options.onIntent?.(intent))
|
|
405
407
|
.then(() => dispatchStandard(controller, intent, options))
|
|
406
|
-
.catch((error) => options.onError?.(error, intent))
|
|
408
|
+
.catch((error) => options.onError?.(error, intent))
|
|
409
|
+
.then(() => undefined);
|
|
407
410
|
},
|
|
408
411
|
...(options.copyText ? { copyText: options.copyText } : {}),
|
|
409
412
|
};
|