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

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.d.ts CHANGED
@@ -12,6 +12,7 @@ export {
12
12
  SessionRow,
13
13
  SupercodeMessenger,
14
14
  TaskPlan,
15
+ ToolRow,
15
16
  TranscriptEntry,
16
17
  hasHarnessLogo,
17
18
  } from './index.js';
package/components.mjs CHANGED
@@ -64,6 +64,11 @@ var MODES = /* @__PURE__ */ new Set(["none", "control", "mirror"]);
64
64
  var STRATEGIES = /* @__PURE__ */ new Set(["start", "resume", "attach", "branch", "reduce"]);
65
65
  var STARTUP = /* @__PURE__ */ new Set(["connecting", "starting", "discovering", "ready"]);
66
66
  var FIDELITY = /* @__PURE__ */ new Set(["byte_lossless", "value_lossless", "semantic"]);
67
+ var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
68
+ var TOOL_DETAILS = /* @__PURE__ */ new Set(["file", "matches", "diff", "terminal", "web", "agent", "plan", "fields"]);
69
+ var MAX_TOOL_FIELDS = 8;
70
+ var MAX_TOOL_FIELD_CHARS = 800;
71
+ var MAX_TOOL_PREVIEW_CHARS = 4e3;
67
72
  function record(value) {
68
73
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
69
74
  }
