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

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