@volter-ai-dev/supercode-ui 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/components.mjs CHANGED
@@ -329,9 +329,12 @@ function compactToolTarget(target, workspace) {
329
329
  function activitySummary(entries) {
330
330
  const counts = /* @__PURE__ */ new Map();
331
331
  for (const entry of entries) counts.set(toolCategory(entry), (counts.get(toolCategory(entry)) ?? 0) + 1);
332
+ const failed = entries.filter((entry) => entry.status === "error").length;
333
+ const pending = entries.filter((entry) => entry.status === "pending").length;
334
+ if (pending) return `${entries.length} actions in progress`;
335
+ if (failed) return `${entries.length} actions \xB7 ${failed} failed`;
332
336
  if ([...counts.keys()].every((key) => key === "read" || key === "search")) return `Explored ${entries.length} ${entries.length === 1 ? "item" : "items"}`;
333
- const labels = { edit: "changed", test: "tests/builds", command: "commands", read: "reads", search: "searches", web: "web", agent: "agents", other: "other" };
334
- return `Activity \xB7 ${Object.entries(labels).flatMap(([key, label]) => counts.has(key) ? [`${counts.get(key)} ${label}`] : []).join(" \xB7 ")}`;
337
+ return `${entries.length} actions`;
335
338
  }
336
339
  function canContinueHere(state) {
337
340
  if (state.mode !== "mirror" || state.canSend) return false;
@@ -467,7 +470,7 @@ function Markdown({ value }) {
467
470
  }
468
471
 
469
472
  // src/conversation.jsx
470
- import { jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
473
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
471
474
  function LoadingStatus({ state, compact = false }) {
472
475
  const copy = {
473
476
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -515,6 +518,76 @@ function ContextDisclosure({ context }) {
515
518
  ] }, item.id ?? index)) })
516
519
  ] });
517
520
  }
521
+ var TOOL_ICONS = {
522
+ read: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
523
+ /* @__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" }),
524
+ /* @__PURE__ */ jsx3("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
525
+ ] }),
526
+ search: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
527
+ /* @__PURE__ */ jsx3("circle", { cx: "8", cy: "8", r: "4.5" }),
528
+ /* @__PURE__ */ jsx3("path", { d: "m11.5 11.5 3 3" })
529
+ ] }),
530
+ edit: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
531
+ /* @__PURE__ */ jsx3("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
532
+ /* @__PURE__ */ jsx3("path", { d: "m10 5 3 3" })
533
+ ] }),
534
+ command: () => /* @__PURE__ */ jsx3(Fragment, { children: /* @__PURE__ */ jsx3("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
535
+ test: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
536
+ /* @__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" }),
537
+ /* @__PURE__ */ jsx3("path", { d: "M5 2.5h8" })
538
+ ] }),
539
+ web: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
540
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "9", r: "6.5" }),
541
+ /* @__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" })
542
+ ] }),
543
+ agent: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
544
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "6", r: "2.5" }),
545
+ /* @__PURE__ */ jsx3("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
546
+ ] }),
547
+ other: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
548
+ /* @__PURE__ */ jsx3("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
549
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "9", r: "3.5" })
550
+ ] })
551
+ };
552
+ function ToolIcon({ category }) {
553
+ const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
554
+ 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, {}) });
555
+ }
556
+ function toolAction(entry, category) {
557
+ const status = entry.status ?? "completed";
558
+ const actions = {
559
+ read: ["Reading", "Read", "Read failed"],
560
+ search: ["Searching", "Searched", "Search failed"],
561
+ edit: ["Editing", "Edited", "Edit failed"],
562
+ command: ["Running command", "Ran command", "Command failed"],
563
+ test: ["Running tests", "Ran tests", "Tests failed"],
564
+ web: ["Browsing", "Browsed", "Browser action failed"],
565
+ agent: ["Starting agent", "Started agent", "Agent failed"]
566
+ };
567
+ const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
568
+ if (actions[category]) return actions[category][position];
569
+ const label = entry.label?.split(/__|\//).at(-1)?.replaceAll(/[_-]+/g, " ") || "Tool";
570
+ return status === "error" ? `${label} failed` : label;
571
+ }
572
+ function argumentLabel(key) {
573
+ const labels = { cmd: "Command", command: "Command", cwd: "Working directory", file_path: "File", target_file: "File", path: "Path", query: "Query", pattern: "Pattern", url: "URL" };
574
+ return labels[key] ?? key.replaceAll(/[_-]+/g, " ").replace(/^./, (letter) => letter.toLocaleUpperCase());
575
+ }
576
+ function argumentRows(argumentsText) {
577
+ if (!argumentsText) return [];
578
+ try {
579
+ const value = JSON.parse(argumentsText);
580
+ if (value && typeof value === "object" && !Array.isArray(value)) {
581
+ return Object.entries(value).map(([key, item]) => ({
582
+ key,
583
+ label: argumentLabel(key),
584
+ value: typeof item === "string" ? item : JSON.stringify(item, null, 2)
585
+ }));
586
+ }
587
+ } catch {
588
+ }
589
+ return [{ key: "arguments", label: "Details", value: argumentsText }];
590
+ }
518
591
  function TranscriptEntry({ entry, state, adapter }) {
519
592
  if (entry.role === "request") return /* @__PURE__ */ jsx3(RequestCard, { entry, adapter, canRespond: state.canRespond });
520
593
  if (entry.role === "reasoning") {
@@ -531,35 +604,37 @@ function TranscriptEntry({ entry, state, adapter }) {
531
604
  ] });
532
605
  }
