@volter-ai-dev/supercode-ui 0.1.13 → 0.1.15

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/conversation.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/conversation.jsx
2
- import { useEffect, useId, useLayoutEffect, useRef, useState } from "preact/hooks";
2
+ import { Fragment as Fragment2 } from "preact";
3
+ import { useEffect as useEffect2, useId, useLayoutEffect, useRef as useRef2, useState } from "preact/hooks";
3
4
 
4
5
  // core.mjs
5
6
  var HARNESS_NAMES = Object.freeze({
@@ -283,18 +284,95 @@ function activitySummary(entries) {
283
284
 
284
285
  // src/markdown.jsx
285
286
  import MarkdownIt from "markdown-it";
286
- import { useMemo } from "preact/hooks";
287
+ import { useEffect, useMemo, useRef } from "preact/hooks";
287
288
  import { jsx } from "preact/jsx-runtime";
288
289
  var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
290
+ var LANGUAGE_LABELS = {
291
+ bash: "Shell",
292
+ css: "CSS",
293
+ html: "HTML",
294
+ js: "JavaScript",
295
+ javascript: "JavaScript",
296
+ jsx: "JSX",
297
+ md: "Markdown",
298
+ markdown: "Markdown",
299
+ py: "Python",
300
+ python: "Python",
301
+ rs: "Rust",
302
+ rust: "Rust",
303
+ sh: "Shell",
304
+ shell: "Shell",
305
+ ts: "TypeScript",
306
+ tsx: "TSX",
307
+ yaml: "YAML",
308
+ yml: "YAML",
309
+ json: "JSON",
310
+ jsonc: "JSONC",
311
+ sql: "SQL",
312
+ xml: "XML"
313
+ };
314
+ var COPY_ICON = '<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="5" width="8" height="8" rx="1.5"></rect><path d="M3 10.5V4.25C3 3.56 3.56 3 4.25 3h6.25"></path></svg>';
315
+ function languageLabel(info) {
316
+ const language = info.trim().split(/\s+/, 1)[0]?.toLocaleLowerCase() ?? "";
317
+ if (!language) return "Code";
318
+ return LANGUAGE_LABELS[language] ?? language.toLocaleUpperCase();
319
+ }
320
+ function frameCode(render, tokens, index, options, env, self) {
321
+ const label = markdown.utils.escapeHtml(languageLabel(tokens[index]?.info ?? ""));
322
+ return `<div class="scui-code-block"><div class="scui-code-head"><span>${label}</span><button class="scui-code-copy" type="button" aria-label="Copy code" title="Copy code">${COPY_ICON}<span>Copy</span></button></div>${render(tokens, index, options, env, self)}</div>`;
323
+ }
324
+ for (const kind of ["fence", "code_block"]) {
325
+ const render = markdown.renderer.rules[kind];
326
+ markdown.renderer.rules[kind] = (tokens, index, options, env, self) => frameCode(render, tokens, index, options, env, self);
327
+ }
289
328
  var defaultLinkOpen = markdown.renderer.rules.link_open;
290
329
  markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
291
330
  tokens[index]?.attrSet("target", "_blank");
292
331
  tokens[index]?.attrSet("rel", "noreferrer noopener");
293
332
  return defaultLinkOpen ? defaultLinkOpen(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
294
333
  };
295
- function Markdown({ value }) {
334
+ function setCopyState(button, status) {
335
+ const labels = {
336
+ idle: ["Copy code", "Copy"],
337
+ copied: ["Code copied", "Copied"],
338
+ failed: ["Copy failed \xB7 retry", "Retry"]
339
+ };
340
+ const [label, visible] = labels[status];
341
+ button.dataset.status = status;
342
+ button.setAttribute("aria-label", label);
343
+ button.setAttribute("title", label);
344
+ const text = button.querySelector("span");
345
+ if (text) text.textContent = visible;
346
+ }
347
+ function Markdown({ value, copyText }) {
296
348
  const html = useMemo(() => markdown.render(value), [value]);
297
- return /* @__PURE__ */ jsx("div", { class: "scui-markdown", dangerouslySetInnerHTML: { __html: html } });
349
+ const resets = useRef(/* @__PURE__ */ new Map());
350
+ useEffect(() => () => {
351
+ for (const timer of resets.current.values()) clearTimeout(timer);
352
+ resets.current.clear();
353
+ }, []);
354
+ const copyCode = async (event) => {
355
+ const button = event.target.closest?.(".scui-code-copy");
356
+ if (!button || !event.currentTarget.contains(button) || !copyText) return;
357
+ const code = button.closest(".scui-code-block")?.querySelector("pre code");
358
+ if (!code) return;
359
+ button.disabled = true;
360
+ try {
361
+ await copyText(code.textContent ?? "");
362
+ setCopyState(button, "copied");
363
+ } catch {
364
+ setCopyState(button, "failed");
365
+ } finally {
366
+ button.disabled = false;
367
+ }
368
+ clearTimeout(resets.current.get(button));
369
+ const timer = setTimeout(() => {
370
+ if (button.isConnected) setCopyState(button, "idle");
371
+ resets.current.delete(button);
372
+ }, 1500);
373
+ resets.current.set(button, timer);
374
+ };
375
+ return /* @__PURE__ */ jsx("div", { class: "scui-markdown", "data-copyable": Boolean(copyText), onClick: copyCode, dangerouslySetInnerHTML: { __html: html } });
298
376
  }
299
377
 
300
378
  // src/memory.js
@@ -305,8 +383,51 @@ function boundedSet(map, key, value) {
305
383
  while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
306
384
  }
307
385
 
308
- // src/conversation.jsx
386
+ // src/icon.jsx
309
387
  import { Fragment, jsx as jsx2, jsxs } from "preact/jsx-runtime";
388
+ var ICONS = {
389
+ back: () => /* @__PURE__ */ jsx2("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
390
+ check: () => /* @__PURE__ */ jsx2("path", { d: "m4 9 3.25 3.25L14 5.5" }),
391
+ chevron: () => /* @__PURE__ */ jsx2("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
392
+ close: () => /* @__PURE__ */ jsxs(Fragment, { children: [
393
+ /* @__PURE__ */ jsx2("path", { d: "m4.75 4.75 8.5 8.5" }),
394
+ /* @__PURE__ */ jsx2("path", { d: "m13.25 4.75-8.5 8.5" })
395
+ ] }),
396
+ copy: () => /* @__PURE__ */ jsxs(Fragment, { children: [
397
+ /* @__PURE__ */ jsx2("rect", { x: "5", y: "5", width: "8", height: "8", rx: "1.5" }),
398
+ /* @__PURE__ */ jsx2("path", { d: "M3 10.5V4.25C3 3.56 3.56 3 4.25 3h6.25" })
399
+ ] }),
400
+ down: () => /* @__PURE__ */ jsxs(Fragment, { children: [
401
+ /* @__PURE__ */ jsx2("path", { d: "M9 3.5v10" }),
402
+ /* @__PURE__ */ jsx2("path", { d: "m4.75 9.5 4.25 4 4.25-4" })
403
+ ] }),
404
+ menu: () => /* @__PURE__ */ jsxs(Fragment, { children: [
405
+ /* @__PURE__ */ jsx2("circle", { cx: "4", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
406
+ /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
407
+ /* @__PURE__ */ jsx2("circle", { cx: "14", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" })
408
+ ] }),
409
+ plus: () => /* @__PURE__ */ jsxs(Fragment, { children: [
410
+ /* @__PURE__ */ jsx2("path", { d: "M9 3.5v11" }),
411
+ /* @__PURE__ */ jsx2("path", { d: "M3.5 9h11" })
412
+ ] }),
413
+ search: () => /* @__PURE__ */ jsxs(Fragment, { children: [
414
+ /* @__PURE__ */ jsx2("circle", { cx: "7.75", cy: "7.75", r: "4.25" }),
415
+ /* @__PURE__ */ jsx2("path", { d: "m11 11 3.5 3.5" })
416
+ ] }),
417
+ send: () => /* @__PURE__ */ jsxs(Fragment, { children: [
418
+ /* @__PURE__ */ jsx2("path", { d: "M9 14.5v-11" }),
419
+ /* @__PURE__ */ jsx2("path", { d: "m4.75 7.75 4.25-4.25 4.25 4.25" })
420
+ ] }),
421
+ stop: () => /* @__PURE__ */ jsx2("rect", { x: "4.5", y: "4.5", width: "9", height: "9", rx: "1.5", fill: "currentColor", stroke: "none" })
422
+ };
423
+ function UiIcon({ name, size = 16, class: className = "" }) {
424
+ const Glyph = ICONS[name];
425
+ if (!Glyph) return null;
426
+ return /* @__PURE__ */ jsx2("svg", { class: `scui-icon ${className}`, style: { "--scui-icon-size": `${size}px` }, viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(Glyph, {}) });
427
+ }
428
+
429
+ // src/conversation.jsx
430
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
310
431
  function LoadingStatus({ state, compact = false }) {
311
432
  const copy = {
312
433
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -314,81 +435,104 @@ function LoadingStatus({ state, compact = false }) {
314
435
  discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
315
436
  ready: ["Ready", "Coding sessions are up to date.", 3]
316
437
  }[state.startup];
317
- return /* @__PURE__ */ jsxs("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
318
- /* @__PURE__ */ jsx2("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx2("i", {}) }),
319
- /* @__PURE__ */ jsxs("span", { class: "scui-loading-copy", children: [
320
- /* @__PURE__ */ jsx2("strong", { children: copy[0] }),
321
- /* @__PURE__ */ jsx2("small", { children: copy[1] })
438
+ return /* @__PURE__ */ jsxs2("div", { class: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
439
+ /* @__PURE__ */ jsx3("span", { class: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx3("i", {}) }),
440
+ /* @__PURE__ */ jsxs2("span", { class: "scui-loading-copy", children: [
441
+ /* @__PURE__ */ jsx3("strong", { children: copy[0] }),
442
+ /* @__PURE__ */ jsx3("small", { children: copy[1] })
322
443
  ] }),
323
- /* @__PURE__ */ jsx2("span", { class: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx2("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
444
+ /* @__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)) })
324
445
  ] });
325
446
  }
326
447
  function RequestCard({ entry, adapter, canRespond }) {
327
448
  const request = entry.request;
328
449
  if (!request) return null;
329
450
  if (request.status === "responded") {
330
- return /* @__PURE__ */ jsxs("div", { class: "scui-request-done", children: [
451
+ return /* @__PURE__ */ jsxs2("div", { class: "scui-request-done", children: [
331
452
  "\u2713 Request answered \xB7 ",
332
453
  request.resolution?.name ?? request.requestKind
333
454
  ] });
334
455
  }
335
- return /* @__PURE__ */ jsxs("section", { class: "scui-request", "aria-label": `${request.requestKind} needs input`, children: [
336
- /* @__PURE__ */ jsx2("strong", { children: "Agent needs input" }),
337
- /* @__PURE__ */ jsx2(Markdown, { value: request.payloadText || entry.text }),
338
- /* @__PURE__ */ jsxs("div", { class: "scui-request-actions", children: [
339
- request.options.map((option) => /* @__PURE__ */ jsx2("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: option.optionId }), children: option.name }, option.optionId)),
340
- request.cancellable ? /* @__PURE__ */ jsx2("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
456
+ return /* @__PURE__ */ jsxs2("section", { class: "scui-request", role: "alert", "aria-label": `${request.requestKind} needs input`, children: [
457
+ /* @__PURE__ */ jsx3("strong", { children: "Agent needs input" }),
458
+ /* @__PURE__ */ jsx3(Markdown, { value: request.payloadText || entry.text, copyText: adapter?.copyText }),
459
+ /* @__PURE__ */ jsxs2("div", { class: "scui-request-actions", children: [
460
+ 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)),
461
+ request.cancellable ? /* @__PURE__ */ jsx3("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
341
462
  ] })
342
463
  ] });
343
464
  }
344
465
  function ContextDisclosure({ context }) {
345
466
  if (!context?.length) return null;
346
- return /* @__PURE__ */ jsxs("details", { class: "scui-context", children: [
347
- /* @__PURE__ */ jsxs("summary", { children: [
467
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-context", children: [
468
+ /* @__PURE__ */ jsxs2("summary", { children: [
348
469
  "Context \xB7 ",
349
470
  context.length
350
471
  ] }),
351
- /* @__PURE__ */ jsx2("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs("p", { children: [
352
- /* @__PURE__ */ jsx2("strong", { children: item.label }),
353
- /* @__PURE__ */ jsx2("span", { children: item.detail })
472
+ /* @__PURE__ */ jsx3("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs2("p", { children: [
473
+ /* @__PURE__ */ jsx3("strong", { children: item.label }),
474
+ /* @__PURE__ */ jsx3("span", { children: item.detail })
354
475
  ] }, item.id ?? index)) })
355
476
  ] });
356
477
  }
478
+ function MessageMeta({ entry, adapter }) {
479
+ const [copyState, setCopyState2] = useState("idle");
480
+ const reset = useRef2(null);
481
+ useEffect2(() => () => clearTimeout(reset.current), []);
482
+ const date = entry.ts === null ? null : new Date(entry.ts);
483
+ const validDate = date && Number.isFinite(date.valueOf()) ? date : null;
484
+ if (!validDate && (!adapter?.copyText || !entry.text)) return null;
485
+ const copy = async () => {
486
+ try {
487
+ await adapter.copyText(entry.text);
488
+ setCopyState2("copied");
489
+ } catch {
490
+ setCopyState2("failed");
491
+ }
492
+ clearTimeout(reset.current);
493
+ reset.current = setTimeout(() => setCopyState2("idle"), 1500);
494
+ };
495
+ const copyLabel = copyState === "copied" ? "Message copied" : copyState === "failed" ? "Copy failed \xB7 retry" : "Copy message";
496
+ return /* @__PURE__ */ jsxs2("footer", { class: "scui-message-meta", children: [
497
+ validDate ? /* @__PURE__ */ jsx3("time", { dateTime: validDate.toISOString(), title: validDate.toLocaleString(), children: validDate.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }) : null,
498
+ adapter?.copyText && entry.text ? /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": copyLabel, title: copyLabel, onClick: copy, "data-status": copyState, children: /* @__PURE__ */ jsx3(UiIcon, { name: "copy", size: 13 }) }) : null
499
+ ] });
500
+ }
357
501
  var TOOL_ICONS = {
358
- read: () => /* @__PURE__ */ jsxs(Fragment, { children: [
359
- /* @__PURE__ */ jsx2("path", { d: "M5 2.75h7.25L15 5.5v7.75A1.75 1.75 0 0 1 13.25 15h-8.5A1.75 1.75 0 0 1 3 13.25v-8.5A2 2 0 0 1 5 2.75Z" }),
360
- /* @__PURE__ */ jsx2("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
502
+ read: () => /* @__PURE__ */ jsxs2(Fragment3, { children: [
503
+ /* @__PURE__ */ jsx3("path", { d: "M5 2.75h7.25L15 5.5v7.75A1.75 1.75 0 0 1 13.25 15h-8.5A1.75 1.75 0 0 1 3 13.25v-8.5A2 2 0 0 1 5 2.75Z" }),
504
+ /* @__PURE__ */ jsx3("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
361
505
  ] }),
362
- search: () => /* @__PURE__ */ jsxs(Fragment, { children: [
363
- /* @__PURE__ */ jsx2("circle", { cx: "8", cy: "8", r: "4.5" }),
364
- /* @__PURE__ */ jsx2("path", { d: "m11.5 11.5 3 3" })
506
+ search: () => /* @__PURE__ */ jsxs2(Fragment3, { children: [
507
+ /* @__PURE__ */ jsx3("circle", { cx: "8", cy: "8", r: "4.5" }),
508
+ /* @__PURE__ */ jsx3("path", { d: "m11.5 11.5 3 3" })
365
509
  ] }),
366
- edit: () => /* @__PURE__ */ jsxs(Fragment, { children: [
367
- /* @__PURE__ */ jsx2("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
368
- /* @__PURE__ */ jsx2("path", { d: "m10 5 3 3" })
510
+ edit: () => /* @__PURE__ */ jsxs2(Fragment3, { children: [
511
+ /* @__PURE__ */ jsx3("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
512
+ /* @__PURE__ */ jsx3("path", { d: "m10 5 3 3" })
369
513
  ] }),
370
- command: () => /* @__PURE__ */ jsx2(Fragment, { children: /* @__PURE__ */ jsx2("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
371
- test: () => /* @__PURE__ */ jsxs(Fragment, { children: [
372
- /* @__PURE__ */ jsx2("path", { d: "M6 2.5v3L3 12a2 2 0 0 0 1.8 3h8.4a2 2 0 0 0 1.8-3l-3-6.5v-3M5 9h8" }),
373
- /* @__PURE__ */ jsx2("path", { d: "M5 2.5h8" })
514
+ command: () => /* @__PURE__ */ jsx3(Fragment3, { children: /* @__PURE__ */ jsx3("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
515
+ test: () => /* @__PURE__ */ jsxs2(Fragment3, { children: [
516
+ /* @__PURE__ */ jsx3("path", { d: "M6 2.5v3L3 12a2 2 0 0 0 1.8 3h8.4a2 2 0 0 0 1.8-3l-3-6.5v-3M5 9h8" }),
517
+ /* @__PURE__ */ jsx3("path", { d: "M5 2.5h8" })
374
518
  ] }),
375
- web: () => /* @__PURE__ */ jsxs(Fragment, { children: [
376
- /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "6.5" }),
377
- /* @__PURE__ */ jsx2("path", { d: "M2.75 9h12.5M9 2.5c2 1.8 3 4 3 6.5s-1 4.7-3 6.5c-2-1.8-3-4-3-6.5s1-4.7 3-6.5Z" })
519
+ web: () => /* @__PURE__ */ jsxs2(Fragment3, { children: [
520
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "9", r: "6.5" }),
521
+ /* @__PURE__ */ jsx3("path", { d: "M2.75 9h12.5M9 2.5c2 1.8 3 4 3 6.5s-1 4.7-3 6.5c-2-1.8-3-4-3-6.5s1-4.7 3-6.5Z" })
378
522
  ] }),
379
- agent: () => /* @__PURE__ */ jsxs(Fragment, { children: [
380
- /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "6", r: "2.5" }),
381
- /* @__PURE__ */ jsx2("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
523
+ agent: () => /* @__PURE__ */ jsxs2(Fragment3, { children: [
524
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "6", r: "2.5" }),
525
+ /* @__PURE__ */ jsx3("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
382
526
  ] }),
383
- plan: () => /* @__PURE__ */ jsx2(Fragment, { children: /* @__PURE__ */ jsx2("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
384
- other: () => /* @__PURE__ */ jsxs(Fragment, { children: [
385
- /* @__PURE__ */ jsx2("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
386
- /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "3.5" })
527
+ plan: () => /* @__PURE__ */ jsx3(Fragment3, { children: /* @__PURE__ */ jsx3("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
528
+ other: () => /* @__PURE__ */ jsxs2(Fragment3, { children: [
529
+ /* @__PURE__ */ jsx3("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
530
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "9", r: "3.5" })
387
531
  ] })
388
532
  };
389
533
  function ToolIcon({ category }) {
390
534
  const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
391
- return /* @__PURE__ */ jsx2("svg", { class: "scui-tool-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.35", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(Glyph, {}) });
535
+ return /* @__PURE__ */ jsx3("svg", { class: "scui-tool-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", "stroke-width": "1.35", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx3(Glyph, {}) });
392
536
  }
393
537
  function toolAction2(entry, category, presentation) {
394
538
  if (presentation?.action) return presentation.action;
@@ -443,86 +587,86 @@ function ToolMetrics({ presentation }) {
443
587
  presentation.exitCode === null ? "" : `exit ${presentation.exitCode}`,
444
588
  formatDuration(presentation.durationMs)
445
589
  ].filter(Boolean);
446
- return metrics.length ? /* @__PURE__ */ jsx2("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx2("span", { children: metric }, metric)) }) : null;
590
+ return metrics.length ? /* @__PURE__ */ jsx3("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx3("span", { children: metric }, metric)) }) : null;
447
591
  }
448
592
  function PendingElapsed({ now }) {
449
593
  const clock = now ?? Date.now;
450
- const started = useRef(clock());
594
+ const started = useRef2(clock());
451
595
  const [elapsed, setElapsed] = useState(0);
452
- useEffect(() => {
596
+ useEffect2(() => {
453
597
  const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
454
598
  return () => clearInterval(timer);
455
599
  }, [clock]);
456
- return /* @__PURE__ */ jsx2("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
600
+ return /* @__PURE__ */ jsx3("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
457
601
  }
458
602
  function LinePreview({ value, kind }) {
459
603
  if (!value) return null;
460
- return /* @__PURE__ */ jsx2("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
604
+ return /* @__PURE__ */ jsx3("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
461
605
  const tone = kind === "diff" ? line.startsWith("+") && !line.startsWith("+++") ? "add" : line.startsWith("-") && !line.startsWith("---") ? "remove" : line.startsWith("@@") ? "hunk" : "plain" : "plain";
462
- return /* @__PURE__ */ jsxs("li", { "data-tone": tone, children: [
463
- /* @__PURE__ */ jsx2("span", { children: index + 1 }),
464
- /* @__PURE__ */ jsx2("code", { children: line || " " })
606
+ return /* @__PURE__ */ jsxs2("li", { "data-tone": tone, children: [
607
+ /* @__PURE__ */ jsx3("span", { children: index + 1 }),
608
+ /* @__PURE__ */ jsx3("code", { children: line || " " })
465
609
  ] }, index);
466
610
  }) });
467
611
  }
468
612
  function TerminalPreview({ presentation, pending, failed }) {
469
- return /* @__PURE__ */ jsxs("section", { class: "scui-terminal", children: [
470
- /* @__PURE__ */ jsxs("header", { children: [
471
- /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", children: [
472
- /* @__PURE__ */ jsx2("i", {}),
473
- /* @__PURE__ */ jsx2("i", {}),
474
- /* @__PURE__ */ jsx2("i", {})
613
+ return /* @__PURE__ */ jsxs2("section", { class: "scui-terminal", children: [
614
+ /* @__PURE__ */ jsxs2("header", { children: [
615
+ /* @__PURE__ */ jsxs2("span", { "aria-hidden": "true", children: [
616
+ /* @__PURE__ */ jsx3("i", {}),
617
+ /* @__PURE__ */ jsx3("i", {}),
618
+ /* @__PURE__ */ jsx3("i", {})
475
619
  ] }),
476
- /* @__PURE__ */ jsx2("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
620
+ /* @__PURE__ */ jsx3("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
477
621
  ] }),
478
- presentation.preview ? /* @__PURE__ */ jsx2("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs("div", { class: "scui-terminal-wait", children: [
479
- /* @__PURE__ */ jsx2("i", {}),
622
+ presentation.preview ? /* @__PURE__ */ jsx3("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs2("div", { class: "scui-terminal-wait", children: [
623
+ /* @__PURE__ */ jsx3("i", {}),
480
624
  " Waiting for output"
481
- ] }) : /* @__PURE__ */ jsx2("div", { class: "scui-terminal-empty", children: "No output" })
625
+ ] }) : /* @__PURE__ */ jsx3("div", { class: "scui-terminal-empty", children: "No output" })
482
626
  ] });
483
627
  }
484
628
  function SearchPreview({ presentation }) {
485
629
  const lines = stripAnsi(presentation.preview).split("\n").filter(Boolean);
486
- return /* @__PURE__ */ jsxs("section", { class: "scui-search-preview", children: [
487
- presentation.query ? /* @__PURE__ */ jsxs("header", { children: [
488
- /* @__PURE__ */ jsx2("span", { children: "Search" }),
489
- /* @__PURE__ */ jsx2("code", { children: presentation.query })
630
+ return /* @__PURE__ */ jsxs2("section", { class: "scui-search-preview", children: [
631
+ presentation.query ? /* @__PURE__ */ jsxs2("header", { children: [
632
+ /* @__PURE__ */ jsx3("span", { children: "Search" }),
633
+ /* @__PURE__ */ jsx3("code", { children: presentation.query })
490
634
  ] }) : null,
491
- lines.length ? /* @__PURE__ */ jsx2("ol", { children: lines.map((line, index) => {
635
+ lines.length ? /* @__PURE__ */ jsx3("ol", { children: lines.map((line, index) => {
492
636
  const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
493
- return /* @__PURE__ */ jsx2("li", { children: match ? /* @__PURE__ */ jsxs(Fragment, { children: [
494
- /* @__PURE__ */ jsx2("code", { children: match[1] }),
495
- /* @__PURE__ */ jsxs("small", { children: [
637
+ return /* @__PURE__ */ jsx3("li", { children: match ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
638
+ /* @__PURE__ */ jsx3("code", { children: match[1] }),
639
+ /* @__PURE__ */ jsxs2("small", { children: [
496
640
  match[2],
497
641
  match[3] ? `:${match[3]}` : ""
498
642
  ] }),
499
- /* @__PURE__ */ jsx2("span", { children: match[4] })
500
- ] }) : /* @__PURE__ */ jsx2("span", { children: line }) }, index);
501
- }) }) : /* @__PURE__ */ jsx2("p", { children: "No textual results" })
643
+ /* @__PURE__ */ jsx3("span", { children: match[4] })
644
+ ] }) : /* @__PURE__ */ jsx3("span", { children: line }) }, index);
645
+ }) }) : /* @__PURE__ */ jsx3("p", { children: "No textual results" })
502
646
  ] });
503
647
  }
504
648
  function ToolPreview({ presentation, entry }) {
505
649
  const pending = entry.status === "pending";
506
650
  const failed = entry.status === "error";
507
- if (presentation.detail === "terminal") return /* @__PURE__ */ jsx2(TerminalPreview, { presentation, pending, failed });
508
- if (presentation.detail === "diff") return presentation.preview ? /* @__PURE__ */ jsx2(LinePreview, { value: presentation.preview, kind: "diff" }) : /* @__PURE__ */ jsx2("div", { class: "scui-tool-empty", children: "Edit completed without a textual diff" });
509
- if (presentation.detail === "file") return presentation.preview ? /* @__PURE__ */ jsx2(LinePreview, { value: presentation.preview, kind: "file" }) : /* @__PURE__ */ jsx2("div", { class: "scui-tool-empty", children: "File contents were not included in this event" });
510
- if (presentation.detail === "matches") return /* @__PURE__ */ jsx2(SearchPreview, { presentation });
511
- if (presentation.detail === "web") return /* @__PURE__ */ jsxs("section", { class: "scui-web-preview", children: [
512
- presentation.url ? /* @__PURE__ */ jsx2("code", { children: presentation.url }) : null,
513
- presentation.preview ? /* @__PURE__ */ jsx2("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx2("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
651
+ if (presentation.detail === "terminal") return /* @__PURE__ */ jsx3(TerminalPreview, { presentation, pending, failed });
652
+ if (presentation.detail === "diff") return presentation.preview ? /* @__PURE__ */ jsx3(LinePreview, { value: presentation.preview, kind: "diff" }) : /* @__PURE__ */ jsx3("div", { class: "scui-tool-empty", children: "Edit completed without a textual diff" });
653
+ if (presentation.detail === "file") return presentation.preview ? /* @__PURE__ */ jsx3(LinePreview, { value: presentation.preview, kind: "file" }) : /* @__PURE__ */ jsx3("div", { class: "scui-tool-empty", children: "File contents were not included in this event" });
654
+ if (presentation.detail === "matches") return /* @__PURE__ */ jsx3(SearchPreview, { presentation });
655
+ if (presentation.detail === "web") return /* @__PURE__ */ jsxs2("section", { class: "scui-web-preview", children: [
656
+ presentation.url ? /* @__PURE__ */ jsx3("code", { children: presentation.url }) : null,
657
+ presentation.preview ? /* @__PURE__ */ jsx3("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx3("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
514
658
  ] });
515
- if (presentation.detail === "agent") return /* @__PURE__ */ jsx2("section", { class: "scui-agent-preview", children: presentation.preview ? /* @__PURE__ */ jsx2("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx2("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
516
- if (presentation.detail === "plan") return /* @__PURE__ */ jsx2("ol", { class: "scui-plan-preview", children: presentation.items?.map((item, index) => /* @__PURE__ */ jsxs("li", { "data-status": item.status, children: [
517
- /* @__PURE__ */ jsx2("i", { "aria-hidden": "true" }),
518
- /* @__PURE__ */ jsx2("span", { children: item.label })
659
+ if (presentation.detail === "agent") return /* @__PURE__ */ jsx3("section", { class: "scui-agent-preview", children: presentation.preview ? /* @__PURE__ */ jsx3("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx3("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
660
+ if (presentation.detail === "plan") return /* @__PURE__ */ jsx3("ol", { class: "scui-plan-preview", children: presentation.items?.map((item, index) => /* @__PURE__ */ jsxs2("li", { "data-status": item.status, children: [
661
+ /* @__PURE__ */ jsx3("i", { "aria-hidden": "true" }),
662
+ /* @__PURE__ */ jsx3("span", { children: item.label })
519
663
  ] }, `${item.label}:${index}`)) });
520
- return presentation.preview ? /* @__PURE__ */ jsx2("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
664
+ return presentation.preview ? /* @__PURE__ */ jsx3("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
521
665
  }
522
666
  function ToolActions({ presentation, adapter }) {
523
667
  const [copied, setCopied] = useState(false);
524
- const reset = useRef(null);
525
- useEffect(() => () => clearTimeout(reset.current), []);
668
+ const reset = useRef2(null);
669
+ useEffect2(() => () => clearTimeout(reset.current), []);
526
670
  if (!adapter?.copyText) return null;
527
671
  const action = presentation.command ? ["Copy command", presentation.command] : presentation.path ? ["Copy path", presentation.path] : presentation.url ? ["Copy URL", presentation.url] : presentation.query ? ["Copy query", presentation.query] : null;
528
672
  const copy = async () => {
@@ -531,27 +675,27 @@ function ToolActions({ presentation, adapter }) {
531
675
  clearTimeout(reset.current);
532
676
  reset.current = setTimeout(() => setCopied(false), 1500);
533
677
  };
534
- return action ? /* @__PURE__ */ jsx2("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx2("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
678
+ return action ? /* @__PURE__ */ jsx3("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx3("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
535
679
  }
536
680
  function ToolStack({ tools }) {
537
681
  if (tools.length < 2) return null;
538
- return /* @__PURE__ */ jsx2("div", { class: "scui-tool-stack", "aria-label": "Coordinated tools", children: tools.map((tool) => /* @__PURE__ */ jsx2("span", { children: tool.replaceAll("__", " \xB7 ").replaceAll("_", " ") }, tool)) });
682
+ return /* @__PURE__ */ jsx3("div", { class: "scui-tool-stack", "aria-label": "Coordinated tools", children: tools.map((tool) => /* @__PURE__ */ jsx3("span", { children: tool.replaceAll("__", " \xB7 ").replaceAll("_", " ") }, tool)) });
539
683
  }
540
684
  function TechnicalDetails({ entry }) {
541
685
  if (!entry.arguments && !entry.resultText) return null;
542
- return /* @__PURE__ */ jsxs("details", { class: "scui-tool-technical", children: [
543
- /* @__PURE__ */ jsx2("summary", { children: "Technical details" }),
544
- /* @__PURE__ */ jsxs("div", { children: [
545
- entry.arguments ? /* @__PURE__ */ jsxs("section", { children: [
546
- /* @__PURE__ */ jsx2("strong", { children: "Native arguments" }),
547
- /* @__PURE__ */ jsx2("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs("div", { children: [
548
- /* @__PURE__ */ jsx2("dt", { children: row.label }),
549
- /* @__PURE__ */ jsx2("dd", { children: /* @__PURE__ */ jsx2("pre", { children: row.value }) })
686
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-tool-technical", children: [
687
+ /* @__PURE__ */ jsx3("summary", { children: "Technical details" }),
688
+ /* @__PURE__ */ jsxs2("div", { children: [
689
+ entry.arguments ? /* @__PURE__ */ jsxs2("section", { children: [
690
+ /* @__PURE__ */ jsx3("strong", { children: "Native arguments" }),
691
+ /* @__PURE__ */ jsx3("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs2("div", { children: [
692
+ /* @__PURE__ */ jsx3("dt", { children: row.label }),
693
+ /* @__PURE__ */ jsx3("dd", { children: /* @__PURE__ */ jsx3("pre", { children: row.value }) })
550
694
  ] }, row.key)) })
551
695
  ] }) : null,
552
- entry.resultText ? /* @__PURE__ */ jsxs("section", { children: [
553
- /* @__PURE__ */ jsx2("strong", { children: "Native result" }),
554
- /* @__PURE__ */ jsxs("pre", { "data-error": entry.status === "error", children: [
696
+ entry.resultText ? /* @__PURE__ */ jsxs2("section", { children: [
697
+ /* @__PURE__ */ jsx3("strong", { children: "Native result" }),
698
+ /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
555
699
  entry.resultText,
556
700
  entry.truncated ? "\n[truncated]" : ""
557
701
  ] })
@@ -560,125 +704,126 @@ function TechnicalDetails({ entry }) {
560
704
  ] });
561
705
  }
562
706
  function TranscriptEntry({ entry, state, adapter }) {
563
- if (entry.role === "request") return /* @__PURE__ */ jsx2(RequestCard, { entry, adapter, canRespond: state.canRespond });
707
+ if (entry.role === "request") return /* @__PURE__ */ jsx3(RequestCard, { entry, adapter, canRespond: state.canRespond });
564
708
  if (entry.role === "reasoning") {
565
- return /* @__PURE__ */ jsxs("details", { class: "scui-reasoning", open: entry.streaming, children: [
566
- /* @__PURE__ */ jsx2("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
567
- /* @__PURE__ */ jsx2(Markdown, { value: entry.text })
709
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-reasoning", open: entry.streaming, children: [
710
+ /* @__PURE__ */ jsx3("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
711
+ /* @__PURE__ */ jsx3(Markdown, { value: entry.text, copyText: adapter?.copyText })
568
712
  ] });
569
713
  }
570
- if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx2("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
571
- return /* @__PURE__ */ jsxs("article", { class: "scui-message", "data-role": entry.role, children: [
572
- /* @__PURE__ */ jsx2(Markdown, { value: entry.text }),
573
- /* @__PURE__ */ jsx2(ContextDisclosure, { context: entry.context }),
574
- entry.truncated ? /* @__PURE__ */ jsx2("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
714
+ if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx3("div", { class: "scui-notice", "data-code": entry.code, children: entry.text });
715
+ return /* @__PURE__ */ jsxs2("article", { class: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
716
+ /* @__PURE__ */ jsx3(Markdown, { value: entry.text, copyText: adapter?.copyText }),
717
+ /* @__PURE__ */ jsx3(ContextDisclosure, { context: entry.context }),
718
+ entry.truncated ? /* @__PURE__ */ jsx3("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
719
+ /* @__PURE__ */ jsx3(MessageMeta, { entry, adapter })
575
720
  ] });
576
721
  }
577
722
  function ToolRow({ entry, workspace, open = false, adapter }) {
578
723
  const presentation = entry.presentation ?? createToolPresentation(entry);
579
724
  const [expanded, setExpanded] = useState(open || entry.status === "pending");
580
- useEffect(() => {
725
+ useEffect2(() => {
581
726
  if (entry.status === "pending") setExpanded(true);
582
727
  }, [entry.status]);
583
728
  const target = compactToolTarget(presentation.target, workspace);
584
729
  const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
585
730
  const category = presentation.category ?? toolCategory(entry);
586
- const summary = /* @__PURE__ */ jsxs(Fragment, { children: [
587
- /* @__PURE__ */ jsx2(ToolIcon, { category }),
588
- /* @__PURE__ */ jsx2("strong", { children: toolAction2(entry, category, presentation) }),
589
- target ? /* @__PURE__ */ jsx2("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
590
- /* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
591
- entry.status === "pending" ? /* @__PURE__ */ jsx2(PendingElapsed, { now: adapter?.now }) : null,
592
- /* @__PURE__ */ jsx2("span", { class: "scui-tool-status", role: "status", "data-status": entry.status ?? "completed", "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? /* @__PURE__ */ jsx2("i", {}) : entry.status === "error" ? "\xD7" : "\u2713" }),
593
- hasDetail ? /* @__PURE__ */ jsx2("span", { class: "scui-tool-chevron", "aria-hidden": "true", children: "\u203A" }) : null
731
+ const summary = /* @__PURE__ */ jsxs2(Fragment3, { children: [
732
+ /* @__PURE__ */ jsx3(ToolIcon, { category }),
733
+ /* @__PURE__ */ jsx3("strong", { children: toolAction2(entry, category, presentation) }),
734
+ target ? /* @__PURE__ */ jsx3("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
735
+ /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
736
+ entry.status === "pending" ? /* @__PURE__ */ jsx3(PendingElapsed, { now: adapter?.now }) : null,
737
+ /* @__PURE__ */ jsx3("span", { class: "scui-tool-status", role: "status", "data-status": entry.status ?? "completed", "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? /* @__PURE__ */ jsx3("i", {}) : /* @__PURE__ */ jsx3(UiIcon, { name: entry.status === "error" ? "close" : "check", size: 12 }) }),
738
+ hasDetail ? /* @__PURE__ */ jsx3(UiIcon, { name: "chevron", size: 14, class: "scui-tool-chevron" }) : null
594
739
  ] });
595
- if (!hasDetail) return /* @__PURE__ */ jsx2("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: /* @__PURE__ */ jsx2("div", { class: "scui-tool-head", children: summary }) });
596
- return /* @__PURE__ */ jsxs("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
597
- /* @__PURE__ */ jsx2("summary", { class: "scui-tool-head", children: summary }),
598
- /* @__PURE__ */ jsxs("div", { class: "scui-tool-detail", children: [
599
- /* @__PURE__ */ jsx2(ToolMetrics, { presentation }),
600
- /* @__PURE__ */ jsx2(ToolStack, { tools: presentation.tools ?? [] }),
601
- /* @__PURE__ */ jsx2(ToolPreview, { presentation, entry }),
602
- presentation.fields.length ? /* @__PURE__ */ jsx2("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs("div", { children: [
603
- /* @__PURE__ */ jsx2("dt", { children: field.label }),
604
- /* @__PURE__ */ jsx2("dd", { children: field.value })
740
+ if (!hasDetail) return /* @__PURE__ */ jsx3("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: /* @__PURE__ */ jsx3("div", { class: "scui-tool-head", children: summary }) });
741
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
742
+ /* @__PURE__ */ jsx3("summary", { class: "scui-tool-head", children: summary }),
743
+ /* @__PURE__ */ jsxs2("div", { class: "scui-tool-detail", children: [
744
+ /* @__PURE__ */ jsx3(ToolMetrics, { presentation }),
745
+ /* @__PURE__ */ jsx3(ToolStack, { tools: presentation.tools ?? [] }),
746
+ /* @__PURE__ */ jsx3(ToolPreview, { presentation, entry }),
747
+ presentation.fields.length ? /* @__PURE__ */ jsx3("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs2("div", { children: [
748
+ /* @__PURE__ */ jsx3("dt", { children: field.label }),
749
+ /* @__PURE__ */ jsx3("dd", { children: field.value })
605
750
  ] }, field.label)) }) : null,
606
- /* @__PURE__ */ jsx2(ToolActions, { presentation, adapter }),
607
- /* @__PURE__ */ jsx2(TechnicalDetails, { entry })
751
+ /* @__PURE__ */ jsx3(ToolActions, { presentation, adapter }),
752
+ /* @__PURE__ */ jsx3(TechnicalDetails, { entry })
608
753
  ] })
609
754
  ] });
610
755
  }
611
756
  function ActivityGroup({ entries, state, adapter }) {
612
- if (entries.length === 1) return /* @__PURE__ */ jsx2("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx2(ToolRow, { entry: entries[0], workspace: state.workspace, adapter }) });
757
+ if (entries.length === 1) return /* @__PURE__ */ jsx3("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx3(ToolRow, { entry: entries[0], workspace: state.workspace, adapter }) });
613
758
  const active = entries.some((entry) => entry.status === "pending");
614
759
  const [open, setOpen] = useState(active);
615
760
  const id = useId();
616
- useEffect(() => {
761
+ useEffect2(() => {
617
762
  if (active) setOpen(true);
618
763
  }, [active]);
619
- return /* @__PURE__ */ jsxs("section", { class: "scui-activity", children: [
620
- /* @__PURE__ */ jsxs("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
621
- /* @__PURE__ */ jsx2("span", { class: "scui-fold", "data-open": open, children: "\u203A" }),
622
- /* @__PURE__ */ jsx2("strong", { children: activitySummary(entries) }),
623
- /* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
624
- /* @__PURE__ */ jsxs("small", { children: [
764
+ return /* @__PURE__ */ jsxs2("section", { class: "scui-activity", children: [
765
+ /* @__PURE__ */ jsxs2("button", { class: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
766
+ /* @__PURE__ */ jsx3("span", { class: "scui-fold", "data-open": open, children: /* @__PURE__ */ jsx3(UiIcon, { name: "chevron", size: 14 }) }),
767
+ /* @__PURE__ */ jsx3("strong", { children: activitySummary(entries) }),
768
+ /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
769
+ /* @__PURE__ */ jsxs2("small", { children: [
625
770
  entries.filter((entry) => entry.status !== "pending").length,
626
771
  "/",
627
772
  entries.length
628
773
  ] })
629
774
  ] }),
630
- open ? /* @__PURE__ */ jsx2("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx2(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
775
+ open ? /* @__PURE__ */ jsx3("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx3(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
631
776
  ] });
632
777
  }
633
778
  function TaskPlan({ plan }) {
634
779
  if (!plan.items.length) return null;
635
780
  const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
636
- return /* @__PURE__ */ jsxs("details", { class: "scui-plan", children: [
637
- /* @__PURE__ */ jsxs("summary", { children: [
638
- /* @__PURE__ */ jsx2("span", { children: "Plan" }),
639
- /* @__PURE__ */ jsxs("small", { children: [
781
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-plan", children: [
782
+ /* @__PURE__ */ jsxs2("summary", { children: [
783
+ /* @__PURE__ */ jsx3("span", { children: "Plan" }),
784
+ /* @__PURE__ */ jsxs2("small", { children: [
640
785
  complete,
641
786
  "/",
642
787
  plan.items.length
643
788
  ] })
644
789
  ] }),
645
- /* @__PURE__ */ jsx2("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs("li", { "data-status": item.status, children: [
646
- /* @__PURE__ */ jsx2("i", { "aria-hidden": "true" }),
790
+ /* @__PURE__ */ jsx3("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs2("li", { "data-status": item.status, children: [
791
+ /* @__PURE__ */ jsx3("i", { "aria-hidden": "true" }),
647
792
  " ",
648
- /* @__PURE__ */ jsx2("span", { children: item.title })
793
+ /* @__PURE__ */ jsx3("span", { children: item.title })
649
794
  ] }, item.id)) })
650
795
  ] });
651
796
  }
652
797
  function SessionDetails({ semantics }) {
653
798
  if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
654
- return /* @__PURE__ */ jsxs("details", { class: "scui-details", children: [
655
- /* @__PURE__ */ jsx2("summary", { children: "Session details" }),
656
- /* @__PURE__ */ jsxs("div", { children: [
657
- semantics.fidelity ? /* @__PURE__ */ jsxs("p", { children: [
658
- /* @__PURE__ */ jsx2("strong", { children: "Fidelity" }),
659
- /* @__PURE__ */ jsx2("span", { children: semantics.fidelity.replaceAll("_", " ") })
799
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-details", children: [
800
+ /* @__PURE__ */ jsx3("summary", { children: "Session details" }),
801
+ /* @__PURE__ */ jsxs2("div", { children: [
802
+ semantics.fidelity ? /* @__PURE__ */ jsxs2("p", { children: [
803
+ /* @__PURE__ */ jsx3("strong", { children: "Fidelity" }),
804
+ /* @__PURE__ */ jsx3("span", { children: semantics.fidelity.replaceAll("_", " ") })
660
805
  ] }) : null,
661
- /* @__PURE__ */ jsxs("p", { children: [
662
- /* @__PURE__ */ jsx2("strong", { children: "Native records" }),
663
- /* @__PURE__ */ jsx2("span", { children: semantics.rawRecords })
806
+ /* @__PURE__ */ jsxs2("p", { children: [
807
+ /* @__PURE__ */ jsx3("strong", { children: "Native records" }),
808
+ /* @__PURE__ */ jsx3("span", { children: semantics.rawRecords })
664
809
  ] }),
665
- semantics.residueCount ? /* @__PURE__ */ jsxs("p", { children: [
666
- /* @__PURE__ */ jsx2("strong", { children: "Residue" }),
667
- /* @__PURE__ */ jsxs("span", { children: [
810
+ semantics.residueCount ? /* @__PURE__ */ jsxs2("p", { children: [
811
+ /* @__PURE__ */ jsx3("strong", { children: "Residue" }),
812
+ /* @__PURE__ */ jsxs2("span", { children: [
668
813
  semantics.residueCount,
669
814
  " retained"
670
815
  ] })
671
816
  ] }) : null,
672
- semantics.parseErrors ? /* @__PURE__ */ jsxs("p", { children: [
673
- /* @__PURE__ */ jsx2("strong", { children: "Parse diagnostics" }),
674
- /* @__PURE__ */ jsx2("span", { children: semantics.parseErrors })
817
+ semantics.parseErrors ? /* @__PURE__ */ jsxs2("p", { children: [
818
+ /* @__PURE__ */ jsx3("strong", { children: "Parse diagnostics" }),
819
+ /* @__PURE__ */ jsx3("span", { children: semantics.parseErrors })
675
820
  ] }) : null,
676
- semantics.subagents.map((agent) => /* @__PURE__ */ jsxs("p", { children: [
677
- /* @__PURE__ */ jsxs("strong", { children: [
821
+ semantics.subagents.map((agent) => /* @__PURE__ */ jsxs2("p", { children: [
822
+ /* @__PURE__ */ jsxs2("strong", { children: [
678
823
  agent.source,
679
824
  " subagent"
680
825
  ] }),
681
- /* @__PURE__ */ jsxs("span", { children: [
826
+ /* @__PURE__ */ jsxs2("span", { children: [
682
827
  agent.messages,
683
828
  " messages \xB7 ",
684
829
  agent.fidelity.replaceAll("_", " ")
@@ -688,13 +833,29 @@ function SessionDetails({ semantics }) {
688
833
  ] });
689
834
  }
690
835
  var conversationMemory = /* @__PURE__ */ new Map();
691
- function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null }) {
692
- const scroller = useRef(null);
836
+ function ConversationAnnouncements({ state }) {
837
+ const previousBusy = useRef2(state.busy);
838
+ const [announcement, setAnnouncement] = useState("");
839
+ useEffect2(() => {
840
+ if (previousBusy.current && !state.busy && !state.error) {
841
+ setAnnouncement(`${harnessDisplayName(state.harness) || "Coding agent"} finished working`);
842
+ }
843
+ previousBusy.current = state.busy;
844
+ }, [state.busy, state.error, state.harness]);
845
+ return /* @__PURE__ */ jsx3("span", { class: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
846
+ }
847
+ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null, unreadAfterMessages = null }) {
848
+ const scroller = useRef2(null);
693
849
  const remembered = conversationMemory.get(memoryKey) ?? { top: null, atBottom: true };
694
850
  const [atBottom, setAtBottom] = useState(remembered.atBottom);
695
- const earlierAnchor = useRef(null);
696
- const restored = useRef(false);
851
+ const earlierAnchor = useRef2(null);
852
+ const restored = useRef2(false);
697
853
  const blocks = groupConversation(state.transcript);
854
+ const unreadBoundary = useRef2(Number.isSafeInteger(unreadAfterMessages) && unreadAfterMessages >= 0 ? unreadAfterMessages : null);
855
+ const unreadBlock = unreadBoundary.current === null ? -1 : blocks.findIndex((block) => {
856
+ const entries = block.kind === "activity" ? block.entries : [block.entry];
857
+ return entries.some((entry) => Number.isSafeInteger(entry.messageIndex) && entry.messageIndex > unreadBoundary.current);
858
+ });
698
859
  const Entry = components.TranscriptEntry ?? TranscriptEntry;
699
860
  const Group = components.ActivityGroup ?? ActivityGroup;
700
861
  const Plan = components.TaskPlan ?? TaskPlan;
@@ -725,48 +886,55 @@ function Conversation({ state, adapter, components = {}, slots = {}, memoryKey =
725
886
  else pin();
726
887
  } else if (atBottom) pin();
727
888
  }, [memoryKey, state.transcript, state.busy, state.operation, pendingMessage?.text, pendingMessage?.status]);
728
- return /* @__PURE__ */ jsxs("div", { class: "scui-conversation-wrap", children: [
729
- /* @__PURE__ */ jsx2("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
889
+ return /* @__PURE__ */ jsxs2("div", { class: "scui-conversation-wrap", children: [
890
+ /* @__PURE__ */ jsx3(ConversationAnnouncements, { state }),
891
+ /* @__PURE__ */ jsx3("div", { class: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
730
892
  const element = event.currentTarget;
731
893
  const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
732
894
  setAtBottom(bottom);
733
895
  remember({ top: element.scrollTop, atBottom: bottom });
734
- }, children: /* @__PURE__ */ jsxs("div", { children: [
735
- Before ? /* @__PURE__ */ jsx2(Before, { state, adapter, value: null }) : null,
736
- /* @__PURE__ */ jsx2(Plan, { plan: state.taskPlan, value: state.taskPlan, state, adapter }),
737
- /* @__PURE__ */ jsx2(SessionDetails, { semantics: state.semantics }),
738
- state.history.hasEarlier ? /* @__PURE__ */ jsx2("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
896
+ }, children: /* @__PURE__ */ jsxs2("div", { children: [
897
+ Before ? /* @__PURE__ */ jsx3(Before, { state, adapter, value: null }) : null,
898
+ /* @__PURE__ */ jsx3(Plan, { plan: state.taskPlan, value: state.taskPlan, state, adapter }),
899
+ /* @__PURE__ */ jsx3(SessionDetails, { semantics: state.semantics }),
900
+ state.history.hasEarlier ? /* @__PURE__ */ jsx3("button", { class: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
739
901
  const element = scroller.current;
740
902
  if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length };
741
903
  setAtBottom(false);
742
904
  adapter.onIntent({ action: "loadEarlier" });
743
905
  }, children: "Load earlier messages" }) : null,
744
- !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx2(LoadingStatus, { state }) : null,
745
- !blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx2(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx2("div", { class: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
746
- blocks.map((block) => block.kind === "activity" ? /* @__PURE__ */ jsx2(Group, { value: block.entries, entries: block.entries, state, adapter }, block.id) : /* @__PURE__ */ jsx2(Entry, { value: block.entry, entry: block.entry, state, adapter }, block.id)),
747
- pendingMessage ? /* @__PURE__ */ jsxs("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, children: [
748
- /* @__PURE__ */ jsx2(Markdown, { value: pendingMessage.text }),
749
- /* @__PURE__ */ jsxs("footer", { children: [
750
- /* @__PURE__ */ jsx2("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
751
- pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs("span", { children: [
752
- /* @__PURE__ */ jsx2("button", { type: "button", onClick: pendingMessage.onRetry, children: "Retry" }),
753
- /* @__PURE__ */ jsx2("button", { type: "button", onClick: pendingMessage.onEdit, children: "Edit" })
906
+ !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx3(LoadingStatus, { state }) : null,
907
+ !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,
908
+ blocks.map((block, index) => /* @__PURE__ */ jsxs2(Fragment2, { children: [
909
+ index === unreadBlock ? /* @__PURE__ */ jsx3("div", { class: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx3("span", { children: "New" }) }) : null,
910
+ block.kind === "activity" ? /* @__PURE__ */ jsx3(Group, { value: block.entries, entries: block.entries, state, adapter }) : /* @__PURE__ */ jsx3(Entry, { value: block.entry, entry: block.entry, state, adapter })
911
+ ] }, block.id)),
912
+ pendingMessage ? /* @__PURE__ */ jsxs2("article", { class: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
913
+ /* @__PURE__ */ jsx3(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
914
+ /* @__PURE__ */ jsxs2("footer", { children: [
915
+ /* @__PURE__ */ jsx3("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
916
+ pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs2("span", { children: [
917
+ /* @__PURE__ */ jsx3("button", { type: "button", onClick: pendingMessage.onRetry, children: "Retry" }),
918
+ /* @__PURE__ */ jsx3("button", { type: "button", onClick: pendingMessage.onEdit, children: "Edit" })
754
919
  ] }) : null
755
920
  ] })
756
921
  ] }) : null,
757
- state.busy ? /* @__PURE__ */ jsxs("div", { class: "scui-working", role: "status", children: [
758
- /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", children: "\u2726" }),
759
- /* @__PURE__ */ jsx2("i", {}),
760
- /* @__PURE__ */ jsx2("i", {}),
761
- /* @__PURE__ */ jsx2("i", {}),
762
- /* @__PURE__ */ jsxs("small", { children: [
922
+ state.busy ? /* @__PURE__ */ jsxs2("div", { class: "scui-working", role: "status", children: [
923
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", children: "\u2726" }),
924
+ /* @__PURE__ */ jsx3("i", {}),
925
+ /* @__PURE__ */ jsx3("i", {}),
926
+ /* @__PURE__ */ jsx3("i", {}),
927
+ /* @__PURE__ */ jsxs2("small", { children: [
763
928
  harnessDisplayName(state.harness),
764
929
  " is working"
765
930
  ] })
766
931
  ] }) : null,
767
- After ? /* @__PURE__ */ jsx2(After, { state, adapter, value: null }) : null
932
+ After ? /* @__PURE__ */ jsx3(After, { state, adapter, value: null }) : null
768
933
  ] }) }),
769
- !atBottom ? /* @__PURE__ */ jsx2("button", { class: "scui-latest", type: "button", onClick: pin, children: "\u2193 Latest" }) : null
934
+ !atBottom ? /* @__PURE__ */ jsxs2("button", { class: "scui-latest", type: "button", onClick: pin, children: [
935
+ /* @__PURE__ */ jsx3(UiIcon, { name: "down", size: 13 }),
936
+ " Latest"
937
+ ] }) : null
770
938
  ] });
771
939
  }
772
940
  export {