@volter-ai-dev/supercode-ui 0.1.0 → 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 +10 -7
- package/components.d.ts +17 -0
- package/components.mjs +416 -346
- package/composer.d.ts +2 -0
- package/composer.mjs +23 -20
- package/controller.mjs +3 -2
- 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/index.d.ts +1 -1
- 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/messenger.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import
|
|
3
|
-
import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
|
1
|
+
// src/messenger.jsx
|
|
2
|
+
import { useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "preact/hooks";
|
|
4
3
|
|
|
5
4
|
// core.mjs
|
|
6
5
|
var HARNESS_NAMES = Object.freeze({
|
|
7
6
|
"claude-code": "Claude Code",
|
|
8
7
|
codex: "Codex",
|
|
8
|
+
gemini: "Gemini CLI",
|
|
9
9
|
opencode: "OpenCode",
|
|
10
10
|
pi: "Pi",
|
|
11
11
|
grok: "Grok"
|
|
@@ -60,7 +60,7 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
60
60
|
});
|
|
61
61
|
var ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool", "reasoning", "request", "notice"]);
|
|
62
62
|
var MODES = /* @__PURE__ */ new Set(["none", "control", "mirror"]);
|
|
63
|
-
var STRATEGIES = /* @__PURE__ */ new Set(["start", "resume", "attach", "branch"]);
|
|
63
|
+
var STRATEGIES = /* @__PURE__ */ new Set(["start", "resume", "attach", "branch", "reduce"]);
|
|
64
64
|
var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering", "ready"]);
|
|
65
65
|
var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
|
|
66
66
|
function record(value) {
|
|
@@ -184,6 +184,35 @@ function readSemantics(value) {
|
|
|
184
184
|
}) : []
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
|
+
function readTerminalHandoff(value) {
|
|
188
|
+
const handoff = record(value);
|
|
189
|
+
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;
|
|
190
|
+
return { program: handoff.program, arguments: [...handoff.arguments], cwd: handoff.cwd };
|
|
191
|
+
}
|
|
192
|
+
function readExportReceipt(value) {
|
|
193
|
+
const receipt = record(value);
|
|
194
|
+
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;
|
|
195
|
+
return {
|
|
196
|
+
targetHarness: receipt.targetHarness,
|
|
197
|
+
fidelity: receipt.fidelity,
|
|
198
|
+
path: receipt.path,
|
|
199
|
+
files: receipt.files,
|
|
200
|
+
residueCount: receipt.residueCount
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function readReductionReceipt(value) {
|
|
204
|
+
const receipt = record(value);
|
|
205
|
+
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;
|
|
206
|
+
return {
|
|
207
|
+
sourceTokens: receipt.sourceTokens,
|
|
208
|
+
reducedTokens: receipt.reducedTokens,
|
|
209
|
+
ratio: receipt.ratio,
|
|
210
|
+
sidecarId: receipt.sidecarId,
|
|
211
|
+
verified: true,
|
|
212
|
+
reversible: true,
|
|
213
|
+
targetHarness: receipt.targetHarness
|
|
214
|
+
};
|
|
215
|
+
}
|
|
187
216
|
function normalizeUiState(value) {
|
|
188
217
|
const raw = record(value) ?? {};
|
|
189
218
|
const pill = record(raw.pill);
|
|
@@ -213,10 +242,10 @@ function normalizeUiState(value) {
|
|
|
213
242
|
workspace: string(raw.workspace),
|
|
214
243
|
taskPlan: readTaskPlan(raw.taskPlan),
|
|
215
244
|
semantics: readSemantics(raw.semantics),
|
|
216
|
-
terminalHandoff:
|
|
245
|
+
terminalHandoff: readTerminalHandoff(raw.terminalHandoff),
|
|
217
246
|
exportBackTarget: typeof raw.exportBackTarget === "string" ? raw.exportBackTarget : null,
|
|
218
|
-
exportReceipt:
|
|
219
|
-
reductionReceipt:
|
|
247
|
+
exportReceipt: readExportReceipt(raw.exportReceipt),
|
|
248
|
+
reductionReceipt: readReductionReceipt(raw.reductionReceipt),
|
|
220
249
|
error: typeof raw.error === "string" ? raw.error : null,
|
|
221
250
|
recoverable: raw.recoverable === true,
|
|
222
251
|
harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
|
|
@@ -321,8 +350,112 @@ function isSendKey(event) {
|
|
|
321
350
|
return event.key === "Enter" && !event.shiftKey && !event.isComposing;
|
|
322
351
|
}
|
|
323
352
|
|
|
324
|
-
// src/
|
|
353
|
+
// src/composer.jsx
|
|
354
|
+
import { useEffect, useRef, useState } from "preact/hooks";
|
|
355
|
+
|
|
356
|
+
// src/memory.js
|
|
357
|
+
var MEMORY_LIMIT = 100;
|
|
358
|
+
function boundedSet(map, key, value) {
|
|
359
|
+
map.delete(key);
|
|
360
|
+
map.set(key, value);
|
|
361
|
+
while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/composer.jsx
|
|
325
365
|
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
366
|
+
var composerMemory = /* @__PURE__ */ new Map();
|
|
367
|
+
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
368
|
+
if (state.mode !== "mirror" || state.canSend) return null;
|
|
369
|
+
const attached = state.attached;
|
|
370
|
+
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
371
|
+
const activeElsewhere = row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
372
|
+
const resume = canContinueHere(state);
|
|
373
|
+
const join = state.canAttach;
|
|
374
|
+
const branch = state.canBranch;
|
|
375
|
+
if (!resume && !join && !branch) return /* @__PURE__ */ jsx("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs("span", { children: [
|
|
376
|
+
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
377
|
+
/* @__PURE__ */ jsx("small", { children: "This session cannot be continued by an available harness." })
|
|
378
|
+
] }) });
|
|
379
|
+
return /* @__PURE__ */ jsxs("div", { class: "scui-continuation", children: [
|
|
380
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
381
|
+
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
382
|
+
/* @__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." })
|
|
383
|
+
] }),
|
|
384
|
+
/* @__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 })
|
|
385
|
+
] });
|
|
386
|
+
}
|
|
387
|
+
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, onPending }) {
|
|
388
|
+
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
|
|
389
|
+
const [draft, setDraft] = useState(remembered.draft);
|
|
390
|
+
const [queue, setQueue] = useState(remembered.queue);
|
|
391
|
+
const textarea = useRef(null);
|
|
392
|
+
const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
|
|
393
|
+
const updateQueue = (update) => setQueue((items) => {
|
|
394
|
+
const next = update(items);
|
|
395
|
+
remember(draft, next);
|
|
396
|
+
return next;
|
|
397
|
+
});
|
|
398
|
+
useEffect(() => {
|
|
399
|
+
if (!state.busy && state.canSend && queue.length) {
|
|
400
|
+
const [next, ...rest] = queue;
|
|
401
|
+
setQueue(rest);
|
|
402
|
+
remember(draft, rest);
|
|
403
|
+
onPending?.(next);
|
|
404
|
+
adapter.onIntent({ action: "send", text: next });
|
|
405
|
+
}
|
|
406
|
+
}, [adapter, draft, memoryKey, onPending, queue, state.busy, state.canSend]);
|
|
407
|
+
useEffect(() => {
|
|
408
|
+
const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
|
|
409
|
+
return () => clearTimeout(timer);
|
|
410
|
+
}, [adapter, draft]);
|
|
411
|
+
const send = () => {
|
|
412
|
+
const text = draft.trim();
|
|
413
|
+
if (!text) return;
|
|
414
|
+
if (state.busy) updateQueue((items) => [...items, text]);
|
|
415
|
+
else if (state.canSend) {
|
|
416
|
+
onPending?.(text);
|
|
417
|
+
adapter.onIntent({ action: "send", text });
|
|
418
|
+
} else return;
|
|
419
|
+
setDraft("");
|
|
420
|
+
remember("", state.busy ? [...queue, text] : queue);
|
|
421
|
+
};
|
|
422
|
+
return /* @__PURE__ */ jsxs("div", { class: "scui-compose", children: [
|
|
423
|
+
queue.length ? /* @__PURE__ */ jsxs("div", { class: "scui-queue", children: [
|
|
424
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
425
|
+
queue.length,
|
|
426
|
+
" queued"
|
|
427
|
+
] }),
|
|
428
|
+
queue.map((item, index) => /* @__PURE__ */ jsxs("span", { children: [
|
|
429
|
+
item,
|
|
430
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: "\xD7" })
|
|
431
|
+
] }, `${index}:${item}`))
|
|
432
|
+
] }) : null,
|
|
433
|
+
/* @__PURE__ */ jsxs("div", { class: "scui-envelope", children: [
|
|
434
|
+
/* @__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) => {
|
|
435
|
+
const value = event.currentTarget.value;
|
|
436
|
+
setDraft(value);
|
|
437
|
+
remember(value, queue);
|
|
438
|
+
}, onKeyDown: (event) => {
|
|
439
|
+
if (isSendKey(event)) {
|
|
440
|
+
event.preventDefault();
|
|
441
|
+
send();
|
|
442
|
+
}
|
|
443
|
+
} }),
|
|
444
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
445
|
+
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,
|
|
446
|
+
/* @__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" })
|
|
447
|
+
] })
|
|
448
|
+
] })
|
|
449
|
+
] });
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/conversation.jsx
|
|
453
|
+
import { useEffect as useEffect2, useId, useLayoutEffect, useRef as useRef2, useState as useState2 } from "preact/hooks";
|
|
454
|
+
|
|
455
|
+
// src/markdown.jsx
|
|
456
|
+
import MarkdownIt from "markdown-it";
|
|
457
|
+
import { useMemo } from "preact/hooks";
|
|
458
|
+
import { jsx as jsx2 } from "preact/jsx-runtime";
|
|
326
459
|
var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
|
|
327
460
|
var defaultLinkOpen = markdown.renderer.rules.link_open;
|
|
328
461
|
markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
|
|
@@ -330,47 +463,13 @@ markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
|
|
|
330
463
|
tokens[index]?.attrSet("rel", "noreferrer noopener");
|
|
331
464
|
return defaultLinkOpen ? defaultLinkOpen(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
|
|
332
465
|
};
|
|
333
|
-
var LOGOS = {
|
|
334
|
-
"claude-code": {
|
|
335
|
-
viewBox: "-1 3.5 26 18",
|
|
336
|
-
paths: [
|
|
337
|
-
["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" }]
|
|
338
|
-
]
|
|
339
|
-
},
|
|
340
|
-
codex: {
|
|
341
|
-
viewBox: "-1 -1 26 26",
|
|
342
|
-
paths: [
|
|
343
|
-
["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" }]
|
|
344
|
-
]
|
|
345
|
-
},
|
|
346
|
-
grok: {
|
|
347
|
-
viewBox: "-1 -1 26 26",
|
|
348
|
-
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" }]]
|
|
349
|
-
},
|
|
350
|
-
opencode: { viewBox: "2.5 0 19 24", paths: [["path", { d: "M16 6H8v12h8V6zm4 16H4V2h16v20z" }]] },
|
|
351
|
-
pi: {
|
|
352
|
-
viewBox: "0 0 24 24",
|
|
353
|
-
paths: [
|
|
354
|
-
["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M1 1h16.5v11H12v5.5H6.5V23H1V1zm5.5 5.5V12H12V6.5H6.5z" }],
|
|
355
|
-
["path", { d: "M17.5 12H23v11h-5.5V12z" }]
|
|
356
|
-
]
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
466
|
function Markdown({ value }) {
|
|
360
467
|
const html = useMemo(() => markdown.render(value), [value]);
|
|
361
|
-
return /* @__PURE__ */
|
|
362
|
-
}
|
|
363
|
-
function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
364
|
-
const logo = LOGOS[id];
|
|
365
|
-
useEffect(() => {
|
|
366
|
-
if (!logo) onMissingLogo?.(id);
|
|
367
|
-
}, [id, logo, onMissingLogo]);
|
|
368
|
-
if (!logo) return null;
|
|
369
|
-
return /* @__PURE__ */ jsxs("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
|
|
370
|
-
/* @__PURE__ */ jsx("svg", { viewBox: logo.viewBox, focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx(Tag, { ...props }, index)) }),
|
|
371
|
-
activity && activity !== "idle" ? /* @__PURE__ */ jsx("i", {}) : null
|
|
372
|
-
] });
|
|
468
|
+
return /* @__PURE__ */ jsx2("div", { class: "scui-markdown", dangerouslySetInnerHTML: { __html: html } });
|
|
373
469
|
}
|
|
470
|
+
|
|
471
|
+
// src/conversation.jsx
|
|
472
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
374
473
|
function LoadingStatus({ state, compact = false }) {
|
|
375
474
|
const copy = {
|
|
376
475
|
connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
|
|
@@ -378,83 +477,83 @@ function LoadingStatus({ state, compact = false }) {
|
|
|
378
477
|
discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
|
|
379
478
|
ready: ["Ready", "Coding sessions are up to date.", 3]
|
|
380
479
|
}[state.startup];
|
|
381
|
-
return /* @__PURE__ */
|
|
382
|
-
/* @__PURE__ */
|
|
383
|
-
/* @__PURE__ */
|
|
384
|
-
/* @__PURE__ */
|
|
385
|
-
/* @__PURE__ */
|
|
480
|
+
return /* @__PURE__ */ jsxs2("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
|
|
481
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("i", {}) }),
|
|
482
|
+
/* @__PURE__ */ jsxs2("span", { class: "scui-loading-copy", children: [
|
|
483
|
+
/* @__PURE__ */ jsx3("strong", { children: copy[0] }),
|
|
484
|
+
/* @__PURE__ */ jsx3("small", { children: copy[1] })
|
|
386
485
|
] }),
|
|
387
|
-
/* @__PURE__ */
|
|
486
|
+
/* @__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)) })
|
|
388
487
|
] });
|
|
389
488
|
}
|
|
390
489
|
function RequestCard({ entry, adapter, canRespond }) {
|
|
391
490
|
const request = entry.request;
|
|
392
491
|
if (!request) return null;
|
|
393
492
|
if (request.status === "responded") {
|
|
394
|
-
return /* @__PURE__ */
|
|
493
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-request-done", children: [
|
|
395
494
|
"\u2713 Request answered \xB7 ",
|
|
396
495
|
request.resolution?.name ?? request.requestKind
|
|
397
496
|
] });
|
|
398
497
|
}
|
|
399
|
-
return /* @__PURE__ */
|
|
400
|
-
/* @__PURE__ */
|
|
401
|
-
/* @__PURE__ */
|
|
402
|
-
/* @__PURE__ */
|
|
403
|
-
request.options.map((option) => /* @__PURE__ */
|
|
404
|
-
request.cancellable ? /* @__PURE__ */
|
|
498
|
+
return /* @__PURE__ */ jsxs2("section", { class: "scui-request", "aria-label": `${request.requestKind} needs input`, children: [
|
|
499
|
+
/* @__PURE__ */ jsx3("strong", { children: "Agent needs input" }),
|
|
500
|
+
/* @__PURE__ */ jsx3(Markdown, { value: request.payloadText || entry.text }),
|
|
501
|
+
/* @__PURE__ */ jsxs2("div", { class: "scui-request-actions", children: [
|
|
502
|
+
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)),
|
|
503
|
+
request.cancellable ? /* @__PURE__ */ jsx3("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
|
|
405
504
|
] })
|
|
406
505
|
] });
|
|
407
506
|
}
|
|
408
507
|
function ContextDisclosure({ context }) {
|
|
409
508
|
if (!context?.length) return null;
|
|
410
|
-
return /* @__PURE__ */
|
|
411
|
-
/* @__PURE__ */
|
|
509
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-context", children: [
|
|
510
|
+
/* @__PURE__ */ jsxs2("summary", { children: [
|
|
412
511
|
"Context \xB7 ",
|
|
413
512
|
context.length
|
|
414
513
|
] }),
|
|
415
|
-
/* @__PURE__ */
|
|
416
|
-
/* @__PURE__ */
|
|
417
|
-
/* @__PURE__ */
|
|
514
|
+
/* @__PURE__ */ jsx3("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs2("p", { children: [
|
|
515
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
516
|
+
/* @__PURE__ */ jsx3("span", { children: item.detail })
|
|
418
517
|
] }, item.id ?? index)) })
|
|
419
518
|
] });
|
|
420
519
|
}
|
|
421
520
|
function TranscriptEntry({ entry, state, adapter }) {
|
|
422
|
-
if (entry.role === "request") return /* @__PURE__ */
|
|
521
|
+
if (entry.role === "request") return /* @__PURE__ */ jsx3(RequestCard, { entry, adapter, canRespond: state.canRespond });
|
|
423
522
|
if (entry.role === "reasoning") {
|
|
424
|
-
return /* @__PURE__ */
|
|
425
|
-
/* @__PURE__ */
|
|
426
|
-
/* @__PURE__ */
|
|
523
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-reasoning", open: entry.streaming, children: [
|
|
524
|
+
/* @__PURE__ */ jsx3("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
|
|
525
|
+
/* @__PURE__ */ jsx3(Markdown, { value: entry.text })
|
|
427
526
|
] });
|
|
428
527
|
}
|
|
429
|
-
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */
|
|
430
|
-
return /* @__PURE__ */
|
|
431
|
-
/* @__PURE__ */
|
|
432
|
-
/* @__PURE__ */
|
|
433
|
-
entry.truncated ? /* @__PURE__ */
|
|
528
|
+
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx3("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
|
|
529
|
+
return /* @__PURE__ */ jsxs2("article", { class: "scui-message", "data-role": entry.role, children: [
|
|
530
|
+
/* @__PURE__ */ jsx3(Markdown, { value: entry.text }),
|
|
531
|
+
/* @__PURE__ */ jsx3(ContextDisclosure, { context: entry.context }),
|
|
532
|
+
entry.truncated ? /* @__PURE__ */ jsx3("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
|
|
434
533
|
] });
|
|
435
534
|
}
|
|
436
535
|
function ToolRow({ entry, workspace }) {
|
|
437
|
-
const [open, setOpen] =
|
|
536
|
+
const [open, setOpen] = useState2(entry.status === "pending");
|
|
438
537
|
const detailId = useId();
|
|
439
538
|
const target = compactToolTarget(toolTarget(entry.arguments), workspace);
|
|
440
539
|
const hasDetail = Boolean(entry.arguments || entry.resultText);
|
|
441
540
|
const category = toolCategory(entry);
|
|
442
|
-
return /* @__PURE__ */
|
|
443
|
-
/* @__PURE__ */
|
|
444
|
-
/* @__PURE__ */
|
|
445
|
-
/* @__PURE__ */
|
|
446
|
-
target ? /* @__PURE__ */
|
|
447
|
-
/* @__PURE__ */
|
|
448
|
-
/* @__PURE__ */
|
|
541
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
|
|
542
|
+
/* @__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: [
|
|
543
|
+
/* @__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] }),
|
|
544
|
+
/* @__PURE__ */ jsx3("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
|
|
545
|
+
target ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
|
|
546
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
|
|
547
|
+
/* @__PURE__ */ jsx3("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
|
|
449
548
|
] }),
|
|
450
|
-
hasDetail && open ? /* @__PURE__ */
|
|
451
|
-
entry.arguments ? /* @__PURE__ */
|
|
452
|
-
/* @__PURE__ */
|
|
549
|
+
hasDetail && open ? /* @__PURE__ */ jsxs2("div", { id: detailId, class: "scui-tool-detail", children: [
|
|
550
|
+
entry.arguments ? /* @__PURE__ */ jsxs2("pre", { children: [
|
|
551
|
+
/* @__PURE__ */ jsx3("b", { children: "Input" }),
|
|
453
552
|
"\n",
|
|
454
553
|
entry.arguments
|
|
455
554
|
] }) : null,
|
|
456
|
-
entry.resultText ? /* @__PURE__ */
|
|
457
|
-
/* @__PURE__ */
|
|
555
|
+
entry.resultText ? /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
|
|
556
|
+
/* @__PURE__ */ jsx3("b", { children: "Output" }),
|
|
458
557
|
"\n",
|
|
459
558
|
entry.resultText,
|
|
460
559
|
entry.truncated ? "\n[truncated]" : ""
|
|
@@ -464,74 +563,74 @@ function ToolRow({ entry, workspace }) {
|
|
|
464
563
|
}
|
|
465
564
|
function ActivityGroup({ entries, state }) {
|
|
466
565
|
const active = entries.some((entry) => entry.status === "pending");
|
|
467
|
-
const [open, setOpen] =
|
|
566
|
+
const [open, setOpen] = useState2(active);
|
|
468
567
|
const id = useId();
|
|
469
|
-
|
|
568
|
+
useEffect2(() => {
|
|
470
569
|
if (active) setOpen(true);
|
|
471
570
|
}, [active]);
|
|
472
|
-
return /* @__PURE__ */
|
|
473
|
-
/* @__PURE__ */
|
|
474
|
-
/* @__PURE__ */
|
|
475
|
-
/* @__PURE__ */
|
|
476
|
-
/* @__PURE__ */
|
|
477
|
-
/* @__PURE__ */
|
|
571
|
+
return /* @__PURE__ */ jsxs2("section", { class: "scui-activity", children: [
|
|
572
|
+
/* @__PURE__ */ jsxs2("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
|
|
573
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-fold", "data-open": open, children: "\u203A" }),
|
|
574
|
+
/* @__PURE__ */ jsx3("strong", { children: activitySummary(entries) }),
|
|
575
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
|
|
576
|
+
/* @__PURE__ */ jsxs2("small", { children: [
|
|
478
577
|
entries.filter((entry) => entry.status === "completed").length,
|
|
479
578
|
"/",
|
|
480
579
|
entries.length
|
|
481
580
|
] })
|
|
482
581
|
] }),
|
|
483
|
-
open ? /* @__PURE__ */
|
|
582
|
+
open ? /* @__PURE__ */ jsx3("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx3(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
|
|
484
583
|
] });
|
|
485
584
|
}
|
|
486
585
|
function TaskPlan({ plan }) {
|
|
487
586
|
if (!plan.items.length) return null;
|
|
488
587
|
const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
|
|
489
|
-
return /* @__PURE__ */
|
|
490
|
-
/* @__PURE__ */
|
|
491
|
-
/* @__PURE__ */
|
|
492
|
-
/* @__PURE__ */
|
|
588
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-plan", children: [
|
|
589
|
+
/* @__PURE__ */ jsxs2("summary", { children: [
|
|
590
|
+
/* @__PURE__ */ jsx3("span", { children: "Plan" }),
|
|
591
|
+
/* @__PURE__ */ jsxs2("small", { children: [
|
|
493
592
|
complete,
|
|
494
593
|
"/",
|
|
495
594
|
plan.items.length
|
|
496
595
|
] })
|
|
497
596
|
] }),
|
|
498
|
-
/* @__PURE__ */
|
|
499
|
-
/* @__PURE__ */
|
|
597
|
+
/* @__PURE__ */ jsx3("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs2("li", { "data-status": item.status, children: [
|
|
598
|
+
/* @__PURE__ */ jsx3("i", { "aria-hidden": "true" }),
|
|
500
599
|
" ",
|
|
501
|
-
/* @__PURE__ */
|
|
600
|
+
/* @__PURE__ */ jsx3("span", { children: item.title })
|
|
502
601
|
] }, item.id)) })
|
|
503
602
|
] });
|
|
504
603
|
}
|
|
505
604
|
function SessionDetails({ semantics }) {
|
|
506
605
|
if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
|
|
507
|
-
return /* @__PURE__ */
|
|
508
|
-
/* @__PURE__ */
|
|
509
|
-
/* @__PURE__ */
|
|
510
|
-
semantics.fidelity ? /* @__PURE__ */
|
|
511
|
-
/* @__PURE__ */
|
|
512
|
-
/* @__PURE__ */
|
|
606
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-details", children: [
|
|
607
|
+
/* @__PURE__ */ jsx3("summary", { children: "Session details" }),
|
|
608
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
609
|
+
semantics.fidelity ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
610
|
+
/* @__PURE__ */ jsx3("strong", { children: "Fidelity" }),
|
|
611
|
+
/* @__PURE__ */ jsx3("span", { children: semantics.fidelity.replaceAll("_", " ") })
|
|
513
612
|
] }) : null,
|
|
514
|
-
/* @__PURE__ */
|
|
515
|
-
/* @__PURE__ */
|
|
516
|
-
/* @__PURE__ */
|
|
613
|
+
/* @__PURE__ */ jsxs2("p", { children: [
|
|
614
|
+
/* @__PURE__ */ jsx3("strong", { children: "Native records" }),
|
|
615
|
+
/* @__PURE__ */ jsx3("span", { children: semantics.rawRecords })
|
|
517
616
|
] }),
|
|
518
|
-
semantics.residueCount ? /* @__PURE__ */
|
|
519
|
-
/* @__PURE__ */
|
|
520
|
-
/* @__PURE__ */
|
|
617
|
+
semantics.residueCount ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
618
|
+
/* @__PURE__ */ jsx3("strong", { children: "Residue" }),
|
|
619
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
521
620
|
semantics.residueCount,
|
|
522
621
|
" retained"
|
|
523
622
|
] })
|
|
524
623
|
] }) : null,
|
|
525
|
-
semantics.parseErrors ? /* @__PURE__ */
|
|
526
|
-
/* @__PURE__ */
|
|
527
|
-
/* @__PURE__ */
|
|
624
|
+
semantics.parseErrors ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
625
|
+
/* @__PURE__ */ jsx3("strong", { children: "Parse diagnostics" }),
|
|
626
|
+
/* @__PURE__ */ jsx3("span", { children: semantics.parseErrors })
|
|
528
627
|
] }) : null,
|
|
529
|
-
semantics.subagents.map((agent) => /* @__PURE__ */
|
|
530
|
-
/* @__PURE__ */
|
|
628
|
+
semantics.subagents.map((agent) => /* @__PURE__ */ jsxs2("p", { children: [
|
|
629
|
+
/* @__PURE__ */ jsxs2("strong", { children: [
|
|
531
630
|
agent.source,
|
|
532
631
|
" subagent"
|
|
533
632
|
] }),
|
|
534
|
-
/* @__PURE__ */
|
|
633
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
535
634
|
agent.messages,
|
|
536
635
|
" messages \xB7 ",
|
|
537
636
|
agent.fidelity.replaceAll("_", " ")
|
|
@@ -541,24 +640,24 @@ function SessionDetails({ semantics }) {
|
|
|
541
640
|
] });
|
|
542
641
|
}
|
|
543
642
|
var conversationMemory = /* @__PURE__ */ new Map();
|
|
544
|
-
var composerMemory = /* @__PURE__ */ new Map();
|
|
545
643
|
function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null }) {
|
|
546
|
-
const scroller =
|
|
644
|
+
const scroller = useRef2(null);
|
|
547
645
|
const remembered = conversationMemory.get(memoryKey) ?? { top: null, atBottom: true };
|
|
548
|
-
const [atBottom, setAtBottom] =
|
|
549
|
-
const earlierAnchor =
|
|
550
|
-
const restored =
|
|
646
|
+
const [atBottom, setAtBottom] = useState2(remembered.atBottom);
|
|
647
|
+
const earlierAnchor = useRef2(null);
|
|
648
|
+
const restored = useRef2(false);
|
|
551
649
|
const blocks = groupConversation(state.transcript);
|
|
552
650
|
const Entry = components.TranscriptEntry ?? TranscriptEntry;
|
|
553
651
|
const Group = components.ActivityGroup ?? ActivityGroup;
|
|
554
652
|
const Before = slots.beforeConversation;
|
|
555
653
|
const After = slots.afterConversation;
|
|
556
654
|
const Empty = slots.emptyConversation;
|
|
655
|
+
const remember = (value) => boundedSet(conversationMemory, memoryKey, value);
|
|
557
656
|
const pin = () => {
|
|
558
657
|
if (!scroller.current) return;
|
|
559
658
|
scroller.current.scrollTop = scroller.current.scrollHeight;
|
|
560
659
|
setAtBottom(true);
|
|
561
|
-
|
|
660
|
+
remember({ top: scroller.current.scrollTop, atBottom: true });
|
|
562
661
|
};
|
|
563
662
|
useLayoutEffect(() => {
|
|
564
663
|
const element = scroller.current;
|
|
@@ -567,7 +666,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
567
666
|
if (anchor && state.transcript.length > anchor.entries) {
|
|
568
667
|
element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
|
|
569
668
|
earlierAnchor.current = null;
|
|
570
|
-
|
|
669
|
+
remember({ top: element.scrollTop, atBottom: false });
|
|
571
670
|
return;
|
|
572
671
|
}
|
|
573
672
|
if (!restored.current) {
|
|
@@ -576,178 +675,148 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
576
675
|
else pin();
|
|
577
676
|
} else if (atBottom) pin();
|
|
578
677
|
}, [memoryKey, state.transcript.length, state.busy]);
|
|
579
|
-
return /* @__PURE__ */
|
|
580
|
-
/* @__PURE__ */
|
|
678
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-conversation-wrap", children: [
|
|
679
|
+
/* @__PURE__ */ jsx3("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
|
|
581
680
|
const element = event.currentTarget;
|
|
582
681
|
const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
|
|
583
682
|
setAtBottom(bottom);
|
|
584
|
-
|
|
585
|
-
}, children: /* @__PURE__ */
|
|
586
|
-
Before ? /* @__PURE__ */
|
|
587
|
-
/* @__PURE__ */
|
|
588
|
-
/* @__PURE__ */
|
|
589
|
-
state.history.hasEarlier ? /* @__PURE__ */
|
|
683
|
+
remember({ top: element.scrollTop, atBottom: bottom });
|
|
684
|
+
}, children: /* @__PURE__ */ jsxs2("div", { children: [
|
|
685
|
+
Before ? /* @__PURE__ */ jsx3(Before, { state, adapter, value: null }) : null,
|
|
686
|
+
/* @__PURE__ */ jsx3(TaskPlan, { plan: state.taskPlan }),
|
|
687
|
+
/* @__PURE__ */ jsx3(SessionDetails, { semantics: state.semantics }),
|
|
688
|
+
state.history.hasEarlier ? /* @__PURE__ */ jsx3("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
|
|
590
689
|
const element = scroller.current;
|
|
591
690
|
if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
|
|
592
691
|
setAtBottom(false);
|
|
593
692
|
adapter.onIntent({ action: "loadEarlier" });
|
|
594
693
|
}, children: "Load earlier messages" }) : null,
|
|
595
|
-
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */
|
|
596
|
-
!blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */
|
|
597
|
-
blocks.map((block) => block.kind === "activity" ? /* @__PURE__ */
|
|
598
|
-
pending ? /* @__PURE__ */
|
|
599
|
-
/* @__PURE__ */
|
|
600
|
-
/* @__PURE__ */
|
|
694
|
+
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx3(LoadingStatus, { state }) : null,
|
|
695
|
+
!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,
|
|
696
|
+
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)),
|
|
697
|
+
pending ? /* @__PURE__ */ jsxs2("article", { class: "scui-message scui-pending", "data-role": "user", children: [
|
|
698
|
+
/* @__PURE__ */ jsx3(Markdown, { value: pending }),
|
|
699
|
+
/* @__PURE__ */ jsx3("small", { children: state.error && !state.busy ? "Not sent" : "Sending\u2026" })
|
|
601
700
|
] }) : null,
|
|
602
|
-
state.busy ? /* @__PURE__ */
|
|
603
|
-
/* @__PURE__ */
|
|
604
|
-
/* @__PURE__ */
|
|
605
|
-
/* @__PURE__ */
|
|
606
|
-
/* @__PURE__ */
|
|
607
|
-
/* @__PURE__ */
|
|
701
|
+
state.busy ? /* @__PURE__ */ jsxs2("div", { class: "scui-working", role: "status", children: [
|
|
702
|
+
/* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
703
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
704
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
705
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
706
|
+
/* @__PURE__ */ jsxs2("small", { children: [
|
|
608
707
|
harnessDisplayName(state.harness),
|
|
609
708
|
" is working"
|
|
610
709
|
] })
|
|
611
710
|
] }) : null,
|
|
612
|
-
After ? /* @__PURE__ */
|
|
711
|
+
After ? /* @__PURE__ */ jsx3(After, { state, adapter, value: null }) : null
|
|
613
712
|
] }) }),
|
|
614
|
-
!atBottom ? /* @__PURE__ */
|
|
713
|
+
!atBottom ? /* @__PURE__ */ jsx3("button", { class: "scui-latest", type: "button", onClick: pin, children: "\u2193 Latest" }) : null
|
|
615
714
|
] });
|
|
616
715
|
}
|
|
716
|
+
|
|
717
|
+
// src/logo.jsx
|
|
718
|
+
import { useEffect as useEffect3 } from "preact/hooks";
|
|
719
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
720
|
+
var LOGOS = {
|
|
721
|
+
"claude-code": {
|
|
722
|
+
viewBox: "-1 3.5 26 18",
|
|
723
|
+
paths: [
|
|
724
|
+
["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" }]
|
|
725
|
+
]
|
|
726
|
+
},
|
|
727
|
+
codex: {
|
|
728
|
+
viewBox: "-1 -1 26 26",
|
|
729
|
+
paths: [
|
|
730
|
+
["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" }]
|
|
731
|
+
]
|
|
732
|
+
},
|
|
733
|
+
gemini: {
|
|
734
|
+
viewBox: "0 0 24 24",
|
|
735
|
+
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" }]]
|
|
736
|
+
},
|
|
737
|
+
grok: {
|
|
738
|
+
viewBox: "-1 -1 26 26",
|
|
739
|
+
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" }]]
|
|
740
|
+
},
|
|
741
|
+
opencode: { viewBox: "2.5 0 19 24", paths: [["path", { d: "M16 6H8v12h8V6zm4 16H4V2h16v20z" }]] },
|
|
742
|
+
pi: {
|
|
743
|
+
viewBox: "0 0 24 24",
|
|
744
|
+
paths: [
|
|
745
|
+
["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M1 1h16.5v11H12v5.5H6.5V23H1V1zm5.5 5.5V12H12V6.5H6.5z" }],
|
|
746
|
+
["path", { d: "M17.5 12H23v11h-5.5V12z" }]
|
|
747
|
+
]
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
|
|
751
|
+
const logo = LOGOS[id];
|
|
752
|
+
useEffect3(() => {
|
|
753
|
+
if (!logo) onMissingLogo?.(id);
|
|
754
|
+
}, [id, logo, onMissingLogo]);
|
|
755
|
+
if (!logo) return null;
|
|
756
|
+
return /* @__PURE__ */ jsxs3("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
|
|
757
|
+
/* @__PURE__ */ jsx4("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx4(Tag, { ...props }, index)) }),
|
|
758
|
+
activity && activity !== "idle" ? /* @__PURE__ */ jsx4("i", {}) : null
|
|
759
|
+
] });
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// src/sessions.jsx
|
|
763
|
+
import { useState as useState3 } from "preact/hooks";
|
|
764
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
617
765
|
function SessionRow({ row, state, onOpen }) {
|
|
618
766
|
const activity = sessionActivity(state, row);
|
|
619
767
|
const preview = state.attention.find((item) => item.key === row.key)?.preview;
|
|
620
|
-
return /* @__PURE__ */
|
|
621
|
-
/* @__PURE__ */
|
|
622
|
-
/* @__PURE__ */
|
|
623
|
-
/* @__PURE__ */
|
|
624
|
-
/* @__PURE__ */
|
|
625
|
-
/* @__PURE__ */
|
|
768
|
+
return /* @__PURE__ */ jsxs4("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, type: "button", onClick: () => onOpen(row), children: [
|
|
769
|
+
/* @__PURE__ */ jsx5(HarnessLogo, { id: row.harness, activity, size: 34 }),
|
|
770
|
+
/* @__PURE__ */ jsxs4("span", { class: "scui-session-copy", children: [
|
|
771
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
772
|
+
/* @__PURE__ */ jsx5("strong", { children: sessionDisplayName(row) }),
|
|
773
|
+
/* @__PURE__ */ jsx5("small", { children: row.age })
|
|
626
774
|
] }),
|
|
627
|
-
/* @__PURE__ */
|
|
628
|
-
/* @__PURE__ */
|
|
629
|
-
/* @__PURE__ */
|
|
775
|
+
/* @__PURE__ */ jsxs4("span", { children: [
|
|
776
|
+
/* @__PURE__ */ jsx5("b", { children: harnessDisplayName(row.harness) }),
|
|
777
|
+
/* @__PURE__ */ jsx5("small", { children: preview || row.cwd || row.name })
|
|
630
778
|
] }),
|
|
631
|
-
state.attachError?.key === row.key ? /* @__PURE__ */
|
|
779
|
+
state.attachError?.key === row.key ? /* @__PURE__ */ jsx5("em", { children: state.attachError.message }) : null
|
|
632
780
|
] })
|
|
633
781
|
] });
|
|
634
782
|
}
|
|
635
783
|
function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS }) {
|
|
636
|
-
const [query, setQuery] =
|
|
784
|
+
const [query, setQuery] = useState3("");
|
|
637
785
|
const rows = filterSessions(state.sessions, query);
|
|
638
786
|
const Row = components.SessionRow ?? SessionRow;
|
|
639
|
-
return /* @__PURE__ */
|
|
640
|
-
/* @__PURE__ */
|
|
641
|
-
/* @__PURE__ */
|
|
642
|
-
/* @__PURE__ */
|
|
643
|
-
/* @__PURE__ */
|
|
787
|
+
return /* @__PURE__ */ jsxs4("section", { class: "scui-list", children: [
|
|
788
|
+
/* @__PURE__ */ jsxs4("header", { class: "scui-head", children: [
|
|
789
|
+
/* @__PURE__ */ jsxs4("span", { class: "scui-head-copy", children: [
|
|
790
|
+
/* @__PURE__ */ jsx5("strong", { children: labels.chats }),
|
|
791
|
+
/* @__PURE__ */ jsxs4("small", { children: [
|
|
644
792
|
state.sessions.length,
|
|
645
793
|
" recent conversations"
|
|
646
794
|
] })
|
|
647
795
|
] }),
|
|
648
|
-
/* @__PURE__ */
|
|
649
|
-
onClose ? /* @__PURE__ */
|
|
796
|
+
/* @__PURE__ */ jsx5("button", { type: "button", "aria-label": labels.newChat, disabled: !state.harnesses.some((item) => item.startable), onClick: onNew, children: "\uFF0B" }),
|
|
797
|
+
onClose ? /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
|
|
650
798
|
] }),
|
|
651
|
-
state.startup !== "ready" ? /* @__PURE__ */
|
|
652
|
-
state.sessions.length > 4 ? /* @__PURE__ */
|
|
653
|
-
/* @__PURE__ */
|
|
654
|
-
/* @__PURE__ */
|
|
655
|
-
/* @__PURE__ */
|
|
656
|
-
] }) : null,
|
|
657
|
-
/* @__PURE__ */ jsxs("div", { class: "scui-session-rows", children: [
|
|
658
|
-
!rows.length && state.startup === "ready" ? /* @__PURE__ */ jsx("div", { class: "scui-empty", children: query ? "No chats match your search." : state.error ?? "No coding chats found." }) : null,
|
|
659
|
-
rows.map((row) => /* @__PURE__ */ jsx(Row, { value: row, row, state, adapter, onOpen }, row.key)),
|
|
660
|
-
state.history.hasMoreSessions ? /* @__PURE__ */ jsx("button", { class: "scui-load", type: "button", onClick: () => adapter.onIntent({ action: "loadSessions" }), children: "Load older chats" }) : null
|
|
661
|
-
] })
|
|
662
|
-
] });
|
|
663
|
-
}
|
|
664
|
-
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
665
|
-
if (state.mode !== "mirror" || state.canSend) return null;
|
|
666
|
-
const attached = state.attached;
|
|
667
|
-
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
668
|
-
const activeElsewhere = row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
669
|
-
const resume = canContinueHere(state);
|
|
670
|
-
const join = state.canAttach;
|
|
671
|
-
const branch = state.canBranch;
|
|
672
|
-
if (!resume && !join && !branch) return /* @__PURE__ */ jsx("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs("span", { children: [
|
|
673
|
-
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
674
|
-
/* @__PURE__ */ jsx("small", { children: "This session cannot be continued by an available harness." })
|
|
675
|
-
] }) });
|
|
676
|
-
return /* @__PURE__ */ jsxs("div", { class: "scui-continuation", children: [
|
|
677
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
678
|
-
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
679
|
-
/* @__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." })
|
|
680
|
-
] }),
|
|
681
|
-
/* @__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 })
|
|
682
|
-
] });
|
|
683
|
-
}
|
|
684
|
-
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, onPending }) {
|
|
685
|
-
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
|
|
686
|
-
const [draft, setDraft] = useState(remembered.draft);
|
|
687
|
-
const [queue, setQueue] = useState(remembered.queue);
|
|
688
|
-
const textarea = useRef(null);
|
|
689
|
-
useEffect(() => {
|
|
690
|
-
if (!state.busy && state.canSend && queue.length) {
|
|
691
|
-
const [next, ...rest] = queue;
|
|
692
|
-
setQueue(rest);
|
|
693
|
-
composerMemory.set(memoryKey, { draft, queue: rest });
|
|
694
|
-
onPending?.(next);
|
|
695
|
-
adapter.onIntent({ action: "send", text: next });
|
|
696
|
-
}
|
|
697
|
-
}, [adapter, draft, memoryKey, onPending, queue, state.busy, state.canSend]);
|
|
698
|
-
useEffect(() => {
|
|
699
|
-
const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
|
|
700
|
-
return () => clearTimeout(timer);
|
|
701
|
-
}, [adapter, draft]);
|
|
702
|
-
const send = () => {
|
|
703
|
-
const text = draft.trim();
|
|
704
|
-
if (!text) return;
|
|
705
|
-
if (state.busy) setQueue((items) => {
|
|
706
|
-
const next = [...items, text];
|
|
707
|
-
composerMemory.set(memoryKey, { draft: "", queue: next });
|
|
708
|
-
return next;
|
|
709
|
-
});
|
|
710
|
-
else if (state.canSend) {
|
|
711
|
-
onPending?.(text);
|
|
712
|
-
adapter.onIntent({ action: "send", text });
|
|
713
|
-
} else return;
|
|
714
|
-
setDraft("");
|
|
715
|
-
composerMemory.set(memoryKey, { draft: "", queue: state.busy ? [...queue, text] : queue });
|
|
716
|
-
};
|
|
717
|
-
return /* @__PURE__ */ jsxs("div", { class: "scui-compose", children: [
|
|
718
|
-
queue.length ? /* @__PURE__ */ jsxs("div", { class: "scui-queue", children: [
|
|
719
|
-
/* @__PURE__ */ jsxs("strong", { children: [
|
|
720
|
-
queue.length,
|
|
721
|
-
" queued"
|
|
722
|
-
] }),
|
|
723
|
-
queue.map((item, index) => /* @__PURE__ */ jsxs("span", { children: [
|
|
724
|
-
item,
|
|
725
|
-
/* @__PURE__ */ jsx("button", { "aria-label": `Remove queued message ${index + 1}`, onClick: () => setQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: "\xD7" })
|
|
726
|
-
] }, `${index}:${item}`))
|
|
799
|
+
state.startup !== "ready" ? /* @__PURE__ */ jsx5(LoadingStatus, { state, compact: rows.length > 0 }) : null,
|
|
800
|
+
state.sessions.length > 4 ? /* @__PURE__ */ jsxs4("label", { class: "scui-search", children: [
|
|
801
|
+
/* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: "\u2315" }),
|
|
802
|
+
/* @__PURE__ */ jsx5("input", { type: "search", "aria-label": labels.searchChats, placeholder: labels.searchChats, value: query, onInput: (event) => setQuery(event.currentTarget.value) }),
|
|
803
|
+
/* @__PURE__ */ jsx5("small", { children: rows.length })
|
|
727
804
|
] }) : null,
|
|
728
|
-
/* @__PURE__ */
|
|
729
|
-
/* @__PURE__ */
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
composerMemory.set(memoryKey, { draft: value, queue });
|
|
733
|
-
}, onKeyDown: (event) => {
|
|
734
|
-
if (isSendKey(event)) {
|
|
735
|
-
event.preventDefault();
|
|
736
|
-
send();
|
|
737
|
-
}
|
|
738
|
-
} }),
|
|
739
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
740
|
-
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,
|
|
741
|
-
/* @__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" })
|
|
742
|
-
] })
|
|
805
|
+
/* @__PURE__ */ jsxs4("div", { class: "scui-session-rows", children: [
|
|
806
|
+
!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,
|
|
807
|
+
rows.map((row) => /* @__PURE__ */ jsx5(Row, { value: row, row, state, adapter, onOpen }, row.key)),
|
|
808
|
+
state.history.hasMoreSessions ? /* @__PURE__ */ jsx5("button", { class: "scui-load", type: "button", onClick: () => adapter.onIntent({ action: "loadSessions" }), children: "Load older chats" }) : null
|
|
743
809
|
] })
|
|
744
810
|
] });
|
|
745
811
|
}
|
|
812
|
+
|
|
813
|
+
// src/messenger.jsx
|
|
814
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
746
815
|
function Receipt({ state, adapter }) {
|
|
747
816
|
const receipt = state.reductionReceipt;
|
|
748
|
-
if (receipt) return /* @__PURE__ */
|
|
749
|
-
/* @__PURE__ */
|
|
750
|
-
/* @__PURE__ */
|
|
817
|
+
if (receipt) return /* @__PURE__ */ jsx6("div", { class: "scui-receipt", children: /* @__PURE__ */ jsxs5("span", { children: [
|
|
818
|
+
/* @__PURE__ */ jsx6("strong", { children: "Reduced and verified" }),
|
|
819
|
+
/* @__PURE__ */ jsxs5("small", { children: [
|
|
751
820
|
receipt.sourceTokens.toLocaleString(),
|
|
752
821
|
" \u2192 ",
|
|
753
822
|
receipt.reducedTokens.toLocaleString(),
|
|
@@ -756,27 +825,27 @@ function Receipt({ state, adapter }) {
|
|
|
756
825
|
"\xD7 \xB7 reversible"
|
|
757
826
|
] })
|
|
758
827
|
] }) });
|
|
759
|
-
if (state.exportReceipt) return /* @__PURE__ */
|
|
760
|
-
/* @__PURE__ */
|
|
761
|
-
/* @__PURE__ */
|
|
828
|
+
if (state.exportReceipt) return /* @__PURE__ */ jsxs5("div", { class: "scui-receipt", children: [
|
|
829
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
830
|
+
/* @__PURE__ */ jsxs5("strong", { children: [
|
|
762
831
|
"Lossless export ready \xB7 ",
|
|
763
832
|
harnessDisplayName(state.exportReceipt.targetHarness)
|
|
764
833
|
] }),
|
|
765
|
-
/* @__PURE__ */
|
|
834
|
+
/* @__PURE__ */ jsxs5("small", { children: [
|
|
766
835
|
state.exportReceipt.path,
|
|
767
836
|
" \xB7 ",
|
|
768
837
|
state.exportReceipt.files,
|
|
769
838
|
" files"
|
|
770
839
|
] })
|
|
771
840
|
] }),
|
|
772
|
-
/* @__PURE__ */
|
|
841
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.copyText?.(state.exportReceipt.path), children: "Copy path" })
|
|
773
842
|
] });
|
|
774
|
-
if (state.terminalHandoff) return /* @__PURE__ */
|
|
775
|
-
/* @__PURE__ */
|
|
776
|
-
/* @__PURE__ */
|
|
777
|
-
/* @__PURE__ */
|
|
843
|
+
if (state.terminalHandoff) return /* @__PURE__ */ jsxs5("div", { class: "scui-receipt", children: [
|
|
844
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
845
|
+
/* @__PURE__ */ jsx6("strong", { children: "Terminal handoff ready" }),
|
|
846
|
+
/* @__PURE__ */ jsx6("small", { children: state.terminalHandoff.cwd })
|
|
778
847
|
] }),
|
|
779
|
-
/* @__PURE__ */
|
|
848
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.copyText?.(terminalCommand(state.terminalHandoff)), children: "Copy command" })
|
|
780
849
|
] });
|
|
781
850
|
return null;
|
|
782
851
|
}
|
|
@@ -786,46 +855,46 @@ function ChatHeader({ state, adapter, onBack, onNew, onClose }) {
|
|
|
786
855
|
const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
|
|
787
856
|
const status = state.needsInput ? "Needs input" : state.busy ? "Working" : state.mode === "mirror" ? "Read-only" : "Ready";
|
|
788
857
|
const menu = state.canDetach || state.canOpenTerminal || state.canBranch || state.canAttach || state.canExport || state.canReduce;
|
|
789
|
-
return /* @__PURE__ */
|
|
790
|
-
/* @__PURE__ */
|
|
791
|
-
/* @__PURE__ */
|
|
792
|
-
/* @__PURE__ */
|
|
793
|
-
/* @__PURE__ */
|
|
794
|
-
/* @__PURE__ */
|
|
858
|
+
return /* @__PURE__ */ jsxs5("header", { class: "scui-head scui-chat-head", children: [
|
|
859
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Back to chats", onClick: onBack, children: "\u2039" }),
|
|
860
|
+
/* @__PURE__ */ jsx6(HarnessLogo, { id: harness, size: 28 }),
|
|
861
|
+
/* @__PURE__ */ jsxs5("span", { class: "scui-head-copy", children: [
|
|
862
|
+
/* @__PURE__ */ jsx6("strong", { children: title }),
|
|
863
|
+
/* @__PURE__ */ jsxs5("small", { children: [
|
|
795
864
|
harnessDisplayName(harness),
|
|
796
865
|
" \xB7 ",
|
|
797
866
|
status
|
|
798
867
|
] })
|
|
799
868
|
] }),
|
|
800
|
-
menu ? /* @__PURE__ */
|
|
801
|
-
/* @__PURE__ */
|
|
802
|
-
/* @__PURE__ */
|
|
803
|
-
state.canDetach ? /* @__PURE__ */
|
|
804
|
-
state.canOpenTerminal ? /* @__PURE__ */
|
|
805
|
-
state.canReduce ? targets.map((target) => /* @__PURE__ */
|
|
806
|
-
state.canBranch ? targets.map((target) => /* @__PURE__ */
|
|
807
|
-
state.canExport && state.exportBackTarget ? /* @__PURE__ */
|
|
869
|
+
menu ? /* @__PURE__ */ jsxs5("details", { class: "scui-menu", children: [
|
|
870
|
+
/* @__PURE__ */ jsx6("summary", { "aria-label": "Conversation actions", children: "\u2022\u2022\u2022" }),
|
|
871
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
872
|
+
state.canDetach ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "detach" }), children: "Detach to read-only" }) : null,
|
|
873
|
+
state.canOpenTerminal ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "terminal" }), children: "Prepare terminal handoff" }) : null,
|
|
874
|
+
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,
|
|
875
|
+
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,
|
|
876
|
+
state.canExport && state.exportBackTarget ? /* @__PURE__ */ jsxs5("button", { type: "button", onClick: () => adapter.onIntent({ action: "export", targetHarness: state.exportBackTarget }), children: [
|
|
808
877
|
"Export back to ",
|
|
809
878
|
harnessDisplayName(state.exportBackTarget)
|
|
810
879
|
] }) : null
|
|
811
880
|
] })
|
|
812
881
|
] }) : null,
|
|
813
|
-
/* @__PURE__ */
|
|
814
|
-
onClose ? /* @__PURE__ */
|
|
882
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: "\uFF0B" }),
|
|
883
|
+
onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
|
|
815
884
|
] });
|
|
816
885
|
}
|
|
817
886
|
function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
|
|
818
887
|
const Header = slots.header;
|
|
819
888
|
const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
|
|
820
|
-
const [pending, setPending] =
|
|
821
|
-
const acknowledged =
|
|
822
|
-
|
|
889
|
+
const [pending, setPending] = useState4(null);
|
|
890
|
+
const acknowledged = useRef3(/* @__PURE__ */ new Set());
|
|
891
|
+
useEffect4(() => {
|
|
823
892
|
setPending(null);
|
|
824
893
|
}, [memoryKey]);
|
|
825
|
-
|
|
894
|
+
useEffect4(() => {
|
|
826
895
|
if (pending && state.transcript.some((entry) => entry.role === "user" && entry.text.trim() === pending.trim())) setPending(null);
|
|
827
896
|
}, [pending, state.transcript]);
|
|
828
|
-
|
|
897
|
+
useEffect4(() => {
|
|
829
898
|
const key = state.attached?.key;
|
|
830
899
|
if (!key || !state.attention.some((item) => item.key === key)) {
|
|
831
900
|
if (key) acknowledged.current.delete(key);
|
|
@@ -836,31 +905,31 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
|
|
|
836
905
|
adapter.onIntent({ action: "ack", key });
|
|
837
906
|
}
|
|
838
907
|
}, [adapter, state.attached?.key, state.attention]);
|
|
839
|
-
return /* @__PURE__ */
|
|
840
|
-
Header ? /* @__PURE__ */
|
|
841
|
-
operationLabel(state.operation) ? /* @__PURE__ */
|
|
842
|
-
/* @__PURE__ */
|
|
908
|
+
return /* @__PURE__ */ jsxs5("section", { class: "scui-chat", children: [
|
|
909
|
+
Header ? /* @__PURE__ */ jsx6(Header, { state, adapter, value: null }) : /* @__PURE__ */ jsx6(ChatHeader, { state, adapter, onBack, onNew, onClose }),
|
|
910
|
+
operationLabel(state.operation) ? /* @__PURE__ */ jsxs5("div", { class: "scui-operation", role: "status", children: [
|
|
911
|
+
/* @__PURE__ */ jsx6("i", {}),
|
|
843
912
|
operationLabel(state.operation)
|
|
844
913
|
] }) : null,
|
|
845
|
-
state.error ? /* @__PURE__ */
|
|
846
|
-
/* @__PURE__ */
|
|
847
|
-
state.recoverable ? /* @__PURE__ */
|
|
914
|
+
state.error ? /* @__PURE__ */ jsxs5("div", { class: "scui-error", role: "alert", children: [
|
|
915
|
+
/* @__PURE__ */ jsx6("span", { children: state.error }),
|
|
916
|
+
state.recoverable ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "refresh" }), children: "Retry" }) : null
|
|
848
917
|
] }) : null,
|
|
849
|
-
/* @__PURE__ */
|
|
850
|
-
/* @__PURE__ */
|
|
851
|
-
/* @__PURE__ */
|
|
852
|
-
state.mode !== "mirror" || state.canSend ? /* @__PURE__ */
|
|
918
|
+
/* @__PURE__ */ jsx6(Receipt, { state, adapter }),
|
|
919
|
+
/* @__PURE__ */ jsx6(Conversation, { state, adapter, components, slots, memoryKey, pending }, memoryKey),
|
|
920
|
+
/* @__PURE__ */ jsx6(ContinuationBar, { state, adapter, labels }),
|
|
921
|
+
state.mode !== "mirror" || state.canSend ? /* @__PURE__ */ jsx6(Composer, { state, adapter, labels, memoryKey, onPending: setPending }, memoryKey) : null
|
|
853
922
|
] });
|
|
854
923
|
}
|
|
855
924
|
function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
|
|
856
925
|
const startable = state.harnesses.filter((item) => item.startable);
|
|
857
|
-
const [harness, setHarness] =
|
|
858
|
-
const [draft, setDraft] =
|
|
859
|
-
const [starting, setStarting] =
|
|
860
|
-
|
|
926
|
+
const [harness, setHarness] = useState4(startable[0]?.id ?? "");
|
|
927
|
+
const [draft, setDraft] = useState4("");
|
|
928
|
+
const [starting, setStarting] = useState4(false);
|
|
929
|
+
useEffect4(() => {
|
|
861
930
|
if (starting && (state.busy || state.transcript.length)) onStarted();
|
|
862
931
|
}, [onStarted, starting, state.busy, state.transcript.length]);
|
|
863
|
-
|
|
932
|
+
useEffect4(() => {
|
|
864
933
|
if (starting && state.error && !state.busy && !state.operation) setStarting(false);
|
|
865
934
|
}, [starting, state.busy, state.error, state.operation]);
|
|
866
935
|
const send = () => {
|
|
@@ -869,37 +938,37 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
|
|
|
869
938
|
setStarting(true);
|
|
870
939
|
adapter.onIntent({ action: "new", harness, text });
|
|
871
940
|
};
|
|
872
|
-
return /* @__PURE__ */
|
|
873
|
-
/* @__PURE__ */
|
|
874
|
-
/* @__PURE__ */
|
|
875
|
-
/* @__PURE__ */
|
|
876
|
-
/* @__PURE__ */
|
|
877
|
-
/* @__PURE__ */
|
|
941
|
+
return /* @__PURE__ */ jsxs5("section", { class: "scui-chat", children: [
|
|
942
|
+
/* @__PURE__ */ jsxs5("header", { class: "scui-head", children: [
|
|
943
|
+
/* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Back", onClick: onBack, children: "\u2039" }),
|
|
944
|
+
/* @__PURE__ */ jsxs5("span", { class: "scui-head-copy", children: [
|
|
945
|
+
/* @__PURE__ */ jsx6("strong", { children: labels.newChat }),
|
|
946
|
+
/* @__PURE__ */ jsx6("small", { children: "No session is created until you send" })
|
|
878
947
|
] }),
|
|
879
|
-
onClose ? /* @__PURE__ */
|
|
948
|
+
onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
|
|
880
949
|
] }),
|
|
881
|
-
/* @__PURE__ */
|
|
882
|
-
/* @__PURE__ */
|
|
883
|
-
/* @__PURE__ */
|
|
884
|
-
/* @__PURE__ */
|
|
950
|
+
/* @__PURE__ */ jsxs5("div", { class: "scui-new", children: [
|
|
951
|
+
/* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
952
|
+
/* @__PURE__ */ jsx6("strong", { children: "What should the agent build or fix?" }),
|
|
953
|
+
/* @__PURE__ */ jsx6("small", { children: "Choose a coding harness and send the first message." })
|
|
885
954
|
] }),
|
|
886
|
-
/* @__PURE__ */
|
|
887
|
-
/* @__PURE__ */
|
|
888
|
-
/* @__PURE__ */
|
|
889
|
-
/* @__PURE__ */
|
|
890
|
-
/* @__PURE__ */
|
|
955
|
+
/* @__PURE__ */ jsxs5("div", { class: "scui-compose", children: [
|
|
956
|
+
/* @__PURE__ */ jsxs5("label", { class: "scui-harness-picker", children: [
|
|
957
|
+
/* @__PURE__ */ jsx6(HarnessLogo, { id: harness, size: 24 }),
|
|
958
|
+
/* @__PURE__ */ jsx6("span", { children: "Coding harness" }),
|
|
959
|
+
/* @__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: [
|
|
891
960
|
item.label,
|
|
892
961
|
item.startable ? "" : " \xB7 unavailable"
|
|
893
962
|
] }, item.id)) })
|
|
894
963
|
] }),
|
|
895
|
-
/* @__PURE__ */
|
|
896
|
-
/* @__PURE__ */
|
|
964
|
+
/* @__PURE__ */ jsxs5("div", { class: "scui-envelope", children: [
|
|
965
|
+
/* @__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) => {
|
|
897
966
|
if (isSendKey(event)) {
|
|
898
967
|
event.preventDefault();
|
|
899
968
|
send();
|
|
900
969
|
}
|
|
901
970
|
} }),
|
|
902
|
-
/* @__PURE__ */
|
|
971
|
+
/* @__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" }) })
|
|
903
972
|
] })
|
|
904
973
|
] })
|
|
905
974
|
] });
|
|
@@ -907,39 +976,40 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
|
|
|
907
976
|
function SupercodeMessenger({ state: stateInput, adapter, class: className = "", initialView, labels, components = {}, slots = {} }) {
|
|
908
977
|
const state = normalizeUiState(stateInput);
|
|
909
978
|
const copy = { ...DEFAULT_LABELS, ...labels };
|
|
910
|
-
const [view, setView] =
|
|
911
|
-
const [opening, setOpening] =
|
|
912
|
-
|
|
979
|
+
const [view, setView] = useState4(initialView ?? (state.attention.length ? "list" : state.attached || state.transcript.length ? "chat" : "list"));
|
|
980
|
+
const [opening, setOpening] = useState4(null);
|
|
981
|
+
useEffect4(() => {
|
|
913
982
|
if (!opening) return;
|
|
914
983
|
if (state.attached?.key === opening.key) {
|
|
915
984
|
setOpening(null);
|
|
916
985
|
setView("chat");
|
|
917
|
-
} else if (state.attachError?.key === opening.key) {
|
|
986
|
+
} else if (state.attachError?.key === opening.key || state.error && !state.operation) {
|
|
918
987
|
setOpening(null);
|
|
919
988
|
}
|
|
920
|
-
}, [opening, state.attachError?.key, state.attached?.key]);
|
|
989
|
+
}, [opening, state.attachError?.key, state.attached?.key, state.error, state.operation]);
|
|
921
990
|
const open = (row) => {
|
|
922
991
|
setOpening(row);
|
|
923
992
|
adapter.onIntent({ action: "ack", key: row.key });
|
|
924
993
|
adapter.onIntent({ action: "attach", key: row.key });
|
|
925
994
|
};
|
|
926
995
|
const close = () => adapter.onClose?.();
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
view === "
|
|
930
|
-
view === "
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
/* @__PURE__ */
|
|
934
|
-
|
|
996
|
+
const Footer = slots.footer;
|
|
997
|
+
return /* @__PURE__ */ jsxs5("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
|
|
998
|
+
view === "list" ? /* @__PURE__ */ jsx6(SessionList, { state, adapter, onOpen: open, onNew: () => setView("new"), onClose: adapter.onClose ? close : void 0, components, labels: copy }) : null,
|
|
999
|
+
view === "new" ? /* @__PURE__ */ jsx6(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: () => setView("chat"), labels: copy }) : null,
|
|
1000
|
+
view === "chat" ? /* @__PURE__ */ jsx6(Chat, { state, adapter, onBack: () => setView("list"), onNew: () => setView("new"), onClose: adapter.onClose ? close : void 0, components, slots, labels: copy }) : null,
|
|
1001
|
+
opening ? /* @__PURE__ */ jsxs5("div", { class: "scui-opening", role: "status", "aria-busy": "true", children: [
|
|
1002
|
+
/* @__PURE__ */ jsx6(HarnessLogo, { id: opening.harness, size: 34 }),
|
|
1003
|
+
/* @__PURE__ */ jsxs5("span", { children: [
|
|
1004
|
+
/* @__PURE__ */ jsxs5("strong", { children: [
|
|
935
1005
|
"Opening ",
|
|
936
1006
|
sessionDisplayName(opening)
|
|
937
1007
|
] }),
|
|
938
|
-
/* @__PURE__ */
|
|
1008
|
+
/* @__PURE__ */ jsx6("small", { children: "Loading the latest transcript window\u2026" })
|
|
939
1009
|
] }),
|
|
940
|
-
/* @__PURE__ */
|
|
1010
|
+
/* @__PURE__ */ jsx6("i", {})
|
|
941
1011
|
] }) : null,
|
|
942
|
-
|
|
1012
|
+
Footer ? /* @__PURE__ */ jsx6(Footer, { state, adapter, value: copy }) : null
|
|
943
1013
|
] });
|
|
944
1014
|
}
|
|
945
1015
|
export {
|