533
606
  function ToolRow({ entry, workspace }) {
534
- const [open, setOpen] = useState2(entry.status === "pending");
535
- const detailId = useId();
536
607
  const target = compactToolTarget(toolTarget(entry.arguments), workspace);
537
608
  const hasDetail = Boolean(entry.arguments || entry.resultText);
538
609
  const category = toolCategory(entry);
539
- return /* @__PURE__ */ jsxs2("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
540
- /* @__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: [
541
- /* @__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] }),
542
- /* @__PURE__ */ jsx3("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
543
- target ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
544
- /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
545
- /* @__PURE__ */ jsx3("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
546
- ] }),
547
- hasDetail && open ? /* @__PURE__ */ jsxs2("div", { id: detailId, class: "scui-tool-detail", children: [
548
- entry.arguments ? /* @__PURE__ */ jsxs2("pre", { children: [
549
- /* @__PURE__ */ jsx3("b", { children: "Input" }),
550
- "\n",
551
- entry.arguments
552
- ] }) : null,
553
- entry.resultText ? /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
554
- /* @__PURE__ */ jsx3("b", { children: "Output" }),
555
- "\n",
556
- entry.resultText,
557
- entry.truncated ? "\n[truncated]" : ""
610
+ const summary = /* @__PURE__ */ jsxs2(Fragment, { children: [
611
+ /* @__PURE__ */ jsx3(ToolIcon, { category }),
612
+ /* @__PURE__ */ jsx3("strong", { children: toolAction(entry, category) }),
613
+ target ? /* @__PURE__ */ jsx3("code", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
614
+ /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
615
+ /* @__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", {}) : entry.status === "error" ? "\xD7" : "\u2713" }),
616
+ hasDetail ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-chevron", "aria-hidden": "true", children: "\u203A" }) : null
617
+ ] });
618
+ 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 }) });
619
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
620
+ /* @__PURE__ */ jsx3("summary", { class: "scui-tool-head", children: summary }),
621
+ /* @__PURE__ */ jsxs2("div", { class: "scui-tool-detail", children: [
622
+ entry.arguments ? /* @__PURE__ */ jsx3("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs2("div", { children: [
623
+ /* @__PURE__ */ jsx3("dt", { children: row.label }),
624
+ /* @__PURE__ */ jsx3("dd", { children: /* @__PURE__ */ jsx3("pre", { children: row.value }) })
625
+ ] }, row.key)) }) : null,
626
+ entry.resultText ? /* @__PURE__ */ jsxs2("section", { children: [
627
+ /* @__PURE__ */ jsx3("strong", { children: entry.status === "error" ? "Error" : "Result" }),
628
+ /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
629
+ entry.resultText,
630
+ entry.truncated ? "\n[truncated]" : ""
631
+ ] })
558
632
  ] }) : null
559
- ] }) : null
633
+ ] })
560
634
  ] });
561
635
  }
562
636
  function ActivityGroup({ entries, state }) {
637
+ if (entries.length === 1) return /* @__PURE__ */ jsx3("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx3(ToolRow, { entry: entries[0], workspace: state.workspace }) });
563
638
  const active = entries.some((entry) => entry.status === "pending");
564
639
  const [open, setOpen] = useState2(active);
565
640
  const id = useId();
@@ -572,7 +647,7 @@ function ActivityGroup({ entries, state }) {
572
647
  /* @__PURE__ */ jsx3("strong", { children: activitySummary(entries) }),
573
648
  /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
574
649
  /* @__PURE__ */ jsxs2("small", { children: [
575
- entries.filter((entry) => entry.status === "completed").length,
650
+ entries.filter((entry) => entry.status !== "pending").length,
576
651
  "/",
577
652
  entries.length
578
653
  ] })
@@ -942,9 +1017,13 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
942
1017
  }
943
1018
  function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
944
1019
  const startable = state.harnesses.filter((item) => item.startable);
1020
+ const startableKey = startable.map((item) => item.id).join("\0");
945
1021
  const [harness, setHarness] = useState4(startable[0]?.id ?? "");
946
1022
  const [draft, setDraft] = useState4("");
947
1023
  const [starting, setStarting] = useState4(false);
1024
+ useEffect4(() => {
1025
+ if (!startable.some((item) => item.id === harness)) setHarness(startable[0]?.id ?? "");
1026
+ }, [harness, startableKey]);
948
1027
  useEffect4(() => {
949
1028
  if (starting && (state.busy || state.transcript.length)) onStarted();
950
1029
  }, [onStarted, starting, state.busy, state.transcript.length]);
package/conversation.mjs CHANGED
@@ -105,9 +105,12 @@ function compactToolTarget(target, workspace) {
105
105
  function activitySummary(entries) {
106
106
  const counts = /* @__PURE__ */ new Map();
107
107
  for (const entry of entries) counts.set(toolCategory(entry), (counts.get(toolCategory(entry)) ?? 0) + 1);
108
+ const failed = entries.filter((entry) => entry.status === "error").length;
109
+ const pending = entries.filter((entry) => entry.status === "pending").length;
110
+ if (pending) return `${entries.length} actions in progress`;
111
+ if (failed) return `${entries.length} actions \xB7 ${failed} failed`;
108
112
  if ([...counts.keys()].every((key) => key === "read" || key === "search")) return `Explored ${entries.length} ${entries.length === 1 ? "item" : "items"}`;
109
- const labels = { edit: "changed", test: "tests/builds", command: "commands", read: "reads", search: "searches", web: "web", agent: "agents", other: "other" };
110
- return `Activity \xB7 ${Object.entries(labels).flatMap(([key, label]) => counts.has(key) ? [`${counts.get(key)} ${label}`] : []).join(" \xB7 ")}`;
113
+ return `${entries.length} actions`;
111
114
  }
112
115
 
113
116
  // src/markdown.jsx
@@ -135,7 +138,7 @@ function boundedSet(map, key, value) {
135
138
  }
136
139
 
137
140
  // src/conversation.jsx
138
- import { jsx as jsx2, jsxs } from "preact/jsx-runtime";
141
+ import { Fragment, jsx as jsx2, jsxs } from "preact/jsx-runtime";
139
142
  function LoadingStatus({ state, compact = false }) {
140
143
  const copy = {
141
144
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -183,6 +186,76 @@ function ContextDisclosure({ context }) {
183
186
  ] }, item.id ?? index)) })
184
187
  ] });
185
188
  }
