@volter-ai-dev/supercode-ui 0.1.1 → 0.1.2

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