@@ -76,6 +81,132 @@ function number(value, fallback = 0) {
76
81
  function nullableNumber(value) {
77
82
  return typeof value === "number" && Number.isFinite(value) ? value : null;
78
83
  }
84
+ function boundedString(value, max) {
85
+ if (typeof value !== "string") return "";
86
+ return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
87
+ }
88
+ function argumentObject(argumentsText) {
89
+ if (!argumentsText) return null;
90
+ try {
91
+ return record(JSON.parse(argumentsText));
92
+ } catch {
93
+ return null;
94
+ }
95
+ }
96
+ function firstString(source, keys) {
97
+ for (const key of keys) {
98
+ if (typeof source?.[key] === "string" && source[key].trim()) return source[key].trim();
99
+ }
100
+ return "";
101
+ }
102
+ function explicitNumber(sources, keys) {
103
+ for (const source of sources) {
104
+ for (const key of keys) {
105
+ const value = source?.[key];
106
+ const parsed = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
107
+ if (typeof parsed === "number" && Number.isFinite(parsed)) return parsed;
108
+ }
109
+ }
110
+ return null;
111
+ }
112
+ function toolDetail(category) {
113
+ return { read: "file", search: "matches", edit: "diff", command: "terminal", test: "terminal", web: "web", agent: "agent", plan: "plan" }[category] ?? "fields";
114
+ }
115
+ function usefulToolFields(args) {
116
+ if (!args) return [];
117
+ const hidden = /* @__PURE__ */ new Set(["command", "cmd", "file_path", "target_file", "path", "query", "pattern", "url", "patch", "diff", "old_string", "new_string", "content", "prompt", "description", "task", "plan", "todos"]);
118
+ return Object.entries(args).flatMap(([key, value]) => {
119
+ if (hidden.has(key) || value === null || value === void 0) return [];
120
+ const rendered = typeof value === "string" ? value : JSON.stringify(value);
121
+ if (!rendered) return [];
122
+ return [{ label: key.replaceAll(/[_-]+/g, " ").replace(/^./, (letter) => letter.toLocaleUpperCase()), value: boundedString(rendered, MAX_TOOL_FIELD_CHARS) }];
123
+ }).slice(0, MAX_TOOL_FIELDS);
124
+ }
125
+ function planItems(args) {
126
+ const source = Array.isArray(args?.plan) ? args.plan : Array.isArray(args?.todos) ? args.todos : [];
127
+ return source.flatMap((item) => {
128
+ if (typeof item === "string" && item.trim()) return [{ label: boundedString(item.trim(), 300), status: "" }];
129
+ const value = record(item);
130
+ const label = firstString(value, ["step", "title", "content", "text"]);
131
+ if (!label) return [];
132
+ return [{ label: boundedString(label, 300), status: firstString(value, ["status"]) }];
133
+ }).slice(0, 12);
134
+ }
135
+ function editPreview(args, resultText) {
136
+ const direct = firstString(args, ["patch", "diff"]);
137
+ if (direct) return direct;
138
+ const oldText = firstString(args, ["old_string"]);
139
+ const newText = firstString(args, ["new_string"]);
140
+ if (oldText || newText) {
141
+ return [
142
+ ...oldText.split("\n").map((line) => `- ${line}`),
143
+ ...newText.split("\n").map((line) => `+ ${line}`)
144
+ ].join("\n");
145
+ }
146
+ return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
147
+ }
148
+ function createToolPresentation(entry) {
149
+ const args = argumentObject(entry.arguments);
150
+ const category = toolCategory({ label: entry.label, arguments: entry.arguments });
151
+ const command = firstString(args, ["command", "cmd"]);
152
+ const path = firstString(args, ["file_path", "target_file", "path"]);
153
+ const query = firstString(args, ["query", "pattern"]);
154
+ const url = firstString(args, ["url"]);
155
+ const subject = firstString(args, ["description", "task", "prompt"]);
156
+ const target = path || command || query || url || subject || toolTarget(entry.arguments);
157
+ const previewSource = category === "edit" ? editPreview(args, entry.resultText) : entry.resultText ?? "";
158
+ const result = record(entry.resultContent);
159
+ const metadata = record(entry.metadata);
160
+ return {
161
+ category,
162
+ detail: toolDetail(category),
163
+ target: boundedString(target, 300),
164
+ command: boundedString(command, MAX_TOOL_FIELD_CHARS),
165
+ path: boundedString(path, MAX_TOOL_FIELD_CHARS),
166
+ query: boundedString(query, MAX_TOOL_FIELD_CHARS),
167
+ url: boundedString(url, MAX_TOOL_FIELD_CHARS),
168
+ subject: boundedString(subject, MAX_TOOL_FIELD_CHARS),
169
+ preview: boundedString(previewSource, MAX_TOOL_PREVIEW_CHARS),
170
+ fields: usefulToolFields(args),
171
+ items: planItems(args),
172
+ exitCode: explicitNumber([result, metadata], ["exit_code", "exitCode"]),
173
+ durationMs: explicitNumber([result, metadata], ["duration_ms", "durationMs", "elapsed_ms", "elapsedMs"]),
174
+ additions: explicitNumber([result, metadata], ["additions", "lines_added"]),
175
+ deletions: explicitNumber([result, metadata], ["deletions", "lines_removed"]),
176
+ matches: explicitNumber([result, metadata], ["matches", "match_count", "result_count"])
177
+ };
178
+ }
179
+ function readToolPresentation(value, entry) {
180
+ const generated = createToolPresentation(entry);
181
+ const item = record(value);
182
+ if (!item) return generated;
183
+ const fields = Array.isArray(item.fields) ? item.fields.flatMap((raw) => {
184
+ const field = record(raw);
185
+ return field && typeof field.label === "string" && typeof field.value === "string" ? [{ label: boundedString(field.label, 80), value: boundedString(field.value, MAX_TOOL_FIELD_CHARS) }] : [];
186
+ }).slice(0, MAX_TOOL_FIELDS) : generated.fields;
187
+ const items = Array.isArray(item.items) ? item.items.flatMap((raw) => {
188
+ const planItem = record(raw);
189
+ return planItem && typeof planItem.label === "string" ? [{ label: boundedString(planItem.label, 300), status: boundedString(planItem.status, 40) }] : [];
190
+ }).slice(0, 12) : generated.items;
191
+ return {
192
+ category: TOOL_CATEGORIES.has(item.category) ? item.category : generated.category,
193
+ detail: TOOL_DETAILS.has(item.detail) ? item.detail : generated.detail,
194
+ target: boundedString(item.target, 300) || generated.target,
195
+ command: boundedString(item.command, MAX_TOOL_FIELD_CHARS) || generated.command,
196
+ path: boundedString(item.path, MAX_TOOL_FIELD_CHARS) || generated.path,
197
+ query: boundedString(item.query, MAX_TOOL_FIELD_CHARS) || generated.query,
198
+ url: boundedString(item.url, MAX_TOOL_FIELD_CHARS) || generated.url,
199
+ subject: boundedString(item.subject, MAX_TOOL_FIELD_CHARS) || generated.subject,
200
+ preview: boundedString(item.preview, MAX_TOOL_PREVIEW_CHARS) || generated.preview,
201
+ fields,
202
+ items,
203
+ exitCode: nullableNumber(item.exitCode) ?? generated.exitCode,
204
+ durationMs: nullableNumber(item.durationMs) ?? generated.durationMs,
205
+ additions: nullableNumber(item.additions) ?? generated.additions,
206
+ deletions: nullableNumber(item.deletions) ?? generated.deletions,
207
+ matches: nullableNumber(item.matches) ?? generated.matches
208
+ };
209
+ }
79
210
  function readTranscript(value) {
80
211
  if (!Array.isArray(value)) return [];
81
212
  const result = [];
@@ -93,6 +224,7 @@ function readTranscript(value) {
93
224
  if (typeof item[key] === "string") entry[key] = item[key];
94
225
  }
95
226
  if (["pending", "completed", "error"].includes(item.status)) entry.status = item.status;
227
+ if (item.role === "tool") entry.presentation = readToolPresentation(item.presentation, entry);
96
228
  if (typeof item.streaming === "boolean") entry.streaming = item.streaming;
97
229
  if (Array.isArray(item.context)) {
98
230
  entry.context = item.context.flatMap((raw) => {
@@ -300,6 +432,7 @@ function groupConversation(entries) {
300
432
  return blocks;
301
433
  }
302
434
  function toolCategory(entry) {
435
+ if (TOOL_CATEGORIES.has(entry.presentation?.category)) return entry.presentation.category;
303
436
  const name = entry.label?.toLocaleLowerCase() ?? "";
304
437
  if (/read|view|open_file|list_dir/.test(name)) return "read";
305
438
  if (/search|find|grep|glob/.test(name)) return "search";
@@ -307,7 +440,8 @@ function toolCategory(entry) {
307
440
  if (/test|typecheck|lint|build/.test(name)) return "test";
308
441
  if (/terminal|bash|shell|command|exec/.test(name)) return /\b(test|typecheck|lint|build)\b/i.test(entry.arguments ?? "") ? "test" : "command";
309
442
  if (/browser|web|fetch|url/.test(name)) return "web";
310
- if (/subagent|spawn|task/.test(name)) return "agent";
443
+ if (/update.?plan|todo|checklist/.test(name)) return "plan";
444
+ if (/subagent|spawn.?agent|delegate|^task$/.test(name)) return "agent";
311
445
  return "other";
312
446
  }
313
447
  function toolTarget(argumentsText) {
@@ -544,6 +678,7 @@ var TOOL_ICONS = {
544
678
  /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "6", r: "2.5" }),
545
679
  /* @__PURE__ */ jsx3("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
546
680
  ] }),
681
+ plan: () => /* @__PURE__ */ jsx3(Fragment, { children: /* @__PURE__ */ jsx3("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
547
682
  other: () => /* @__PURE__ */ jsxs2(Fragment, { children: [
548
683
  /* @__PURE__ */ jsx3("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
549
684
  /* @__PURE__ */ jsx3("circle", { cx: "9", cy: "9", r: "3.5" })
@@ -562,7 +697,8 @@ function toolAction(entry, category) {
562
697
  command: ["Running command", "Ran command", "Command failed"],
563
698
  test: ["Running tests", "Ran tests", "Tests failed"],
564
699
  web: ["Browsing", "Browsed", "Browser action failed"],
565
- agent: ["Starting agent", "Started agent", "Agent failed"]
700
+ agent: ["Starting agent", "Started agent", "Agent failed"],
701
+ plan: ["Updating plan", "Updated plan", "Plan update failed"]
566
702
  };
567
703
  const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
568
704
  if (actions[category]) return actions[category][position];
@@ -588,6 +724,113 @@ function argumentRows(argumentsText) {
588
724
  }
589
725
  return [{ key: "arguments", label: "Details", value: argumentsText }];
590
726
  }
727
+ function stripAnsi(value) {
728
+ return value?.replaceAll(/[\u001B\u009B][[\]()#;?]*(?:(?:(?:[a-zA-Z\d]*(?:;[-a-zA-Z\d\/#&.:=?%@~_]+)*)?\u0007)|(?:(?:\d{1,4}(?:[;:]\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~]))/g, "") ?? "";
729
+ }
730
+ function formatDuration(value) {
731
+ if (value === null) return "";
732
+ if (value < 1e3) return `${Math.round(value)}ms`;
733
+ return `${(value / 1e3).toFixed(value < 1e4 ? 1 : 0)}s`;
734
+ }
735
+ function ToolMetrics({ presentation }) {
736
+ const metrics = [
737
+ presentation.matches === null ? "" : `${presentation.matches} ${presentation.matches === 1 ? "match" : "matches"}`,
738
+ presentation.additions === null ? "" : `+${presentation.additions}`,
739
+ presentation.deletions === null ? "" : `\u2212${presentation.deletions}`,
740
+ presentation.exitCode === null ? "" : `exit ${presentation.exitCode}`,
741
+ formatDuration(presentation.durationMs)
742
+ ].filter(Boolean);
743
+ return metrics.length ? /* @__PURE__ */ jsx3("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx3("span", { children: metric }, metric)) }) : null;
744
+ }
745
+ function LinePreview({ value, kind }) {
746
+ if (!value) return null;
747
+ return /* @__PURE__ */ jsx3("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
748
+ const tone = kind === "diff" ? line.startsWith("+") && !line.startsWith("+++") ? "add" : line.startsWith("-") && !line.startsWith("---") ? "remove" : line.startsWith("@@") ? "hunk" : "plain" : "plain";
749
+ return /* @__PURE__ */ jsxs2("li", { "data-tone": tone, children: [
750
+ /* @__PURE__ */ jsx3("span", { children: index + 1 }),
751
+ /* @__PURE__ */ jsx3("code", { children: line || " " })
752
+ ] }, index);
753
+ }) });
754
+ }
755
+ function TerminalPreview({ presentation, pending, failed }) {
756
+ return /* @__PURE__ */ jsxs2("section", { class: "scui-terminal", children: [
757
+ /* @__PURE__ */ jsxs2("header", { children: [
758
+ /* @__PURE__ */ jsxs2("span", { "aria-hidden": "true", children: [
759
+ /* @__PURE__ */ jsx3("i", {}),
760
+ /* @__PURE__ */ jsx3("i", {}),
761
+ /* @__PURE__ */ jsx3("i", {})
762
+ ] }),
763
+ /* @__PURE__ */ jsx3("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
764
+ ] }),
765
+ presentation.preview ? /* @__PURE__ */ jsx3("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs2("div", { class: "scui-terminal-wait", children: [
766
+ /* @__PURE__ */ jsx3("i", {}),
767
+ " Waiting for output"
768
+ ] }) : /* @__PURE__ */ jsx3("div", { class: "scui-terminal-empty", children: "No output" })
769
+ ] });
770
+ }
771
+ function SearchPreview({ presentation }) {
772
+ const lines = stripAnsi(presentation.preview).split("\n").filter(Boolean);
773
+ return /* @__PURE__ */ jsxs2("section", { class: "scui-search-preview", children: [
774
+ presentation.query ? /* @__PURE__ */ jsxs2("header", { children: [
775
+ /* @__PURE__ */ jsx3("span", { children: "Search" }),
776
+ /* @__PURE__ */ jsx3("code", { children: presentation.query })
777
+ ] }) : null,
778
+ lines.length ? /* @__PURE__ */ jsx3("ol", { children: lines.map((line, index) => {
779
+ const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
780
+ return /* @__PURE__ */ jsx3("li", { children: match ? /* @__PURE__ */ jsxs2(Fragment, { children: [
781
+ /* @__PURE__ */ jsx3("code", { children: match[1] }),
782
+ /* @__PURE__ */ jsxs2("small", { children: [
783
+ match[2],
784
+ match[3] ? `:${match[3]}` : ""
785
+ ] }),
786
+ /* @__PURE__ */ jsx3("span", { children: match[4] })
787
+ ] }) : /* @__PURE__ */ jsx3("span", { children: line }) }, index);
788
+ }) }) : /* @__PURE__ */ jsx3("p", { children: "No textual results" })
789
+ ] });
790
+ }
791
+ function ToolPreview({ presentation, entry }) {
792
+ const pending = entry.status === "pending";
793
+ const failed = entry.status === "error";
794
+ if (presentation.detail === "terminal") return /* @__PURE__ */ jsx3(TerminalPreview, { presentation, pending, failed });
795
+ 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" });
796
+ 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" });
797
+ if (presentation.detail === "matches") return /* @__PURE__ */ jsx3(SearchPreview, { presentation });
798
+ if (presentation.detail === "web") return /* @__PURE__ */ jsxs2("section", { class: "scui-web-preview", children: [
799
+ presentation.url ? /* @__PURE__ */ jsx3("code", { children: presentation.url }) : null,
800
+ presentation.preview ? /* @__PURE__ */ jsx3("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx3("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
801
+ ] });
802
+ if (presentation.detail === "agent") return /* @__PURE__ */ jsxs2("section", { class: "scui-agent-preview", children: [
803
+ presentation.subject ? /* @__PURE__ */ jsx3("p", { children: presentation.subject }) : null,
804
+ presentation.preview ? /* @__PURE__ */ jsx3("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx3("small", { children: pending ? "Agent is working" : "No textual handoff returned" })
805
+ ] });
806
+ 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: [
807
+ /* @__PURE__ */ jsx3("i", { "aria-hidden": "true" }),
808
+ /* @__PURE__ */ jsx3("span", { children: item.label })
809
+ ] }, `${item.label}:${index}`)) });
810
+ return presentation.preview ? /* @__PURE__ */ jsx3("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
811
+ }
812
+ function TechnicalDetails({ entry }) {
813
+ if (!entry.arguments && !entry.resultText) return null;
814
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-tool-technical", children: [
815
+ /* @__PURE__ */ jsx3("summary", { children: "Technical details" }),
816
+ /* @__PURE__ */ jsxs2("div", { children: [
817
+ entry.arguments ? /* @__PURE__ */ jsxs2("section", { children: [
818
+ /* @__PURE__ */ jsx3("strong", { children: "Native arguments" }),
819
+ /* @__PURE__ */ jsx3("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs2("div", { children: [
820
+ /* @__PURE__ */ jsx3("dt", { children: row.label }),
821
+ /* @__PURE__ */ jsx3("dd", { children: /* @__PURE__ */ jsx3("pre", { children: row.value }) })
822
+ ] }, row.key)) })
823
+ ] }) : null,
824
+ entry.resultText ? /* @__PURE__ */ jsxs2("section", { children: [
825
+ /* @__PURE__ */ jsx3("strong", { children: "Native result" }),
826
+ /* @__PURE__ */ jsxs2("pre", { "data-error": entry.status === "error", children: [
827
+ entry.resultText,
828
+ entry.truncated ? "\n[truncated]" : ""
829
+ ] })
830
+ ] }) : null
831
+ ] })
832
+ ] });
833
+ }
591
834
  function TranscriptEntry({ entry, state, adapter }) {
592
835
  if (entry.role === "request") return /* @__PURE__ */ jsx3(RequestCard, { entry, adapter, canRespond: state.canRespond });
593
836
  if (entry.role === "reasoning") {
@@ -603,33 +846,30 @@ function TranscriptEntry({ entry, state, adapter }) {
603
846
  entry.truncated ? /* @__PURE__ */ jsx3("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
604
847
  ] });
605
848
  }