189
+ var TOOL_ICONS = {
190
+ read: () => /* @__PURE__ */ jsxs(Fragment, { children: [
191
+ /* @__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" }),
192
+ /* @__PURE__ */ jsx2("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
193
+ ] }),
194
+ search: () => /* @__PURE__ */ jsxs(Fragment, { children: [
195
+ /* @__PURE__ */ jsx2("circle", { cx: "8", cy: "8", r: "4.5" }),
196
+ /* @__PURE__ */ jsx2("path", { d: "m11.5 11.5 3 3" })
197
+ ] }),
198
+ edit: () => /* @__PURE__ */ jsxs(Fragment, { children: [
199
+ /* @__PURE__ */ jsx2("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
200
+ /* @__PURE__ */ jsx2("path", { d: "m10 5 3 3" })
201
+ ] }),
202
+ command: () => /* @__PURE__ */ jsx2(Fragment, { children: /* @__PURE__ */ jsx2("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
203
+ test: () => /* @__PURE__ */ jsxs(Fragment, { children: [
204
+ /* @__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" }),
205
+ /* @__PURE__ */ jsx2("path", { d: "M5 2.5h8" })
206
+ ] }),
207
+ web: () => /* @__PURE__ */ jsxs(Fragment, { children: [
208
+ /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "6.5" }),
209
+ /* @__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" })
210
+ ] }),
211
+ agent: () => /* @__PURE__ */ jsxs(Fragment, { children: [
212
+ /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "6", r: "2.5" }),
213
+ /* @__PURE__ */ jsx2("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
214
+ ] }),
215
+ other: () => /* @__PURE__ */ jsxs(Fragment, { children: [
216
+ /* @__PURE__ */ jsx2("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
217
+ /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "3.5" })
218
+ ] })
219
+ };
220
+ function ToolIcon({ category }) {
221
+ const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
222
+ 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, {}) });
223
+ }
224
+ function toolAction(entry, category) {
225
+ const status = entry.status ?? "completed";
226
+ const actions = {
227
+ read: ["Reading", "Read", "Read failed"],
228
+ search: ["Searching", "Searched", "Search failed"],
229
+ edit: ["Editing", "Edited", "Edit failed"],
230
+ command: ["Running command", "Ran command", "Command failed"],
231
+ test: ["Running tests", "Ran tests", "Tests failed"],
232
+ web: ["Browsing", "Browsed", "Browser action failed"],
233
+ agent: ["Starting agent", "Started agent", "Agent failed"]
234
+ };
235
+ const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
236
+ if (actions[category]) return actions[category][position];
237
+ const label = entry.label?.split(/__|\//).at(-1)?.replaceAll(/[_-]+/g, " ") || "Tool";
238
+ return status === "error" ? `${label} failed` : label;
239
+ }
240
+ function argumentLabel(key) {
241
+ const labels = { cmd: "Command", command: "Command", cwd: "Working directory", file_path: "File", target_file: "File", path: "Path", query: "Query", pattern: "Pattern", url: "URL" };
242
+ return labels[key] ?? key.replaceAll(/[_-]+/g, " ").replace(/^./, (letter) => letter.toLocaleUpperCase());
243
+ }
244
+ function argumentRows(argumentsText) {
245
+ if (!argumentsText) return [];
246
+ try {
247
+ const value = JSON.parse(argumentsText);
248
+ if (value && typeof value === "object" && !Array.isArray(value)) {
249
+ return Object.entries(value).map(([key, item]) => ({
250
+ key,
251
+ label: argumentLabel(key),
252
+ value: typeof item === "string" ? item : JSON.stringify(item, null, 2)
253
+ }));
254
+ }
255
+ } catch {
256
+ }
257
+ return [{ key: "arguments", label: "Details", value: argumentsText }];
258
+ }
186
259
  function TranscriptEntry({ entry, state, adapter }) {
187
260
  if (entry.role === "request") return /* @__PURE__ */ jsx2(RequestCard, { entry, adapter, canRespond: state.canRespond });
188
261
  if (entry.role === "reasoning") {
@@ -199,35 +272,37 @@ function TranscriptEntry({ entry, state, adapter }) {
199
272
  ] });
200
273
  }
201
274
  function ToolRow({ entry, workspace }) {
202
- const [open, setOpen] = useState(entry.status === "pending");
203
- const detailId = useId();
204
275
  const target = compactToolTarget(toolTarget(entry.arguments), workspace);
205
276
  const hasDetail = Boolean(entry.arguments || entry.resultText);
206
277
  const category = toolCategory(entry);
207
- return /* @__PURE__ */ jsxs("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
208
- /* @__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: [
209
- /* @__PURE__ */ jsx2("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] }),
210
- /* @__PURE__ */ jsx2("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
211
- target ? /* @__PURE__ */ jsx2("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
212
- /* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
213
- /* @__PURE__ */ jsx2("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
214
- ] }),
215
- hasDetail && open ? /* @__PURE__ */ jsxs("div", { id: detailId, class: "scui-tool-detail", children: [
216
- entry.arguments ? /* @__PURE__ */ jsxs("pre", { children: [
217
- /* @__PURE__ */ jsx2("b", { children: "Input" }),
218
- "\n",
219
- entry.arguments
220
- ] }) : null,
221
- entry.resultText ? /* @__PURE__ */ jsxs("pre", { "data-error": entry.status === "error", children: [
222
- /* @__PURE__ */ jsx2("b", { children: "Output" }),
223
- "\n",
224
- entry.resultText,
225
- entry.truncated ? "\n[truncated]" : ""
278
+ const summary = /* @__PURE__ */ jsxs(Fragment, { children: [
279
+ /* @__PURE__ */ jsx2(ToolIcon, { category }),
280
+ /* @__PURE__ */ jsx2("strong", { children: toolAction(entry, category) }),
281
+ target ? /* @__PURE__ */ jsx2("code", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
282
+ /* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
283
+ /* @__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" }),
284
+ hasDetail ? /* @__PURE__ */ jsx2("span", { class: "scui-tool-chevron", "aria-hidden": "true", children: "\u203A" }) : null
285
+ ] });
286
+ 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 }) });
287
+ return /* @__PURE__ */ jsxs("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
288
+ /* @__PURE__ */ jsx2("summary", { class: "scui-tool-head", children: summary }),
289
+ /* @__PURE__ */ jsxs("div", { class: "scui-tool-detail", children: [
290
+ entry.arguments ? /* @__PURE__ */ jsx2("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs("div", { children: [
291
+ /* @__PURE__ */ jsx2("dt", { children: row.label }),
292
+ /* @__PURE__ */ jsx2("dd", { children: /* @__PURE__ */ jsx2("pre", { children: row.value }) })
293
+ ] }, row.key)) }) : null,
294
+ entry.resultText ? /* @__PURE__ */ jsxs("section", { children: [
295
+ /* @__PURE__ */ jsx2("strong", { children: entry.status === "error" ? "Error" : "Result" }),
296
+ /* @__PURE__ */ jsxs("pre", { "data-error": entry.status === "error", children: [
297
+ entry.resultText,
298
+ entry.truncated ? "\n[truncated]" : ""
299
+ ] })
226
300
  ] }) : null
227
- ] }) : null
301
+ ] })
228
302
  ] });
