@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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter-ai-dev/supercode-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Composable default UI kit for Supercode-powered coding-agent experiences",
|
|
6
6
|
"exports": {
|
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
"types": "./messenger.d.ts",
|
|
45
45
|
"import": "./messenger.mjs"
|
|
46
46
|
},
|
|
47
|
+
"./preact/settings": {
|
|
48
|
+
"types": "./settings.d.ts",
|
|
49
|
+
"import": "./settings.mjs"
|
|
50
|
+
},
|
|
47
51
|
"./embed": {
|
|
48
52
|
"types": "./embed.d.ts",
|
|
49
53
|
"import": "./embed.mjs"
|
|
@@ -70,6 +74,8 @@
|
|
|
70
74
|
"composer.d.ts",
|
|
71
75
|
"messenger.mjs",
|
|
72
76
|
"messenger.d.ts",
|
|
77
|
+
"settings.mjs",
|
|
78
|
+
"settings.d.ts",
|
|
73
79
|
"embed.mjs",
|
|
74
80
|
"embed.d.ts",
|
|
75
81
|
"index.mjs",
|
|
@@ -78,7 +84,7 @@
|
|
|
78
84
|
"README.md"
|
|
79
85
|
],
|
|
80
86
|
"scripts": {
|
|
81
|
-
"build": "esbuild src/components.jsx src/embed.jsx src/logo.jsx src/icon.jsx src/conversation.jsx src/sessions.jsx src/composer.jsx src/messenger.jsx --bundle --format=esm --platform=browser --jsx=automatic --jsx-import-source=preact --external:preact --external:preact/* --external:markdown-it --outdir=. --out-extension:.js=.mjs",
|
|
87
|
+
"build": "esbuild src/components.jsx src/embed.jsx src/logo.jsx src/icon.jsx src/conversation.jsx src/sessions.jsx src/composer.jsx src/messenger.jsx src/settings.jsx --bundle --format=esm --platform=browser --jsx=automatic --jsx-import-source=preact --external:preact --external:preact/* --external:markdown-it --outdir=. --out-extension:.js=.mjs",
|
|
82
88
|
"build:fixture": "esbuild test/browser-entry.jsx --bundle --format=esm --platform=browser --jsx=automatic --jsx-import-source=preact --outfile=test/browser-bundle.mjs",
|
|
83
89
|
"storybook": "npm run build && storybook dev -p 6006",
|
|
84
90
|
"build:storybook": "npm run build && storybook build",
|
package/sessions.mjs
CHANGED
|
@@ -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([]),
|
|
@@ -59,6 +62,15 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
59
62
|
owned: null,
|
|
60
63
|
attachError: null
|
|
61
64
|
});
|
|
65
|
+
function relativeAge(updatedAt, now = Date.now()) {
|
|
66
|
+
if (typeof updatedAt !== "number" || !Number.isFinite(updatedAt) || updatedAt <= 0) return "";
|
|
67
|
+
const delta = Math.max(0, now - updatedAt);
|
|
68
|
+
if (delta < 6e4) return "now";
|
|
69
|
+
if (delta < 36e5) return `${Math.floor(delta / 6e4)}m ago`;
|
|
70
|
+
if (delta < 864e5) return `${Math.floor(delta / 36e5)}h ago`;
|
|
71
|
+
if (delta < 6048e5) return `${Math.floor(delta / 864e5)}d ago`;
|
|
72
|
+
return `${Math.floor(delta / 6048e5)}w ago`;
|
|
73
|
+
}
|
|
62
74
|
function harnessDisplayName(id) {
|
|
63
75
|
return HARNESS_NAMES[id] ?? id;
|
|
64
76
|
}
|
|
@@ -291,28 +303,35 @@ function sessionPathParts(value) {
|
|
|
291
303
|
trailing: complete.slice(boundary + 1)
|
|
292
304
|
};
|
|
293
305
|
}
|
|
294
|
-
function SessionRow({ row, state, onOpen }) {
|
|
306
|
+
function SessionRow({ row, state, onOpen, now = Date.now() }) {
|
|
295
307
|
const activity = sessionActivity(state, row);
|
|
308
|
+
const working = activity === "working";
|
|
296
309
|
const attention = state.attention.find((item) => item.key === row.key);
|
|
297
310
|
const title = sessionDisplayName(row);
|
|
298
311
|
const path = sessionPathParts(row.cwd);
|
|
299
312
|
const preview = row.preview || attention?.preview || "";
|
|
300
313
|
const unreadCount = attention?.unreadCount ?? 0;
|
|
301
314
|
const unreadLabel = unreadCount > 99 ? "99+" : String(unreadCount);
|
|
302
|
-
|
|
315
|
+
const age = relativeAge(row.previewUpdatedAt ?? row.updatedAt, now) || row.age;
|
|
316
|
+
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)}${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: [
|
|
303
317
|
/* @__PURE__ */ jsx6(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
304
318
|
/* @__PURE__ */ jsxs5("span", { class: "scui-session-copy", children: [
|
|
305
319
|
/* @__PURE__ */ jsxs5("span", { class: "scui-session-title", children: [
|
|
306
320
|
/* @__PURE__ */ jsx6("strong", { children: title }),
|
|
307
|
-
|
|
321
|
+
/* @__PURE__ */ jsx6("span", { class: "scui-session-meta", children: age ? /* @__PURE__ */ jsx6("time", { children: age }) : null })
|
|
308
322
|
] }),
|
|
309
323
|
path.complete ? /* @__PURE__ */ jsxs5("small", { class: "scui-session-path", title: row.cwd, children: [
|
|
310
324
|
/* @__PURE__ */ jsx6("span", { class: "scui-session-path-leading", children: path.leading }),
|
|
311
325
|
path.separator ? /* @__PURE__ */ jsx6("span", { class: "scui-session-path-separator", children: path.separator }) : null,
|
|
312
326
|
path.trailing ? /* @__PURE__ */ jsx6("span", { class: "scui-session-path-trailing", children: path.trailing }) : null
|
|
313
327
|
] }) : null,
|
|
314
|
-
preview || unreadCount ? /* @__PURE__ */ jsxs5("span", { class: "scui-session-preview", children: [
|
|
315
|
-
|
|
328
|
+
working || preview || unreadCount ? /* @__PURE__ */ jsxs5("span", { class: "scui-session-preview", children: [
|
|
329
|
+
working ? /* @__PURE__ */ jsxs5("span", { class: "scui-session-working", "aria-hidden": "true", children: [
|
|
330
|
+
/* @__PURE__ */ jsx6("i", {}),
|
|
331
|
+
/* @__PURE__ */ jsx6("i", {}),
|
|
332
|
+
/* @__PURE__ */ jsx6("i", {})
|
|
333
|
+
] }) : null,
|
|
334
|
+
preview || working ? /* @__PURE__ */ jsx6("small", { children: preview || "Working\u2026" }) : null,
|
|
316
335
|
unreadCount ? /* @__PURE__ */ jsx6("b", { "aria-label": `${unreadCount} unread messages`, children: unreadLabel }) : null
|
|
317
336
|
] }) : null,
|
|
318
337
|
state.attachError?.key === row.key ? /* @__PURE__ */ jsx6("em", { children: state.attachError.message }) : null
|
|
@@ -323,6 +342,7 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
323
342
|
const remembered = sessionListMemory.get(memoryKey) ?? { query: "", top: 0 };
|
|
324
343
|
const [query, setQuery] = useState3(remembered.query);
|
|
325
344
|
const [loadingMore, setLoadingMore] = useState3(false);
|
|
345
|
+
const [now, setNow] = useState3(() => Date.now());
|
|
326
346
|
const root = useRef4(null);
|
|
327
347
|
const rowScroller = useRef4(null);
|
|
328
348
|
const rows = filterSessions(state.sessions, query);
|
|
@@ -338,6 +358,10 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
338
358
|
useEffect5(() => {
|
|
339
359
|
if (loadingMore) setLoadingMore(false);
|
|
340
360
|
}, [state.error, state.history.hasMoreSessions, state.sessions.length]);
|
|
361
|
+
useEffect5(() => {
|
|
362
|
+
const timer = setInterval(() => setNow(Date.now()), 1e4);
|
|
363
|
+
return () => clearInterval(timer);
|
|
364
|
+
}, []);
|
|
341
365
|
const loadMore = () => {
|
|
342
366
|
if (loadingMore) return;
|
|
343
367
|
setLoadingMore(true);
|
|
@@ -371,7 +395,7 @@ function SessionList({ state, adapter, onOpen, onNew, onClose, components = {},
|
|
|
371
395
|
] }) : null,
|
|
372
396
|
/* @__PURE__ */ jsxs5("div", { class: "scui-session-rows", ref: rowScroller, onScroll: (event) => boundedSet(sessionListMemory, memoryKey, { query, top: event.currentTarget.scrollTop }), children: [
|
|
373
397
|
!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,
|
|
374
|
-
rows.map((row) => /* @__PURE__ */ jsx6(Row, { value: row, row, state, adapter, onOpen }, row.key)),
|
|
398
|
+
rows.map((row) => /* @__PURE__ */ jsx6(Row, { value: row, row, state, adapter, onOpen, now }, row.key)),
|
|
375
399
|
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
|
|
376
400
|
] })
|
|
377
401
|
] });
|
package/settings.d.ts
ADDED
package/settings.mjs
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// src/settings.jsx
|
|
2
|
+
import { useEffect, useId, useMemo, useRef, useState } from "preact/hooks";
|
|
3
|
+
|
|
4
|
+
// core.mjs
|
|
5
|
+
var HARNESS_NAMES = Object.freeze({
|
|
6
|
+
"claude-code": "Claude Code",
|
|
7
|
+
codex: "Codex",
|
|
8
|
+
gemini: "Gemini CLI",
|
|
9
|
+
goose: "Goose",
|
|
10
|
+
opencode: "OpenCode",
|
|
11
|
+
pi: "Pi",
|
|
12
|
+
grok: "Grok"
|
|
13
|
+
});
|
|
14
|
+
var DEFAULT_LABELS = Object.freeze({
|
|
15
|
+
chats: "Chats",
|
|
16
|
+
newChat: "New chat",
|
|
17
|
+
searchChats: "Search chats",
|
|
18
|
+
askAgent: "Ask your agent\u2026",
|
|
19
|
+
continueHere: "Continue here",
|
|
20
|
+
joinLive: "Join live",
|
|
21
|
+
forkHere: "Fork here"
|
|
22
|
+
});
|
|
23
|
+
var EMPTY_UI_STATE = Object.freeze({
|
|
24
|
+
pill: Object.freeze({ tone: "off", label: "connecting\u2026" }),
|
|
25
|
+
startup: "connecting",
|
|
26
|
+
transcript: Object.freeze([]),
|
|
27
|
+
busy: false,
|
|
28
|
+
operation: null,
|
|
29
|
+
needsInput: false,
|
|
30
|
+
harness: "",
|
|
31
|
+
mode: "none",
|
|
32
|
+
strategy: null,
|
|
33
|
+
canSend: false,
|
|
34
|
+
canResume: false,
|
|
35
|
+
canBranch: false,
|
|
36
|
+
canAttach: false,
|
|
37
|
+
canDetach: false,
|
|
38
|
+
canOpenTerminal: false,
|
|
39
|
+
canExport: false,
|
|
40
|
+
canReduce: false,
|
|
41
|
+
canInterrupt: false,
|
|
42
|
+
canRespond: false,
|
|
43
|
+
canConfigureSettings: false,
|
|
44
|
+
messaging: null,
|
|
45
|
+
workspace: "",
|
|
46
|
+
taskPlan: Object.freeze({ source: "none", items: Object.freeze([]), residueCount: 0, observedAt: null }),
|
|
47
|
+
semantics: Object.freeze({ fidelity: null, residue: Object.freeze([]), residueCount: 0, parseErrors: 0, rawRecords: 0, subagents: Object.freeze([]) }),
|
|
48
|
+
terminalHandoff: null,
|
|
49
|
+
exportBackTarget: null,
|
|
50
|
+
exportReceipt: null,
|
|
51
|
+
reductionReceipt: null,
|
|
52
|
+
interopSettings: null,
|
|
53
|
+
interopSettingsError: null,
|
|
54
|
+
error: null,
|
|
55
|
+
recoverable: false,
|
|
56
|
+
harnesses: Object.freeze([]),
|
|
57
|
+
history: Object.freeze({ sessionLimit: 0, hasMoreSessions: false, transcriptLimit: 120, hasEarlier: false }),
|
|
58
|
+
savedDraft: "",
|
|
59
|
+
attention: Object.freeze([]),
|
|
60
|
+
sessions: Object.freeze([]),
|
|
61
|
+
attached: null,
|
|
62
|
+
owned: null,
|
|
63
|
+
attachError: null
|
|
64
|
+
});
|
|
65
|
+
function harnessDisplayName(id) {
|
|
66
|
+
return HARNESS_NAMES[id] ?? id;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/icon.jsx
|
|
70
|
+
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
71
|
+
var ICONS = {
|
|
72
|
+
attach: () => /* @__PURE__ */ jsx("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" }),
|
|
73
|
+
back: () => /* @__PURE__ */ jsx("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
|
|
74
|
+
check: () => /* @__PURE__ */ jsx("path", { d: "m4 9 3.25 3.25L14 5.5" }),
|
|
75
|
+
chevron: () => /* @__PURE__ */ jsx("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
|
|
76
|
+
close: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
77
|
+
/* @__PURE__ */ jsx("path", { d: "m4.75 4.75 8.5 8.5" }),
|
|
78
|
+
/* @__PURE__ */ jsx("path", { d: "m13.25 4.75-8.5 8.5" })
|
|
79
|
+
] }),
|
|
80
|
+
copy: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
81
|
+
/* @__PURE__ */ jsx("rect", { x: "5", y: "5", width: "8", height: "8", rx: "1.5" }),
|
|
82
|
+
/* @__PURE__ */ jsx("path", { d: "M3 10.5V4.25C3 3.56 3.56 3 4.25 3h6.25" })
|
|
83
|
+
] }),
|
|
84
|
+
down: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
85
|
+
/* @__PURE__ */ jsx("path", { d: "M9 3.5v10" }),
|
|
86
|
+
/* @__PURE__ */ jsx("path", { d: "m4.75 9.5 4.25 4 4.25-4" })
|
|
87
|
+
] }),
|
|
88
|
+
image: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
89
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "3.5", width: "12", height: "11", rx: "1.75" }),
|
|
90
|
+
/* @__PURE__ */ jsx("circle", { cx: "6.5", cy: "7", r: "1.25" }),
|
|
91
|
+
/* @__PURE__ */ jsx("path", { d: "m4.5 13 3.25-3 2.1 1.85 1.65-1.5L14 13" })
|
|
92
|
+
] }),
|
|
93
|
+
menu: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
94
|
+
/* @__PURE__ */ jsx("circle", { cx: "4", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
|
|
95
|
+
/* @__PURE__ */ jsx("circle", { cx: "9", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
|
|
96
|
+
/* @__PURE__ */ jsx("circle", { cx: "14", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" })
|
|
97
|
+
] }),
|
|
98
|
+
plus: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
99
|
+
/* @__PURE__ */ jsx("path", { d: "M9 3.5v11" }),
|
|
100
|
+
/* @__PURE__ */ jsx("path", { d: "M3.5 9h11" })
|
|
101
|
+
] }),
|
|
102
|
+
search: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
103
|
+
/* @__PURE__ */ jsx("circle", { cx: "7.75", cy: "7.75", r: "4.25" }),
|
|
104
|
+
/* @__PURE__ */ jsx("path", { d: "m11 11 3.5 3.5" })
|
|
105
|
+
] }),
|
|
106
|
+
send: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
107
|
+
/* @__PURE__ */ jsx("path", { d: "M9 14.5v-11" }),
|
|
108
|
+
/* @__PURE__ */ jsx("path", { d: "m4.75 7.75 4.25-4.25 4.25 4.25" })
|
|
109
|
+
] }),
|
|
110
|
+
stop: () => /* @__PURE__ */ jsx("rect", { x: "4.5", y: "4.5", width: "9", height: "9", rx: "1.5", fill: "currentColor", stroke: "none" })
|
|
111
|
+
};
|
|
112
|
+
function UiIcon({ name, size = 16, class: className = "" }) {
|
|
113
|
+
const Glyph = ICONS[name];
|
|
114
|
+
if (!Glyph) return null;
|
|
115
|
+
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, {}) });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/settings.jsx
|
|
119
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
120
|
+
function HarnessAdvisory({ state, onReview }) {
|
|
121
|
+
const advisory = state.interopSettings?.advisories[0];
|
|
122
|
+
if (!advisory && !state.interopSettingsError) return null;
|
|
123
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-advisory", "data-severity": advisory?.severity ?? "error", role: advisory?.severity === "error" || !advisory ? "alert" : "status", children: [
|
|
124
|
+
/* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "!" }),
|
|
125
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
126
|
+
/* @__PURE__ */ jsx2("strong", { children: advisory?.title ?? "Could not inspect harness settings" }),
|
|
127
|
+
/* @__PURE__ */ jsx2("small", { children: advisory?.message ?? state.interopSettingsError })
|
|
128
|
+
] }),
|
|
129
|
+
advisory && state.canConfigureSettings ? /* @__PURE__ */ jsx2("button", { type: "button", onClick: () => onReview(advisory.recommendation.change), children: "Review" }) : null
|
|
130
|
+
] });
|
|
131
|
+
}
|
|
132
|
+
function initialValues(report, recommendedChange) {
|
|
133
|
+
return Object.fromEntries(report.controls.map((control) => [
|
|
134
|
+
control.key,
|
|
135
|
+
recommendedChange?.key === control.key ? recommendedChange.value : control.configuredValue ?? control.effectiveValue ?? control.choices[0]?.value ?? null
|
|
136
|
+
]));
|
|
137
|
+
}
|
|
138
|
+
function HarnessSettingsPanel({ state, adapter, onClose, recommendedChange = null }) {
|
|
139
|
+
const report = state.interopSettings;
|
|
140
|
+
const titleId = useId();
|
|
141
|
+
const panel = useRef(null);
|
|
142
|
+
const valuesKey = `${report?.revision ?? ""}:${recommendedChange?.key ?? ""}:${recommendedChange?.value ?? ""}`;
|
|
143
|
+
const defaults = useMemo(() => report ? initialValues(report, recommendedChange) : {}, [valuesKey]);
|
|
144
|
+
const [values, setValues] = useState(defaults);
|
|
145
|
+
useEffect(() => setValues(defaults), [defaults]);
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
panel.current?.querySelector("select, button")?.focus({ preventScroll: true });
|
|
148
|
+
const dismiss = (event) => {
|
|
149
|
+
if (event.key === "Escape") {
|
|
150
|
+
event.preventDefault();
|
|
151
|
+
onClose();
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
document.addEventListener("keydown", dismiss);
|
|
155
|
+
return () => document.removeEventListener("keydown", dismiss);
|
|
156
|
+
}, [onClose]);
|
|
157
|
+
if (!report) return /* @__PURE__ */ jsx2("section", { ref: panel, class: "scui-settings", role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: /* @__PURE__ */ jsxs2("header", { children: [
|
|
158
|
+
/* @__PURE__ */ jsx2("button", { type: "button", "aria-label": "Close settings", onClick: onClose, children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 18 }) }),
|
|
159
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
160
|
+
/* @__PURE__ */ jsx2("strong", { id: titleId, children: "Harness settings" }),
|
|
161
|
+
/* @__PURE__ */ jsx2("small", { children: state.interopSettingsError ?? "No interoperability controls are available." })
|
|
162
|
+
] })
|
|
163
|
+
] }) });
|
|
164
|
+
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 }] : []);
|
|
165
|
+
const submit = (event) => {
|
|
166
|
+
event.preventDefault();
|
|
167
|
+
if (!changed.length || !state.canConfigureSettings) return;
|
|
168
|
+
adapter.onIntent({ action: "configureHarness", harness: report.harness, changes: changed, expectedRevision: report.revision });
|
|
169
|
+
};
|
|
170
|
+
return /* @__PURE__ */ jsxs2("section", { ref: panel, class: "scui-settings", role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: [
|
|
171
|
+
/* @__PURE__ */ jsxs2("header", { children: [
|
|
172
|
+
/* @__PURE__ */ jsx2("button", { type: "button", "aria-label": "Close settings", onClick: onClose, children: /* @__PURE__ */ jsx2(UiIcon, { name: "close", size: 18 }) }),
|
|
173
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
174
|
+
/* @__PURE__ */ jsxs2("strong", { id: titleId, children: [
|
|
175
|
+
harnessDisplayName(report.harness),
|
|
176
|
+
" interoperability"
|
|
177
|
+
] }),
|
|
178
|
+
/* @__PURE__ */ jsx2("small", { children: "Native harness settings used by Supercode" })
|
|
179
|
+
] })
|
|
180
|
+
] }),
|
|
181
|
+
/* @__PURE__ */ jsxs2("form", { onSubmit: submit, children: [
|
|
182
|
+
report.controls.map((control) => {
|
|
183
|
+
const choice = control.choices.find((item) => item.value === values[control.key]);
|
|
184
|
+
const recommendation = report.advisories.map((advisory) => advisory.recommendation).find((item) => item.change.key === control.key && item.change.value === values[control.key]);
|
|
185
|
+
const consequence = choice?.risk ?? recommendation?.consequence;
|
|
186
|
+
return /* @__PURE__ */ jsxs2("fieldset", { disabled: !control.writable || Boolean(state.operation), children: [
|
|
187
|
+
/* @__PURE__ */ jsxs2("label", { for: `scui-setting-${control.key}`, children: [
|
|
188
|
+
/* @__PURE__ */ jsx2("strong", { children: control.label }),
|
|
189
|
+
/* @__PURE__ */ jsx2("small", { children: control.description })
|
|
190
|
+
] }),
|
|
191
|
+
/* @__PURE__ */ jsxs2("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: [
|
|
192
|
+
control.resettable ? /* @__PURE__ */ jsx2("option", { value: "@default", children: "Use harness default" }) : null,
|
|
193
|
+
control.choices.map((item) => /* @__PURE__ */ jsx2("option", { value: item.value, children: item.label }, item.value))
|
|
194
|
+
] }),
|
|
195
|
+
choice ? /* @__PURE__ */ jsx2("p", { children: choice.description }) : null,
|
|
196
|
+
consequence ? /* @__PURE__ */ jsxs2("p", { class: "scui-setting-risk", children: [
|
|
197
|
+
/* @__PURE__ */ jsx2("strong", { children: "Security consequence" }),
|
|
198
|
+
consequence
|
|
199
|
+
] }) : null,
|
|
200
|
+
/* @__PURE__ */ jsxs2("small", { class: "scui-setting-source", children: [
|
|
201
|
+
control.effectiveNote,
|
|
202
|
+
control.sourcePath ? ` Source: ${control.sourcePath}` : ""
|
|
203
|
+
] })
|
|
204
|
+
] }, control.key);
|
|
205
|
+
}),
|
|
206
|
+
/* @__PURE__ */ jsxs2("footer", { children: [
|
|
207
|
+
/* @__PURE__ */ jsx2("button", { type: "button", onClick: onClose, children: "Cancel" }),
|
|
208
|
+
/* @__PURE__ */ jsx2("button", { type: "submit", disabled: !changed.length || !state.canConfigureSettings || Boolean(state.operation), children: state.operation === "configureHarness" ? "Applying\u2026" : "Apply changes" })
|
|
209
|
+
] })
|
|
210
|
+
] })
|
|
211
|
+
] });
|
|
212
|
+
}
|
|
213
|
+
export {
|
|
214
|
+
HarnessAdvisory,
|
|
215
|
+
HarnessSettingsPanel
|
|
216
|
+
};
|
package/styles.css
CHANGED
|
@@ -73,8 +73,7 @@
|
|
|
73
73
|
.scui-logo[data-harness="pi"] { color:#111; background:#efefeb }
|
|
74
74
|
.scui-logo[data-harness="supercode"] { background:#111923 }
|
|
75
75
|
.scui-logo > i { position:absolute; right:-5%; bottom:-5%; width:32%; height:32%; border:2px solid var(--scui-bg); border-radius:50%; background:var(--scui-muted) }
|
|
76
|
-
.scui-logo[data-activity="working"] > i { background:var(--scui-
|
|
77
|
-
.scui-logo[data-activity="running"] > i { background:var(--scui-positive) }
|
|
76
|
+
.scui-logo[data-activity="working"] > i,.scui-logo[data-activity="running"] > i { background:var(--scui-positive) }
|
|
78
77
|
.scui-logo[data-activity="needs-input"] > i { background:var(--scui-warning) }
|
|
79
78
|
.scui-logo[data-activity="failed"] > i { background:var(--scui-danger) }
|
|
80
79
|
.scui-logo[data-activity="finished"] > i,.scui-logo[data-activity="unseen"] > i { background:var(--scui-positive) }
|
|
@@ -98,7 +97,7 @@
|
|
|
98
97
|
.scui-session-copy { display:grid; flex:1; min-width:0; gap:1px }
|
|
99
98
|
.scui-session-copy > span { display:flex; align-items:baseline; gap:7px; min-width:0 }
|
|
100
99
|
.scui-session-copy strong,.scui-session-copy span > small { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }
|
|
101
|
-
.scui-session-copy strong { flex:1; font-size:12.5px }.scui-session-
|
|
100
|
+
.scui-session-copy strong { flex:1; font-size:12.5px }.scui-session-meta { display:flex; flex:none; align-items:center }.scui-session-title time { color:var(--scui-muted); font-size:10px }.scui-session-working { display:flex; flex:none; width:14px; height:8px; align-self:center; align-items:center; justify-content:space-between; color:var(--scui-muted) }.scui-session-working > i { width:3px; height:3px; border-radius:50%; background:currentColor; animation:scui-session-dots 1.2s ease-in-out infinite }.scui-session-working > i:nth-child(2) { animation-delay:.15s }.scui-session-working > i:nth-child(3) { animation-delay:.3s }
|
|
102
101
|
.scui-session-path { display:flex; min-width:0; overflow:hidden; color:var(--scui-muted); font-size:9.5px; white-space:nowrap }
|
|
103
102
|
.scui-session-path-leading { flex:0 1 auto; overflow:hidden; text-overflow:ellipsis }.scui-session-path-separator { flex:none }.scui-session-path-trailing { flex:none; max-width:58%; overflow:hidden; direction:rtl; text-align:left; text-overflow:ellipsis; unicode-bidi:plaintext }
|
|
104
103
|
.scui-session-preview small { flex:1; min-width:0; color:var(--scui-muted); font-size:10.5px }.scui-session-preview b { display:grid; flex:none; min-width:16px; height:16px; padding:0 4px; place-items:center; border-radius:8px; background:var(--scui-accent); color:var(--scui-bg); font-size:9px; line-height:16px }
|
|
@@ -110,6 +109,15 @@
|
|
|
110
109
|
.scui-error { color:var(--scui-danger) }.scui-error span,.scui-receipt span { flex:1; min-width:0 }
|
|
111
110
|
.scui-error button,.scui-receipt button { border:0; background:transparent; color:var(--scui-accent); cursor:pointer }
|
|
112
111
|
.scui-receipt span { display:grid }.scui-receipt small { overflow:hidden; color:var(--scui-muted); text-overflow:ellipsis; white-space:nowrap }
|
|
112
|
+
.scui-advisory { display:flex; flex:none; align-items:center; gap:7px; padding:6px 8px; border-top:1px solid var(--scui-border); background:var(--scui-bg-raised); font-size:10px }
|
|
113
|
+
.scui-advisory > span:first-child { display:grid; width:17px; height:17px; flex:none; place-items:center; border:1px solid color-mix(in srgb,var(--scui-warning) 48%,var(--scui-border)); border-radius:50%; color:var(--scui-warning); font-size:10px; font-weight:700 }
|
|
114
|
+
.scui-advisory[data-severity="error"] > span:first-child { border-color:color-mix(in srgb,var(--scui-danger) 48%,var(--scui-border)); color:var(--scui-danger) }
|
|
115
|
+
.scui-advisory > span:nth-child(2) { display:grid; min-width:0; flex:1 }.scui-advisory strong,.scui-advisory small { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }.scui-advisory small { color:var(--scui-muted) }
|
|
116
|
+
.scui-advisory button { flex:none; padding:4px 7px; border:1px solid var(--scui-border-strong); border-radius:6px; background:var(--scui-bg); cursor:pointer }
|
|
117
|
+
.scui-settings { position:absolute; z-index:30; inset:0; display:flex; min-height:0; flex-direction:column; background:var(--scui-bg); color:var(--scui-fg) }
|
|
118
|
+
.scui-settings > header { display:flex; min-height:49px; flex:none; align-items:center; gap:8px; padding:7px 10px; border-bottom:1px solid var(--scui-border); background:var(--scui-bg-raised) }.scui-settings > header button { display:grid; width:30px; height:30px; padding:0; place-items:center; border:0; border-radius:8px; background:transparent; cursor:pointer }.scui-settings > header button:hover { background:var(--scui-fill) }.scui-settings > header span { display:grid; min-width:0 }.scui-settings > header small { color:var(--scui-muted); font-size:10px }
|
|
119
|
+
.scui-settings form { display:flex; min-height:0; flex:1; flex-direction:column; overflow:auto }.scui-settings fieldset { display:grid; gap:7px; margin:0; padding:12px; border:0 }.scui-settings fieldset + fieldset { border-top:1px solid var(--scui-border) }.scui-settings fieldset > label { display:grid; gap:2px }.scui-settings fieldset > label small,.scui-settings fieldset > p,.scui-setting-source { color:var(--scui-muted); font-size:10.5px }.scui-settings select { width:100%; padding:7px 8px; border:1px solid var(--scui-border-strong); border-radius:7px; background:var(--scui-bg); color:var(--scui-fg) }.scui-settings fieldset > p { margin:0 }.scui-setting-risk { display:grid; gap:2px; padding:7px; border-left:2px solid var(--scui-warning); background:color-mix(in srgb,var(--scui-warning) 7%,transparent) }.scui-setting-risk strong { color:var(--scui-fg); font-size:10px }.scui-setting-source { overflow-wrap:anywhere }
|
|
120
|
+
.scui-settings form > footer { display:flex; gap:6px; justify-content:flex-end; margin-top:auto; padding:8px; border-top:1px solid var(--scui-border); background:var(--scui-bg-raised) }.scui-settings form > footer button { padding:6px 9px; border:1px solid var(--scui-border-strong); border-radius:7px; background:var(--scui-bg); cursor:pointer }.scui-settings form > footer button[type="submit"] { border-color:var(--scui-fg); background:var(--scui-fg); color:var(--scui-bg) }.scui-settings button:disabled { opacity:.5; cursor:default }
|
|
113
121
|
|
|
114
122
|
.scui-conversation-wrap { position:relative; display:flex; flex:1; min-height:0 }
|
|
115
123
|
.scui-conversation { flex:1; min-width:0; overflow:auto; overscroll-behavior:contain; padding:12px 16px 18px }
|
|
@@ -190,6 +198,7 @@
|
|
|
190
198
|
@keyframes scui-breathe { 50% { transform:scale(.72); opacity:.5 } }
|
|
191
199
|
@keyframes scui-progress { from { transform:translateX(-100%) } to { transform:translateX(180%) } }
|
|
192
200
|
@keyframes scui-dots { 50% { transform:translateY(-3px); opacity:.45 } }
|
|
201
|
+
@keyframes scui-session-dots { 50% { transform:translateY(-1px); opacity:.55 } }
|
|
193
202
|
@media (prefers-reduced-motion:reduce) { .scui-root * { animation-duration:.001ms !important; animation-iteration-count:1 !important; transition:none !important } }
|
|
194
203
|
@media (pointer:coarse) {
|
|
195
204
|
.scui-head > button,.scui-menu-trigger { width:40px; height:40px }
|