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

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,15 @@
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
+ goose: "Goose",
12
13
  opencode: "OpenCode",
13
14
  pi: "Pi",
14
15
  grok: "Grok"
@@ -63,7 +64,7 @@ var EMPTY_UI_STATE = Object.freeze({
63
64
  });
64
65
  var ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool", "reasoning", "request", "notice"]);
65
66
  var MODES = /* @__PURE__ */ new Set(["none", "control", "mirror"]);
66
- var STRATEGIES = /* @__PURE__ */ new Set(["start", "resume", "attach", "branch"]);
67
+ var STRATEGIES = /* @__PURE__ */ new Set(["start", "resume", "attach", "branch", "reduce"]);
67
68
  var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering", "ready"]);
68
69
  var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
69
70
  function record(value) {
@@ -187,6 +188,35 @@ function readSemantics(value) {
187
188
  }) : []
188
189
  };
189
190
  }
191
+ function readTerminalHandoff(value) {
192
+ const handoff = record(value);
193
+ 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;
194
+ return { program: handoff.program, arguments: [...handoff.arguments], cwd: handoff.cwd };
195
+ }
196
+ function readExportReceipt(value) {
197
+ const receipt = record(value);
198
+ 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;
199
+ return {
200
+ targetHarness: receipt.targetHarness,
201
+ fidelity: receipt.fidelity,
202
+ path: receipt.path,
203
+ files: receipt.files,
204
+ residueCount: receipt.residueCount
205
+ };
206
+ }
207
+ function readReductionReceipt(value) {
208
+ const receipt = record(value);
209
+ 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;
210
+ return {
211
+ sourceTokens: receipt.sourceTokens,
212
+ reducedTokens: receipt.reducedTokens,
213
+ ratio: receipt.ratio,
214
+ sidecarId: receipt.sidecarId,
215
+ verified: true,
216
+ reversible: true,
217
+ targetHarness: receipt.targetHarness
218
+ };
219
+ }
190
220
  function normalizeUiState(value) {
191
221
  const raw = record(value) ?? {};
192
222
  const pill = record(raw.pill);
@@ -216,10 +246,10 @@ function normalizeUiState(value) {
216
246
  workspace: string(raw.workspace),
217
247
  taskPlan: readTaskPlan(raw.taskPlan),
218
248
  semantics: readSemantics(raw.semantics),
219
- terminalHandoff: record(raw.terminalHandoff),
249
+ terminalHandoff: readTerminalHandoff(raw.terminalHandoff),
220
250
  exportBackTarget: typeof raw.exportBackTarget === "string" ? raw.exportBackTarget : null,
221
- exportReceipt: record(raw.exportReceipt),
222
- reductionReceipt: record(raw.reductionReceipt),
251
+ exportReceipt: readExportReceipt(raw.exportReceipt),
252
+ reductionReceipt: readReductionReceipt(raw.reductionReceipt),
223
253
  error: typeof raw.error === "string" ? raw.error : null,
224
254
  recoverable: raw.recoverable === true,
225
255
  harnesses: Array.isArray(raw.harnesses) ? raw.harnesses.flatMap((candidate) => {
@@ -324,8 +354,112 @@ function isSendKey(event) {
324
354
  return event.key === "Enter" && !event.shiftKey && !event.isComposing;
325
355
  }
326
356
 
327
- // src/components.jsx
357
+ // src/composer.jsx
358
+ import { useEffect, useRef, useState } from "preact/hooks";
359
+
360
+ // src/memory.js
361
+ var MEMORY_LIMIT = 100;
362
+ function boundedSet(map, key, value) {
363
+ map.delete(key);
364
+ map.set(key, value);
365
+ while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
366
+ }
367
+
368
+ // src/composer.jsx
328
369
  import { jsx, jsxs } from "preact/jsx-runtime";
370
+ var composerMemory = /* @__PURE__ */ new Map();
371
+ function ContinuationBar({ state, adapter, labels = DEFAULT_LABELS }) {
372
+ if (state.mode !== "mirror" || state.canSend) return null;
373
+ const attached = state.attached;
374
+ const row = attached?.key ? state.sessions.find((item) => item.key === attached.key) : null;
375
+ const activeElsewhere = row?.runtimeStatus === "busy" || row?.runtimeStatus === "idle";
376
+ const resume = canContinueHere(state);
377
+ const join = state.canAttach;
378
+ const branch = state.canBranch;
379
+ if (!resume && !join && !branch) return /* @__PURE__ */ jsx("div", { class: "scui-continuation", children: /* @__PURE__ */ jsxs("span", { children: [
380
+ /* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
381
+ /* @__PURE__ */ jsx("small", { children: "This session cannot be continued by an available harness." })
382
+ ] }) });
383
+ return /* @__PURE__ */ jsxs("div", { class: "scui-continuation", children: [
384
+ /* @__PURE__ */ jsxs("span", { children: [
385
+ /* @__PURE__ */ jsx("strong", { children: activeElsewhere ? "Active elsewhere" : "Read-only" }),
386
+ /* @__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." })
387
+ ] }),
388
+ /* @__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 })
389
+ ] });
390
+ }
391
+ function Composer({ state, adapter, labels = DEFAULT_LABELS, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, onPending }) {
392
+ const remembered = composerMemory.get(memoryKey) ?? { draft: state.savedDraft, queue: [] };
393
+ const [draft, setDraft] = useState(remembered.draft);
394
+ const [queue, setQueue] = useState(remembered.queue);
395
+ const textarea = useRef(null);
396
+ const remember = (nextDraft, nextQueue) => boundedSet(composerMemory, memoryKey, { draft: nextDraft, queue: nextQueue });
397
+ const updateQueue = (update) => setQueue((items) => {
398
+ const next = update(items);
399
+ remember(draft, next);
400
+ return next;
401
+ });
402
+ useEffect(() => {
403
+ if (!state.busy && state.canSend && queue.length) {
404
+ const [next, ...rest] = queue;
405
+ setQueue(rest);
406
+ remember(draft, rest);
407
+ onPending?.(next);
408
+ adapter.onIntent({ action: "send", text: next });
409
+ }
410
+ }, [adapter, draft, memoryKey, onPending, queue, state.busy, state.canSend]);
411
+ useEffect(() => {
412
+ const timer = setTimeout(() => adapter.onIntent({ action: "draft", text: draft }), 250);
413
+ return () => clearTimeout(timer);
414
+ }, [adapter, draft]);
415
+ const send = () => {
416
+ const text = draft.trim();
417
+ if (!text) return;
418
+ if (state.busy) updateQueue((items) => [...items, text]);
419
+ else if (state.canSend) {
420
+ onPending?.(text);
421
+ adapter.onIntent({ action: "send", text });
422
+ } else return;
423
+ setDraft("");
424
+ remember("", state.busy ? [...queue, text] : queue);
425
+ };
426
+ return /* @__PURE__ */ jsxs("div", { class: "scui-compose", children: [
427
+ queue.length ? /* @__PURE__ */ jsxs("div", { class: "scui-queue", children: [
428
+ /* @__PURE__ */ jsxs("strong", { children: [
429
+ queue.length,
430
+ " queued"
431
+ ] }),
432
+ queue.map((item, index) => /* @__PURE__ */ jsxs("span", { children: [
433
+ item,
434
+ /* @__PURE__ */ jsx("button", { type: "button", "aria-label": `Remove queued message ${index + 1}`, onClick: () => updateQueue((items) => items.filter((_, itemIndex) => itemIndex !== index)), children: "\xD7" })
435
+ ] }, `${index}:${item}`))
436
+ ] }) : null,
437
+ /* @__PURE__ */ jsxs("div", { class: "scui-envelope", children: [
438
+ /* @__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) => {
439
+ const value = event.currentTarget.value;
440
+ setDraft(value);
441
+ remember(value, queue);
442
+ }, onKeyDown: (event) => {
443
+ if (isSendKey(event)) {
444
+ event.preventDefault();
445
+ send();
446
+ }
447
+ } }),
448
+ /* @__PURE__ */ jsxs("span", { children: [
449
+ 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,
450
+ /* @__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" })
451
+ ] })
452
+ ] })
453
+ ] });
454
+ }
455
+
456
+ // src/conversation.jsx
457
+ import { useEffect as useEffect2, useId, useLayoutEffect, useRef as useRef2, useState as useState2 } from "preact/hooks";
458
+
459
+ // src/markdown.jsx
460
+ import MarkdownIt from "markdown-it";
461
+ import { useMemo } from "preact/hooks";
462
+ import { jsx as jsx2 } from "preact/jsx-runtime";
329
463
  var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
330
464
  var defaultLinkOpen = markdown.renderer.rules.link_open;
331
465
  markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
@@ -333,47 +467,13 @@ markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
333
467
  tokens[index]?.attrSet("rel", "noreferrer noopener");
334
468
  return defaultLinkOpen ? defaultLinkOpen(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
335
469
  };
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
470
  function Markdown({ value }) {
363
471
  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
- ] });
472
+ return /* @__PURE__ */ jsx2("div", { class: "scui-markdown", dangerouslySetInnerHTML: { __html: html } });
376
473
  }
474
+
475
+ // src/conversation.jsx
476
+ import { jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
377
477
  function LoadingStatus({ state, compact = false }) {
378
478
  const copy = {
379
479
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -381,83 +481,83 @@ function LoadingStatus({ state, compact = false }) {
381
481
  discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
382
482
  ready: ["Ready", "Coding sessions are up to date.", 3]
383
483
  }[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] })
484
+ return /* @__PURE__ */ jsxs2("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
485
+ /* @__PURE__ */ jsx3("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("i", {}) }),
486
+ /* @__PURE__ */ jsxs2("span", { class: "scui-loading-copy", children: [
487
+ /* @__PURE__ */ jsx3("strong", { children: copy[0] }),
488
+ /* @__PURE__ */ jsx3("small", { children: copy[1] })
389
489
  ] }),
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)) })
490
+ /* @__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
491
  ] });
392
492
  }
393
493
  function RequestCard({ entry, adapter, canRespond }) {
394
494
  const request = entry.request;
395
495
  if (!request) return null;
396
496
  if (request.status === "responded") {
397
- return /* @__PURE__ */ jsxs("div", { class: "scui-request-done", children: [
497
+ return /* @__PURE__ */ jsxs2("div", { class: "scui-request-done", children: [
398
498
  "\u2713 Request answered \xB7 ",
399
499
  request.resolution?.name ?? request.requestKind
400
500
  ] });
401
501
  }
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
502
+ return /* @__PURE__ */ jsxs2("section", { class: "scui-request", "aria-label": `${request.requestKind} needs input`, children: [
503
+ /* @__PURE__ */ jsx3("strong", { children: "Agent needs input" }),
504
+ /* @__PURE__ */ jsx3(Markdown, { value: request.payloadText || entry.text }),
505
+ /* @__PURE__ */ jsxs2("div", { class: "scui-request-actions", children: [
506
+ 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)),
507
+ request.cancellable ? /* @__PURE__ */ jsx3("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
408
508
  ] })
409
509
  ] });
410
510
  }
411
511
  function ContextDisclosure({ context }) {
412
512
  if (!context?.length) return null;
413
- return /* @__PURE__ */ jsxs("details", { class: "scui-context", children: [
414
- /* @__PURE__ */ jsxs("summary", { children: [
513
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-context", children: [
514
+ /* @__PURE__ */ jsxs2("summary", { children: [
415
515
  "Context \xB7 ",
416
516
  context.length
417
517
  ] }),
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 })
518
+ /* @__PURE__ */ jsx3("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs2("p", { children: [
519
+ /* @__PURE__ */ jsx3("strong", { children: item.label }),
520
+ /* @__PURE__ */ jsx3("span", { children: item.detail })
421
521
  ] }, item.id ?? index)) })
422
522
  ] });
423
523
  }
424
524
  function TranscriptEntry({ entry, state, adapter }) {
425
- if (entry.role === "request") return /* @__PURE__ */ jsx(RequestCard, { entry, adapter, canRespond: state.canRespond });
525
+ if (entry.role === "request") return /* @__PURE__ */ jsx3(RequestCard, { entry, adapter, canRespond: state.canRespond });
426
526
  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 })
527
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-reasoning", open: entry.streaming, children: [
528
+ /* @__PURE__ */ jsx3("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
529
+ /* @__PURE__ */ jsx3(Markdown, { value: entry.text })
430
530
  ] });
431
531
  }
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
532
+ if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx3("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
533
+ return /* @__PURE__ */ jsxs2("article", { class: "scui-message", "data-role": entry.role, children: [
534
+ /* @__PURE__ */ jsx3(Markdown, { value: entry.text }),
535
+ /* @__PURE__ */ jsx3(ContextDisclosure, { context: entry.context }),
536
+ entry.truncated ? /* @__PURE__ */ jsx3("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
437
537
  ] });
438
538
  }
439
539
  function ToolRow({ entry, workspace }) {
440
- const [open, setOpen] = useState(entry.status === "pending");
540
+ const [open, setOpen] = useState2(entry.status === "pending");
441
541
  const detailId = useId();
442
542
  const target = compactToolTarget(toolTarget(entry.arguments), workspace);
443
543
  const hasDetail = Boolean(entry.arguments || entry.resultText);
444
544
  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" })
545
+ return /* @__PURE__ */ jsxs2("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
546
+ /* @__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: [
547
+ /* @__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] }),
548
+ /* @__PURE__ */ jsx3("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
549
+ target ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
550
+ /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
551
+ /* @__PURE__ */ jsx3("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
452
552
  ] }),
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" }),
553
+ hasDetail && open ? /* @__PURE__ */ jsxs2("div", { id: detailId, class: "scui-tool-detail", children: [
554
+ entry.arguments ? /* @__PURE__ */ jsxs2("pre", { children: [
555
+ /* @__PURE__ */ jsx3("b", { children: "Input" }),
456
556
  "\n",
457
557
  entry.arguments
458
558
  ] }) : null,
459
- entry.resultText ? /* @__PURE__ */ jsxs("pre", { "data-error": entry.status === "error", children: [
460
- /* @__PURE__ */ jsx("b", { children: "Output" }),
559
+ entry.resultText ? /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
560
+ /* @__PURE__ */ jsx3("b", { children: "Output" }),
461
561
  "\n",
462
562
  entry.resultText,
463
563
  entry.truncated ? "\n[truncated]" : ""
@@ -467,74 +567,74 @@ function ToolRow({ entry, workspace }) {
467
567
  }
468
568
  function ActivityGroup({ entries, state }) {
469
569
  const active = entries.some((entry) => entry.status === "pending");
470
- const [open, setOpen] = useState(active);
570
+ const [open, setOpen] = useState2(active);
471
571
  const id = useId();
472
- useEffect(() => {
572
+ useEffect2(() => {
473
573
  if (active) setOpen(true);
474
574
  }, [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: [
575
+ return /* @__PURE__ */ jsxs2("section", { class: "scui-activity", children: [
576
+ /* @__PURE__ */ jsxs2("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
577
+ /* @__PURE__ */ jsx3("span", { class: "scui-fold", "data-open": open, children: "\u203A" }),
578
+ /* @__PURE__ */ jsx3("strong", { children: activitySummary(entries) }),
579
+ /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
580
+ /* @__PURE__ */ jsxs2("small", { children: [
481
581
  entries.filter((entry) => entry.status === "completed").length,
482
582
  "/",
483
583
  entries.length
484
584
  ] })
485
585
  ] }),
486
- open ? /* @__PURE__ */ jsx("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
586
+ open ? /* @__PURE__ */ jsx3("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx3(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
487
587
  ] });
488
588
  }
489
589
  function TaskPlan({ plan }) {
490
590
  if (!plan.items.length) return null;
491
591
  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: [
592
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-plan", children: [
593
+ /* @__PURE__ */ jsxs2("summary", { children: [
594
+ /* @__PURE__ */ jsx3("span", { children: "Plan" }),
595
+ /* @__PURE__ */ jsxs2("small", { children: [
496
596
  complete,
497
597
  "/",
498
598
  plan.items.length
499
599
  ] })
500
600
  ] }),
501
- /* @__PURE__ */ jsx("ol", { children: plan.items.map((item) => /* @__PURE__ */ jsxs("li", { "data-status": item.status, children: [
502
- /* @__PURE__ */ jsx("i", { "aria-hidden": "true" }),
601
+ /* @__PURE__ */ jsx3("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs2("li", { "data-status": item.status, children: [
602
+ /* @__PURE__ */ jsx3("i", { "aria-hidden": "true" }),
503
603
  " ",
504
- /* @__PURE__ */ jsx("span", { children: item.title })
604
+ /* @__PURE__ */ jsx3("span", { children: item.title })
505
605
  ] }, item.id)) })
506
606
  ] });
507
607
  }
508
608
  function SessionDetails({ semantics }) {
509
609
  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("_", " ") })
610
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-details", children: [
611
+ /* @__PURE__ */ jsx3("summary", { children: "Session details" }),
612
+ /* @__PURE__ */ jsxs2("div", { children: [
613
+ semantics.fidelity ? /* @__PURE__ */ jsxs2("p", { children: [
614
+ /* @__PURE__ */ jsx3("strong", { children: "Fidelity" }),
615
+ /* @__PURE__ */ jsx3("span", { children: semantics.fidelity.replaceAll("_", " ") })
516
616
  ] }) : null,
517
- /* @__PURE__ */ jsxs("p", { children: [
518
- /* @__PURE__ */ jsx("strong", { children: "Native records" }),
519
- /* @__PURE__ */ jsx("span", { children: semantics.rawRecords })
617
+ /* @__PURE__ */ jsxs2("p", { children: [
618
+ /* @__PURE__ */ jsx3("strong", { children: "Native records" }),
619
+ /* @__PURE__ */ jsx3("span", { children: semantics.rawRecords })
520
620
  ] }),
521
- semantics.residueCount ? /* @__PURE__ */ jsxs("p", { children: [
522
- /* @__PURE__ */ jsx("strong", { children: "Residue" }),
523
- /* @__PURE__ */ jsxs("span", { children: [
621
+ semantics.residueCount ? /* @__PURE__ */ jsxs2("p", { children: [
622
+ /* @__PURE__ */ jsx3("strong", { children: "Residue" }),
623
+ /* @__PURE__ */ jsxs2("span", { children: [
524
624
  semantics.residueCount,
525
625
  " retained"
526
626
  ] })
527
627
  ] }) : null,
528
- semantics.parseErrors ? /* @__PURE__ */ jsxs("p", { children: [
529
- /* @__PURE__ */ jsx("strong", { children: "Parse diagnostics" }),
530
- /* @__PURE__ */ jsx("span", { children: semantics.parseErrors })
628
+ semantics.parseErrors ? /* @__PURE__ */ jsxs2("p", { children: [
629
+ /* @__PURE__ */ jsx3("strong", { children: "Parse diagnostics" }),
630
+ /* @__PURE__ */ jsx3("span", { children: semantics.parseErrors })
531
631
  ] }) : null,
532
- semantics.subagents.map((agent) => /* @__PURE__ */ jsxs("p", { children: [
533
- /* @__PURE__ */ jsxs("strong", { children: [
632
+ semantics.subagents.map((agent) => /* @__PURE__ */ jsxs2("p", { children: [
633
+ /* @__PURE__ */ jsxs2("strong", { children: [
534
634
  agent.source,
535
635
  " subagent"
536
636
  ] }),
537
- /* @__PURE__ */ jsxs("span", { children: [
637
+ /* @__PURE__ */ jsxs2("span", { children: [
538
638
  agent.messages,
539
639
  " messages \xB7 ",
540
640
  agent.fidelity.replaceAll("_", " ")
@@ -544,24 +644,24 @@ function SessionDetails({ semantics }) {
544
644
  ] });
545
645
  }
546
646
  var conversationMemory = /* @__PURE__ */ new Map();
547
- var composerMemory = /* @__PURE__ */ new Map();
548
647
  function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null }) {
549
- const scroller = useRef(null);
648
+ const scroller = useRef2(null);
550
649
  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);
650
+ const [atBottom, setAtBottom] = useState2(remembered.atBottom);
651
+ const earlierAnchor = useRef2(null);
652
+ const restored = useRef2(false);
554
653
  const blocks = groupConversation(state.transcript);
555
654
  const Entry = components.TranscriptEntry ?? TranscriptEntry;
556
655
  const Group = components.ActivityGroup ?? ActivityGroup;
557
656
  const Before = slots.beforeConversation;
558
657
  const After = slots.afterConversation;
559
658
  const Empty = slots.emptyConversation;
659
+ const remember = (value) => boundedSet(conversationMemory, memoryKey, value);
560
660
  const pin = () => {
561
661
  if (!scroller.current) return;
562
662
  scroller.current.scrollTop = scroller.current.scrollHeight;
563
663
  setAtBottom(true);
564
- conversationMemory.set(memoryKey, { top: scroller.current.scrollTop, atBottom: true });
664
+ remember({ top: scroller.current.scrollTop, atBottom: true });
565
665
  };
566
666
  useLayoutEffect(() => {
567
667
  const element = scroller.current;
@@ -570,7 +670,7 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
570
670
  if (anchor && state.transcript.length > anchor.entries) {
571
671
  element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
572
672
  earlierAnchor.current = null;
573
- conversationMemory.set(memoryKey, { top: element.scrollTop, atBottom: false });
673
+ remember({ top: element.scrollTop, atBottom: false });
574
674
  return;
575
675
  }
576
676
  if (!restored.current) {
@@ -579,178 +679,153 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
579
679
  else pin();
580
680
  } else if (atBottom) pin();
581
681
  }, [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) => {
682
+ return /* @__PURE__ */ jsxs2("div", { class: "scui-conversation-wrap", children: [
683
+ /* @__PURE__ */ jsx3("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
584
684
  const element = event.currentTarget;
585
685
  const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
586
686
  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: () => {
687
+ remember({ top: element.scrollTop, atBottom: bottom });
688
+ }, children: /* @__PURE__ */ jsxs2("div", { children: [
689
+ Before ? /* @__PURE__ */ jsx3(Before, { state, adapter, value: null }) : null,
690
+ /* @__PURE__ */ jsx3(TaskPlan, { plan: state.taskPlan }),
691
+ /* @__PURE__ */ jsx3(SessionDetails, { semantics: state.semantics }),
692
+ state.history.hasEarlier ? /* @__PURE__ */ jsx3("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
593
693
  const element = scroller.current;
594
694
  if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
595
695
  setAtBottom(false);
596
696
  adapter.onIntent({ action: "loadEarlier" });
597
697
  }, 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" })
698
+ !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx3(LoadingStatus, { state }) : null,
699
+ !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,
700
+ 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)),
701
+ pending ? /* @__PURE__ */ jsxs2("article", { class: "scui-message scui-pending", "data-role": "user", children: [
702
+ /* @__PURE__ */ jsx3(Markdown, { value: pending }),
703
+ /* @__PURE__ */ jsx3("small", { children: state.error && !state.busy ? "Not sent" : "Sending\u2026" })
604
704
  ] }) : 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: [
705
+ state.busy ? /* @__PURE__ */ jsxs2("div", { class: "scui-working", role: "status", children: [
706
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u2726" }),
707
+ /* @__PURE__ */ jsx3("i", {}),
708
+ /* @__PURE__ */ jsx3("i", {}),
709
+ /* @__PURE__ */ jsx3("i", {}),
710
+ /* @__PURE__ */ jsxs2("small", { children: [
611
711
  harnessDisplayName(state.harness),
612
712
  " is working"
613
713
  ] })
614
714
  ] }) : null,
615
- After ? /* @__PURE__ */ jsx(After, { state, adapter, value: null }) : null
715
+ After ? /* @__PURE__ */ jsx3(After, { state, adapter, value: null }) : null
616
716
  ] }) }),
617
- !atBottom ? /* @__PURE__ */ jsx("button", { class: "scui-latest", type: "button", onClick: pin, children: "\u2193 Latest" }) : null
717
+ !atBottom ? /* @__PURE__ */ jsx3("button", { class: "scui-latest", type: "button", onClick: pin, children: "\u2193 Latest" }) : null
618
718
  ] });
619
719
  }
720
+
721
+ // src/logo.jsx
722
+ import { useEffect as useEffect3 } from "preact/hooks";
723
+ import { jsx as jsx4, jsxs as jsxs3 } from "preact/jsx-runtime";
724
+ var LOGOS = {
725
+ "claude-code": {
726
+ viewBox: "-1 3.5 26 18",
727
+ paths: [
728
+ ["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" }]
729
+ ]
730
+ },
731
+ codex: {
732
+ viewBox: "-1 -1 26 26",
733
+ paths: [
734
+ ["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" }]
735
+ ]
736
+ },
737
+ gemini: {
738
+ viewBox: "0 0 24 24",
739
+ 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" }]]
740
+ },
741
+ grok: {
742
+ viewBox: "-1 -1 26 26",
743
+ 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" }]]
744
+ },
745
+ // Canonical mark from block/goose's documentation/static/img/goose.svg.
746
+ goose: {
747
+ viewBox: "0 0 45 45",
748
+ paths: [["path", { d: "M43.2098 39.2492L39.8118 36.4522C37.9646 34.9318 36.3923 33.1051 35.1631 31.0529C33.4647 28.2172 31.1178 25.8243 28.3164 24.071L26.9482 23.2744C26.4794 22.9485 26.1525 22.4405 26.106 21.8675C26.0762 21.4981 26.1647 21.1678 26.3712 20.8771C27.0837 19.873 30.9617 15.6995 31.6365 15.1411C32.5056 14.4228 33.4739 13.8253 34.3724 13.1412C34.5001 13.0438 34.6283 12.9469 34.7545 12.8481C35.0574 12.6088 35.3295 12.3671 35.5458 12.0803C36.5993 10.8604 36.5783 9.82938 36.5783 9.82938C36.4677 9.5534 36.0645 8.69902 35.2449 8.29825C35.9696 8.28406 36.7872 8.55564 37.1582 8.91873C37.6039 8.21947 37.8922 7.76585 38.3404 7.00347C38.4471 6.82241 38.5038 6.48771 38.2998 6.30029C38.1114 6.11287 37.6416 6.01697 37.4606 6.12364C36.4692 6.70693 35.5047 7.33475 34.6351 7.88525C34.6351 7.88525 33.6046 7.86372 32.3842 8.91775C32.097 9.13452 31.8552 9.4066 31.6282 9.69433C31.5171 9.83476 31.4202 9.96297 31.3233 10.0912C30.6387 10.9901 30.0417 11.958 29.3234 12.8271C28.7656 13.5023 24.5915 17.3798 23.5874 18.0923C23.2967 18.2988 22.9669 18.3879 22.597 18.3575C22.0245 18.3115 21.5161 17.9842 21.1902 17.5154L20.3935 16.1472C18.6402 13.3448 16.2474 10.9989 13.4117 9.30041C11.3594 8.0712 9.5332 6.49847 8.01234 4.65172L5.2153 1.25377C5.0773 1.08642 4.81306 1.11382 4.71422 1.30662C4.39615 1.92612 3.78888 3.23411 3.32353 4.99327C3.92786 5.81095 5.26717 7.35089 6.8624 8.65351C6.97348 8.74403 6.88246 8.92313 6.74447 8.88496C5.36846 8.51013 4.03062 7.90825 3.02944 7.39542C2.94772 7.35383 2.84887 7.4057 2.83713 7.49672C2.68152 8.74354 2.64139 10.1127 2.80581 11.5562C4.02572 12.1596 5.85143 12.8804 7.76816 13.3389C7.90713 13.3722 7.90273 13.5723 7.76229 13.5992C6.26982 13.8801 4.70688 13.9427 3.43656 13.9261C3.3475 13.9251 3.28193 14.0093 3.30591 14.0949C3.56085 14.9958 3.90632 15.9118 4.3619 16.8342C4.55029 17.2487 4.75532 17.6553 4.97504 18.0532C6.21207 18.107 7.47946 17.9964 8.75369 17.7713C8.97095 17.7331 9.08741 18.0189 8.90391 18.1417C8.03877 18.7201 7.11588 19.2183 6.25758 19.6283C6.14259 19.6836 6.1054 19.8304 6.18125 19.9327C6.69114 20.6236 7.25191 21.2774 7.86114 21.8866C7.86114 21.8866 10.8608 24.9763 10.9425 25.2185C12.6928 23.4261 15.5701 21.4394 18.7474 19.7047C14.4921 23.1672 12.1198 25.7235 10.9258 27.1758L10.0935 28.3439C9.66091 28.9507 9.2856 29.5951 8.97193 30.2709C7.92231 32.5292 6.19201 37.0966 6.19201 37.0966C6.0594 37.4543 6.16755 37.8072 6.39753 38.0371C6.66031 38.2999 7.01263 38.4076 7.37033 38.275C7.37033 38.275 11.9368 36.5447 14.1961 35.495C14.8719 35.1814 15.5168 34.8056 16.1231 34.3735L17.4095 33.457C18.0907 32.9715 19.0234 33.0489 19.615 33.6405L22.5804 36.6058C23.1896 37.2151 23.8433 37.7758 24.5343 38.2857C24.637 38.3611 24.7833 38.3244 24.8386 38.2094C25.2492 37.3516 25.7473 36.4277 26.3252 35.5631C26.4481 35.3796 26.7343 35.4965 26.6957 35.7133C26.4701 36.988 26.3605 38.2554 26.3086 39.3035C27.2178 39.9172 28.5551 40.5606 30.3721 41.1611C30.4577 41.185 30.5419 41.1195 30.5409 41.0304C30.5237 39.7596 30.5864 38.1967 30.8677 36.7047C30.8942 36.5638 31.0943 36.5593 31.1281 36.6988C31.5861 38.616 32.3069 40.4417 32.8041 41.5829C34.3543 41.8256 35.7234 41.7855 36.9703 41.6298C37.0618 41.6186 37.1136 41.5197 37.0715 41.4375C36.5587 40.4364 35.9568 39.0975 35.582 37.7225C35.5443 37.584 35.7229 37.4935 35.8135 37.6046C37.1161 39.1998 38.656 40.5391 39.3548 41.1175C41.2333 40.6786 42.5413 40.0713 43.1604 39.7528C43.3532 39.6539 43.3806 39.3897 43.2132 39.2517Z" }]]
749
+ },
750
+ opencode: { viewBox: "2.5 0 19 24", paths: [["path", { d: "M16 6H8v12h8V6zm4 16H4V2h16v20z" }]] },
751
+ pi: {
752
+ viewBox: "0 0 24 24",
753
+ paths: [
754
+ ["path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M1 1h16.5v11H12v5.5H6.5V23H1V1zm5.5 5.5V12H12V6.5H6.5z" }],
755
+ ["path", { d: "M17.5 12H23v11h-5.5V12z" }]
756
+ ]
757
+ }
758
+ };
759
+ function HarnessLogo({ id, activity, size = 28, onMissingLogo }) {
760
+ const logo = LOGOS[id];
761
+ useEffect3(() => {
762
+ if (!logo) onMissingLogo?.(id);
763
+ }, [id, logo, onMissingLogo]);
764
+ if (!logo) return null;
765
+ return /* @__PURE__ */ jsxs3("span", { class: "scui-logo", "data-harness": id, "data-activity": activity, style: `--scui-logo-size:${size}px`, "aria-hidden": "true", children: [
766
+ /* @__PURE__ */ jsx4("svg", { viewBox: logo.viewBox, preserveAspectRatio: "xMidYMid meet", focusable: "false", children: logo.paths.map(([Tag, props], index) => /* @__PURE__ */ jsx4(Tag, { ...props }, index)) }),
767
+ activity && activity !== "idle" ? /* @__PURE__ */ jsx4("i", {}) : null
768
+ ] });
769
+ }
770
+
771
+ // src/sessions.jsx
772
+ import { useState as useState3 } from "preact/hooks";
773
+ import { jsx as jsx5, jsxs as jsxs4 } from "preact/jsx-runtime";
620
774
  function SessionRow({ row, state, onOpen }) {
621
775
  const activity = sessionActivity(state, row);
622
776
  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 })
777
+ return /* @__PURE__ */ jsxs4("button", { class: "scui-session", "data-active": row.active, "data-activity": activity, type: "button", onClick: () => onOpen(row), children: [
778
+ /* @__PURE__ */ jsx5(HarnessLogo, { id: row.harness, activity, size: 34 }),
779
+ /* @__PURE__ */ jsxs4("span", { class: "scui-session-copy", children: [
780
+ /* @__PURE__ */ jsxs4("span", { children: [
781
+ /* @__PURE__ */ jsx5("strong", { children: sessionDisplayName(row) }),
782
+ /* @__PURE__ */ jsx5("small", { children: row.age })
629
783
  ] }),
630
- /* @__PURE__ */ jsxs("span", { children: [
631
- /* @__PURE__ */ jsx("b", { children: harnessDisplayName(row.harness) }),
632
- /* @__PURE__ */ jsx("small", { children: preview || row.cwd || row.name })
784
+ /* @__PURE__ */ jsxs4("span", { children: [
785
+ /* @__PURE__ */ jsx5("b", { children: harnessDisplayName(row.harness) }),
786
+ /* @__PURE__ */ jsx5("small", { children: preview || row.cwd || row.name })
633
787
  ] }),
634
- state.attachError?.key === row.key ? /* @__PURE__ */ jsx("em", { children: state.attachError.message }) : null
788
+ state.attachError?.key === row.key ? /* @__PURE__ */ jsx5("em", { children: state.attachError.message }) : null
635
789
  ] })
636
790
  ] });
637
791
  }
638
792
  function SessionList({ state, adapter, onOpen, onNew, onClose, components = {}, labels = DEFAULT_LABELS }) {
639
- const [query, setQuery] = useState("");
793
+ const [query, setQuery] = useState3("");
640
794
  const rows = filterSessions(state.sessions, query);
641
795
  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: [
796
+ return /* @__PURE__ */ jsxs4("section", { class: "scui-list", children: [
797
+ /* @__PURE__ */ jsxs4("header", { class: "scui-head", children: [
798
+ /* @__PURE__ */ jsxs4("span", { class: "scui-head-copy", children: [
799
+ /* @__PURE__ */ jsx5("strong", { children: labels.chats }),
800
+ /* @__PURE__ */ jsxs4("small", { children: [
647
801
  state.sessions.length,
648
802
  " recent conversations"
649
803
  ] })
650
804
  ] }),
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
805
+ /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": labels.newChat, disabled: !state.harnesses.some((item) => item.startable), onClick: onNew, children: "\uFF0B" }),
806
+ onClose ? /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
653
807
  ] }),
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 })
808
+ state.startup !== "ready" ? /* @__PURE__ */ jsx5(LoadingStatus, { state, compact: rows.length > 0 }) : null,
809
+ state.sessions.length > 4 ? /* @__PURE__ */ jsxs4("label", { class: "scui-search", children: [
810
+ /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: "\u2315" }),
811
+ /* @__PURE__ */ jsx5("input", { type: "search", "aria-label": labels.searchChats, placeholder: labels.searchChats, value: query, onInput: (event) => setQuery(event.currentTarget.value) }),
812
+ /* @__PURE__ */ jsx5("small", { children: rows.length })
659
813
  ] }) : 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
- ] })
814
+ /* @__PURE__ */ jsxs4("div", { class: "scui-session-rows", children: [
815
+ !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,
816
+ rows.map((row) => /* @__PURE__ */ jsx5(Row, { value: row, row, state, adapter, onOpen }, row.key)),
817
+ state.history.hasMoreSessions ? /* @__PURE__ */ jsx5("button", { class: "scui-load", type: "button", onClick: () => adapter.onIntent({ action: "loadSessions" }), children: "Load older chats" }) : null
746
818
  ] })
747
819
  ] });
748
820
  }
821
+
822
+ // src/messenger.jsx
823
+ import { jsx as jsx6, jsxs as jsxs5 } from "preact/jsx-runtime";
749
824
  function Receipt({ state, adapter }) {
750
825
  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: [
826
+ if (receipt) return /* @__PURE__ */ jsx6("div", { class: "scui-receipt", children: /* @__PURE__ */ jsxs5("span", { children: [
827
+ /* @__PURE__ */ jsx6("strong", { children: "Reduced and verified" }),
828
+ /* @__PURE__ */ jsxs5("small", { children: [
754
829
  receipt.sourceTokens.toLocaleString(),
755
830
  " \u2192 ",
756
831
  receipt.reducedTokens.toLocaleString(),
@@ -759,27 +834,27 @@ function Receipt({ state, adapter }) {
759
834
  "\xD7 \xB7 reversible"
760
835
  ] })
761
836
  ] }) });
762
- if (state.exportReceipt) return /* @__PURE__ */ jsxs("div", { class: "scui-receipt", children: [
763
- /* @__PURE__ */ jsxs("span", { children: [
764
- /* @__PURE__ */ jsxs("strong", { children: [
837
+ if (state.exportReceipt) return /* @__PURE__ */ jsxs5("div", { class: "scui-receipt", children: [
838
+ /* @__PURE__ */ jsxs5("span", { children: [
839
+ /* @__PURE__ */ jsxs5("strong", { children: [
765
840
  "Lossless export ready \xB7 ",
766
841
  harnessDisplayName(state.exportReceipt.targetHarness)
767
842
  ] }),
768
- /* @__PURE__ */ jsxs("small", { children: [
843
+ /* @__PURE__ */ jsxs5("small", { children: [
769
844
  state.exportReceipt.path,
770
845
  " \xB7 ",
771
846
  state.exportReceipt.files,
772
847
  " files"
773
848
  ] })
774
849
  ] }),
775
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => adapter.copyText?.(state.exportReceipt.path), children: "Copy path" })
850
+ /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.copyText?.(state.exportReceipt.path), children: "Copy path" })
776
851
  ] });
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 })
852
+ if (state.terminalHandoff) return /* @__PURE__ */ jsxs5("div", { class: "scui-receipt", children: [
853
+ /* @__PURE__ */ jsxs5("span", { children: [
854
+ /* @__PURE__ */ jsx6("strong", { children: "Terminal handoff ready" }),
855
+ /* @__PURE__ */ jsx6("small", { children: state.terminalHandoff.cwd })
781
856
  ] }),
782
- /* @__PURE__ */ jsx("button", { type: "button", onClick: () => adapter.copyText?.(terminalCommand(state.terminalHandoff)), children: "Copy command" })
857
+ /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.copyText?.(terminalCommand(state.terminalHandoff)), children: "Copy command" })
783
858
  ] });
784
859
  return null;
785
860
  }
@@ -789,46 +864,46 @@ function ChatHeader({ state, adapter, onBack, onNew, onClose }) {
789
864
  const title = state.attached ? sessionDisplayName(state.attached) : harnessDisplayName(harness) || "Agent chat";
790
865
  const status = state.needsInput ? "Needs input" : state.busy ? "Working" : state.mode === "mirror" ? "Read-only" : "Ready";
791
866
  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: [
867
+ return /* @__PURE__ */ jsxs5("header", { class: "scui-head scui-chat-head", children: [
868
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Back to chats", onClick: onBack, children: "\u2039" }),
869
+ /* @__PURE__ */ jsx6(HarnessLogo, { id: harness, size: 28 }),
870
+ /* @__PURE__ */ jsxs5("span", { class: "scui-head-copy", children: [
871
+ /* @__PURE__ */ jsx6("strong", { children: title }),
872
+ /* @__PURE__ */ jsxs5("small", { children: [
798
873
  harnessDisplayName(harness),
799
874
  " \xB7 ",
800
875
  status
801
876
  ] })
802
877
  ] }),
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: [
878
+ menu ? /* @__PURE__ */ jsxs5("details", { class: "scui-menu", children: [
879
+ /* @__PURE__ */ jsx6("summary", { "aria-label": "Conversation actions", children: "\u2022\u2022\u2022" }),
880
+ /* @__PURE__ */ jsxs5("div", { children: [
881
+ state.canDetach ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "detach" }), children: "Detach to read-only" }) : null,
882
+ state.canOpenTerminal ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "terminal" }), children: "Prepare terminal handoff" }) : null,
883
+ 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,
884
+ 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,
885
+ state.canExport && state.exportBackTarget ? /* @__PURE__ */ jsxs5("button", { type: "button", onClick: () => adapter.onIntent({ action: "export", targetHarness: state.exportBackTarget }), children: [
811
886
  "Export back to ",
812
887
  harnessDisplayName(state.exportBackTarget)
813
888
  ] }) : null
814
889
  ] })
815
890
  ] }) : 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
891
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "New chat", onClick: onNew, children: "\uFF0B" }),
892
+ onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
818
893
  ] });
819
894
  }
820
895
  function Chat({ state, adapter, onBack, onNew, onClose, components, slots, labels }) {
821
896
  const Header = slots.header;
822
897
  const memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`;
823
- const [pending, setPending] = useState(null);
824
- const acknowledged = useRef(/* @__PURE__ */ new Set());
825
- useEffect(() => {
898
+ const [pending, setPending] = useState4(null);
899
+ const acknowledged = useRef3(/* @__PURE__ */ new Set());
900
+ useEffect4(() => {
826
901
  setPending(null);
827
902
  }, [memoryKey]);
828
- useEffect(() => {
903
+ useEffect4(() => {
829
904
  if (pending && state.transcript.some((entry) => entry.role === "user" && entry.text.trim() === pending.trim())) setPending(null);
830
905
  }, [pending, state.transcript]);
831
- useEffect(() => {
906
+ useEffect4(() => {
832
907
  const key = state.attached?.key;
833
908
  if (!key || !state.attention.some((item) => item.key === key)) {
834
909
  if (key) acknowledged.current.delete(key);
@@ -839,31 +914,31 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
839
914
  adapter.onIntent({ action: "ack", key });
840
915
  }
841
916
  }, [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", {}),
917
+ return /* @__PURE__ */ jsxs5("section", { class: "scui-chat", children: [
918
+ Header ? /* @__PURE__ */ jsx6(Header, { state, adapter, value: null }) : /* @__PURE__ */ jsx6(ChatHeader, { state, adapter, onBack, onNew, onClose }),
919
+ operationLabel(state.operation) ? /* @__PURE__ */ jsxs5("div", { class: "scui-operation", role: "status", children: [
920
+ /* @__PURE__ */ jsx6("i", {}),
846
921
  operationLabel(state.operation)
847
922
  ] }) : 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
923
+ state.error ? /* @__PURE__ */ jsxs5("div", { class: "scui-error", role: "alert", children: [
924
+ /* @__PURE__ */ jsx6("span", { children: state.error }),
925
+ state.recoverable ? /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => adapter.onIntent({ action: "refresh" }), children: "Retry" }) : null
851
926
  ] }) : 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
927
+ /* @__PURE__ */ jsx6(Receipt, { state, adapter }),
928
+ /* @__PURE__ */ jsx6(Conversation, { state, adapter, components, slots, memoryKey, pending }, memoryKey),
929
+ /* @__PURE__ */ jsx6(ContinuationBar, { state, adapter, labels }),
930
+ state.mode !== "mirror" || state.canSend ? /* @__PURE__ */ jsx6(Composer, { state, adapter, labels, memoryKey, onPending: setPending }, memoryKey) : null
856
931
  ] });
857
932
  }
858
933
  function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
859
934
  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(() => {
935
+ const [harness, setHarness] = useState4(startable[0]?.id ?? "");
936
+ const [draft, setDraft] = useState4("");
937
+ const [starting, setStarting] = useState4(false);
938
+ useEffect4(() => {
864
939
  if (starting && (state.busy || state.transcript.length)) onStarted();
865
940
  }, [onStarted, starting, state.busy, state.transcript.length]);
866
- useEffect(() => {
941
+ useEffect4(() => {
867
942
  if (starting && state.error && !state.busy && !state.operation) setStarting(false);
868
943
  }, [starting, state.busy, state.error, state.operation]);
869
944
  const send = () => {
@@ -872,37 +947,37 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
872
947
  setStarting(true);
873
948
  adapter.onIntent({ action: "new", harness, text });
874
949
  };
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" })
950
+ return /* @__PURE__ */ jsxs5("section", { class: "scui-chat", children: [
951
+ /* @__PURE__ */ jsxs5("header", { class: "scui-head", children: [
952
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Back", onClick: onBack, children: "\u2039" }),
953
+ /* @__PURE__ */ jsxs5("span", { class: "scui-head-copy", children: [
954
+ /* @__PURE__ */ jsx6("strong", { children: labels.newChat }),
955
+ /* @__PURE__ */ jsx6("small", { children: "No session is created until you send" })
881
956
  ] }),
882
- onClose ? /* @__PURE__ */ jsx("button", { "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
957
+ onClose ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Close", onClick: onClose, children: "\xD7" }) : null
883
958
  ] }),
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." })
959
+ /* @__PURE__ */ jsxs5("div", { class: "scui-new", children: [
960
+ /* @__PURE__ */ jsx6("span", { "aria-hidden": "true", children: "\u2726" }),
961
+ /* @__PURE__ */ jsx6("strong", { children: "What should the agent build or fix?" }),
962
+ /* @__PURE__ */ jsx6("small", { children: "Choose a coding harness and send the first message." })
888
963
  ] }),
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: [
964
+ /* @__PURE__ */ jsxs5("div", { class: "scui-compose", children: [
965
+ /* @__PURE__ */ jsxs5("label", { class: "scui-harness-picker", children: [
966
+ /* @__PURE__ */ jsx6(HarnessLogo, { id: harness, size: 24 }),
967
+ /* @__PURE__ */ jsx6("span", { children: "Coding harness" }),
968
+ /* @__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
969
  item.label,
895
970
  item.startable ? "" : " \xB7 unavailable"
896
971
  ] }, item.id)) })
897
972
  ] }),
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) => {
973
+ /* @__PURE__ */ jsxs5("div", { class: "scui-envelope", children: [
974
+ /* @__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
975
  if (isSendKey(event)) {
901
976
  event.preventDefault();
902
977
  send();
903
978
  }
904
979
  } }),
905
- /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx("button", { class: "scui-send", disabled: !draft.trim() || !harness || starting, onClick: send, children: starting ? "\u25CC" : "\u2191" }) })
980
+ /* @__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
981
  ] })
907
982
  ] })
908
983
  ] });
@@ -910,48 +985,49 @@ function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
910
985
  function SupercodeMessenger({ state: stateInput, adapter, class: className = "", initialView, labels, components = {}, slots = {} }) {
911
986
  const state = normalizeUiState(stateInput);
912
987
  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(() => {
988
+ const [view, setView] = useState4(initialView ?? (state.attention.length ? "list" : state.attached || state.transcript.length ? "chat" : "list"));
989
+ const [opening, setOpening] = useState4(null);
990
+ useEffect4(() => {
916
991
  if (!opening) return;
917
992
  if (state.attached?.key === opening.key) {
918
993
  setOpening(null);
919
994
  setView("chat");
920
- } else if (state.attachError?.key === opening.key) {
995
+ } else if (state.attachError?.key === opening.key || state.error && !state.operation) {
921
996
  setOpening(null);
922
997
  }
923
- }, [opening, state.attachError?.key, state.attached?.key]);
998
+ }, [opening, state.attachError?.key, state.attached?.key, state.error, state.operation]);
924
999
  const open = (row) => {
925
1000
  setOpening(row);
926
1001
  adapter.onIntent({ action: "ack", key: row.key });
927
1002
  adapter.onIntent({ action: "attach", key: row.key });
928
1003
  };
929
1004
  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: [
1005
+ const Footer = slots.footer;
1006
+ return /* @__PURE__ */ jsxs5("main", { class: `scui-root ${className}`, "data-view": view, "data-mode": state.mode, "aria-label": "Supercode messenger", children: [
1007
+ view === "list" ? /* @__PURE__ */ jsx6(SessionList, { state, adapter, onOpen: open, onNew: () => setView("new"), onClose: adapter.onClose ? close : void 0, components, labels: copy }) : null,
1008
+ view === "new" ? /* @__PURE__ */ jsx6(NewChat, { state, adapter, onBack: () => setView("list"), onClose: adapter.onClose ? close : void 0, onStarted: () => setView("chat"), labels: copy }) : null,
1009
+ view === "chat" ? /* @__PURE__ */ jsx6(Chat, { state, adapter, onBack: () => setView("list"), onNew: () => setView("new"), onClose: adapter.onClose ? close : void 0, components, slots, labels: copy }) : null,
1010
+ opening ? /* @__PURE__ */ jsxs5("div", { class: "scui-opening", role: "status", "aria-busy": "true", children: [
1011
+ /* @__PURE__ */ jsx6(HarnessLogo, { id: opening.harness, size: 34 }),
1012
+ /* @__PURE__ */ jsxs5("span", { children: [
1013
+ /* @__PURE__ */ jsxs5("strong", { children: [
938
1014
  "Opening ",
939
1015
  sessionDisplayName(opening)
940
1016
  ] }),
941
- /* @__PURE__ */ jsx("small", { children: "Loading the latest transcript window\u2026" })
1017
+ /* @__PURE__ */ jsx6("small", { children: "Loading the latest transcript window\u2026" })
942
1018
  ] }),
943
- /* @__PURE__ */ jsx("i", {})
1019
+ /* @__PURE__ */ jsx6("i", {})
944
1020
  ] }) : null,
945
- slots.footer ? /* @__PURE__ */ jsx(slots.footer, { state, adapter, value: copy }) : null
1021
+ Footer ? /* @__PURE__ */ jsx6(Footer, { state, adapter, value: copy }) : null
946
1022
  ] });
947
1023
  }
948
1024
 
949
1025
  // src/embed.jsx
950
- import { jsx as jsx2 } from "preact/jsx-runtime";
1026
+ import { jsx as jsx7 } from "preact/jsx-runtime";
951
1027
  function mountSupercodeMessenger(element, options) {
952
1028
  if (!(element instanceof Element)) throw new TypeError("mountSupercodeMessenger requires an Element");
953
1029
  let state = options.state;
954
- const draw = () => render(/* @__PURE__ */ jsx2(SupercodeMessenger, { ...options, state }), element);
1030
+ const draw = () => render(/* @__PURE__ */ jsx7(SupercodeMessenger, { ...options, state }), element);
955
1031
  options.adapter.onIntent({ action: "mounted" });
956
1032
  draw();
957
1033
  return {