229
303
  }
230
304
  function ActivityGroup({ entries, state }) {
305
+ if (entries.length === 1) return /* @__PURE__ */ jsx2("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx2(ToolRow, { entry: entries[0], workspace: state.workspace }) });
231
306
  const active = entries.some((entry) => entry.status === "pending");
232
307
  const [open, setOpen] = useState(active);
233
308
  const id = useId();
@@ -240,7 +315,7 @@ function ActivityGroup({ entries, state }) {
240
315
  /* @__PURE__ */ jsx2("strong", { children: activitySummary(entries) }),
241
316
  /* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
242
317
  /* @__PURE__ */ jsxs("small", { children: [
243
- entries.filter((entry) => entry.status === "completed").length,
318
+ entries.filter((entry) => entry.status !== "pending").length,
244
319
  "/",
245
320
  entries.length
246
321
  ] })
package/core.mjs CHANGED
@@ -390,9 +390,12 @@ export function compactToolTarget(target, workspace) {
390
390
  export function activitySummary(entries) {
391
391
  const counts = new Map();
392
392
  for (const entry of entries) counts.set(toolCategory(entry), (counts.get(toolCategory(entry)) ?? 0) + 1);
393
+ const failed = entries.filter((entry) => entry.status === 'error').length;
394
+ const pending = entries.filter((entry) => entry.status === 'pending').length;
395
+ if (pending) return `${entries.length} actions in progress`;
396
+ if (failed) return `${entries.length} actions · ${failed} failed`;
393
397
  if ([...counts.keys()].every((key) => key === 'read' || key === 'search')) return `Explored ${entries.length} ${entries.length === 1 ? 'item' : 'items'}`;
394
- const labels = { edit: 'changed', test: 'tests/builds', command: 'commands', read: 'reads', search: 'searches', web: 'web', agent: 'agents', other: 'other' };
395
- return `Activity · ${Object.entries(labels).flatMap(([key, label]) => counts.has(key) ? [`${counts.get(key)} ${label}`] : []).join(' · ')}`;
398
+ return `${entries.length} actions`;
396
399
  }
397
400
 
398
401
  export function canContinueHere(state) {
package/embed.mjs CHANGED
@@ -332,9 +332,12 @@ function compactToolTarget(target, workspace) {
332
332
  function activitySummary(entries) {
333
333
  const counts = /* @__PURE__ */ new Map();
334
334
  for (const entry of entries) counts.set(toolCategory(entry), (counts.get(toolCategory(entry)) ?? 0) + 1);
335
+ const failed = entries.filter((entry) => entry.status === "error").length;
336
+ const pending = entries.filter((entry) => entry.status === "pending").length;
337
+ if (pending) return `${entries.length} actions in progress`;
338
+ if (failed) return `${entries.length} actions \xB7 ${failed} failed`;
335
339
  if ([...counts.keys()].every((key) => key === "read" || key === "search")) return `Explored ${entries.length} ${entries.length === 1 ? "item" : "items"}`;
336
- const labels = { edit: "changed", test: "tests/builds", command: "commands", read: "reads", search: "searches", web: "web", agent: "agents", other: "other" };
337
- return `Activity \xB7 ${Object.entries(labels).flatMap(([key, label]) => counts.has(key) ? [`${counts.get(key)} ${label}`] : []).join(" \xB7 ")}`;
340
+ return `${entries.length} actions`;
338
341
  }
339
342
  function canContinueHere(state) {
340
343
  if (state.mode !== "mirror" || state.canSend) return false;
@@ -473,7 +476,7 @@ function Markdown({ value }) {
473
476
  }
474
477
 
475
478
  // src/conversation.jsx
476
- import { jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
479
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
477
480
  function LoadingStatus({ state, compact = false }) {
478
481
  const copy = {
479
482
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -521,6 +524,76 @@ function ContextDisclosure({ context }) {
521
524
  ] }, item.id ?? index)) })
522
525
  ] });
523
526
  }
527
+ var TOOL_ICONS = {
528
+ read: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
529
+ /* @__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" }),
530
+ /* @__PURE__ */ jsx3("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
531
+ ] }),
532
+ search: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
533
+ /* @__PURE__ */ jsx3("circle", { cx: "8", cy: "8", r: "4.5" }),
534
+ /* @__PURE__ */ jsx3("path", { d: "m11.5 11.5 3 3" })
535
+ ] }),
536
+ edit: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
537
+ /* @__PURE__ */ jsx3("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
538
+ /* @__PURE__ */ jsx3("path", { d: "m10 5 3 3" })
539
+ ] }),
540
+ command: () => /* @__PURE__ */ jsx3(Fragment, { children: /* @__PURE__ */ jsx3("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
541
+ test: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
542
+ /* @__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" }),
543
+ /* @__PURE__ */ jsx3("path", { d: "M5 2.5h8" })
544
+ ] }),
545
+ web: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
546
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "9", r: "6.5" }),
547
+ /* @__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" })
548
+ ] }),
549
+ agent: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
550
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "6", r: "2.5" }),
551
+ /* @__PURE__ */ jsx3("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
552
+ ] }),
553
+ other: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
554
+ /* @__PURE__ */ jsx3("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
555
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "9", r: "3.5" })
556
+ ] })
557
+ };
558
+ function ToolIcon({ category }) {
559
+ const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
560
+ 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, {}) });
561
+ }
562
+ function toolAction(entry, category) {
563
+ const status = entry.status ?? "completed";
564
+ const actions = {
565
+ read: ["Reading", "Read", "Read failed"],
566
+ search: ["Searching", "Searched", "Search failed"],
567
+ edit: ["Editing", "Edited", "Edit failed"],
568
+ command: ["Running command", "Ran command", "Command failed"],
569
+ test: ["Running tests", "Ran tests", "Tests failed"],
570
+ web: ["Browsing", "Browsed", "Browser action failed"],
571
+ agent: ["Starting agent", "Started agent", "Agent failed"]
572
+ };
573
+ const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
574
+ if (actions[category]) return actions[category][position];
575
+ const label = entry.label?.split(/__|\//).at(-1)?.replaceAll(/[_-]+/g, " ") || "Tool";
576
+ return status === "error" ? `${label} failed` : label;
577
+ }
578
+ function argumentLabel(key) {
579
+ const labels = { cmd: "Command", command: "Command", cwd: "Working directory", file_path: "File", target_file: "File", path: "Path", query: "Query", pattern: "Pattern", url: "URL" };
580
+ return labels[key] ?? key.replaceAll(/[_-]+/g, " ").replace(/^./, (letter) => letter.toLocaleUpperCase());
581
+ }
582
+ function argumentRows(argumentsText) {
583
+ if (!argumentsText) return [];
584
+ try {
585
+ const value = JSON.parse(argumentsText);
586
+ if (value && typeof value === "object" && !Array.isArray(value)) {
587
+ return Object.entries(value).map(([key, item]) => ({
588
+ key,
589
+ label: argumentLabel(key),
590
+ value: typeof item === "string" ? item : JSON.stringify(item, null, 2)
591
+ }));
592
+ }
593
+ } catch {
594
+ }
595
+ return [{ key: "arguments", label: "Details", value: argumentsText }];
596
+ }
524
597
  function TranscriptEntry({ entry, state, adapter }) {
525
598
  if (entry.role === "request") return /* @__PURE__ */ jsx3(RequestCard, { entry, adapter, canRespond: state.canRespond });
526
599
  if (entry.role === "reasoning") {
@@ -537,35 +610,37 @@ function TranscriptEntry({ entry, state, adapter }) {
537
610
  ] });
538
611
  }
