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

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