@volter-ai-dev/supercode-ui 0.1.18 → 0.1.21
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 +9 -0
- package/components.mjs +602 -348
- package/composer.mjs +209 -34
- package/controller.mjs +21 -2
- package/conversation.mjs +226 -201
- package/core.mjs +13 -1
- package/embed.mjs +604 -350
- package/icon.mjs +6 -0
- package/index.d.ts +17 -4
- package/messenger.mjs +602 -348
- package/package.json +1 -1
- package/sessions.mjs +47 -37
- package/styles.css +5 -1
package/package.json
CHANGED
package/sessions.mjs
CHANGED
|
@@ -78,7 +78,7 @@ function sessionActivity(state, row) {
|
|
|
78
78
|
function filterSessions(rows, query) {
|
|
79
79
|
const needle = query.trim().toLocaleLowerCase();
|
|
80
80
|
if (!needle) return [...rows];
|
|
81
|
-
return rows.filter((row) => [row.name, row.title, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => value.toLocaleLowerCase().includes(needle)));
|
|
81
|
+
return rows.filter((row) => [row.name, row.title, row.preview, row.cwd, row.harness, harnessDisplayName(row.harness)].some((value) => typeof value === "string" && value.toLocaleLowerCase().includes(needle)));
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
// src/conversation.jsx
|
|
@@ -146,6 +146,7 @@ function boundedSet(map, key, value) {
|
|
|
146
146
|
// src/icon.jsx
|
|
147
147
|
import { Fragment, jsx as jsx2, jsxs } from "preact/jsx-runtime";
|
|
148
148
|
var ICONS = {
|
|
149
|
+
attach: () => /* @__PURE__ */ jsx2("path", { d: "M6.25 9.75 10.6 5.4a2.1 2.1 0 0 1 2.97 2.97l-5.4 5.4a3.3 3.3 0 0 1-4.67-4.66l5.52-5.52" }),
|
|
149
150
|
back: () => /* @__PURE__ */ jsx2("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
|
|
150
151
|
check: () => /* @__PURE__ */ jsx2("path", { d: "m4 9 3.25 3.25L14 5.5" }),
|
|
151
152
|
chevron: () => /* @__PURE__ */ jsx2("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
|
|
@@ -161,6 +162,11 @@ var ICONS = {
|
|
|
161
162
|
/* @__PURE__ */ jsx2("path", { d: "M9 3.5v10" }),
|
|
162
163
|
/* @__PURE__ */ jsx2("path", { d: "m4.75 9.5 4.25 4 4.25-4" })
|
|
163
164
|
] }),
|
|
165
|
+
image: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
166
|
+
/* @__PURE__ */ jsx2("rect", { x: "3", y: "3.5", width: "12", height: "11", rx: "1.75" }),
|
|
167
|
+
/* @__PURE__ */ jsx2("circle", { cx: "6.5", cy: "7", r: "1.25" }),
|
|
168
|
+
/* @__PURE__ */ jsx2("path", { d: "m4.5 13 3.25-3 2.1 1.85 1.65-1.5L14 13" })
|
|
169
|
+
] }),
|
|
164
170
|
menu: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
165
171
|
/* @__PURE__ */ jsx2("circle", { cx: "4", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
|
|
166
172
|
/* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
|
|
@@ -186,8 +192,12 @@ function UiIcon({ name, size = 16, class: className = "" }) {
|
|
|
186
192
|
return /* @__PURE__ */ jsx2("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__ */ jsx2(Glyph, {}) });
|
|
187
193
|
}
|
|
188
194
|
|
|
195
|
+
// src/context.jsx
|
|
196
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
197
|
+
var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
198
|
+
|
|
189
199
|
// src/conversation.jsx
|
|
190
|
-
import { Fragment as Fragment3, jsx as
|
|
200
|
+
import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
191
201
|
function LoadingStatus({ state, compact = false }) {
|
|
192
202
|
const copy = {
|
|
193
203
|
connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
|
|
@@ -195,19 +205,19 @@ function LoadingStatus({ state, compact = false }) {
|
|
|
195
205
|
discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
|
|
196
206
|
ready: ["Ready", "Coding sessions are up to date.", 3]
|
|
197
207
|
}[state.startup];
|
|
198
|
-
return /* @__PURE__ */
|
|
199
|
-
/* @__PURE__ */
|
|
200
|
-
/* @__PURE__ */
|
|
201
|
-
/* @__PURE__ */
|
|
202
|
-
/* @__PURE__ */
|
|
208
|
+
return /* @__PURE__ */ jsxs3("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
|
|
209
|
+
/* @__PURE__ */ jsx4("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("i", {}) }),
|
|
210
|
+
/* @__PURE__ */ jsxs3("span", { class: "scui-loading-copy", children: [
|
|
211
|
+
/* @__PURE__ */ jsx4("strong", { children: copy[0] }),
|
|
212
|
+
/* @__PURE__ */ jsx4("small", { children: copy[1] })
|
|
203
213
|
] }),
|
|
204
|
-
/* @__PURE__ */
|
|
214
|
+
/* @__PURE__ */ jsx4("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx4("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
|
|
205
215
|
] });
|
|
206
216
|
}
|
|
207
217
|
|
|
208
218
|
// src/logo.jsx
|
|
209
219
|
import { useEffect as useEffect3 } from "preact/hooks";
|
|
210
|
-
import { jsx as
|
|
220
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
211
221
|
var LOGOS = {
|
|
212
222
|
"claude-code": {
|
|
213
223
|
viewBox: "-1 3.5 26 18",
|
|
@@ -258,29 +268,29 @@ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
|
258
268
|
if (!logo) onMissingLogo?.(id);
|
|
259
269
|
}, [id, logo, onMissingLogo]);
|
|
260
270
|
if (!logo) return null;
|
|
261
|
-
return /* @__PURE__ */
|
|
262
|
-
/* @__PURE__ */
|
|
263
|
-
activity && activity !== "idle" ? /* @__PURE__ */
|
|
271
|
+
return /* @__PURE__ */ jsxs4("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
|
|
272
|
+
/* @__PURE__ */ jsx5("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx5(Tag, { ...props }, index)) }),
|
|
273
|
+
activity && activity !== "idle" ? /* @__PURE__ */ jsx5("i", {}) : null
|
|
264
274
|
] });
|
|
265
275
|
}
|
|
266
276
|
|
|
267
277
|
// src/sessions.jsx
|
|
268
|
-
import { jsx as
|
|
278
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
269
279
|
var sessionListMemory = /* @__PURE__ */ new Map();
|
|
270
280
|
function SessionRow({ row, state, onOpen }) {
|
|
271
281
|
const activity = sessionActivity(state, row);
|
|
272
282
|
const attentionPreview = state.attention.find((item) => item.key === row.key)?.preview;
|
|
273
283
|
const title = sessionDisplayName(row);
|
|
274
284
|
const detail = attentionPreview || row.preview || (row.name && row.name !== title ? row.name : row.cwd);
|
|
275
|
-
return /* @__PURE__ */
|
|
276
|
-
/* @__PURE__ */
|
|
277
|
-
/* @__PURE__ */
|
|
278
|
-
/* @__PURE__ */
|
|
279
|
-
/* @__PURE__ */
|
|
280
|
-
/* @__PURE__ */
|
|
285
|
+
return /* @__PURE__ */ jsxs5("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, "data-session-key": row.key, type: "button", "aria-label": `${title} \xB7 ${harnessDisplayName(row.harness)}${detail ? ` \xB7 ${detail}` : ""}${row.age ? ` \xB7 ${row.age}` : ""}`, "aria-current": row.active ? "true" : void 0, onClick: () => onOpen(row), children: [
|
|
286
|
+
/* @__PURE__ */ jsx6(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
287
|
+
/* @__PURE__ */ jsxs5("span", { class: "scui-session-copy", children: [
|
|
288
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
289
|
+
/* @__PURE__ */ jsx6("strong", { children: title }),
|
|
290
|
+
/* @__PURE__ */ jsx6("small", { children: row.age })
|
|
281
291
|
] }),
|
|
282
|
-
detail ? /* @__PURE__ */
|
|
283
|
-
state.attachError?.key === row.key ? /* @__PURE__ */
|
|
292
|
+
detail ? /* @__PURE__ */ jsx6("span", { children: /* @__PURE__ */ jsx6("small", { title: row.cwd, children: detail }) }) : null,
|
|
293
|
+
state.attachError?.key === row.key ? /* @__PURE__ */ jsx6("em", { children: state.attachError.message }) : null
|
|
284
294
|
] })
|
|
285
295
|
] });
|
|
286
296
|
}
|
|
@@ -311,33 +321,33 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
311
321
|
Promise.resolve(result).then(() => setLoadingMore(false), () => setLoadingMore(false));
|
|
312
322
|
}
|
|
313
323
|
};
|
|
314
|
-
return /* @__PURE__ */
|
|
315
|
-
/* @__PURE__ */
|
|
316
|
-
/* @__PURE__ */
|
|
317
|
-
/* @__PURE__ */
|
|
318
|
-
/* @__PURE__ */
|
|
324
|
+
return /* @__PURE__ */ jsxs5("section", { class: "scui-list", ref: root, children: [
|
|
325
|
+
/* @__PURE__ */ jsxs5("header", { class: "scui-head", children: [
|
|
326
|
+
/* @__PURE__ */ jsxs5("span", { class: "scui-head-copy", children: [
|
|
327
|
+
/* @__PURE__ */ jsx6("strong", { children: labels.chats }),
|
|
328
|
+
/* @__PURE__ */ jsxs5("small", { children: [
|
|
319
329
|
state.sessions.length,
|
|
320
330
|
" recent conversations"
|
|
321
331
|
] })
|
|
322
332
|
] }),
|
|
323
|
-
/* @__PURE__ */
|
|
324
|
-
onClose ? /* @__PURE__ */
|
|
333
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "data-list-focus": "new", "aria-label": labels.newChat, disabled: !state.harnesses.some((item) => item.startable), onClick: onNew, children: /* @__PURE__ */ jsx6(UiIcon, { name: "plus", size: 18 }) }),
|
|
334
|
+
onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx6(UiIcon, { name: "close", size: 18 }) }) : null
|
|
325
335
|
] }),
|
|
326
|
-
state.startup !== "ready" ? /* @__PURE__ */
|
|
327
|
-
state.sessions.length > 4 ? /* @__PURE__ */
|
|
328
|
-
/* @__PURE__ */
|
|
329
|
-
/* @__PURE__ */
|
|
336
|
+
state.startup !== "ready" ? /* @__PURE__ */ jsx6(LoadingStatus, { state, compact: rows.length > 0 }) : null,
|
|
337
|
+
state.sessions.length > 4 ? /* @__PURE__ */ jsxs5("label", { class: "scui-search", children: [
|
|
338
|
+
/* @__PURE__ */ jsx6(UiIcon, { name: "search", size: 15 }),
|
|
339
|
+
/* @__PURE__ */ jsx6("input", { type: "search", "aria-label": labels.searchChats, placeholder: labels.searchChats, value: query, onInput: (event) => {
|
|
330
340
|
const value = event.currentTarget.value;
|
|
331
341
|
setQuery(value);
|
|
332
342
|
boundedSet(sessionListMemory, memoryKey, { query: value, top: 0 });
|
|
333
343
|
if (rowScroller.current) rowScroller.current.scrollTop = 0;
|
|
334
344
|
} }),
|
|
335
|
-
/* @__PURE__ */
|
|
345
|
+
/* @__PURE__ */ jsx6("small", { children: rows.length })
|
|
336
346
|
] }) : null,
|
|
337
|
-
/* @__PURE__ */
|
|
338
|
-
!rows.length && state.startup === "ready" ? /* @__PURE__ */
|
|
339
|
-
rows.map((row) => /* @__PURE__ */
|
|
340
|
-
state.history.hasMoreSessions ? /* @__PURE__ */
|
|
347
|
+
/* @__PURE__ */ jsxs5("div", { class: "scui-session-rows", ref: rowScroller, onScroll: (event) => boundedSet(sessionListMemory, memoryKey, { query, top: event.currentTarget.scrollTop }), children: [
|
|
348
|
+
!rows.length && state.startup === "ready" ? /* @__PURE__ */ jsx6("div", { class: "scui-empty", children: query ? "No chats match your search." : state.error ?? "No coding chats found." }) : null,
|
|
349
|
+
rows.map((row) => /* @__PURE__ */ jsx6(Row, { value: row, row, state, adapter, onOpen }, row.key)),
|
|
350
|
+
state.history.hasMoreSessions ? /* @__PURE__ */ jsx6("button", { class: "scui-load", type: "button", disabled: loadingMore, onClick: loadMore, children: loadingMore ? "Loading older chats\u2026" : "Load older chats" }) : null
|
|
341
351
|
] })
|
|
342
352
|
] });
|
|
343
353
|
}
|
package/styles.css
CHANGED
|
@@ -171,8 +171,12 @@
|
|
|
171
171
|
.scui-continuation { display:flex; align-items:center; gap:8px; padding:7px 9px; border-top:1px solid var(--scui-border); background:var(--scui-bg-raised) }.scui-continuation > span { display:grid; flex:1 }.scui-continuation small { color:var(--scui-muted); font-size:10px }.scui-continuation button { padding:5px 8px; border:1px solid var(--scui-accent); border-radius:7px; background:transparent; color:var(--scui-accent); cursor:pointer }
|
|
172
172
|
.scui-compose { flex:none; padding:8px; border-top:1px solid var(--scui-border); background:var(--scui-bg-raised) }
|
|
173
173
|
.scui-envelope { display:flex; align-items:flex-end; gap:7px; padding:7px; border:1px solid var(--scui-border-strong); border-radius:16px; background:var(--scui-bg) }.scui-envelope textarea { flex:1; min-width:0; min-height:34px; max-height:150px; resize:none; overflow-y:hidden; border:0; outline:0; background:transparent; color:var(--scui-fg) }.scui-envelope > span { display:flex; gap:4px }
|
|
174
|
+
.scui-attach { display:grid; flex:0 0 34px; width:34px; height:34px; place-items:center; border:0; border-radius:50%; background:transparent; color:var(--scui-muted) }.scui-attach:hover:not(:disabled) { background:var(--scui-fill); color:var(--scui-fg) }
|
|
175
|
+
.scui-compose-context { display:flex; gap:5px; margin-bottom:6px; overflow-x:auto; scrollbar-width:thin }.scui-compose-context > span { display:flex; flex:0 0 auto; max-width:210px; align-items:center; gap:5px; padding:4px 5px 4px 7px; border:1px solid var(--scui-border); border-radius:999px; background:var(--scui-fill); font-size:10px }.scui-compose-context strong { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }.scui-compose-context button { display:grid; width:18px; height:18px; padding:0; place-items:center; border:0; border-radius:50%; background:transparent }.scui-compose-context button:hover { background:color-mix(in srgb,var(--scui-fg) 9%,transparent) }.scui-context-error { display:block; margin:0 2px 6px; color:var(--scui-danger) }
|
|
176
|
+
.scui-compose-images { display:flex; gap:6px; margin-bottom:6px; overflow-x:auto; scrollbar-width:thin }.scui-compose-images > span { position:relative; display:grid; flex:0 0 58px; width:58px; height:58px; overflow:hidden; border:1px solid var(--scui-border); border-radius:8px; background:var(--scui-fill); place-items:center }.scui-compose-images img { width:100%; height:100%; object-fit:cover }.scui-compose-images strong { position:absolute; right:2px; bottom:2px; left:2px; overflow:hidden; padding:2px 3px; border-radius:4px; background:rgba(0,0,0,.65); color:#fff; font-size:8px; font-weight:500; text-overflow:ellipsis; white-space:nowrap }.scui-compose-images button { position:absolute; z-index:1; top:2px; right:2px; display:grid; width:19px; height:19px; padding:0; border:1px solid rgba(255,255,255,.32); border-radius:50%; background:rgba(0,0,0,.68); color:#fff; place-items:center; cursor:pointer }
|
|
177
|
+
.scui-message-images { display:flex; max-width:280px; gap:5px; margin-bottom:6px; flex-wrap:wrap }.scui-message-images img { display:block; width:auto; min-width:72px; max-width:100%; height:auto; max-height:210px; border:1px solid var(--scui-border); border-radius:8px; object-fit:contain; background:var(--scui-fill) }.scui-message-images > span { display:flex; align-items:center; gap:5px; padding:5px 7px; border:1px solid var(--scui-border); border-radius:7px; color:var(--scui-muted); font-size:10px }
|
|
174
178
|
.scui-send,.scui-stop { display:grid; width:29px; height:29px; padding:0; place-items:center; border:0; border-radius:8px; background:var(--scui-accent); color:#fff; cursor:pointer }.scui-stop { background:var(--scui-danger) }.scui-send:disabled,.scui-stop:disabled { opacity:.4; cursor:default }.scui-control-spinner { box-sizing:border-box; width:13px; height:13px; border:1.5px solid currentColor; border-right-color:transparent; border-radius:50%; animation:scui-spin .75s linear infinite }
|
|
175
|
-
.scui-queue { display:grid; gap:4px; max-height:85px; margin-bottom:6px; overflow:auto; font-size:10.5px }.scui-queue > span { display:flex; gap:6px; padding:4px 6px; border-radius:5px; background:var(--scui-fill) }.scui-queue > span button { margin-left:auto; border:0; background:transparent }
|
|
179
|
+
.scui-queue { display:grid; gap:4px; max-height:85px; margin-bottom:6px; overflow:auto; font-size:10.5px }.scui-queue > span { display:flex; gap:6px; padding:4px 6px; border-radius:5px; background:var(--scui-fill) }.scui-queue > span > span { display:grid; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap }.scui-queue small { color:var(--scui-muted) }.scui-queue > span button { margin-left:auto; border:0; background:transparent }
|
|
176
180
|
.scui-harness-picker { display:flex; align-items:center; gap:7px; margin-bottom:7px }.scui-harness-picker select { margin-left:auto; max-width:55%; padding:4px; border:1px solid var(--scui-border); border-radius:6px; background:var(--scui-bg); color:var(--scui-fg) }
|
|
177
181
|
.scui-new { display:grid; justify-items:center; gap:5px; margin:auto; padding:20px; color:var(--scui-muted); text-align:center }.scui-new > span { color:var(--scui-accent); font-size:28px }.scui-new strong { color:var(--scui-fg) }
|
|
178
182
|
.scui-opening { position:absolute; z-index:30; inset:49px 0 0; display:flex; align-items:center; justify-content:center; gap:10px; padding:20px; background:var(--scui-bg) }.scui-opening > span { display:grid }.scui-opening small { color:var(--scui-muted) }.scui-opening > i { width:16px; height:16px; border:2px solid var(--scui-border); border-top-color:var(--scui-accent); border-radius:50%; animation:scui-spin .8s linear infinite }
|