539
612
  function ToolRow({ entry, workspace }) {
540
- const [open, setOpen] = useState2(entry.status === "pending");
541
- const detailId = useId();
542
613
  const target = compactToolTarget(toolTarget(entry.arguments), workspace);
543
614
  const hasDetail = Boolean(entry.arguments || entry.resultText);
544
615
  const category = toolCategory(entry);
545
- return /* @__PURE__ */ jsxs2("div", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
546
- /* @__PURE__ */ jsxs2("button", { type: "button", class: "scui-tool-head", disabled: !hasDetail, "aria-expanded": hasDetail ? open : void 0, "aria-controls": hasDetail ? detailId : void 0, onClick: () => hasDetail && setOpen((value) => !value), children: [
547
- /* @__PURE__ */ jsx3("span", { class: "scui-tool-glyph", "aria-hidden": "true", children: { read: "\u25A4", search: "\u2315", edit: "\u270E", command: ">_", test: "\u25C7", web: "\u25CE", agent: "\u2659", other: "\u25C6" }[category] }),
548
- /* @__PURE__ */ jsx3("strong", { children: entry.label?.split(/__|\//).at(-1)?.replaceAll("_", " ") || "Tool" }),
549
- target ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
550
- /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
551
- /* @__PURE__ */ jsx3("span", { "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? "\u25CC" : entry.status === "error" ? "\xD7" : "\u2713" })
552
- ] }),
553
- hasDetail && open ? /* @__PURE__ */ jsxs2("div", { id: detailId, class: "scui-tool-detail", children: [
554
- entry.arguments ? /* @__PURE__ */ jsxs2("pre", { children: [
555
- /* @__PURE__ */ jsx3("b", { children: "Input" }),
556
- "\n",
557
- entry.arguments
558
- ] }) : null,
559
- entry.resultText ? /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
560
- /* @__PURE__ */ jsx3("b", { children: "Output" }),
561
- "\n",
562
- entry.resultText,
563
- entry.truncated ? "\n[truncated]" : ""
616
+ const summary = /* @__PURE__ */ jsxs2(Fragment, { children: [
617
+ /* @__PURE__ */ jsx3(ToolIcon, { category }),
618
+ /* @__PURE__ */ jsx3("strong", { children: toolAction(entry, category) }),
619
+ target ? /* @__PURE__ */ jsx3("code", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
620
+ /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
621
+ /* @__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", {}) : entry.status === "error" ? "\xD7" : "\u2713" }),
622
+ hasDetail ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-chevron", "aria-hidden": "true", children: "\u203A" }) : null
623
+ ] });
624
+ 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 }) });
625
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
626
+ /* @__PURE__ */ jsx3("summary", { class: "scui-tool-head", children: summary }),
627
+ /* @__PURE__ */ jsxs2("div", { class: "scui-tool-detail", children: [
628
+ entry.arguments ? /* @__PURE__ */ jsx3("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs2("div", { children: [
629
+ /* @__PURE__ */ jsx3("dt", { children: row.label }),
630
+ /* @__PURE__ */ jsx3("dd", { children: /* @__PURE__ */ jsx3("pre", { children: row.value }) })
631
+ ] }, row.key)) }) : null,
632
+ entry.resultText ? /* @__PURE__ */ jsxs2("section", { children: [
633
+ /* @__PURE__ */ jsx3("strong", { children: entry.status === "error" ? "Error" : "Result" }),
634
+ /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
635
+ entry.resultText,
636
+ entry.truncated ? "\n[truncated]" : ""
637
+ ] })
564
638
  ] }) : null
565
- ] }) : null
639
+ ] })
566
640
  ] });