606
- function ToolRow({ entry, workspace }) {
607
- const target = compactToolTarget(toolTarget(entry.arguments), workspace);
608
- const hasDetail = Boolean(entry.arguments || entry.resultText);
609
- const category = toolCategory(entry);
849
+ function ToolRow({ entry, workspace, open = false }) {
850
+ const presentation = entry.presentation ?? createToolPresentation(entry);
851
+ const target = compactToolTarget(presentation.target, workspace);
852
+ const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
853
+ const category = presentation.category ?? toolCategory(entry);
610
854
  const summary = /* @__PURE__ */ jsxs2(Fragment, { children: [
611
855
  /* @__PURE__ */ jsx3(ToolIcon, { category }),
612
856
  /* @__PURE__ */ jsx3("strong", { children: toolAction(entry, category) }),
613
- target ? /* @__PURE__ */ jsx3("code", { class: "scui-tool-target", title: toolTarget(entry.arguments), children: target }) : null,
857
+ target ? /* @__PURE__ */ jsx3("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
614
858
  /* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
615
859
  /* @__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
860
  hasDetail ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-chevron", "aria-hidden": "true", children: "\u203A" }) : null
617
861
  ] });
618
862
  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: [
863
+ return /* @__PURE__ */ jsxs2("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: open || entry.status === "pending", children: [
620
864
  /* @__PURE__ */ jsx3("summary", { class: "scui-tool-head", children: summary }),
621
865
  /* @__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
- ] })
632
- ] }) : null
866
+ /* @__PURE__ */ jsx3(ToolMetrics, { presentation }),
867
+ /* @__PURE__ */ jsx3(ToolPreview, { presentation, entry }),
868
+ presentation.fields.length ? /* @__PURE__ */ jsx3("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs2("div", { children: [
869
+ /* @__PURE__ */ jsx3("dt", { children: field.label }),
870
+ /* @__PURE__ */ jsx3("dd", { children: field.value })
871
+ ] }, field.label)) }) : null,
872
+ /* @__PURE__ */ jsx3(TechnicalDetails, { entry })
633
873
  ] })
