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

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