567
641
  }
568
642
  function ActivityGroup({ entries, state }) {
643
+ if (entries.length === 1) return /* @__PURE__ */ jsx3("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx3(ToolRow, { entry: entries[0], workspace: state.workspace }) });
569
644
  const active = entries.some((entry) => entry.status === "pending");
570
645
  const [open, setOpen] = useState2(active);
571
646
  const id = useId();
@@ -578,7 +653,7 @@ function ActivityGroup({ entries, state }) {
578
653
  /* @__PURE__ */ jsx3("strong", { children: activitySummary(entries) }),
579
654
  /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
580
655
  /* @__PURE__ */ jsxs2("small", { children: [
581
- entries.filter((entry) => entry.status === "completed").length,
656
+ entries.filter((entry) => entry.status !== "pending").length,
582
657
  "/",
583
658
  entries.length
584
659
  ] })
@@ -942,9 +1017,13 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
942
1017
  }
943
1018
  function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
944
1019
  const startable = state.harnesses.filter((item) => item.startable);
1020
+ const startableKey = startable.map((item) => item.id).join("\0");
945
1021
  const [harness, setHarness] = useState4(startable[0]?.id ?? "");
946
1022
  const [draft, setDraft] = useState4("");
947
1023
  const [starting, setStarting] = useState4(false);
1024
+ useEffect4(() => {
1025
+ if (!startable.some((item) => item.id === harness)) setHarness(startable[0]?.id ?? "");
1026
+ }, [harness, startableKey]);
948
1027
  useEffect4(() => {
949
1028
  if (starting && (state.busy || state.transcript.length)) onStarted();
950
1029
  }, [onStarted, starting, state.busy, state.transcript.length]);
package/messenger.mjs CHANGED
@@ -329,9 +329,12 @@ function compactToolTarget(target, workspace) {
329
329
  function activitySummary(entries) {
330
330
  const counts = /* @__PURE__ */ new Map();
331
331
  for (const entry of entries) counts.set(toolCategory(entry), (counts.get(toolCategory(entry)) ?? 0) + 1);
332
+ const failed = entries.filter((entry) => entry.status === "error").length;
333
+ const pending = entries.filter((entry) => entry.status === "pending").length;
334
+ if (pending) return `${entries.length} actions in progress`;
335
+ if (failed) return `${entries.length} actions \xB7 ${failed} failed`;
332
336
  if ([...counts.keys()].every((key) => key === "read" || key === "search")) return `Explored ${entries.length} ${entries.length === 1 ? "item" : "items"}`;
333
- const labels = { edit: "changed", test: "tests/builds", command: "commands", read: "reads", search: "searches", web: "web", agent: "agents", other: "other" };
334
- return `Activity \xB7 ${Object.entries(labels).flatMap(([key, label]) => counts.has(key) ? [`${counts.get(key)} ${label}`] : []).join(" \xB7 ")}`;
337
+ return `${entries.length} actions`;
335
338
  }
336
339
  function canContinueHere(state) {
337
340
  if (state.mode !== "mirror" || state.canSend) return false;
@@ -470,7 +473,7 @@ function Markdown({ value }) {
470
473
  }
471
474
 
472
475
  // src/conversation.jsx
473
- import { jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
476
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "preact/jsx-runtime";
474
477
  function LoadingStatus({ state, compact = false }) {
475
478
  const copy = {
476
479
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
@@ -518,6 +521,76 @@ function ContextDisclosure({ context }) {
518
521
  ] }, item.id ?? index)) })
519
522
  ] });
520
523
  }
524
+ var TOOL_ICONS = {
525
+ read: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
526
+ /* @__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" }),
527
+ /* @__PURE__ */ jsx3("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
528
+ ] }),
529
+ search: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
530
+ /* @__PURE__ */ jsx3("circle", { cx: "8", cy: "8", r: "4.5" }),
531
+ /* @__PURE__ */ jsx3("path", { d: "m11.5 11.5 3 3" })
532
+ ] }),
533
+ edit: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
534
+ /* @__PURE__ */ jsx3("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
535
+ /* @__PURE__ */ jsx3("path", { d: "m10 5 3 3" })
536
+ ] }),
537
+ command: () => /* @__PURE__ */ jsx3(Fragment, { children: /* @__PURE__ */ jsx3("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
538
+ test: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
539
+ /* @__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" }),
540
+ /* @__PURE__ */ jsx3("path", { d: "M5 2.5h8" })
541
+ ] }),
542
+ web: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
543
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "9", r: "6.5" }),
544
+ /* @__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" })
545
+ ] }),
546
+ agent: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
547
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "6", r: "2.5" }),
548
+ /* @__PURE__ */ jsx3("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
549
+ ] }),
550
+ other: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
551
+ /* @__PURE__ */ jsx3("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
552
+ /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "9", r: "3.5" })
553
+ ] })
554
+ };
555
+ function ToolIcon({ category }) {
556
+ const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
557
+ 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, {}) });
558
+ }
559
+ function toolAction(entry, category) {
560
+ const status = entry.status ?? "completed";
561
+ const actions = {
562
+ read: ["Reading", "Read", "Read failed"],
563
+ search: ["Searching", "Searched", "Search failed"],
564
+ edit: ["Editing", "Edited", "Edit failed"],
565
+ command: ["Running command", "Ran command", "Command failed"],
566
+ test: ["Running tests", "Ran tests", "Tests failed"],
567
+ web: ["Browsing", "Browsed", "Browser action failed"],
568
+ agent: ["Starting agent", "Started agent", "Agent failed"]
569
+ };
570
+ const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
571
+ if (actions[category]) return actions[category][position];
572
+ const label = entry.label?.split(/__|\//).at(-1)?.replaceAll(/[_-]+/g, " ") || "Tool";
573
+ return status === "error" ? `${label} failed` : label;
574
+ }
575
+ function argumentLabel(key) {
576
+ const labels = { cmd: "Command", command: "Command", cwd: "Working directory", file_path: "File", target_file: "File", path: "Path", query: "Query", pattern: "Pattern", url: "URL" };
577
+ return labels[key] ?? key.replaceAll(/[_-]+/g, " ").replace(/^./, (letter) => letter.toLocaleUpperCase());
578
+ }
579
+ function argumentRows(argumentsText) {
580
+ if (!argumentsText) return [];
581
+ try {
582
+ const value = JSON.parse(argumentsText);
583
+ if (value && typeof value === "object" && !Array.isArray(value)) {
584
+ return Object.entries(value).map(([key, item]) => ({
585
+ key,
586
+ label: argumentLabel(key),
587
+ value: typeof item === "string" ? item : JSON.stringify(item, null, 2)
588
+ }));
589
+ }
590
+ } catch {
591
+ }
592
+ return [{ key: "arguments", label: "Details", value: argumentsText }];
593
+ }
521
594
  function TranscriptEntry({ entry, state, adapter }) {
522
595
  if (entry.role === "request") return /* @__PURE__ */ jsx3(RequestCard, { entry, adapter, canRespond: state.canRespond });
523
596
  if (entry.role === "reasoning") {
@@ -534,35 +607,37 @@ function TranscriptEntry({ entry, state, adapter }) {
534
607
  ] });
535
608
  }