634
874
  ] });
635
875
  }
@@ -1123,6 +1363,7 @@ export {
1123
1363
  SessionRow,
1124
1364
  SupercodeMessenger,
1125
1365
  TaskPlan,
1366
+ ToolRow,
1126
1367
  TranscriptEntry,
1127
1368
  hasHarnessLogo
1128
1369
  };
package/controller.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { normalizeUiState } from './core.mjs';
1
+ import { createToolPresentation, normalizeUiState } from './core.mjs';
2
2
 
3
3
  const HARNESS_LABELS = {
4
4
  'claude-code': 'Claude Code',
@@ -126,7 +126,7 @@ function projectConversationEntry(entry, maxEntryChars) {
126
126
  const argumentsText = truncate((entry.arguments ?? '').trim(), maxEntryChars);
127
127
  const result = truncate((entry.resultText ?? '').trim(), maxEntryChars);
128
128
  const primary = entry.status === 'pending' ? argumentsText : result;
129
- return {
129
+ const projected = {
130
130
  id: entry.id,
131
131
  role: 'tool',
132
132
  text: primary.text,
@@ -137,6 +137,12 @@ function projectConversationEntry(entry, maxEntryChars) {
137
137
  resultText: result.text,
138
138
  status: entry.status,
139
139
  };
140
+ projected.presentation = createToolPresentation({
141
+ ...projected,
142
+ resultContent: entry.resultContent,
143
+ metadata: entry.metadata,
144
+ });
145
+ return projected;
140
146
  }
141
147
  if (entry.kind === 'reasoning') {
142
148
  const body = truncate(entry.text, maxEntryChars);
package/conversation.d.ts CHANGED
@@ -5,6 +5,7 @@ export type {
5
5
  SessionSemanticsModel,
6
6
  SupercodeUiState,
7
7
  TaskPlanProps,
8
+ ToolRowProps,
8
9
  TaskPlanModel,
9
10
  TranscriptEntryModel,
10
11
  TranscriptEntryProps,
@@ -17,5 +18,6 @@ export {
17
18
  RequestCard,
18
19
  SessionDetails,
19
20
  TaskPlan,
21
+ ToolRow,
20
22
  TranscriptEntry,
21
23
  } from './index.js';