@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/components.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import
|
|
3
|
-
import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks";
|
|
1
|
+
// src/composer.jsx
|
|
2
|
+
import { useEffect, useRef, useState } 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,109 @@ function isSendKey(event) {
|
|
|
321
350
|
return event.key === "Enter" && !event.shiftKey && !event.isComposing;
|
|
322
351
|
}
|
|
323
352
|
|
|
324
|
-
// src/
|
|
353
|
+
// src/memory.js
|
|
354
|
+
var MEMORY_LIMIT = 100;
|
|
355
|
+
function boundedSet(map, key, value) {
|
|
356
|
+
map.delete(key);
|
|
357
|
+
map.set(key, value);
|
|
358
|
+
while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/composer.jsx
|
|
325
362
|
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
363
|
+
var composerMemory = /* @__PURE__ */ new Map();
|
|
364
|
+
function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
|
|
365
|
+
if (state.mode !== "mirror" || state.canSend) return null;
|
|
366
|
+
const attached = state.attached;
|
|
367
|
+
const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
|
|
368
|
+
const activeElsewhere = row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
|
|
369
|
+
const resume = canContinueHere(state);
|
|
370
|
+
const join = state.canAttach;
|
|
371
|
+
const branch = state.canBranch;
|
|
372
|
+
if (!resume && !join && !branch) return /* @__PURE__ */ jsx("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs("span", { children: [
|
|
373
|
+
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
374
|
+
/* @__PURE__ */ jsx("small", { children: "This session cannot be continued by an available harness." })
|
|
375
|
+
] }) });
|
|
376
|
+
return /* @__PURE__ */ jsxs("div", { class: "scui-continuation", children: [
|
|
377
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
378
|
+
/* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
|
|
379
|
+
/* @__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." })
|
|
380
|
+
] }),
|
|
381
|
+
/* @__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 })
|
|
382
|
+
] });
|
|
383
|
+
}
|
|
384
|
+
function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, onPending }) {
|
|
385
|
+
const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
|
|
386
|
+
const [draft, setDraft] = useState(remembered.draft);
|
|
387
|
+
const [queue, setQueue] = useState(remembered.queue);
|
|
388
|
+
const textarea = useRef(null);
|
|
389
|
+
const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
|
|
390
|
+
const updateQueue = (update) => setQueue((items) => {
|
|
391
|
+
const next = update(items);
|
|
392
|
+
remember(draft, next);
|
|
393
|
+
return next;
|
|
394
|
+
});
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
if (!state.busy && state.canSend && queue.length) {
|
|
397
|
+
const [next, ...rest] = queue;
|
|
398
|
+
setQueue(rest);
|
|
399
|
+
remember(draft, rest);
|
|
400
|
+
onPending?.(next);
|
|
401
|
+
adapter.onIntent({ action: "send", text: next });
|
|
402
|
+
}
|
|
403
|
+
}, [adapter, draft, memoryKey, onPending, queue, state.busy, state.canSend]);
|
|
404
|
+
useEffect(() => {
|
|
405
|
+
const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
|
|
406
|
+
return () => clearTimeout(timer);
|
|
407
|
+
}, [adapter, draft]);
|
|
408
|
+
const send = () => {
|
|
409
|
+
const text = draft.trim();
|
|
410
|
+
if (!text) return;
|
|
411
|
+
if (state.busy) updateQueue((items) => [...items, text]);
|
|
412
|
+
else if (state.canSend) {
|
|
413
|
+
onPending?.(text);
|
|
414
|
+
adapter.onIntent({ action: "send", text });
|
|
415
|
+
} else return;
|
|
416
|
+
setDraft("");
|
|
417
|
+
remember("", state.busy ? [...queue, text] : queue);
|
|
418
|
+
};
|
|
419
|
+
return /* @__PURE__ */ jsxs("div", { class: "scui-compose", children: [
|
|
420
|
+
queue.length ? /* @__PURE__ */ jsxs("div", { class: "scui-queue", children: [
|
|
421
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
422
|
+
queue.length,
|
|
423
|
+
" queued"
|
|
424
|
+
] }),
|
|
425
|
+
queue.map((item, index) => /* @__PURE__ */ jsxs("span", { children: [
|
|
426
|
+
item,
|
|
427
|
+
/* @__PURE__ */ jsx("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: "\xD7" })
|
|
428
|
+
] }, `${index}:${item}`))
|
|
429
|
+
] }) : null,
|
|
430
|
+
/* @__PURE__ */ jsxs("div", { class: "scui-envelope", children: [
|
|
431
|
+
/* @__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) => {
|
|
432
|
+
const value = event.currentTarget.value;
|
|
433
|
+
setDraft(value);
|
|
434
|
+
remember(value, queue);
|
|
435
|
+
}, onKeyDown: (event) => {
|
|
436
|
+
if (isSendKey(event)) {
|
|
437
|
+
event.preventDefault();
|
|
438
|
+
send();
|
|
439
|
+
}
|
|
440
|
+
} }),
|
|
441
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
442
|
+
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,
|
|
443
|
+
/* @__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" })
|
|
444
|
+
] })
|
|
445
|
+
] })
|
|
446
|
+
] });
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/conversation.jsx
|
|
450
|
+
import { useEffect as useEffect2, useId, useLayoutEffect, useRef as useRef2, useState as useState2 } from "preact/hooks";
|
|
451
|
+
|
|
452
|
+
// src/markdown.jsx
|
|
453
|
+
import MarkdownIt from "markdown-it";
|
|
454
|
+
import { useMemo } from "preact/hooks";
|
|
455
|
+
import { jsx as jsx2 } from "preact/jsx-runtime";
|
|
326
456
|
var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
|
|
327
457
|
var defaultLinkOpen = markdown.renderer.rules.link_open;
|
|
328
458
|
markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
|
|
@@ -330,50 +460,13 @@ markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
|
|
|
330
460
|
tokens[index]?.attrSet("rel", "noreferrer noopener");
|
|
331
461
|
return defaultLinkOpen ? defaultLinkOpen(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
|
|
332
462
|
};
|
|
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
|
-
function hasHarnessLogo(id) {
|
|
360
|
-
return Object.hasOwn(LOGOS, id);
|
|
361
|
-
}
|
|
362
463
|
function Markdown({ value }) {
|
|
363
464
|
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
|
-
] });
|
|
465
|
+
return /* @__PURE__ */ jsx2("div", { class: "scui-markdown", dangerouslySetInnerHTML: { __html: html } });
|
|
376
466
|
}
|
|
467
|
+
|
|
468
|
+
// src/conversation.jsx
|
|
469
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
377
470
|
function LoadingStatus({ state, compact = false }) {
|
|
378
471
|
const copy = {
|
|
379
472
|
connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
|
|
@@ -381,83 +474,83 @@ function LoadingStatus({ state, compact = false }) {
|
|
|
381
474
|
discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
|
|
382
475
|
ready: ["Ready", "Coding sessions are up to date.", 3]
|
|
383
476
|
}[state.startup];
|
|
384
|
-
return /* @__PURE__ */
|
|
385
|
-
/* @__PURE__ */
|
|
386
|
-
/* @__PURE__ */
|
|
387
|
-
/* @__PURE__ */
|
|
388
|
-
/* @__PURE__ */
|
|
477
|
+
return /* @__PURE__ */ jsxs2("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
|
|
478
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("i", {}) }),
|
|
479
|
+
/* @__PURE__ */ jsxs2("span", { class: "scui-loading-copy", children: [
|
|
480
|
+
/* @__PURE__ */ jsx3("strong", { children: copy[0] }),
|
|
481
|
+
/* @__PURE__ */ jsx3("small", { children: copy[1] })
|
|
389
482
|
] }),
|
|
390
|
-
/* @__PURE__ */
|
|
483
|
+
/* @__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
484
|
] });
|
|
392
485
|
}
|
|
393
486
|
function RequestCard({ entry, adapter, canRespond }) {
|
|
394
487
|
const request = entry.request;
|
|
395
488
|
if (!request) return null;
|
|
396
489
|
if (request.status === "responded") {
|
|
397
|
-
return /* @__PURE__ */
|
|
490
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-request-done", children: [
|
|
398
491
|
"\u2713 Request answered \xB7 ",
|
|
399
492
|
request.resolution?.name ?? request.requestKind
|
|
400
493
|
] });
|
|
401
494
|
}
|
|
402
|
-
return /* @__PURE__ */
|
|
403
|
-
/* @__PURE__ */
|
|
404
|
-
/* @__PURE__ */
|
|
405
|
-
/* @__PURE__ */
|
|
406
|
-
request.options.map((option) => /* @__PURE__ */
|
|
407
|
-
request.cancellable ? /* @__PURE__ */
|
|
495
|
+
return /* @__PURE__ */ jsxs2("section", { class: "scui-request", "aria-label": `${request.requestKind} needs input`, children: [
|
|
496
|
+
/* @__PURE__ */ jsx3("strong", { children: "Agent needs input" }),
|
|
497
|
+
/* @__PURE__ */ jsx3(Markdown, { value: request.payloadText || entry.text }),
|
|
498
|
+
/* @__PURE__ */ jsxs2("div", { class: "scui-request-actions", children: [
|
|
499
|
+
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)),
|
|
500
|
+
request.cancellable ? /* @__PURE__ */ jsx3("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
|
|
408
501
|
] })
|
|
409
502
|
] });
|
|
410
503
|
}
|
|
411
504
|
function ContextDisclosure({ context }) {
|
|
412
505
|
if (!context?.length) return null;
|
|
413
|
-
return /* @__PURE__ */
|
|
414
|
-
/* @__PURE__ */
|
|
506
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-context", children: [
|
|
507
|
+
/* @__PURE__ */ jsxs2("summary", { children: [
|
|
415
508
|
"Context \xB7 ",
|
|
416
509
|
context.length
|
|
417
510
|
] }),
|
|
418
|
-
/* @__PURE__ */
|
|
419
|
-
/* @__PURE__ */
|
|
420
|
-
/* @__PURE__ */
|
|
511
|
+
/* @__PURE__ */ jsx3("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs2("p", { children: [
|
|
512
|
+
/* @__PURE__ */ jsx3("strong", { children: item.label }),
|
|
513
|
+
/* @__PURE__ */ jsx3("span", { children: item.detail })
|
|
421
514
|
] }, item.id ?? index)) })
|
|
422
515
|
] });
|
|
423
516
|
}
|
|
424
517
|
function TranscriptEntry({ entry, state, adapter }) {
|
|
425
|
-
if (entry.role === "request") return /* @__PURE__ */
|
|
518
|
+
if (entry.role === "request") return /* @__PURE__ */ jsx3(RequestCard, { entry, adapter, canRespond: state.canRespond });
|
|
426
519
|
if (entry.role === "reasoning") {
|
|
427
|
-
return /* @__PURE__ */
|
|
428
|
-
/* @__PURE__ */
|
|
429
|
-
/* @__PURE__ */
|
|
520
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-reasoning", open: entry.streaming, children: [
|
|
521
|
+
/* @__PURE__ */ jsx3("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
|
|
522
|
+
/* @__PURE__ */ jsx3(Markdown, { value: entry.text })
|
|
430
523
|
] });
|
|
431
524
|
}
|
|
432
|
-
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */
|
|
433
|
-
return /* @__PURE__ */
|
|
434
|
-
/* @__PURE__ */
|
|
435
|
-
/* @__PURE__ */
|
|
436
|
-
entry.truncated ? /* @__PURE__ */
|
|
525
|
+
if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx3("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
|
|
526
|
+
return /* @__PURE__ */ jsxs2("article", { class: "scui-message", "data-role": entry.role, children: [
|
|
527
|
+
/* @__PURE__ */ jsx3(Markdown, { value: entry.text }),
|
|
528
|
+
/* @__PURE__ */ jsx3(ContextDisclosure, { context: entry.context }),
|
|
529
|
+
entry.truncated ? /* @__PURE__ */ jsx3("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
|
|
437
530
|
] });
|
|
438
531
|
}
|
|
439
532
|
function ToolRow({ entry, workspace }) {
|
|
440
|
-
const [open, setOpen] =
|
|
533
|
+
const [open, setOpen] = useState2(entry.status === "pending");
|
|
441
534
|
const detailId = useId();
|
|
442
535
|
const target = compactToolTarget(toolTarget(entry.arguments), workspace);
|
|
443
536
|
const hasDetail = Boolean(entry.arguments || entry.resultText);
|
|
444
537
|
const category = toolCategory(entry);
|
|
445
|
-
return /* @__PURE__ */
|
|
446
|
-
/* @__PURE__ */
|
|
447
|
-
/* @__PURE__ */
|
|
448
|
-
/* @__PURE__ */
|
|
449
|
-
target ? /* @__PURE__ */
|
|
450
|
-
/* @__PURE__ */
|
|
451
|
-
/* @__PURE__ */
|
|
538
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
|
|
539
|
+
/* @__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: [
|
|
540
|
+
/* @__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] }),
|
|
541
|
+
/* @__PURE__ */ jsx3("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
|
|
542
|
+
target ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
|
|
543
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
|
|
544
|
+
/* @__PURE__ */ jsx3("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
|
|
452
545
|
] }),
|
|
453
|
-
hasDetail && open ? /* @__PURE__ */
|
|
454
|
-
entry.arguments ? /* @__PURE__ */
|
|
455
|
-
/* @__PURE__ */
|
|
546
|
+
hasDetail && open ? /* @__PURE__ */ jsxs2("div", { id: detailId, class: "scui-tool-detail", children: [
|
|
547
|
+
entry.arguments ? /* @__PURE__ */ jsxs2("pre", { children: [
|
|
548
|
+
/* @__PURE__ */ jsx3("b", { children: "Input" }),
|
|
456
549
|
"\n",
|
|
457
550
|
entry.arguments
|
|
458
551
|
] }) : null,
|
|
459
|
-
entry.resultText ? /* @__PURE__ */
|
|
460
|
-
/* @__PURE__ */
|
|
552
|
+
entry.resultText ? /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
|
|
553
|
+
/* @__PURE__ */ jsx3("b", { children: "Output" }),
|
|
461
554
|
"\n",
|
|
462
555
|
entry.resultText,
|
|
463
556
|
entry.truncated ? "\n[truncated]" : ""
|
|
@@ -467,74 +560,74 @@ function ToolRow({ entry, workspace }) {
|
|
|
467
560
|
}
|
|
468
561
|
function ActivityGroup({ entries, state }) {
|
|
469
562
|
const active = entries.some((entry) => entry.status === "pending");
|
|
470
|
-
const [open, setOpen] =
|
|
563
|
+
const [open, setOpen] = useState2(active);
|
|
471
564
|
const id = useId();
|
|
472
|
-
|
|
565
|
+
useEffect2(() => {
|
|
473
566
|
if (active) setOpen(true);
|
|
474
567
|
}, [active]);
|
|
475
|
-
return /* @__PURE__ */
|
|
476
|
-
/* @__PURE__ */
|
|
477
|
-
/* @__PURE__ */
|
|
478
|
-
/* @__PURE__ */
|
|
479
|
-
/* @__PURE__ */
|
|
480
|
-
/* @__PURE__ */
|
|
568
|
+
return /* @__PURE__ */ jsxs2("section", { class: "scui-activity", children: [
|
|
569
|
+
/* @__PURE__ */ jsxs2("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
|
|
570
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-fold", "data-open": open, children: "\u203A" }),
|
|
571
|
+
/* @__PURE__ */ jsx3("strong", { children: activitySummary(entries) }),
|
|
572
|
+
/* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
|
|
573
|
+
/* @__PURE__ */ jsxs2("small", { children: [
|
|
481
574
|
entries.filter((entry) => entry.status === "completed").length,
|
|
482
575
|
"/",
|
|
483
576
|
entries.length
|
|
484
577
|
] })
|
|
485
578
|
] }),
|
|
486
|
-
open ? /* @__PURE__ */
|
|
579
|
+
open ? /* @__PURE__ */ jsx3("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx3(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
|
|
487
580
|
] });
|
|
488
581
|
}
|
|
489
582
|
function TaskPlan({ plan }) {
|
|
490
583
|
if (!plan.items.length) return null;
|
|
491
584
|
const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
|
|
492
|
-
return /* @__PURE__ */
|
|
493
|
-
/* @__PURE__ */
|
|
494
|
-
/* @__PURE__ */
|
|
495
|
-
/* @__PURE__ */
|
|
585
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-plan", children: [
|
|
586
|
+
/* @__PURE__ */ jsxs2("summary", { children: [
|
|
587
|
+
/* @__PURE__ */ jsx3("span", { children: "Plan" }),
|
|
588
|
+
/* @__PURE__ */ jsxs2("small", { children: [
|
|
496
589
|
complete,
|
|
497
590
|
"/",
|
|
498
591
|
plan.items.length
|
|
499
592
|
] })
|
|
500
593
|
] }),
|
|
501
|
-
/* @__PURE__ */
|
|
502
|
-
/* @__PURE__ */
|
|
594
|
+
/* @__PURE__ */ jsx3("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs2("li", { "data-status": item.status, children: [
|
|
595
|
+
/* @__PURE__ */ jsx3("i", { "aria-hidden": "true" }),
|
|
503
596
|
" ",
|
|
504
|
-
/* @__PURE__ */
|
|
597
|
+
/* @__PURE__ */ jsx3("span", { children: item.title })
|
|
505
598
|
] }, item.id)) })
|
|
506
599
|
] });
|
|
507
600
|
}
|
|
508
601
|
function SessionDetails({ semantics }) {
|
|
509
602
|
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__ */
|
|
603
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-details", children: [
|
|
604
|
+
/* @__PURE__ */ jsx3("summary", { children: "Session details" }),
|
|
605
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
606
|
+
semantics.fidelity ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
607
|
+
/* @__PURE__ */ jsx3("strong", { children: "Fidelity" }),
|
|
608
|
+
/* @__PURE__ */ jsx3("span", { children: semantics.fidelity.replaceAll("_", " ") })
|
|
516
609
|
] }) : null,
|
|
517
|
-
/* @__PURE__ */
|
|
518
|
-
/* @__PURE__ */
|
|
519
|
-
/* @__PURE__ */
|
|
610
|
+
/* @__PURE__ */ jsxs2("p", { children: [
|
|
611
|
+
/* @__PURE__ */ jsx3("strong", { children: "Native records" }),
|
|
612
|
+
/* @__PURE__ */ jsx3("span", { children: semantics.rawRecords })
|
|
520
613
|
] }),
|
|
521
|
-
semantics.residueCount ? /* @__PURE__ */
|
|
522
|
-
/* @__PURE__ */
|
|
523
|
-
/* @__PURE__ */
|
|
614
|
+
semantics.residueCount ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
615
|
+
/* @__PURE__ */ jsx3("strong", { children: "Residue" }),
|
|
616
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
524
617
|
semantics.residueCount,
|
|
525
618
|
" retained"
|
|
526
619
|
] })
|
|
527
620
|
] }) : null,
|
|
528
|
-
semantics.parseErrors ? /* @__PURE__ */
|
|
529
|
-
/* @__PURE__ */
|
|
530
|
-
/* @__PURE__ */
|
|
621
|
+
semantics.parseErrors ? /* @__PURE__ */ jsxs2("p", { children: [
|
|
622
|
+
/* @__PURE__ */ jsx3("strong", { children: "Parse diagnostics" }),
|
|
623
|
+
/* @__PURE__ */ jsx3("span", { children: semantics.parseErrors })
|
|
531
624
|
] }) : null,
|
|
532
|
-
semantics.subagents.map((agent) => /* @__PURE__ */
|
|
533
|
-
/* @__PURE__ */
|
|
625
|
+
semantics.subagents.map((agent) => /* @__PURE__ */ jsxs2("p", { children: [
|
|
626
|
+
/* @__PURE__ */ jsxs2("strong", { children: [
|
|
534
627
|
agent.source,
|
|
535
628
|
" subagent"
|
|
536
629
|
] }),
|
|
537
|
-
/* @__PURE__ */
|
|
630
|
+
/* @__PURE__ */ jsxs2("span", { children: [
|
|
538
631
|
agent.messages,
|
|
539
632
|
" messages \xB7 ",
|
|
540
633
|
agent.fidelity.replaceAll("_", " ")
|
|
@@ -544,24 +637,24 @@ function SessionDetails({ semantics }) {
|
|
|
544
637
|
] });
|
|
545
638
|
}
|
|
546
639
|
var conversationMemory = /* @__PURE__ */ new Map();
|
|
547
|
-
var composerMemory = /* @__PURE__ */ new Map();
|
|
548
640
|
function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null }) {
|
|
549
|
-
const scroller =
|
|
641
|
+
const scroller = useRef2(null);
|
|
550
642
|
const remembered = conversationMemory.get(memoryKey) ?? { top: null, atBottom: true };
|
|
551
|
-
const [atBottom, setAtBottom] =
|
|
552
|
-
const earlierAnchor =
|
|
553
|
-
const restored =
|
|
643
|
+
const [atBottom, setAtBottom] = useState2(remembered.atBottom);
|
|
644
|
+
const earlierAnchor = useRef2(null);
|
|
645
|
+
const restored = useRef2(false);
|
|
554
646
|
const blocks = groupConversation(state.transcript);
|
|
555
647
|
const Entry = components.TranscriptEntry ?? TranscriptEntry;
|
|
556
648
|
const Group = components.ActivityGroup ?? ActivityGroup;
|
|
557
649
|
const Before = slots.beforeConversation;
|
|
558
650
|
const After = slots.afterConversation;
|
|
559
651
|
const Empty = slots.emptyConversation;
|
|
652
|
+
const remember = (value) => boundedSet(conversationMemory, memoryKey, value);
|
|
560
653
|
const pin = () => {
|
|
561
654
|
if (!scroller.current) return;
|
|
562
655
|
scroller.current.scrollTop = scroller.current.scrollHeight;
|
|
563
656
|
setAtBottom(true);
|
|
564
|
-
|
|
657
|
+
remember({ top: scroller.current.scrollTop, atBottom: true });
|
|
565
658
|
};
|
|
566
659
|
useLayoutEffect(() => {
|
|
567
660
|
const element = scroller.current;
|
|
@@ -570,7 +663,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
570
663
|
if (anchor && state.transcript.length > anchor.entries) {
|
|
571
664
|
element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
|
|
572
665
|
earlierAnchor.current = null;
|
|
573
|
-
|
|
666
|
+
remember({ top: element.scrollTop, atBottom: false });
|
|
574
667
|
return;
|
|
575
668
|
}
|
|
576
669
|
if (!restored.current) {
|
|
@@ -579,178 +672,154 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
|
|
|
579
672
|
else pin();
|
|
580
673
|
} else if (atBottom) pin();
|
|
581
674
|
}, [memoryKey, state.transcript.length, state.busy]);
|
|
582
|
-
return /* @__PURE__ */
|
|
583
|
-
/* @__PURE__ */
|
|
675
|
+
return /* @__PURE__ */ jsxs2("div", { class: "scui-conversation-wrap", children: [
|
|
676
|
+
/* @__PURE__ */ jsx3("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
|
|
584
677
|
const element = event.currentTarget;
|
|
585
678
|
const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
|
|
586
679
|
setAtBottom(bottom);
|
|
587
|
-
|
|
588
|
-
}, children: /* @__PURE__ */
|
|
589
|
-
Before ? /* @__PURE__ */
|
|
590
|
-
/* @__PURE__ */
|
|
591
|
-
/* @__PURE__ */
|
|
592
|
-
state.history.hasEarlier ? /* @__PURE__ */
|
|
680
|
+
remember({ top: element.scrollTop, atBottom: bottom });
|
|
681
|
+
}, children: /* @__PURE__ */ jsxs2("div", { children: [
|
|
682
|
+
Before ? /* @__PURE__ */ jsx3(Before, { state, adapter, value: null }) : null,
|
|
683
|
+
/* @__PURE__ */ jsx3(TaskPlan, { plan: state.taskPlan }),
|
|
684
|
+
/* @__PURE__ */ jsx3(SessionDetails, { semantics: state.semantics }),
|
|
685
|
+
state.history.hasEarlier ? /* @__PURE__ */ jsx3("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
|
|
593
686
|
const element = scroller.current;
|
|
594
687
|
if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
|
|
595
688
|
setAtBottom(false);
|
|
596
689
|
adapter.onIntent({ action: "loadEarlier" });
|
|
597
690
|
}, 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__ */
|
|
691
|
+
!blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx3(LoadingStatus, { state }) : null,
|
|
692
|
+
!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,
|
|
693
|
+
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)),
|
|
694
|
+
pending ? /* @__PURE__ */ jsxs2("article", { class: "scui-message scui-pending", "data-role": "user", children: [
|
|
695
|
+
/* @__PURE__ */ jsx3(Markdown, { value: pending }),
|
|
696
|
+
/* @__PURE__ */ jsx3("small", { children: state.error && !state.busy ? "Not sent" : "Sending\u2026" })
|
|
604
697
|
] }) : null,
|
|
605
|
-
state.busy ? /* @__PURE__ */
|
|
606
|
-
/* @__PURE__ */
|
|
607
|
-
/* @__PURE__ */
|
|
608
|
-
/* @__PURE__ */
|
|
609
|
-
/* @__PURE__ */
|
|
610
|
-
/* @__PURE__ */
|
|
698
|
+
state.busy ? /* @__PURE__ */ jsxs2("div", { class: "scui-working", role: "status", children: [
|
|
699
|
+
/* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u2726" }),
|
|
700
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
701
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
702
|
+
/* @__PURE__ */ jsx3("i", {}),
|
|
703
|
+
/* @__PURE__ */ jsxs2("small", { children: [
|
|
611
704
|
harnessDisplayName(state.harness),
|
|
612
705
|
" is working"
|
|
613
706
|
] })
|
|
614
707
|
] }) : null,
|
|
615
|
-
After ? /* @__PURE__ */
|
|
708
|
+
After ? /* @__PURE__ */ jsx3(After, { state, adapter, value: null }) : null
|
|
616
709
|
] }) }),
|
|
617
|
-
!atBottom ? /* @__PURE__ */
|
|
710
|
+
!atBottom ? /* @__PURE__ */ jsx3("button", { class: "scui-latest", type: "button", onClick: pin, children: "\u2193 Latest" }) : null
|
|
711
|
+
] });
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// src/logo.jsx
|
|
715
|
+
import { useEffect as useEffect3 } from "preact/hooks";
|
|
716
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
717
|
+
var LOGOS = {
|
|
718
|
+
"claude-code": {
|
|
719
|
+
viewBox: "-1 3.5 26 18",
|
|
720
|
+
paths: [
|
|
721
|
+
["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" }]
|
|
722
|
+
]
|
|
723
|
+
},
|
|
724
|
+
codex: {
|
|
725
|
+
viewBox: "-1 -1 26 26",
|
|
726
|
+
paths: [
|
|
727
|
+
["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" }]
|
|
728
|
+
]
|
|
729
|
+
},
|
|
730
|
+
gemini: {
|
|
731
|
+
viewBox: "0 0 24 24",
|
|
732
|
+
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" }]]
|
|
733
|
+
},
|
|
734
|
+
grok: {
|
|
735
|
+
viewBox: "-1 -1 26 26",
|
|
736
|
+
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" }]]
|
|
737
|
+
},
|
|
738
|
+
opencode: { viewBox: "2.5 0 19 24", paths: [["path", { d: "M16 6H8v12h8V6zm4 16H4V2h16v20z" }]] },
|
|
739
|
+
pi: {
|
|
740
|
+
viewBox: "0 0 24 24",
|
|
741
|
+
paths: [
|
|
742
|
+
["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M1 1h16.5v11H12v5.5H6.5V23H1V1zm5.5 5.5V12H12V6.5H6.5z" }],
|
|
743
|
+
["path", { d: "M17.5 12H23v11h-5.5V12z" }]
|
|
744
|
+
]
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
function hasHarnessLogo(id) {
|
|
748
|
+
return Object.hasOwn(LOGOS, id);
|
|
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
|
|
618
759
|
] });
|
|
619
760
|
}
|
|
761
|
+
|
|
762
|
+
// src/messenger.jsx
|
|
763
|
+
import { useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "preact/hooks";
|
|
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,39 +979,40 @@ 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
|
export {
|