536
609
  function ToolRow({ entry, workspace }) {
537
- const [open, setOpen] = useState2(entry.status === "pending");
538
- const detailId = useId();
539
610
  const target = compactToolTarget(toolTarget(entry.arguments), workspace);
540
611
  const hasDetail = Boolean(entry.arguments || entry.resultText);
541
612
  const category = toolCategory(entry);
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" })
549
- ] }),
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" }),
553
- "\n",
554
- entry.arguments
555
- ] }) : null,
556
- entry.resultText ? /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
557
- /* @__PURE__ */ jsx3("b", { children: "Output" }),
558
- "\n",
559
- entry.resultText,
560
- entry.truncated ? "\n[truncated]" : ""
613
+ const summary = /* @__PURE__ */ jsxs2(Fragment, { children: [
614
+ /* @__PURE__ */ jsx3(ToolIcon, { category }),
615
+ /* @__PURE__ */ jsx3("strong", { children: toolAction(entry, category) }),
616
+ target ? /* @__PURE__ */ jsx3("code", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
617
+ /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
618
+ /* @__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", {}) : entry.status === "error" ? "\xD7" : "\u2713" }),
619
+ hasDetail ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-chevron", "aria-hidden": "true", children: "\u203A" }) : null
620
+ ] });
621
+ 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 }) });
622
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
623
+ /* @__PURE__ */ jsx3("summary", { class: "scui-tool-head", children: summary }),
624
+ /* @__PURE__ */ jsxs2("div", { class: "scui-tool-detail", children: [
625
+ entry.arguments ? /* @__PURE__ */ jsx3("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs2("div", { children: [
626
+ /* @__PURE__ */ jsx3("dt", { children: row.label }),
627
+ /* @__PURE__ */ jsx3("dd", { children: /* @__PURE__ */ jsx3("pre", { children: row.value }) })
628
+ ] }, row.key)) }) : null,
629
+ entry.resultText ? /* @__PURE__ */ jsxs2("section", { children: [
630
+ /* @__PURE__ */ jsx3("strong", { children: entry.status === "error" ? "Error" : "Result" }),
631
+ /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
632
+ entry.resultText,
633
+ entry.truncated ? "\n[truncated]" : ""
634
+ ] })
561
635
  ] }) : null
562
- ] }) : null
636
+ ] })
563
637
  ] });
564
638
  }
