@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/embed.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// src/embed.jsx
|
|
2
2
|
import { render } from "preact";
|
|
3
3
|
|
|
4
|
-
// src/
|
|
5
|
-
import
|
|
6
|
-
import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
|
4
|
+
// src/messenger.jsx
|
|
5
|
+
import { useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "preact/hooks";
|
|
7
6
|
|
|
8
7
|
// core.mjs
|
|
9
8
|
var HARNESS_NAMES = Object.freeze({
|
|
10
9
|
"claude-code": "Claude Code",
|
|
11
10
|
codex: "Codex",
|
|
11
|
+
gemini: "Gemini CLI",
|
|
12
12
|
opencode: "OpenCode",
|
|
13
13
|
pi: "Pi",
|
|
14
14
|
grok: "Grok"
|
|
@@ -63,7 +63,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
63
63
|
});
|
|
64
64
|
var ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool", "reasoning", "request", "notice"]);
|
|
65
65
|
var MODES = /* @__PURE__ */ new Set(["none", "control", "mirror"]);
|
|
66
|
-
var STRATEGIES = /* @__PURE__ */ new Set(["start", "resume", "attach", "branch"]);
|
|
66
|
+
var STRATEGIES = /* @__PURE__ */ new Set(["start", "resume", "attach", "branch", "reduce"]);
|
|
67
67
|
var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering", "ready"]);
|
|
68
68
|
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
69
69
|
function record(value) {
|
|
@@ -187,6 +187,35 @@ function readSemantics(value) {
|
|
|
187
187
|
}) : []
|
|
188
188
|
};
|
|
189
189
|
}
|
|
190
|
+
function readTerminalHandoff(value) {
|
|
191
|
+
const handoff = record(value);
|
|
192
|
+
if (!handoff || typeof handoff.program !== "string" || !handoff.program.trim() || !Array.isArray(handoff.arguments) || !handoff.arguments.every((argument) => typeof argument === "string") || typeof handoff.cwd !== "string") return null;
|
|
193
|
+
return { program: handoff.program, arguments: [...handoff.arguments], cwd: handoff.cwd };
|
|
194
|
+
}
|
|
195
|
+
function readExportReceipt(value) {
|
|
196
|
+
const receipt = record(value);
|
|
197
|
+
if (!receipt || typeof receipt.targetHarness !== "string" || !["byte_lossless", "value_lossless"].includes(receipt.fidelity) || typeof receipt.path !== "string" || !receipt.path.trim() || !Number.isInteger(receipt.files) || receipt.files < 1 || !Number.isInteger(receipt.residueCount) || receipt.residueCount < 0) return null;
|
|
198
|
+
return {
|
|
199
|
+
targetHarness: receipt.targetHarness,
|
|
200
|
+
fidelity: receipt.fidelity,
|
|
201
|
+
path: receipt.path,
|
|
202
|
+
files: receipt.files,
|
|
203
|
+
residueCount: receipt.residueCount
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function readReductionReceipt(value) {
|
|
207
|
+
const receipt = record(value);
|
|
208
|
+
if (!receipt || typeof receipt.sourceTokens !== "number" || !Number.isFinite(receipt.sourceTokens) || typeof receipt.reducedTokens !== "number" || !Number.isFinite(receipt.reducedTokens) || receipt.sourceTokens <= receipt.reducedTokens || receipt.reducedTokens < 0 || typeof receipt.ratio !== "number" || !Number.isFinite(receipt.ratio) || receipt.ratio <= 1 || typeof receipt.sidecarId !== "string" || !receipt.sidecarId.trim() || receipt.verified !== true || receipt.reversible !== true || typeof receipt.targetHarness !== "string" || !receipt.targetHarness.trim()) return null;
|
|
209
|
+
return {
|
|
210
|
+
sourceTokens: receipt.sourceTokens,
|
|
211
|
+
reducedTokens: receipt.reducedTokens,
|
|
212
|
+
ratio: receipt.ratio,
|
|
213
|
+
sidecarId: receipt.sidecarId,
|
|
214
|
+
verified: true,
|
|
215
|
+
reversible: true,
|
|
216
|
+
targetHarness: receipt.targetHarness
|
|
217
|
+
};
|
|
218
|
+
}
|
|
190
219
|
function normalizeUiState(value) {
|
|
191
220
|
const raw = record(value) ?? {};
|
|
192
221
|
const pill = record(raw.pill);
|
|
@@ -216,10 +245,10 @@ function normalizeUiState(value) {
|
|
|
216
245
|
workspace: string(raw.workspace),
|
|
217
246
|
taskPlan: readTaskPlan(raw.taskPlan),
|
|
218
247
|
semantics: readSemantics(raw.semantics),
|
|
219
|
-
terminalHandoff:
|
|
248
|
+
terminalHandoff: readTerminalHandoff(raw.terminalHandoff),
|
|
220
249
|
exportBackTarget: typeof raw.exportBackTarget === "string" ? raw.exportBackTarget : null,
|
|
221
|
-
exportReceipt:
|
|
222
|
-
reductionReceipt:
|
|
250
|
+
exportReceipt: readExportReceipt(raw.exportReceipt),
|
|
251
|
+
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
223
252
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
224
253
|
recoverable: raw.recoverable === true,
|
|
225
254
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
@@ -324,8 +353,112 @@ function isSendKey(event) {
|
|
|
324
353
|
return event.key === "Enter" && !event.shiftKey && !event.isComposing;
|
|
325
354
|
}
|
|
326
355
|
|
|
327
|
-
// src/
|
|
356
|
+
// src/composer.jsx
|
|
357
|
+
import { useEffect, useRef, useState } from "preact/hooks";
|
|
358
|
+
|
|
359
|
+
// src/memory.js
|
|
360
|
+
var MEMORY_LIMIT = 100;
|
|
361
|
+
function boundedSet(map, key, value) {
|
|
362
|
+
map.delete(key);
|
|
363
|
+
map.set(key, value);
|
|
364
|
+
while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// src/composer.jsx
|
|
328
368
|
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
369
|
+
var composerMemory = /* @__PURE__ */ new Map();
|
|
370
|
+
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
371
|
+
if (state.mode !== "mirror" || state.canSend) return null;
|
|
372
|
+
const attached = state.attached;
|
|
373
|
+
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
374
|
+
const activeElsewhere = row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
375
|
+
const resume = canContinueHere(state);
|
|
376
|
+
const join = state.canAttach;
|
|
377
|
+
const branch = state.canBranch;
|
|
378
|
+
if (!resume && !join && !branch) return /* @__PURE__ */ jsx("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs("span", { children: [
|
|
379
|
+
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
380
|
+
/* @__PURE__ */ jsx("small", { children: "This session cannot be continued by an available harness." })
|
|
381
|
+
] }) });
|
|
382
|
+
return /* @__PURE__ */ jsxs("div", { class: "scui-continuation", children: [
|
|
383
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
384
|
+
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
385
|
+
/* @__PURE__ */ jsx("small", { children: join ? "Join the proven live runtime without taking it over." : resume ? `Resume this ${harnessDisplayName(state.harness)} session here.` : "Start an independent continuation." })
|
|
386
|
+
] }),
|
|
387
|
+
/* @__PURE__ */ jsx("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 })
|
|
388
|
+
] });
|
|
389
|
+
}
|
|
390
|
+
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, onPending }) {
|
|
391
|
+
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
|
|
392
|
+
const [draft, setDraft] = useState(remembered.draft);
|
|
393
|
+
const [queue, setQueue] = useState(remembered.queue);
|
|
394
|
+
const textarea = useRef(null);
|
|
395
|
+
const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
|
|
396
|
+
const updateQueue = (update) => setQueue((items) => {
|
|
397
|
+
const next = update(items);
|
|
398
|
+
remember(draft, next);
|
|
399
|
+
return next;
|
|
400
|
+
});
|
|
401
|
+
useEffect(() => {
|
|
402
|
+
if (!state.busy && state.canSend && queue.length) {
|
|
403
|
+
const [next, ...rest] = queue;
|
|
404
|
+
setQueue(rest);
|
|
405
|
+
remember(draft, rest);
|
|
406
|
+
onPending?.(next);
|
|
407
|
+
adapter.onIntent({ action: "send", text: next });
|
|
408
|
+
}
|
|
409
|
+
}, [adapter, draft, memoryKey, onPending, queue, state.busy, state.canSend]);
|
|
410
|
+
useEffect(() => {
|
|
411
|
+
const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
|
|
412
|
+
return () => clearTimeout(timer);
|
|
413
|
+
}, [adapter, draft]);
|
|
414
|
+
const send = () => {
|
|
415
|
+
const text = draft.trim();
|
|
416
|
+
if (!text) return;
|
|
417
|
+
if (state.busy) updateQueue((items) => [...items, text]);
|
|
418
|
+
else if (state.canSend) {
|
|
419
|
+
onPending?.(text);
|
|
420
|
+
adapter.onIntent({ action: "send", text });
|
|
421
|
+
} else return;
|
|
422
|
+
setDraft("");
|
|
423
|
+
remember("", state.busy ? [...queue, text] : queue);
|
|
424
|
+
};
|
|
425
|
+
return /* @__PURE__ */ jsxs("div", { class: "scui-compose", children: [
|
|
426
|
+
queue.length ? /* @__PURE__ */ jsxs("div", { class: "scui-queue", children: [
|
|
427
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
428
|
+
queue.length,
|
|
429
|
+
" queued"
|
|
430
|
+
] }),
|
|
431
|
+
queue.map((item, index) => /* @__PURE__ */ jsxs("span", { children: [
|
|
432
|
+
item,
|
|
433
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: "\xD7" })
|
|
434
|
+
] }, `${index}:${item}`))
|
|
435
|
+
] }) : null,
|
|
436
|
+
/* @__PURE__ */ jsxs("div", { class: "scui-envelope", children: [
|
|
437
|
+
/* @__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) => {
|
|
438
|
+
const value = event.currentTarget.value;
|
|
439
|
+
setDraft(value);
|
|
440
|
+
remember(value, queue);
|
|
441
|
+
}, onKeyDown: (event) => {
|
|
442
|
+
if (isSendKey(event)) {
|
|
443
|
+
event.preventDefault();
|
|
444
|
+
send();
|
|
445
|
+
}
|
|
446
|
+
} }),
|
|
447
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
448
|
+
state.busy ? /* @__PURE__ */ jsx("button", { class: "scui-stop", type: "button", "aria-label": "Stop agent", disabled: !state.canInterrupt, onClick: () => adapter.onIntent({ action: "interrupt" }), children: "\u25A0" }) : null,
|
|
449
|
+
/* @__PURE__ */ jsx("button", { class: "scui-send", type: "button", "aria-label": state.busy ? "Queue message" : "Send message", disabled: !draft.trim() || !state.busy && !state.canSend, onClick: send, children: state.busy ? "+" : "\u2191" })
|
|
450
|
+
] })
|
|
451
|
+
] })
|
|
452
|
+
] });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// src/conversation.jsx
|
|
456
|
+
import { useEffect as useEffect2, useId, useLayoutEffect, useRef as useRef2, useState as useState2 } from "preact/hooks";
|
|
457
|
+
|
|
458
|
+
// src/markdown.jsx
|
|
459
|
+
import MarkdownIt from "markdown-it";
|
|
460
|
+
import { useMemo } from "preact/hooks";
|
|
461
|
+
import { jsx as jsx2 } from "preact/jsx-runtime";
|
|
329
462
|
var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
|
|
330
463
|
var defaultLinkOpen = markdown.renderer.rules.link_open;
|
|
331
464
|
markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
|
|
@@ -333,47 +466,13 @@ markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
|
|
|
333
466
|
tokens[index]?.attrSet("rel", "noreferrer noopener");
|
|
334
467
|
return defaultLinkOpen ? defaultLinkOpen(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
|
|
335
468
|
};
|
|
336
|
-
var LOGOS = {
|
|
337
|
-
"claude-code": {
|
|
338
|
-
viewBox: "-1 3.5 26 18",
|
|
339
|
-
paths: [
|
|
340
|
-
["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z" }]
|
|
341
|
-
]
|
|
342
|
-
},
|
|
343
|
-
codex: {
|
|
344
|
-
viewBox: "-1 -1 26 26",
|
|
345
|
-
paths: [
|
|
346
|
-
["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M8.086.457a6.105 6.105 0 013.046-.415c1.333.153 2.521.72 3.564 1.7a.117.117 0 00.107.029c1.408-.346 2.762-.224 4.061.366l.063.03.154.076c1.357.703 2.33 1.77 2.918 3.198.278.679.418 1.388.421 2.126a5.655 5.655 0 01-.18 1.631.167.167 0 00.04.155 5.982 5.982 0 011.578 2.891c.385 1.901-.01 3.615-1.183 5.14l-.182.22a6.063 6.063 0 01-2.934 1.851.162.162 0 00-.108.102c-.255.736-.511 1.364-.987 1.992-1.199 1.582-2.962 2.462-4.948 2.451-1.583-.008-2.986-.587-4.21-1.736a.145.145 0 00-.14-.032c-.518.167-1.04.191-1.604.185a5.924 5.924 0 01-2.595-.622 6.058 6.058 0 01-2.146-1.781c-.203-.269-.404-.522-.551-.821a7.74 7.74 0 01-.495-1.283 6.11 6.11 0 01-.017-3.064.166.166 0 00.008-.074.115.115 0 00-.037-.064 5.958 5.958 0 01-1.38-2.202 5.196 5.196 0 01-.333-1.589 6.915 6.915 0 01.188-2.132c.45-1.484 1.309-2.648 2.577-3.493.282-.188.55-.334.802-.438.286-.12.573-.22.861-.304a.129.129 0 00.087-.087A6.016 6.016 0 015.635 2.31C6.315 1.464 7.132.846 8.086.457zm-.804 7.85a.848.848 0 00-1.473.842l1.694 2.965-1.688 2.848a.849.849 0 001.46.864l1.94-3.272a.849.849 0 00.007-.854l-1.94-3.393zm5.446 6.24a.849.849 0 000 1.695h4.848a.849.849 0 000-1.696h-4.848z" }]
|
|
347
|
-
]
|
|
348
|
-
},
|
|
349
|
-
grok: {
|
|
350
|
-
viewBox: "-1 -1 26 26",
|
|
351
|
-
paths: [["path", { d: "M9.27 15.29l7.978-5.897c.391-.29.95-.177 1.137.272.98 2.369.542 5.215-1.41 7.169-1.951 1.954-4.667 2.382-7.149 1.406l-2.711 1.257c3.889 2.661 8.611 2.003 11.562-.953 2.341-2.344 3.066-5.539 2.388-8.42l.006.007c-.983-4.232.242-5.924 2.75-9.383.06-.082.12-.164.179-.248l-3.301 3.305v-.01L9.267 15.292M7.623 16.723c-2.792-2.67-2.31-6.801.071-9.184 1.761-1.763 4.647-2.483 7.166-1.425l2.705-1.25a7.808 7.808 0 00-1.829-1A8.975 8.975 0 005.984 5.83c-2.533 2.536-3.33 6.436-1.962 9.764 1.022 2.487-.653 4.246-2.34 6.022-.599.63-1.199 1.259-1.682 1.925l7.62-6.815" }]]
|
|
352
|
-
},
|
|
353
|
-
opencode: { viewBox: "2.5 0 19 24", paths: [["path", { d: "M16 6H8v12h8V6zm4 16H4V2h16v20z" }]] },
|
|
354
|
-
pi: {
|
|
355
|
-
viewBox: "0 0 24 24",
|
|
356
|
-
paths: [
|
|
357
|
-
["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M1 1h16.5v11H12v5.5H6.5V23H1V1zm5.5 5.5V12H12V6.5H6.5z" }],
|
|
358
|
-
["path", { d: "M17.5 12H23v11h-5.5V12z" }]
|
|
359
|
-
]
|
|
360
|
-
}
|
|
361
|
-
};
|
|
362
469
|
function Markdown({ value }) {
|
|
363
470
|
const html = useMemo(() => markdown.render(value), [value]);
|
|
364
|
-
return /* @__PURE__ */
|
|
365
|
-
}
|
|
366
|
-
function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
367
|
-
const logo = LOGOS[id];
|
|
368
|
-
useEffect(() => {
|
|
369
|
-
if (!logo) onMissingLogo?.(id);
|
|
370
|
-
}, [id, logo, onMissingLogo]);
|
|
371
|
-
if (!logo) return null;
|
|
372
|
-
return /* @__PURE__ */ jsxs("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
|
|
373
|
-
/* @__PURE__ */ jsx("svg", { viewBox: logo.viewBox, focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx(Tag, { ...props }, index)) }),
|
|
374
|
-
activity && activity !== "idle" ? /* @__PURE__ */ jsx("i", {}) : null
|
|
375
|
-
] });
|
|
471
|
+
return /* @__PURE__ */ jsx2("div", { class: "scui-markdown", dangerouslySetInnerHTML: { __html: html } });
|
|
376
472
|
}
|
|
473
|
+
|
|
474
|
+
// src/conversation.jsx
|
|
475
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
377
476
|
function LoadingStatus({ state, compact = false }) {
|
|
378
477
|
const copy = {
|
|
379
478
|
connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
|
|
@@ -381,83 +480,83 @@ function LoadingStatus({ state, compact = false }) {
|
|
|
381
480
|
discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
|
|
382
481
|
ready: ["Ready", "Coding sessions are up to date.", 3]
|
|
383
482
|
}[state.startup];
|
|
384
|
-
return /* @__PURE__ */
|
|
385
|
-
/* @__PURE__ */
|
|
386
|
-
/* @__PURE__ */
|
|
387
|
-
/* @__PURE__ */
|
|
388
|
-
/* @__PURE__ */
|
|
483
|
+
return /* @__PURE__ */ jsxs2("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
|
|
484
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("i", {}) }),
|
|
485
|
+
/* @__PURE__ */ jsxs2("span", { class: "scui-loading-copy", children: [
|
|
486
|
+
/* @__PURE__ */ jsx3("strong", { children: copy[0] }),
|
|
487
|
+
/* @__PURE__ */ jsx3("small", { children: copy[1] })
|
|
389
488
|
] }),
|
|
390
|
-
/* @__PURE__ */
|
|
489
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx3("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
|
|
391
490
|
] });
|
|
392
491
|
}
|
|
393
492
|
function RequestCard({ entry, adapter, canRespond }) {
|
|
394
493
|
const request = entry.request;
|
|
395
494
|
if (!request) return null;
|
|
396
495
|
if (request.status === "responded") {
|
|
397
|
-
return /* @__PURE__ */
|
|
496
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-request-done", children: [
|
|
398
497
|
"\u2713 Request answered \xB7 ",
|
|
399
498
|
request.resolution?.name ?? request.requestKind
|
|
400
499
|
] });
|
|
401
500
|
}
|
|
402
|
-
return /* @__PURE__ */
|
|
403
|
-
/* @__PURE__ */
|
|
404
|
-
/* @__PURE__ */
|
|
405
|
-
/* @__PURE__ */
|
|
406
|
-
request.options.map((option) => /* @__PURE__ */
|
|
407
|
-
request.cancellable ? /* @__PURE__ */
|
|
501
|
+
return /* @__PURE__ */ jsxs2("section", { class: "scui-request", "aria-label": `${request.requestKind} needs input`, children: [
|
|
502
|
+
/* @__PURE__ */ jsx3("strong", { children: "Agent needs input" }),
|
|
503
|
+
/* @__PURE__ */ jsx3(Markdown, { value: request.payloadText || entry.text }),
|
|
504
|
+
/* @__PURE__ */ jsxs2("div", { class: "scui-request-actions", children: [
|
|
505
|
+
request.options.map((option) => /* @__PURE__ */ jsx3("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: option.optionId }), children: option.name }, option.optionId)),
|
|
506
|
+
request.cancellable ? /* @__PURE__ */ jsx3("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
|
|
408
507
|
] })
|
|
409
508
|
] });
|
|
410
509
|
}
|
|
411
510
|
function ContextDisclosure({ context }) {
|
|
412
511
|
if (!context?.length) return null;
|
|
413
|
-
return /* @__PURE__ */
|
|
414
|
-
/* @__PURE__ */
|
|
512
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-context", children: [
|
|
513
|
+
/* @__PURE__ */ jsxs2("summary", { children: [
|
|
415
514
|
"Context \xB7 ",
|
|
416
515
|
context.length
|
|
417
516
|
] }),
|
|
418
|
-
/* @__PURE__ */
|
|
419
|
-
/* @__PURE__ */
|
|
420
|
-
/* @__PURE__ */
|
|
517
|
+
/* @__PURE__ */ jsx3("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs2("p", { children: [
|
|
518
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
519
|
+
/* @__PURE__ */ jsx3("span", { children: item.detail })
|
|
421
520
|
] }, item.id ?? index)) })
|
|
422
521
|
] });
|
|
423
522
|
}
|
|
424
523
|
function TranscriptEntry({ entry, state, adapter }) {
|
|
425
|
-
if (entry.role === "request") return /* @__PURE__ */
|
|
524
|
+
if (entry.role === "request") return /* @__PURE__ */ jsx3(RequestCard, { entry, adapter, canRespond: state.canRespond });
|
|
426
525
|
if (entry.role === "reasoning") {
|
|
427
|
-
return /* @__PURE__ */
|
|
428
|
-
/* @__PURE__ */
|
|
429
|
-
/* @__PURE__ */
|
|
526
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-reasoning", open: entry.streaming, children: [
|
|
527
|
+
/* @__PURE__ */ jsx3("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
|
|
528
|
+
/* @__PURE__ */ jsx3(Markdown, { value: entry.text })
|
|
430
529
|
] });
|
|
431
530
|
}
|
|
432
|
-
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */
|
|
433
|
-
return /* @__PURE__ */
|
|
434
|
-
/* @__PURE__ */
|
|
435
|
-
/* @__PURE__ */
|
|
436
|
-
entry.truncated ? /* @__PURE__ */
|
|
531
|
+
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx3("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
|
|
532
|
+
return /* @__PURE__ */ jsxs2("article", { class: "scui-message", "data-role": entry.role, children: [
|
|
533
|
+
/* @__PURE__ */ jsx3(Markdown, { value: entry.text }),
|
|
534
|
+
/* @__PURE__ */ jsx3(ContextDisclosure, { context: entry.context }),
|
|
535
|
+
entry.truncated ? /* @__PURE__ */ jsx3("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
|
|
437
536
|
] });
|
|
438
537
|
}
|
|
439
538
|
function ToolRow({ entry, workspace }) {
|
|
440
|
-
const [open, setOpen] =
|
|
539
|
+
const [open, setOpen] = useState2(entry.status === "pending");
|
|
441
540
|
const detailId = useId();
|
|
442
541
|
const target = compactToolTarget(toolTarget(entry.arguments), workspace);
|
|
443
542
|
const hasDetail = Boolean(entry.arguments || entry.resultText);
|
|
444
543
|
const category = toolCategory(entry);
|
|
445
|
-
return /* @__PURE__ */
|
|
446
|
-
/* @__PURE__ */
|
|
447
|
-
/* @__PURE__ */
|
|
448
|
-
/* @__PURE__ */
|
|
449
|
-
target ? /* @__PURE__ */
|
|
450
|
-
/* @__PURE__ */
|
|
451
|
-
/* @__PURE__ */
|
|
544
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
|
|
545
|
+
/* @__PURE__ */ jsxs2("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: [
|
|
546
|
+
/* @__PURE__ */ jsx3("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] }),
|
|
547
|
+
/* @__PURE__ */ jsx3("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
|
|
548
|
+
target ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
|
|
549
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
|
|
550
|
+
/* @__PURE__ */ jsx3("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
|
|
452
551
|
] }),
|
|
453
|
-
hasDetail && open ? /* @__PURE__ */
|
|
454
|
-
entry.arguments ? /* @__PURE__ */
|
|
455
|
-
/* @__PURE__ */
|
|
552
|
+
hasDetail && open ? /* @__PURE__ */ jsxs2("div", { id: detailId, class: "scui-tool-detail", children: [
|
|
553
|
+
entry.arguments ? /* @__PURE__ */ jsxs2("pre", { children: [
|
|
554
|
+
/* @__PURE__ */ jsx3("b", { children: "Input" }),
|
|
456
555
|
"\n",
|
|
457
556
|
entry.arguments
|
|
458
557
|
] }) : null,
|
|
459
|
-
entry.resultText ? /* @__PURE__ */
|
|
460
|
-
/* @__PURE__ */
|
|
558
|
+
entry.resultText ? /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
|
|
559
|
+
/* @__PURE__ */ jsx3("b", { children: "Output" }),
|
|
461
560
|
"\n",
|
|
462
561
|
entry.resultText,
|
|
463
562
|
entry.truncated ? "\n[truncated]" : ""
|
|
@@ -467,74 +566,74 @@ function ToolRow({ entry, workspace }) {
|
|
|
467
566
|
}
|
|
468
567
|
function ActivityGroup({ entries, state }) {
|
|
469
568
|
const active = entries.some((entry) => entry.status === "pending");
|
|
470
|
-
const [open, setOpen] =
|
|
569
|
+
const [open, setOpen] = useState2(active);
|
|
471
570
|
const id = useId();
|
|
472
|
-
|
|
571
|
+
useEffect2(() => {
|
|
473
572
|
if (active) setOpen(true);
|
|
474
573
|
}, [active]);
|
|
475
|
-
return /* @__PURE__ */
|
|
476
|
-
/* @__PURE__ */
|
|
477
|
-
/* @__PURE__ */
|
|
478
|
-
/* @__PURE__ */
|
|
479
|
-
/* @__PURE__ */
|
|
480
|
-
/* @__PURE__ */
|
|
574
|
+
return /* @__PURE__ */ jsxs2("section", { class: "scui-activity", children: [
|
|
575
|
+
/* @__PURE__ */ jsxs2("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
|
|
576
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-fold", "data-open": open, children: "\u203A" }),
|
|
577
|
+
/* @__PURE__ */ jsx3("strong", { children: activitySummary(entries) }),
|
|
578
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
|
|
579
|
+
/* @__PURE__ */ jsxs2("small", { children: [
|
|
481
580
|
entries.filter((entry) => entry.status === "completed").length,
|
|
482
581
|
"/",
|
|
483
582
|
entries.length
|
|
484
583
|
] })
|
|
485
584
|
] }),
|
|
486
|
-
open ? /* @__PURE__ */
|
|
585
|
+
open ? /* @__PURE__ */ jsx3("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx3(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
|
|
487
586
|
] });
|
|
488
587
|
}
|
|
489
588
|
function TaskPlan({ plan }) {
|
|
490
589
|
if (!plan.items.length) return null;
|
|
491
590
|
const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
|
|
492
|
-
return /* @__PURE__ */
|
|
493
|
-
/* @__PURE__ */
|
|
494
|
-
/* @__PURE__ */
|
|
495
|
-
/* @__PURE__ */
|
|
591
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-plan", children: [
|
|
592
|
+
/* @__PURE__ */ jsxs2("summary", { children: [
|
|
593
|
+
/* @__PURE__ */ jsx3("span", { children: "Plan" }),
|
|
594
|
+
/* @__PURE__ */ jsxs2("small", { children: [
|
|
496
595
|
complete,
|
|
497
596
|
"/",
|
|
498
597
|
plan.items.length
|
|
499
598
|
] })
|
|
500
599
|
] }),
|
|
501
|
-
/* @__PURE__ */
|
|
502
|
-
/* @__PURE__ */
|
|
600
|
+
/* @__PURE__ */ jsx3("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs2("li", { "data-status": item.status, children: [
|
|
601
|
+
/* @__PURE__ */ jsx3("i", { "aria-hidden": "true" }),
|
|
503
602
|
" ",
|
|
504
|
-
/* @__PURE__ */
|
|
603
|
+
/* @__PURE__ */ jsx3("span", { children: item.title })
|
|
505
604
|
] }, item.id)) })
|
|
506
605
|
] });
|
|
507
606
|
}
|
|
508
607
|
function SessionDetails({ semantics }) {
|
|
509
608
|
if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
|
|
510
|
-
return /* @__PURE__ */
|
|
511
|
-
/* @__PURE__ */
|
|
512
|
-
/* @__PURE__ */
|
|
513
|
-
semantics.fidelity ? /* @__PURE__ */
|
|
514
|
-
/* @__PURE__ */
|
|
515
|
-
/* @__PURE__ */
|
|
609
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-details", children: [
|
|
610
|
+
/* @__PURE__ */ jsx3("summary", { children: "Session details" }),
|
|
611
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
612
|
+
semantics.fidelity ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
613
|
+
/* @__PURE__ */ jsx3("strong", { children: "Fidelity" }),
|
|
614
|
+
/* @__PURE__ */ jsx3("span", { children: semantics.fidelity.replaceAll("_", " ") })
|
|
516
615
|
] }) : null,
|
|
517
|
-
/* @__PURE__ */
|
|
518
|
-
/* @__PURE__ */
|
|
519
|
-
/* @__PURE__ */
|
|
616
|
+
/* @__PURE__ */ jsxs2("p", { children: [
|
|
617
|
+
/* @__PURE__ */ jsx3("strong", { children: "Native records" }),
|
|
618
|
+
/* @__PURE__ */ jsx3("span", { children: semantics.rawRecords })
|
|
520
619
|
] }),
|
|
521
|
-
semantics.residueCount ? /* @__PURE__ */
|
|
522
|
-
/* @__PURE__ */
|
|
523
|
-
/* @__PURE__ */
|
|
620
|
+
semantics.residueCount ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
621
|
+
/* @__PURE__ */ jsx3("strong", { children: "Residue" }),
|
|
622
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
524
623
|
semantics.residueCount,
|
|
525
624
|
" retained"
|
|
526
625
|
] })
|
|
527
626
|
] }) : null,
|
|
528
|
-
semantics.parseErrors ? /* @__PURE__ */
|
|
529
|
-
/* @__PURE__ */
|
|
530
|
-
/* @__PURE__ */
|
|
627
|
+
semantics.parseErrors ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
628
|
+
/* @__PURE__ */ jsx3("strong", { children: "Parse diagnostics" }),
|
|
629
|
+
/* @__PURE__ */ jsx3("span", { children: semantics.parseErrors })
|
|
531
630
|
] }) : null,
|
|
532
|
-
semantics.subagents.map((agent) => /* @__PURE__ */
|
|
533
|
-
/* @__PURE__ */
|
|
631
|
+
semantics.subagents.map((agent) => /* @__PURE__ */ jsxs2("p", { children: [
|
|
632
|
+
/* @__PURE__ */ jsxs2("strong", { children: [
|
|
534
633
|
agent.source,
|
|
535
634
|
" subagent"
|
|
536
635
|
] }),
|
|
537
|
-
/* @__PURE__ */
|
|
636
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
538
637
|
agent.messages,
|
|
539
638
|
" messages \xB7 ",
|
|
540
639
|
agent.fidelity.replaceAll("_", " ")
|
|
@@ -544,24 +643,24 @@ function SessionDetails({ semantics }) {
|
|
|
544
643
|
] });
|
|
545
644
|
}
|
|
546
645
|
var conversationMemory = /* @__PURE__ */ new Map();
|
|
547
|
-
var composerMemory = /* @__PURE__ */ new Map();
|
|
548
646
|
function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null }) {
|
|
549
|
-
const scroller =
|
|
647
|
+
const scroller = useRef2(null);
|
|
550
648
|
const remembered = conversationMemory.get(memoryKey) ?? { top: null, atBottom: true };
|
|
551
|
-
const [atBottom, setAtBottom] =
|
|
552
|
-
const earlierAnchor =
|
|
553
|
-
const restored =
|
|
649
|
+
const [atBottom, setAtBottom] = useState2(remembered.atBottom);
|
|
650
|
+
const earlierAnchor = useRef2(null);
|
|
651
|
+
const restored = useRef2(false);
|
|
554
652
|
const blocks = groupConversation(state.transcript);
|
|
555
653
|
const Entry = components.TranscriptEntry ?? TranscriptEntry;
|
|
556
654
|
const Group = components.ActivityGroup ?? ActivityGroup;
|
|
557
655
|
const Before = slots.beforeConversation;
|
|
558
656
|
const After = slots.afterConversation;
|
|
559
657
|
const Empty = slots.emptyConversation;
|
|
658
|
+
const remember = (value) => boundedSet(conversationMemory, memoryKey, value);
|
|
560
659
|
const pin = () => {
|
|
561
660
|
if (!scroller.current) return;
|
|
562
661
|
scroller.current.scrollTop = scroller.current.scrollHeight;
|
|
563
662
|
setAtBottom(true);
|
|
564
|
-
|
|
663
|
+
remember({ top: scroller.current.scrollTop, atBottom: true });
|
|
565
664
|
};
|
|
566
665
|
useLayoutEffect(() => {
|
|
567
666
|
const element = scroller.current;
|
|
@@ -570,7 +669,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
570
669
|
if (anchor && state.transcript.length > anchor.entries) {
|
|
571
670
|
element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
|
|
572
671
|
earlierAnchor.current = null;
|
|
573
|
-
|
|
672
|
+
remember({ top: element.scrollTop, atBottom: false });
|
|
574
673
|
return;
|
|
575
674
|
}
|
|
576
675
|
if (!restored.current) {
|
|
@@ -579,178 +678,148 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
579
678
|
else pin();
|
|
580
679
|
} else if (atBottom) pin();
|
|
581
680
|
}, [memoryKey, state.transcript.length, state.busy]);
|
|
582
|
-
return /* @__PURE__ */
|
|
583
|
-
/* @__PURE__ */
|
|
681
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-conversation-wrap", children: [
|
|
682
|
+
/* @__PURE__ */ jsx3("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
|
|
584
683
|
const element = event.currentTarget;
|
|
585
684
|
const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
|
|
586
685
|
setAtBottom(bottom);
|
|
587
|
-
|
|
588
|
-
}, children: /* @__PURE__ */
|
|
589
|
-
Before ? /* @__PURE__ */
|
|
590
|
-
/* @__PURE__ */
|
|
591
|
-
/* @__PURE__ */
|
|
592
|
-
state.history.hasEarlier ? /* @__PURE__ */
|
|
686
|
+
remember({ top: element.scrollTop, atBottom: bottom });
|
|
687
|
+
}, children: /* @__PURE__ */ jsxs2("div", { children: [
|
|
688
|
+
Before ? /* @__PURE__ */ jsx3(Before, { state, adapter, value: null }) : null,
|
|
689
|
+
/* @__PURE__ */ jsx3(TaskPlan, { plan: state.taskPlan }),
|
|
690
|
+
/* @__PURE__ */ jsx3(SessionDetails, { semantics: state.semantics }),
|
|
691
|
+
state.history.hasEarlier ? /* @__PURE__ */ jsx3("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
|
|
593
692
|
const element = scroller.current;
|
|
594
693
|
if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
|
|
595
694
|
setAtBottom(false);
|
|
596
695
|
adapter.onIntent({ action: "loadEarlier" });
|
|
597
696
|
}, children: "Load earlier messages" }) : null,
|
|
598
|
-
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */
|
|
599
|
-
!blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */
|
|
600
|
-
blocks.map((block) => block.kind === "activity" ? /* @__PURE__ */
|
|
601
|
-
pending ? /* @__PURE__ */
|
|
602
|
-
/* @__PURE__ */
|
|
603
|
-
/* @__PURE__ */
|
|
697
|
+
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx3(LoadingStatus, { state }) : null,
|
|
698
|
+
!blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx3(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx3("div", { class: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
|
|
699
|
+
blocks.map((block) => block.kind === "activity" ? /* @__PURE__ */ jsx3(Group, { value: block.entries, entries: block.entries, state, adapter }, block.id) : /* @__PURE__ */ jsx3(Entry, { value: block.entry, entry: block.entry, state, adapter }, block.id)),
|
|
700
|
+
pending ? /* @__PURE__ */ jsxs2("article", { class: "scui-message scui-pending", "data-role": "user", children: [
|
|
701
|
+
/* @__PURE__ */ jsx3(Markdown, { value: pending }),
|
|
702
|
+
/* @__PURE__ */ jsx3("small", { children: state.error && !state.busy ? "Not sent" : "Sending\u2026" })
|
|
604
703
|
] }) : null,
|
|
605
|
-
state.busy ? /* @__PURE__ */
|
|
606
|
-
/* @__PURE__ */
|
|
607
|
-
/* @__PURE__ */
|
|
608
|
-
/* @__PURE__ */
|
|
609
|
-
/* @__PURE__ */
|
|
610
|
-
/* @__PURE__ */
|
|
704
|
+
state.busy ? /* @__PURE__ */ jsxs2("div", { class: "scui-working", role: "status", children: [
|
|
705
|
+
/* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
706
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
707
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
708
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
709
|
+
/* @__PURE__ */ jsxs2("small", { children: [
|
|
611
710
|
harnessDisplayName(state.harness),
|
|
612
711
|
" is working"
|
|
613
712
|
] })
|
|
614
713
|
] }) : null,
|
|
615
|
-
After ? /* @__PURE__ */
|
|
714
|
+
After ? /* @__PURE__ */ jsx3(After, { state, adapter, value: null }) : null
|
|
616
715
|
] }) }),
|
|
617
|
-
!atBottom ? /* @__PURE__ */
|
|
716
|
+
!atBottom ? /* @__PURE__ */ jsx3("button", { class: "scui-latest", type: "button", onClick: pin, children: "\u2193 Latest" }) : null
|
|
618
717
|
] });
|
|
619
718
|
}
|
|
719
|
+
|
|
720
|
+
// src/logo.jsx
|
|
721
|
+
import { useEffect as useEffect3 } from "preact/hooks";
|
|
722
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
723
|
+
var LOGOS = {
|
|
724
|
+
"claude-code": {
|
|
725
|
+
viewBox: "-1 3.5 26 18",
|
|
726
|
+
paths: [
|
|
727
|
+
["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z" }]
|
|
728
|
+
]
|
|
729
|
+
},
|
|
730
|
+
codex: {
|
|
731
|
+
viewBox: "-1 -1 26 26",
|
|
732
|
+
paths: [
|
|
733
|
+
["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M8.086.457a6.105 6.105 0 013.046-.415c1.333.153 2.521.72 3.564 1.7a.117.117 0 00.107.029c1.408-.346 2.762-.224 4.061.366l.063.03.154.076c1.357.703 2.33 1.77 2.918 3.198.278.679.418 1.388.421 2.126a5.655 5.655 0 01-.18 1.631.167.167 0 00.04.155 5.982 5.982 0 011.578 2.891c.385 1.901-.01 3.615-1.183 5.14l-.182.22a6.063 6.063 0 01-2.934 1.851.162.162 0 00-.108.102c-.255.736-.511 1.364-.987 1.992-1.199 1.582-2.962 2.462-4.948 2.451-1.583-.008-2.986-.587-4.21-1.736a.145.145 0 00-.14-.032c-.518.167-1.04.191-1.604.185a5.924 5.924 0 01-2.595-.622 6.058 6.058 0 01-2.146-1.781c-.203-.269-.404-.522-.551-.821a7.74 7.74 0 01-.495-1.283 6.11 6.11 0 01-.017-3.064.166.166 0 00.008-.074.115.115 0 00-.037-.064 5.958 5.958 0 01-1.38-2.202 5.196 5.196 0 01-.333-1.589 6.915 6.915 0 01.188-2.132c.45-1.484 1.309-2.648 2.577-3.493.282-.188.55-.334.802-.438.286-.12.573-.22.861-.304a.129.129 0 00.087-.087A6.016 6.016 0 015.635 2.31C6.315 1.464 7.132.846 8.086.457zm-.804 7.85a.848.848 0 00-1.473.842l1.694 2.965-1.688 2.848a.849.849 0 001.46.864l1.94-3.272a.849.849 0 00.007-.854l-1.94-3.393zm5.446 6.24a.849.849 0 000 1.695h4.848a.849.849 0 000-1.696h-4.848z" }]
|
|
734
|
+
]
|
|
735
|
+
},
|
|
736
|
+
gemini: {
|
|
737
|
+
viewBox: "0 0 24 24",
|
|
738
|
+
paths: [["path", { d: "M12 24C12 17.373 6.627 12 0 12 6.627 12 12 6.627 12 0c0 6.627 5.373 12 12 12-6.627 0-12 5.373-12 12z" }]]
|
|
739
|
+
},
|
|
740
|
+
grok: {
|
|
741
|
+
viewBox: "-1 -1 26 26",
|
|
742
|
+
paths: [["path", { d: "M9.27 15.29l7.978-5.897c.391-.29.95-.177 1.137.272.98 2.369.542 5.215-1.41 7.169-1.951 1.954-4.667 2.382-7.149 1.406l-2.711 1.257c3.889 2.661 8.611 2.003 11.562-.953 2.341-2.344 3.066-5.539 2.388-8.42l.006.007c-.983-4.232.242-5.924 2.75-9.383.06-.082.12-.164.179-.248l-3.301 3.305v-.01L9.267 15.292M7.623 16.723c-2.792-2.67-2.31-6.801.071-9.184 1.761-1.763 4.647-2.483 7.166-1.425l2.705-1.25a7.808 7.808 0 00-1.829-1A8.975 8.975 0 005.984 5.83c-2.533 2.536-3.33 6.436-1.962 9.764 1.022 2.487-.653 4.246-2.34 6.022-.599.63-1.199 1.259-1.682 1.925l7.62-6.815" }]]
|
|
743
|
+
},
|
|
744
|
+
opencode: { viewBox: "2.5 0 19 24", paths: [["path", { d: "M16 6H8v12h8V6zm4 16H4V2h16v20z" }]] },
|
|
745
|
+
pi: {
|
|
746
|
+
viewBox: "0 0 24 24",
|
|
747
|
+
paths: [
|
|
748
|
+
["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M1 1h16.5v11H12v5.5H6.5V23H1V1zm5.5 5.5V12H12V6.5H6.5z" }],
|
|
749
|
+
["path", { d: "M17.5 12H23v11h-5.5V12z" }]
|
|
750
|
+
]
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
754
|
+
const logo = LOGOS[id];
|
|
755
|
+
useEffect3(() => {
|
|
756
|
+
if (!logo) onMissingLogo?.(id);
|
|
757
|
+
}, [id, logo, onMissingLogo]);
|
|
758
|
+
if (!logo) return null;
|
|
759
|
+
return /* @__PURE__ */ jsxs3("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
|
|
760
|
+
/* @__PURE__ */ jsx4("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx4(Tag, { ...props }, index)) }),
|
|
761
|
+
activity && activity !== "idle" ? /* @__PURE__ */ jsx4("i", {}) : null
|
|
762
|
+
] });
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// src/sessions.jsx
|
|
766
|
+
import { useState as useState3 } from "preact/hooks";
|
|
767
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
620
768
|
function SessionRow({ row, state, onOpen }) {
|
|
621
769
|
const activity = sessionActivity(state, row);
|
|
622
770
|
const preview = state.attention.find((item) => item.key === row.key)?.preview;
|
|
623
|
-
return /* @__PURE__ */
|
|
624
|
-
/* @__PURE__ */
|
|
625
|
-
/* @__PURE__ */
|
|
626
|
-
/* @__PURE__ */
|
|
627
|
-
/* @__PURE__ */
|
|
628
|
-
/* @__PURE__ */
|
|
771
|
+
return /* @__PURE__ */ jsxs4("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, type: "button", onClick: () => onOpen(row), children: [
|
|
772
|
+
/* @__PURE__ */ jsx5(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
773
|
+
/* @__PURE__ */ jsxs4("span", { class: "scui-session-copy", children: [
|
|
774
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
775
|
+
/* @__PURE__ */ jsx5("strong", { children: sessionDisplayName(row) }),
|
|
776
|
+
/* @__PURE__ */ jsx5("small", { children: row.age })
|
|
629
777
|
] }),
|
|
630
|
-
/* @__PURE__ */
|
|
631
|
-
/* @__PURE__ */
|
|
632
|
-
/* @__PURE__ */
|
|
778
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
779
|
+
/* @__PURE__ */ jsx5("b", { children: harnessDisplayName(row.harness) }),
|
|
780
|
+
/* @__PURE__ */ jsx5("small", { children: preview || row.cwd || row.name })
|
|
633
781
|
] }),
|
|
634
|
-
state.attachError?.key === row.key ? /* @__PURE__ */
|
|
782
|
+
state.attachError?.key === row.key ? /* @__PURE__ */ jsx5("em", { children: state.attachError.message }) : null
|
|
635
783
|
] })
|
|
636
784
|
] });
|
|
637
785
|
}
|
|
638
786
|
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS }) {
|
|
639
|
-
const [query, setQuery] =
|
|
787
|
+
const [query, setQuery] = useState3("");
|
|
640
788
|
const rows = filterSessions(state.sessions, query);
|
|
641
789
|
const Row = components.SessionRow ?? SessionRow;
|
|
642
|
-
return /* @__PURE__ */
|
|
643
|
-
/* @__PURE__ */
|
|
644
|
-
/* @__PURE__ */
|
|
645
|
-
/* @__PURE__ */
|
|
646
|
-
/* @__PURE__ */
|
|
790
|
+
return /* @__PURE__ */ jsxs4("section", { class: "scui-list", children: [
|
|
791
|
+
/* @__PURE__ */ jsxs4("header", { class: "scui-head", children: [
|
|
792
|
+
/* @__PURE__ */ jsxs4("span", { class: "scui-head-copy", children: [
|
|
793
|
+
/* @__PURE__ */ jsx5("strong", { children: labels.chats }),
|
|
794
|
+
/* @__PURE__ */ jsxs4("small", { children: [
|
|
647
795
|
state.sessions.length,
|
|
648
796
|
" recent conversations"
|
|
649
797
|
] })
|
|
650
798
|
] }),
|
|
651
|
-
/* @__PURE__ */
|
|
652
|
-
onClose ? /* @__PURE__ */
|
|
799
|
+
/* @__PURE__ */ jsx5("button", { type: "button", "aria-label": labels.newChat, disabled: !state.harnesses.some((item) => item.startable), onClick: onNew, children: "\uFF0B" }),
|
|
800
|
+
onClose ? /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
|
|
653
801
|
] }),
|
|
654
|
-
state.startup !== "ready" ? /* @__PURE__ */
|
|
655
|
-
state.sessions.length > 4 ? /* @__PURE__ */
|
|
656
|
-
/* @__PURE__ */
|
|
657
|
-
/* @__PURE__ */
|
|
658
|
-
/* @__PURE__ */
|
|
802
|
+
state.startup !== "ready" ? /* @__PURE__ */ jsx5(LoadingStatus, { state, compact: rows.length > 0 }) : null,
|
|
803
|
+
state.sessions.length > 4 ? /* @__PURE__ */ jsxs4("label", { class: "scui-search", children: [
|
|
804
|
+
/* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: "\u2315" }),
|
|
805
|
+
/* @__PURE__ */ jsx5("input", { type: "search", "aria-label": labels.searchChats, placeholder: labels.searchChats, value: query, onInput: (event) => setQuery(event.currentTarget.value) }),
|
|
806
|
+
/* @__PURE__ */ jsx5("small", { children: rows.length })
|
|
659
807
|
] }) : null,
|
|
660
|
-
/* @__PURE__ */
|
|
661
|
-
!rows.length && state.startup === "ready" ? /* @__PURE__ */
|
|
662
|
-
rows.map((row) => /* @__PURE__ */
|
|
663
|
-
state.history.hasMoreSessions ? /* @__PURE__ */
|
|
664
|
-
] })
|
|
665
|
-
] });
|
|
666
|
-
}
|
|
667
|
-
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
668
|
-
if (state.mode !== "mirror" || state.canSend) return null;
|
|
669
|
-
const attached = state.attached;
|
|
670
|
-
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
671
|
-
const activeElsewhere = row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
672
|
-
const resume = canContinueHere(state);
|
|
673
|
-
const join = state.canAttach;
|
|
674
|
-
const branch = state.canBranch;
|
|
675
|
-
if (!resume && !join && !branch) return /* @__PURE__ */ jsx("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs("span", { children: [
|
|
676
|
-
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
677
|
-
/* @__PURE__ */ jsx("small", { children: "This session cannot be continued by an available harness." })
|
|
678
|
-
] }) });
|
|
679
|
-
return /* @__PURE__ */ jsxs("div", { class: "scui-continuation", children: [
|
|
680
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
681
|
-
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
682
|
-
/* @__PURE__ */ jsx("small", { children: join ? "Join the proven live runtime without taking it over." : resume ? `Resume this ${harnessDisplayName(state.harness)} session here.` : "Start an independent continuation." })
|
|
683
|
-
] }),
|
|
684
|
-
/* @__PURE__ */ jsx("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 })
|
|
685
|
-
] });
|
|
686
|
-
}
|
|
687
|
-
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, onPending }) {
|
|
688
|
-
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
|
|
689
|
-
const [draft, setDraft] = useState(remembered.draft);
|
|
690
|
-
const [queue, setQueue] = useState(remembered.queue);
|
|
691
|
-
const textarea = useRef(null);
|
|
692
|
-
useEffect(() => {
|
|
693
|
-
if (!state.busy && state.canSend && queue.length) {
|
|
694
|
-
const [next, ...rest] = queue;
|
|
695
|
-
setQueue(rest);
|
|
696
|
-
composerMemory.set(memoryKey, { draft, queue: rest });
|
|
697
|
-
onPending?.(next);
|
|
698
|
-
adapter.onIntent({ action: "send", text: next });
|
|
699
|
-
}
|
|
700
|
-
}, [adapter, draft, memoryKey, onPending, queue, state.busy, state.canSend]);
|
|
701
|
-
useEffect(() => {
|
|
702
|
-
const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
|
|
703
|
-
return () => clearTimeout(timer);
|
|
704
|
-
}, [adapter, draft]);
|
|
705
|
-
const send = () => {
|
|
706
|
-
const text = draft.trim();
|
|
707
|
-
if (!text) return;
|
|
708
|
-
if (state.busy) setQueue((items) => {
|
|
709
|
-
const next = [...items, text];
|
|
710
|
-
composerMemory.set(memoryKey, { draft: "", queue: next });
|
|
711
|
-
return next;
|
|
712
|
-
});
|
|
713
|
-
else if (state.canSend) {
|
|
714
|
-
onPending?.(text);
|
|
715
|
-
adapter.onIntent({ action: "send", text });
|
|
716
|
-
} else return;
|
|
717
|
-
setDraft("");
|
|
718
|
-
composerMemory.set(memoryKey, { draft: "", queue: state.busy ? [...queue, text] : queue });
|
|
719
|
-
};
|
|
720
|
-
return /* @__PURE__ */ jsxs("div", { class: "scui-compose", children: [
|
|
721
|
-
queue.length ? /* @__PURE__ */ jsxs("div", { class: "scui-queue", children: [
|
|
722
|
-
/* @__PURE__ */ jsxs("strong", { children: [
|
|
723
|
-
queue.length,
|
|
724
|
-
" queued"
|
|
725
|
-
] }),
|
|
726
|
-
queue.map((item, index) => /* @__PURE__ */ jsxs("span", { children: [
|
|
727
|
-
item,
|
|
728
|
-
/* @__PURE__ */ jsx("button", { "aria-label": `Remove queued message ${index + 1}`, onClick: () => setQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: "\xD7" })
|
|
729
|
-
] }, `${index}:${item}`))
|
|
730
|
-
] }) : null,
|
|
731
|
-
/* @__PURE__ */ jsxs("div", { class: "scui-envelope", children: [
|
|
732
|
-
/* @__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) => {
|
|
733
|
-
const value = event.currentTarget.value;
|
|
734
|
-
setDraft(value);
|
|
735
|
-
composerMemory.set(memoryKey, { draft: value, queue });
|
|
736
|
-
}, onKeyDown: (event) => {
|
|
737
|
-
if (isSendKey(event)) {
|
|
738
|
-
event.preventDefault();
|
|
739
|
-
send();
|
|
740
|
-
}
|
|
741
|
-
} }),
|
|
742
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
743
|
-
state.busy ? /* @__PURE__ */ jsx("button", { class: "scui-stop", type: "button", "aria-label": "Stop agent", disabled: !state.canInterrupt, onClick: () => adapter.onIntent({ action: "interrupt" }), children: "\u25A0" }) : null,
|
|
744
|
-
/* @__PURE__ */ jsx("button", { class: "scui-send", type: "button", "aria-label": state.busy ? "Queue message" : "Send message", disabled: !draft.trim() || !state.busy && !state.canSend, onClick: send, children: state.busy ? "+" : "\u2191" })
|
|
745
|
-
] })
|
|
808
|
+
/* @__PURE__ */ jsxs4("div", { class: "scui-session-rows", children: [
|
|
809
|
+
!rows.length && state.startup === "ready" ? /* @__PURE__ */ jsx5("div", { class: "scui-empty", children: query ? "No chats match your search." : state.error ?? "No coding chats found." }) : null,
|
|
810
|
+
rows.map((row) => /* @__PURE__ */ jsx5(Row, { value: row, row, state, adapter, onOpen }, row.key)),
|
|
811
|
+
state.history.hasMoreSessions ? /* @__PURE__ */ jsx5("button", { class: "scui-load", type: "button", onClick: () => adapter.onIntent({ action: "loadSessions" }), children: "Load older chats" }) : null
|
|
746
812
|
] })
|
|
747
813
|
] });
|
|
748
814
|
}
|
|
815
|
+
|
|
816
|
+
// src/messenger.jsx
|
|
817
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
749
818
|
function Receipt({ state, adapter }) {
|
|
750
819
|
const receipt = state.reductionReceipt;
|
|
751
|
-
if (receipt) return /* @__PURE__ */
|
|
752
|
-
/* @__PURE__ */
|
|
753
|
-
/* @__PURE__ */
|
|
820
|
+
if (receipt) return /* @__PURE__ */ jsx6("div", { class: "scui-receipt", children: /* @__PURE__ */ jsxs5("span", { children: [
|
|
821
|
+
/* @__PURE__ */ jsx6("strong", { children: "Reduced and verified" }),
|
|
822
|
+
/* @__PURE__ */ jsxs5("small", { children: [
|
|
754
823
|
receipt.sourceTokens.toLocaleString(),
|
|
755
824
|
" \u2192 ",
|
|
756
825
|
receipt.reducedTokens.toLocaleString(),
|
|
@@ -759,27 +828,27 @@ function Receipt({ state, adapter }) {
|
|
|
759
828
|
"\xD7 \xB7 reversible"
|
|
760
829
|
] })
|
|
761
830
|
] }) });
|
|
762
|
-
if (state.exportReceipt) return /* @__PURE__ */
|
|
763
|
-
/* @__PURE__ */
|
|
764
|
-
/* @__PURE__ */
|
|
831
|
+
if (state.exportReceipt) return /* @__PURE__ */ jsxs5("div", { class: "scui-receipt", children: [
|
|
832
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
833
|
+
/* @__PURE__ */ jsxs5("strong", { children: [
|
|
765
834
|
"Lossless export ready \xB7 ",
|
|
766
835
|
harnessDisplayName(state.exportReceipt.targetHarness)
|
|
767
836
|
] }),
|
|
768
|
-
/* @__PURE__ */
|
|
837
|
+
/* @__PURE__ */ jsxs5("small", { children: [
|
|
769
838
|
state.exportReceipt.path,
|
|
770
839
|
" \xB7 ",
|
|
771
840
|
state.exportReceipt.files,
|
|
772
841
|
" files"
|
|
773
842
|
] })
|
|
774
843
|
] }),
|
|
775
|
-
/* @__PURE__ */
|
|
844
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.copyText?.(state.exportReceipt.path), children: "Copy path" })
|
|
776
845
|
] });
|
|
777
|
-
if (state.terminalHandoff) return /* @__PURE__ */
|
|
778
|
-
/* @__PURE__ */
|
|
779
|
-
/* @__PURE__ */
|
|
780
|
-
/* @__PURE__ */
|
|
846
|
+
if (state.terminalHandoff) return /* @__PURE__ */ jsxs5("div", { class: "scui-receipt", children: [
|
|
847
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
848
|
+
/* @__PURE__ */ jsx6("strong", { children: "Terminal handoff ready" }),
|
|
849
|
+
/* @__PURE__ */ jsx6("small", { children: state.terminalHandoff.cwd })
|
|
781
850
|
] }),
|
|
782
|
-
/* @__PURE__ */
|
|
851
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.copyText?.(terminalCommand(state.terminalHandoff)), children: "Copy command" })
|
|
783
852
|
] });
|
|
784
853
|
return null;
|
|
785
854
|
}
|
|
@@ -789,46 +858,46 @@ function ChatHeader({ state, adapter, onBack, onNew, onClose }) {
|
|
|
789
858
|
const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
|
|
790
859
|
const status = state.needsInput ? "Needs input" : state.busy ? "Working" : state.mode === "mirror" ? "Read-only" : "Ready";
|
|
791
860
|
const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce;
|
|
792
|
-
return /* @__PURE__ */
|
|
793
|
-
/* @__PURE__ */
|
|
794
|
-
/* @__PURE__ */
|
|
795
|
-
/* @__PURE__ */
|
|
796
|
-
/* @__PURE__ */
|
|
797
|
-
/* @__PURE__ */
|
|
861
|
+
return /* @__PURE__ */ jsxs5("header", { class: "scui-head scui-chat-head", children: [
|
|
862
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Back to chats", onClick: onBack, children: "\u2039" }),
|
|
863
|
+
/* @__PURE__ */ jsx6(HarnessLogo, { id: harness, size: 28 }),
|
|
864
|
+
/* @__PURE__ */ jsxs5("span", { class: "scui-head-copy", children: [
|
|
865
|
+
/* @__PURE__ */ jsx6("strong", { children: title }),
|
|
866
|
+
/* @__PURE__ */ jsxs5("small", { children: [
|
|
798
867
|
harnessDisplayName(harness),
|
|
799
868
|
" \xB7 ",
|
|
800
869
|
status
|
|
801
870
|
] })
|
|
802
871
|
] }),
|
|
803
|
-
menu ? /* @__PURE__ */
|
|
804
|
-
/* @__PURE__ */
|
|
805
|
-
/* @__PURE__ */
|
|
806
|
-
state.canDetach ? /* @__PURE__ */
|
|
807
|
-
state.canOpenTerminal ? /* @__PURE__ */
|
|
808
|
-
state.canReduce ? targets.map((target) => /* @__PURE__ */
|
|
809
|
-
state.canBranch ? targets.map((target) => /* @__PURE__ */
|
|
810
|
-
state.canExport && state.exportBackTarget ? /* @__PURE__ */
|
|
872
|
+
menu ? /* @__PURE__ */ jsxs5("details", { class: "scui-menu", children: [
|
|
873
|
+
/* @__PURE__ */ jsx6("summary", { "aria-label": "Conversation actions", children: "\u2022\u2022\u2022" }),
|
|
874
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
875
|
+
state.canDetach ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "detach" }), children: "Detach to read-only" }) : null,
|
|
876
|
+
state.canOpenTerminal ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "terminal" }), children: "Prepare terminal handoff" }) : null,
|
|
877
|
+
state.canReduce ? targets.map((target) => /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "reduce", targetHarness: target.id }), children: target.id === state.harness ? `Reduce and continue in ${target.label}` : `Reduce and switch to ${target.label}` }, `reduce:${target.id}`)) : null,
|
|
878
|
+
state.canBranch ? targets.map((target) => /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "branch", targetHarness: target.id }), children: target.id === state.harness ? `Fork in ${target.label}` : `Continue with ${target.label}` }, `branch:${target.id}`)) : null,
|
|
879
|
+
state.canExport && state.exportBackTarget ? /* @__PURE__ */ jsxs5("button", { type: "button", onClick: () => adapter.onIntent({ action: "export", targetHarness: state.exportBackTarget }), children: [
|
|
811
880
|
"Export back to ",
|
|
812
881
|
harnessDisplayName(state.exportBackTarget)
|
|
813
882
|
] }) : null
|
|
814
883
|
] })
|
|
815
884
|
] }) : null,
|
|
816
|
-
/* @__PURE__ */
|
|
817
|
-
onClose ? /* @__PURE__ */
|
|
885
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: "\uFF0B" }),
|
|
886
|
+
onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
|
|
818
887
|
] });
|
|
819
888
|
}
|
|
820
889
|
function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
|
|
821
890
|
const Header = slots.header;
|
|
822
891
|
const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
|
|
823
|
-
const [pending, setPending] =
|
|
824
|
-
const acknowledged =
|
|
825
|
-
|
|
892
|
+
const [pending, setPending] = useState4(null);
|
|
893
|
+
const acknowledged = useRef3(/* @__PURE__ */ new Set());
|
|
894
|
+
useEffect4(() => {
|
|
826
895
|
setPending(null);
|
|
827
896
|
}, [memoryKey]);
|
|
828
|
-
|
|
897
|
+
useEffect4(() => {
|
|
829
898
|
if (pending && state.transcript.some((entry) => entry.role === "user" && entry.text.trim() === pending.trim())) setPending(null);
|
|
830
899
|
}, [pending, state.transcript]);
|
|
831
|
-
|
|
900
|
+
useEffect4(() => {
|
|
832
901
|
const key = state.attached?.key;
|
|
833
902
|
if (!key || !state.attention.some((item) => item.key === key)) {
|
|
834
903
|
if (key) acknowledged.current.delete(key);
|
|
@@ -839,31 +908,31 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
839
908
|
adapter.onIntent({ action: "ack", key });
|
|
840
909
|
}
|
|
841
910
|
}, [adapter, state.attached?.key, state.attention]);
|
|
842
|
-
return /* @__PURE__ */
|
|
843
|
-
Header ? /* @__PURE__ */
|
|
844
|
-
operationLabel(state.operation) ? /* @__PURE__ */
|
|
845
|
-
/* @__PURE__ */
|
|
911
|
+
return /* @__PURE__ */ jsxs5("section", { class: "scui-chat", children: [
|
|
912
|
+
Header ? /* @__PURE__ */ jsx6(Header, { state, adapter, value: null }) : /* @__PURE__ */ jsx6(ChatHeader, { state, adapter, onBack, onNew, onClose }),
|
|
913
|
+
operationLabel(state.operation) ? /* @__PURE__ */ jsxs5("div", { class: "scui-operation", role: "status", children: [
|
|
914
|
+
/* @__PURE__ */ jsx6("i", {}),
|
|
846
915
|
operationLabel(state.operation)
|
|
847
916
|
] }) : null,
|
|
848
|
-
state.error ? /* @__PURE__ */
|
|
849
|
-
/* @__PURE__ */
|
|
850
|
-
state.recoverable ? /* @__PURE__ */
|
|
917
|
+
state.error ? /* @__PURE__ */ jsxs5("div", { class: "scui-error", role: "alert", children: [
|
|
918
|
+
/* @__PURE__ */ jsx6("span", { children: state.error }),
|
|
919
|
+
state.recoverable ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "refresh" }), children: "Retry" }) : null
|
|
851
920
|
] }) : null,
|
|
852
|
-
/* @__PURE__ */
|
|
853
|
-
/* @__PURE__ */
|
|
854
|
-
/* @__PURE__ */
|
|
855
|
-
state.mode !== "mirror" || state.canSend ? /* @__PURE__ */
|
|
921
|
+
/* @__PURE__ */ jsx6(Receipt, { state, adapter }),
|
|
922
|
+
/* @__PURE__ */ jsx6(Conversation, { state, adapter, components, slots, memoryKey, pending }, memoryKey),
|
|
923
|
+
/* @__PURE__ */ jsx6(ContinuationBar, { state, adapter, labels }),
|
|
924
|
+
state.mode !== "mirror" || state.canSend ? /* @__PURE__ */ jsx6(Composer, { state, adapter, labels, memoryKey, onPending: setPending }, memoryKey) : null
|
|
856
925
|
] });
|
|
857
926
|
}
|
|
858
927
|
function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
|
|
859
928
|
const startable = state.harnesses.filter((item) => item.startable);
|
|
860
|
-
const [harness, setHarness] =
|
|
861
|
-
const [draft, setDraft] =
|
|
862
|
-
const [starting, setStarting] =
|
|
863
|
-
|
|
929
|
+
const [harness, setHarness] = useState4(startable[0]?.id ?? "");
|
|
930
|
+
const [draft, setDraft] = useState4("");
|
|
931
|
+
const [starting, setStarting] = useState4(false);
|
|
932
|
+
useEffect4(() => {
|
|
864
933
|
if (starting && (state.busy || state.transcript.length)) onStarted();
|
|
865
934
|
}, [onStarted, starting, state.busy, state.transcript.length]);
|
|
866
|
-
|
|
935
|
+
useEffect4(() => {
|
|
867
936
|
if (starting && state.error && !state.busy && !state.operation) setStarting(false);
|
|
868
937
|
}, [starting, state.busy, state.error, state.operation]);
|
|
869
938
|
const send = () => {
|
|
@@ -872,37 +941,37 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
|
|
|
872
941
|
setStarting(true);
|
|
873
942
|
adapter.onIntent({ action: "new", harness, text });
|
|
874
943
|
};
|
|
875
|
-
return /* @__PURE__ */
|
|
876
|
-
/* @__PURE__ */
|
|
877
|
-
/* @__PURE__ */
|
|
878
|
-
/* @__PURE__ */
|
|
879
|
-
/* @__PURE__ */
|
|
880
|
-
/* @__PURE__ */
|
|
944
|
+
return /* @__PURE__ */ jsxs5("section", { class: "scui-chat", children: [
|
|
945
|
+
/* @__PURE__ */ jsxs5("header", { class: "scui-head", children: [
|
|
946
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Back", onClick: onBack, children: "\u2039" }),
|
|
947
|
+
/* @__PURE__ */ jsxs5("span", { class: "scui-head-copy", children: [
|
|
948
|
+
/* @__PURE__ */ jsx6("strong", { children: labels.newChat }),
|
|
949
|
+
/* @__PURE__ */ jsx6("small", { children: "No session is created until you send" })
|
|
881
950
|
] }),
|
|
882
|
-
onClose ? /* @__PURE__ */
|
|
951
|
+
onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
|
|
883
952
|
] }),
|
|
884
|
-
/* @__PURE__ */
|
|
885
|
-
/* @__PURE__ */
|
|
886
|
-
/* @__PURE__ */
|
|
887
|
-
/* @__PURE__ */
|
|
953
|
+
/* @__PURE__ */ jsxs5("div", { class: "scui-new", children: [
|
|
954
|
+
/* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
955
|
+
/* @__PURE__ */ jsx6("strong", { children: "What should the agent build or fix?" }),
|
|
956
|
+
/* @__PURE__ */ jsx6("small", { children: "Choose a coding harness and send the first message." })
|
|
888
957
|
] }),
|
|
889
|
-
/* @__PURE__ */
|
|
890
|
-
/* @__PURE__ */
|
|
891
|
-
/* @__PURE__ */
|
|
892
|
-
/* @__PURE__ */
|
|
893
|
-
/* @__PURE__ */
|
|
958
|
+
/* @__PURE__ */ jsxs5("div", { class: "scui-compose", children: [
|
|
959
|
+
/* @__PURE__ */ jsxs5("label", { class: "scui-harness-picker", children: [
|
|
960
|
+
/* @__PURE__ */ jsx6(HarnessLogo, { id: harness, size: 24 }),
|
|
961
|
+
/* @__PURE__ */ jsx6("span", { children: "Coding harness" }),
|
|
962
|
+
/* @__PURE__ */ jsx6("select", { value: harness, disabled: starting, onChange: (event) => setHarness(event.currentTarget.value), children: state.harnesses.map((item) => /* @__PURE__ */ jsxs5("option", { value: item.id, disabled: !item.startable, children: [
|
|
894
963
|
item.label,
|
|
895
964
|
item.startable ? "" : " \xB7 unavailable"
|
|
896
965
|
] }, item.id)) })
|
|
897
966
|
] }),
|
|
898
|
-
/* @__PURE__ */
|
|
899
|
-
/* @__PURE__ */
|
|
967
|
+
/* @__PURE__ */ jsxs5("div", { class: "scui-envelope", children: [
|
|
968
|
+
/* @__PURE__ */ jsx6("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 || starting, onInput: (event) => setDraft(event.currentTarget.value), onKeyDown: (event) => {
|
|
900
969
|
if (isSendKey(event)) {
|
|
901
970
|
event.preventDefault();
|
|
902
971
|
send();
|
|
903
972
|
}
|
|
904
973
|
} }),
|
|
905
|
-
/* @__PURE__ */
|
|
974
|
+
/* @__PURE__ */ jsx6("span", { children: /* @__PURE__ */ jsx6("button", { type: "button", class: "scui-send", "aria-label": "Start chat", disabled: !draft.trim() || !harness || starting, onClick: send, children: starting ? "\u25CC" : "\u2191" }) })
|
|
906
975
|
] })
|
|
907
976
|
] })
|
|
908
977
|
] });
|
|
@@ -910,48 +979,49 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
|
|
|
910
979
|
function SupercodeMessenger({ state: stateInput, adapter, class: className = "", initialView, labels, components = {}, slots = {} }) {
|
|
911
980
|
const state = normalizeUiState(stateInput);
|
|
912
981
|
const copy = { ...DEFAULT_LABELS, ...labels };
|
|
913
|
-
const [view, setView] =
|
|
914
|
-
const [opening, setOpening] =
|
|
915
|
-
|
|
982
|
+
const [view, setView] = useState4(initialView ?? (state.attention.length ? "list" : state.attached || state.transcript.length ? "chat" : "list"));
|
|
983
|
+
const [opening, setOpening] = useState4(null);
|
|
984
|
+
useEffect4(() => {
|
|
916
985
|
if (!opening) return;
|
|
917
986
|
if (state.attached?.key === opening.key) {
|
|
918
987
|
setOpening(null);
|
|
919
988
|
setView("chat");
|
|
920
|
-
} else if (state.attachError?.key === opening.key) {
|
|
989
|
+
} else if (state.attachError?.key === opening.key || state.error && !state.operation) {
|
|
921
990
|
setOpening(null);
|
|
922
991
|
}
|
|
923
|
-
}, [opening, state.attachError?.key, state.attached?.key]);
|
|
992
|
+
}, [opening, state.attachError?.key, state.attached?.key, state.error, state.operation]);
|
|
924
993
|
const open = (row) => {
|
|
925
994
|
setOpening(row);
|
|
926
995
|
adapter.onIntent({ action: "ack", key: row.key });
|
|
927
996
|
adapter.onIntent({ action: "attach", key: row.key });
|
|
928
997
|
};
|
|
929
998
|
const close = () => adapter.onClose?.();
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
view === "
|
|
933
|
-
view === "
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
/* @__PURE__ */
|
|
937
|
-
|
|
999
|
+
const Footer = slots.footer;
|
|
1000
|
+
return /* @__PURE__ */ jsxs5("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
|
|
1001
|
+
view === "list" ? /* @__PURE__ */ jsx6(SessionList, { state, adapter, onOpen: open, onNew: () => setView("new"), onClose: adapter.onClose ? close : void 0, components, labels: copy }) : null,
|
|
1002
|
+
view === "new" ? /* @__PURE__ */ jsx6(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: () => setView("chat"), labels: copy }) : null,
|
|
1003
|
+
view === "chat" ? /* @__PURE__ */ jsx6(Chat, { state, adapter, onBack: () => setView("list"), onNew: () => setView("new"), onClose: adapter.onClose ? close : void 0, components, slots, labels: copy }) : null,
|
|
1004
|
+
opening ? /* @__PURE__ */ jsxs5("div", { class: "scui-opening", role: "status", "aria-busy": "true", children: [
|
|
1005
|
+
/* @__PURE__ */ jsx6(HarnessLogo, { id: opening.harness, size: 34 }),
|
|
1006
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
1007
|
+
/* @__PURE__ */ jsxs5("strong", { children: [
|
|
938
1008
|
"Opening ",
|
|
939
1009
|
sessionDisplayName(opening)
|
|
940
1010
|
] }),
|
|
941
|
-
/* @__PURE__ */
|
|
1011
|
+
/* @__PURE__ */ jsx6("small", { children: "Loading the latest transcript window\u2026" })
|
|
942
1012
|
] }),
|
|
943
|
-
/* @__PURE__ */
|
|
1013
|
+
/* @__PURE__ */ jsx6("i", {})
|
|
944
1014
|
] }) : null,
|
|
945
|
-
|
|
1015
|
+
Footer ? /* @__PURE__ */ jsx6(Footer, { state, adapter, value: copy }) : null
|
|
946
1016
|
] });
|
|
947
1017
|
}
|
|
948
1018
|
|
|
949
1019
|
// src/embed.jsx
|
|
950
|
-
import { jsx as
|
|
1020
|
+
import { jsx as jsx7 } from "preact/jsx-runtime";
|
|
951
1021
|
function mountSupercodeMessenger(element, options) {
|
|
952
1022
|
if (!(element instanceof Element)) throw new TypeError("mountSupercodeMessenger requires an Element");
|
|
953
1023
|
let state = options.state;
|
|
954
|
-
const draw = () => render(/* @__PURE__ */
|
|
1024
|
+
const draw = () => render(/* @__PURE__ */ jsx7(SupercodeMessenger, { ...options, state }), element);
|
|
955
1025
|
options.adapter.onIntent({ action: "mounted" });
|
|
956
1026
|
draw();
|
|
957
1027
|
return {
|