565
639
  function ActivityGroup({ entries, state }) {
640
+ if (entries.length === 1) return /* @__PURE__ */ jsx3("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx3(ToolRow, { entry: entries[0], workspace: state.workspace }) });
566
641
  const active = entries.some((entry) => entry.status === "pending");
567
642
  const [open, setOpen] = useState2(active);
568
643
  const id = useId();
@@ -575,7 +650,7 @@ function ActivityGroup({ entries, state }) {
575
650
  /* @__PURE__ */ jsx3("strong", { children: activitySummary(entries) }),
576
651
  /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
577
652
  /* @__PURE__ */ jsxs2("small", { children: [
578
- entries.filter((entry) => entry.status === "completed").length,
653
+ entries.filter((entry) => entry.status !== "pending").length,
579
654
  "/",
580
655
  entries.length
581
656
  ] })
@@ -939,9 +1014,13 @@ function Chat({ state, adapter, onBack, onNew, onClose, components, slots, label
939
1014
  }
940
1015
  function NewChat({ state, adapter, onBack, onClose, onStarted, labels }) {
941
1016
  const startable = state.harnesses.filter((item) => item.startable);
1017
+ const startableKey = startable.map((item) => item.id).join("\0");
942
1018
  const [harness, setHarness] = useState4(startable[0]?.id ?? "");
943
1019
  const [draft, setDraft] = useState4("");
944
1020
  const [starting, setStarting] = useState4(false);
1021
+ useEffect4(() => {
1022
+ if (!startable.some((item) => item.id === harness)) setHarness(startable[0]?.id ?? "");
1023
+ }, [harness, startableKey]);
945
1024
  useEffect4(() => {
946
1025
  if (starting && (state.busy || state.transcript.length)) onStarted();
947
1026
  }, [onStarted, starting, state.busy, state.transcript.length]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter-ai-dev/supercode-ui",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "description": "Composable default UI kit for Supercode-powered coding-agent experiences",
6
6
  "exports": {
package/sessions.mjs CHANGED
@@ -97,7 +97,7 @@ markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
97
97
  };
98
98
 
99
99
  // src/conversation.jsx
100
- import { jsx as jsx2, jsxs } from "preact/jsx-runtime";
100
+ import { Fragment, jsx as jsx2, jsxs } from "preact/jsx-runtime";
101
101
  function LoadingStatus({ state, compact = false }) {
102
102
  const copy = {
103
103
  connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
package/styles.css CHANGED
@@ -129,13 +129,16 @@
129
129
  .scui-truncated { display:block; margin-top:5px; color:var(--scui-warning) }
130
130
  .scui-notice { align-self:center; max-width:90%; padding:5px 8px; border-radius:7px; background:var(--scui-bg-raised); color:var(--scui-muted); font-size:10.5px; text-align:center }
131
131
 
132
- .scui-activity { overflow:hidden; border:1px solid var(--scui-border); border-radius:9px; background:var(--scui-bg-raised) }
133
- .scui-activity-head,.scui-tool-head { display:flex; align-items:center; gap:6px; width:100%; min-height:32px; padding:0 8px; border:0; background:transparent; text-align:left; cursor:pointer }
134
- .scui-activity-head strong { font-size:11px }.scui-activity-head small { color:var(--scui-muted) }.scui-spacer { flex:1 }
132
+ .scui-activity { min-width:0; color:var(--scui-muted) }
133
+ .scui-activity-head,.scui-tool-head { display:flex; align-items:center; gap:6px; box-sizing:border-box; width:100%; min-height:27px; padding:0 3px; border:0; background:transparent; color:inherit; text-align:left }
134
+ .scui-activity-head { cursor:pointer }.scui-activity-head strong { color:var(--scui-muted); font-size:10.5px; font-weight:600 }.scui-activity-head small { color:var(--scui-muted) }.scui-spacer { flex:1 }
135
135
  .scui-fold { font-size:16px; transition:transform 120ms }.scui-fold[data-open="true"] { transform:rotate(90deg) }
136
- .scui-tool { border-top:1px solid var(--scui-border) }.scui-tool-head:disabled { cursor:default }.scui-tool-glyph { width:18px; color:var(--scui-accent); text-align:center }.scui-tool-head strong { font-size:10.5px; text-transform:capitalize }
137
- .scui-tool-target { min-width:0; overflow:hidden; color:var(--scui-muted); font:10px ui-monospace,SFMono-Regular,Menlo,monospace; text-overflow:ellipsis; white-space:nowrap }
138
- .scui-tool-detail { padding:0 7px 7px }.scui-tool-detail pre { max-height:220px; margin:0 0 5px; padding:7px; overflow:auto; border-radius:6px; background:var(--scui-bg); font:10px/1.45 ui-monospace,SFMono-Regular,Menlo,monospace; white-space:pre-wrap }.scui-tool-detail pre[data-error="true"] { color:var(--scui-danger) }
136
+ .scui-activity:not([data-single="true"]) > div { margin-left:9px; padding-left:7px; border-left:1px solid var(--scui-border) }
137
+ .scui-tool { min-width:0 }.scui-tool summary { list-style:none }.scui-tool summary::-webkit-details-marker { display:none }.scui-tool-head { cursor:default }.scui-tool > summary.scui-tool-head { cursor:pointer }.scui-tool-icon { flex:0 0 14px; width:14px; height:14px; color:var(--scui-muted) }.scui-tool-head strong { flex:none; color:var(--scui-fg); font-size:10.5px; font-weight:600; white-space:nowrap }
138
+ .scui-tool-target { min-width:0; overflow:hidden; padding:0; background:transparent; color:var(--scui-muted); font:10px ui-monospace,SFMono-Regular,Menlo,monospace; text-overflow:ellipsis; white-space:nowrap }
139
+ .scui-tool-status { display:grid; flex:0 0 13px; width:13px; height:13px; place-items:center; color:var(--scui-success); font-size:10px }.scui-tool-status[data-status="pending"] { color:var(--scui-accent) }.scui-tool-status[data-status="error"] { color:var(--scui-danger); font-size:13px }.scui-tool-status i { box-sizing:border-box; width:11px; height:11px; border:1.5px solid currentColor; border-right-color:transparent; border-radius:50%; animation:scui-spin .75s linear infinite }
140
+ .scui-tool-chevron { flex:none; font-size:15px; line-height:1; transition:transform 120ms }.scui-tool[open] .scui-tool-chevron { transform:rotate(90deg) }
141
+ .scui-tool-detail { display:grid; gap:7px; max-height:220px; margin:2px 0 6px 20px; padding:8px; overflow:auto; border-left:1px solid var(--scui-border); background:var(--scui-bg-raised); font-size:10px }.scui-tool-detail dl,.scui-tool-detail section,.scui-tool-detail dl > div { display:grid; gap:3px; margin:0 }.scui-tool-detail dt,.scui-tool-detail section > strong { color:var(--scui-muted); font-weight:600 }.scui-tool-detail dd { min-width:0; margin:0 }.scui-tool-detail pre { margin:0; overflow-wrap:anywhere; color:var(--scui-fg); font:10px/1.45 ui-monospace,SFMono-Regular,Menlo,monospace; white-space:pre-wrap }.scui-tool-detail pre[data-error="true"] { color:var(--scui-danger) }
139
142
  .scui-request { padding:9px; border:1px solid var(--scui-warning); border-radius:9px; background:color-mix(in srgb,var(--scui-warning) 8%,var(--scui-bg)) }.scui-request-actions { display:flex; flex-wrap:wrap; gap:5px }.scui-request-actions button { padding:5px 8px; border:1px solid var(--scui-border-strong); border-radius:6px; background:var(--scui-bg); cursor:pointer }
140
143
  .scui-request-done { color:var(--scui-muted); font-size:10.5px }
141
144
  .scui-plan > summary { display:flex; justify-content:space-between; padding:6px 8px; border:1px solid var(--scui-border); border-radius:7px; background:var(--scui-bg-raised) }.scui-plan ol { display:grid; gap:4px; box-sizing:border-box; max-height:140px; margin:5px 0 0; padding:7px 8px 7px 25px; overflow:auto; border:1px solid var(--scui-border); border-radius:7px }.scui-plan li[data-status="completed"] { color:var(--scui-fg); text-decoration:line-through }