@volter-ai-dev/supercode-ui 0.1.9 → 0.1.10
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 +141 -40
- package/conversation.mjs +137 -40
- package/core.mjs +111 -29
- package/embed.mjs +141 -40
- package/index.d.ts +5 -1
- package/messenger.mjs +141 -40
- package/package.json +1 -1
- package/styles.css +3 -0
package/components.mjs
CHANGED
|
@@ -85,10 +85,10 @@ function boundedString(value, max) {
|
|
|
85
85
|
if (typeof value !== "string") return "";
|
|
86
86
|
return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
|
|
87
87
|
}
|
|
88
|
-
function
|
|
88
|
+
function argumentValue(argumentsText) {
|
|
89
89
|
if (!argumentsText) return null;
|
|
90
90
|
try {
|
|
91
|
-
return
|
|
91
|
+
return JSON.parse(argumentsText);
|
|
92
92
|
} catch {
|
|
93
93
|
return null;
|
|
94
94
|
}
|
|
@@ -99,6 +99,33 @@ function firstString(source, keys) {
|
|
|
99
99
|
}
|
|
100
100
|
return "";
|
|
101
101
|
}
|
|
102
|
+
function decodedLiteral(value) {
|
|
103
|
+
if (!value) return "";
|
|
104
|
+
if (value.startsWith('"')) {
|
|
105
|
+
try {
|
|
106
|
+
return JSON.parse(value);
|
|
107
|
+
} catch {
|
|
108
|
+
return "";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return value.slice(1, -1).replaceAll("\\n", "\n").replaceAll("\\t", " ").replaceAll("\\r", "\r").replaceAll("\\`", "`").replaceAll("\\'", "'").replaceAll("\\\\", "\\");
|
|
112
|
+
}
|
|
113
|
+
function sourceString(source, keys) {
|
|
114
|
+
if (!source) return "";
|
|
115
|
+
const names = keys.join("|");
|
|
116
|
+
const match = new RegExp(`\\b(?:${names})\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
117
|
+
return decodedLiteral(match?.[1]);
|
|
118
|
+
}
|
|
119
|
+
function toolEnvelope(entry) {
|
|
120
|
+
const value = argumentValue(entry.arguments);
|
|
121
|
+
const source = typeof value === "string" ? value : "";
|
|
122
|
+
const tools = source ? [...new Set([...source.matchAll(/\btools\.([A-Za-z0-9_]+)/g)].map((match) => match[1]))].slice(0, 8) : [];
|
|
123
|
+
const name = tools.length === 1 ? tools[0] : entry.label ?? "tool";
|
|
124
|
+
return { args: record(value), source, tools, name };
|
|
125
|
+
}
|
|
126
|
+
function patchPath(source) {
|
|
127
|
+
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]+)/.exec(source)?.[1]?.trim() ?? "";
|
|
128
|
+
}
|
|
102
129
|
function explicitNumber(sources, keys) {
|
|
103
130
|
for (const source of sources) {
|
|
104
131
|
for (const key of keys) {
|
|
@@ -132,7 +159,7 @@ function planItems(args) {
|
|
|
132
159
|
return [{ label: boundedString(label, 300), status: firstString(value, ["status"]) }];
|
|
133
160
|
}).slice(0, 12);
|
|
134
161
|
}
|
|
135
|
-
function editPreview(args, resultText) {
|
|
162
|
+
function editPreview(args, resultText, source) {
|
|
136
163
|
const direct = firstString(args, ["patch", "diff"]);
|
|
137
164
|
if (direct) return direct;
|
|
138
165
|
const oldText = firstString(args, ["old_string"]);
|
|
@@ -143,21 +170,63 @@ function editPreview(args, resultText) {
|
|
|
143
170
|
...newText.split("\n").map((line) => `+ ${line}`)
|
|
144
171
|
].join("\n");
|
|
145
172
|
}
|
|
173
|
+
const patch = /\*\*\* Begin Patch[\s\S]*?\*\*\* End Patch/.exec(source ?? "")?.[0];
|
|
174
|
+
if (patch) return patch;
|
|
146
175
|
return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
|
|
147
176
|
}
|
|
177
|
+
function classifyTool(name, command) {
|
|
178
|
+
const normalized = name.toLocaleLowerCase();
|
|
179
|
+
if (/write_stdin|^wait$/.test(normalized)) return "command";
|
|
180
|
+
if (/update.?plan|todo|checklist|taskcreate|taskupdate/.test(normalized)) return "plan";
|
|
181
|
+
if (/search.?replace|edit|write|patch|replace|create_file|apply_patch/.test(normalized)) return "edit";
|
|
182
|
+
if (/read|view|open_file|list_dir/.test(normalized)) return "read";
|
|
183
|
+
if (/search|find|grep|glob|toolsearch/.test(normalized)) return "search";
|
|
184
|
+
if (/browser|web|fetch|url/.test(normalized)) return "web";
|
|
185
|
+
if (/agent|subagent|sendmessage|delegate|^task$/.test(normalized)) return "agent";
|
|
186
|
+
if (/test|typecheck|lint|build/.test(normalized)) return "test";
|
|
187
|
+
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return /\b(test|typecheck|lint|build)\b/i.test(command) ? "test" : "command";
|
|
188
|
+
return "other";
|
|
189
|
+
}
|
|
190
|
+
function toolAction(status, category, name, tools) {
|
|
191
|
+
const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
|
|
192
|
+
if (tools.length > 1) return [`Running ${tools.length} actions`, `Ran ${tools.length} actions`, `${tools.length} actions failed`][position];
|
|
193
|
+
const normalized = name.toLocaleLowerCase();
|
|
194
|
+
if (/sendmessage/.test(normalized)) return ["Messaging agent", "Messaged agent", "Agent message failed"][position];
|
|
195
|
+
if (/kill_command_or_subagent/.test(normalized)) return ["Stopping", "Stopped", "Stop failed"][position];
|
|
196
|
+
if (/get_command_or_subagent_output|write_stdin|^wait$/.test(normalized)) return ["Waiting for", "Checked", "Check failed"][position];
|
|
197
|
+
const actions = {
|
|
198
|
+
read: ["Reading", "Read", "Read failed"],
|
|
199
|
+
search: ["Searching", "Searched", "Search failed"],
|
|
200
|
+
edit: ["Editing", "Edited", "Edit failed"],
|
|
201
|
+
command: ["Running command", "Ran command", "Command failed"],
|
|
202
|
+
test: ["Running tests", "Ran tests", "Tests failed"],
|
|
203
|
+
web: ["Browsing", "Browsed", "Browser action failed"],
|
|
204
|
+
agent: ["Starting agent", "Started agent", "Agent failed"],
|
|
205
|
+
plan: ["Updating plan", "Updated plan", "Plan update failed"]
|
|
206
|
+
};
|
|
207
|
+
return actions[category]?.[position] ?? (status === "error" ? `${name} failed` : name.replaceAll(/[_-]+/g, " "));
|
|
208
|
+
}
|
|
148
209
|
function createToolPresentation(entry) {
|
|
149
|
-
const
|
|
150
|
-
const
|
|
151
|
-
const command = firstString(args, ["command", "cmd"]);
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
const
|
|
210
|
+
const envelope = toolEnvelope(entry);
|
|
211
|
+
const args = envelope.args;
|
|
212
|
+
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.source, ["command", "cmd"]);
|
|
213
|
+
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
214
|
+
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.source, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
|
|
215
|
+
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.source, ["query", "pattern", "q"]);
|
|
216
|
+
const url = firstString(args, ["url"]) || sourceString(envelope.source, ["url", "ref_id"]);
|
|
217
|
+
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.source, ["subject", "description", "summary", "task", "prompt"]);
|
|
218
|
+
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? "background task" : /write_stdin|^wait$/i.test(envelope.name) ? "background command" : "";
|
|
219
|
+
const items = planItems(args);
|
|
220
|
+
const taskId = firstString(args, ["taskId", "task_id"]);
|
|
221
|
+
const planTarget = category === "plan" ? items.length ? `${items.length} ${items.length === 1 ? "item" : "items"}` : taskId ? `task ${taskId}` : "" : "";
|
|
222
|
+
const target = path || command || query || url || subject || background || planTarget || (envelope.tools.length > 1 ? `${envelope.tools.length} coordinated actions` : toolTarget(entry.arguments));
|
|
223
|
+
const previewSource = category === "edit" ? editPreview(args, entry.resultText, envelope.source) : entry.resultText ?? "";
|
|
158
224
|
const result = record(entry.resultContent);
|
|
159
225
|
const metadata = record(entry.metadata);
|
|
226
|
+
const resultMetadata = record(result?.metadata);
|
|
160
227
|
return {
|
|
228
|
+
name: boundedString(envelope.name, 120),
|
|
229
|
+
action: boundedString(toolAction(entry.status ?? "completed", category, envelope.name, envelope.tools), 120),
|
|
161
230
|
category,
|
|
162
231
|
detail: toolDetail(category),
|
|
163
232
|
target: boundedString(target, 300),
|
|
@@ -168,12 +237,13 @@ function createToolPresentation(entry) {
|
|
|
168
237
|
subject: boundedString(subject, MAX_TOOL_FIELD_CHARS),
|
|
169
238
|
preview: boundedString(previewSource, MAX_TOOL_PREVIEW_CHARS),
|
|
170
239
|
fields: usefulToolFields(args),
|
|
171
|
-
items
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
240
|
+
items,
|
|
241
|
+
tools: envelope.tools,
|
|
242
|
+
exitCode: explicitNumber([result, resultMetadata, metadata], ["exit_code", "exitCode", "pi_bash_exit_code"]),
|
|
243
|
+
durationMs: explicitNumber([result, resultMetadata, metadata], ["duration_ms", "durationMs", "elapsed_ms", "elapsedMs", "totalDurationMs"]),
|
|
244
|
+
additions: explicitNumber([result, resultMetadata, metadata], ["additions", "lines_added"]),
|
|
245
|
+
deletions: explicitNumber([result, resultMetadata, metadata], ["deletions", "lines_removed"]),
|
|
246
|
+
matches: explicitNumber([result, resultMetadata, metadata], ["matches", "match_count", "result_count"])
|
|
177
247
|
};
|
|
178
248
|
}
|
|
179
249
|
function readToolPresentation(value, entry) {
|
|
@@ -188,7 +258,10 @@ function readToolPresentation(value, entry) {
|
|
|
188
258
|
const planItem = record(raw);
|
|
189
259
|
return planItem && typeof planItem.label === "string" ? [{ label: boundedString(planItem.label, 300), status: boundedString(planItem.status, 40) }] : [];
|
|
190
260
|
}).slice(0, 12) : generated.items;
|
|
261
|
+
const tools = Array.isArray(item.tools) ? item.tools.filter((tool) => typeof tool === "string").map((tool) => boundedString(tool, 120)).slice(0, 8) : generated.tools;
|
|
191
262
|
return {
|
|
263
|
+
name: boundedString(item.name, 120) || generated.name,
|
|
264
|
+
action: boundedString(item.action, 120) || generated.action,
|
|
192
265
|
category: TOOL_CATEGORIES.has(item.category) ? item.category : generated.category,
|
|
193
266
|
detail: TOOL_DETAILS.has(item.detail) ? item.detail : generated.detail,
|
|
194
267
|
target: boundedString(item.target, 300) || generated.target,
|
|
@@ -200,6 +273,7 @@ function readToolPresentation(value, entry) {
|
|
|
200
273
|
preview: boundedString(item.preview, MAX_TOOL_PREVIEW_CHARS) || generated.preview,
|
|
201
274
|
fields,
|
|
202
275
|
items,
|
|
276
|
+
tools,
|
|
203
277
|
exitCode: nullableNumber(item.exitCode) ?? generated.exitCode,
|
|
204
278
|
durationMs: nullableNumber(item.durationMs) ?? generated.durationMs,
|
|
205
279
|
additions: nullableNumber(item.additions) ?? generated.additions,
|
|
@@ -433,16 +507,9 @@ function groupConversation(entries) {
|
|
|
433
507
|
}
|
|
434
508
|
function toolCategory(entry) {
|
|
435
509
|
if (TOOL_CATEGORIES.has(entry.presentation?.category)) return entry.presentation.category;
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
if (/edit|write|patch|replace|create_file/.test(name)) return "edit";
|
|
440
|
-
if (/test|typecheck|lint|build/.test(name)) return "test";
|
|
441
|
-
if (/terminal|bash|shell|command|exec/.test(name)) return /\b(test|typecheck|lint|build)\b/i.test(entry.arguments ?? "") ? "test" : "command";
|
|
442
|
-
if (/browser|web|fetch|url/.test(name)) return "web";
|
|
443
|
-
if (/update.?plan|todo|checklist/.test(name)) return "plan";
|
|
444
|
-
if (/subagent|spawn.?agent|delegate|^task$/.test(name)) return "agent";
|
|
445
|
-
return "other";
|
|
510
|
+
const envelope = toolEnvelope(entry);
|
|
511
|
+
const command = firstString(envelope.args, ["command", "cmd"]) || sourceString(envelope.source, ["command", "cmd"]);
|
|
512
|
+
return classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
446
513
|
}
|
|
447
514
|
function toolTarget(argumentsText) {
|
|
448
515
|
if (!argumentsText) return "";
|
|
@@ -468,7 +535,8 @@ function activitySummary(entries) {
|
|
|
468
535
|
if (pending) return `${entries.length} actions in progress`;
|
|
469
536
|
if (failed) return `${entries.length} actions \xB7 ${failed} failed`;
|
|
470
537
|
if ([...counts.keys()].every((key) => key === "read" || key === "search")) return `Explored ${entries.length} ${entries.length === 1 ? "item" : "items"}`;
|
|
471
|
-
|
|
538
|
+
const nouns = { read: ["read", "reads"], search: ["search", "searches"], edit: ["edit", "edits"], command: ["command", "commands"], test: ["test run", "test runs"], web: ["web action", "web actions"], agent: ["agent action", "agent actions"], plan: ["plan update", "plan updates"], other: ["action", "actions"] };
|
|
539
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([category, count]) => `${count} ${nouns[category][count === 1 ? 0 : 1]}`).join(" \xB7 ");
|
|
472
540
|
}
|
|
473
541
|
function canContinueHere(state) {
|
|
474
542
|
if (state.mode !== "mirror" || state.canSend) return false;
|
|
@@ -688,7 +756,8 @@ function ToolIcon({ category }) {
|
|
|
688
756
|
const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
|
|
689
757
|
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, {}) });
|
|
690
758
|
}
|
|
691
|
-
function
|
|
759
|
+
function toolAction2(entry, category, presentation) {
|
|
760
|
+
if (presentation?.action) return presentation.action;
|
|
692
761
|
const status = entry.status ?? "completed";
|
|
693
762
|
const actions = {
|
|
694
763
|
read: ["Reading", "Read", "Read failed"],
|
|
@@ -742,6 +811,16 @@ function ToolMetrics({ presentation }) {
|
|
|
742
811
|
].filter(Boolean);
|
|
743
812
|
return metrics.length ? /* @__PURE__ */ jsx3("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx3("span", { children: metric }, metric)) }) : null;
|
|
744
813
|
}
|
|
814
|
+
function PendingElapsed({ now }) {
|
|
815
|
+
const clock = now ?? Date.now;
|
|
816
|
+
const started = useRef2(clock());
|
|
817
|
+
const [elapsed, setElapsed] = useState2(0);
|
|
818
|
+
useEffect2(() => {
|
|
819
|
+
const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
|
|
820
|
+
return () => clearInterval(timer);
|
|
821
|
+
}, [clock]);
|
|
822
|
+
return /* @__PURE__ */ jsx3("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
|
|
823
|
+
}
|
|
745
824
|
function LinePreview({ value, kind }) {
|
|
746
825
|
if (!value) return null;
|
|
747
826
|
return /* @__PURE__ */ jsx3("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
|
|
@@ -799,16 +878,31 @@ function ToolPreview({ presentation, entry }) {
|
|
|
799
878
|
presentation.url ? /* @__PURE__ */ jsx3("code", { children: presentation.url }) : null,
|
|
800
879
|
presentation.preview ? /* @__PURE__ */ jsx3("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx3("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
|
|
801
880
|
] });
|
|
802
|
-
if (presentation.detail === "agent") return /* @__PURE__ */
|
|
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
|
-
] });
|
|
881
|
+
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" }) });
|
|
806
882
|
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
883
|
/* @__PURE__ */ jsx3("i", { "aria-hidden": "true" }),
|
|
808
884
|
/* @__PURE__ */ jsx3("span", { children: item.label })
|
|
809
885
|
] }, `${item.label}:${index}`)) });
|
|
810
886
|
return presentation.preview ? /* @__PURE__ */ jsx3("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
|
|
811
887
|
}
|
|
888
|
+
function ToolActions({ presentation, adapter }) {
|
|
889
|
+
const [copied, setCopied] = useState2(false);
|
|
890
|
+
const reset = useRef2(null);
|
|
891
|
+
useEffect2(() => () => clearTimeout(reset.current), []);
|
|
892
|
+
if (!adapter?.copyText) return null;
|
|
893
|
+
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;
|
|
894
|
+
const copy = async () => {
|
|
895
|
+
await adapter.copyText(action[1]);
|
|
896
|
+
setCopied(true);
|
|
897
|
+
clearTimeout(reset.current);
|
|
898
|
+
reset.current = setTimeout(() => setCopied(false), 1500);
|
|
899
|
+
};
|
|
900
|
+
return action ? /* @__PURE__ */ jsx3("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx3("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
|
|
901
|
+
}
|
|
902
|
+
function ToolStack({ tools }) {
|
|
903
|
+
if (tools.length < 2) return null;
|
|
904
|
+
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)) });
|
|
905
|
+
}
|
|
812
906
|
function TechnicalDetails({ entry }) {
|
|
813
907
|
if (!entry.arguments && !entry.resultText) return null;
|
|
814
908
|
return /* @__PURE__ */ jsxs2("details", { class: "scui-tool-technical", children: [
|
|
@@ -846,35 +940,42 @@ function TranscriptEntry({ entry, state, adapter }) {
|
|
|
846
940
|
entry.truncated ? /* @__PURE__ */ jsx3("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
|
|
847
941
|
] });
|
|
848
942
|
}
|
|
849
|
-
function ToolRow({ entry, workspace, open = false }) {
|
|
943
|
+
function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
850
944
|
const presentation = entry.presentation ?? createToolPresentation(entry);
|
|
945
|
+
const [expanded, setExpanded] = useState2(open || entry.status === "pending");
|
|
946
|
+
useEffect2(() => {
|
|
947
|
+
if (entry.status === "pending") setExpanded(true);
|
|
948
|
+
}, [entry.status]);
|
|
851
949
|
const target = compactToolTarget(presentation.target, workspace);
|
|
852
950
|
const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
|
|
853
951
|
const category = presentation.category ?? toolCategory(entry);
|
|
854
952
|
const summary = /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
855
953
|
/* @__PURE__ */ jsx3(ToolIcon, { category }),
|
|
856
|
-
/* @__PURE__ */ jsx3("strong", { children:
|
|
954
|
+
/* @__PURE__ */ jsx3("strong", { children: toolAction2(entry, category, presentation) }),
|
|
857
955
|
target ? /* @__PURE__ */ jsx3("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
|
|
858
956
|
/* @__PURE__ */ jsx3("span", { class: "scui-spacer" }),
|
|
957
|
+
entry.status === "pending" ? /* @__PURE__ */ jsx3(PendingElapsed, { now: adapter?.now }) : null,
|
|
859
958
|
/* @__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" }),
|
|
860
959
|
hasDetail ? /* @__PURE__ */ jsx3("span", { class: "scui-tool-chevron", "aria-hidden": "true", children: "\u203A" }) : null
|
|
861
960
|
] });
|
|
862
961
|
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 }) });
|
|
863
|
-
return /* @__PURE__ */ jsxs2("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open:
|
|
962
|
+
return /* @__PURE__ */ jsxs2("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
|
|
864
963
|
/* @__PURE__ */ jsx3("summary", { class: "scui-tool-head", children: summary }),
|
|
865
964
|
/* @__PURE__ */ jsxs2("div", { class: "scui-tool-detail", children: [
|
|
866
965
|
/* @__PURE__ */ jsx3(ToolMetrics, { presentation }),
|
|
966
|
+
/* @__PURE__ */ jsx3(ToolStack, { tools: presentation.tools ?? [] }),
|
|
867
967
|
/* @__PURE__ */ jsx3(ToolPreview, { presentation, entry }),
|
|
868
968
|
presentation.fields.length ? /* @__PURE__ */ jsx3("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs2("div", { children: [
|
|
869
969
|
/* @__PURE__ */ jsx3("dt", { children: field.label }),
|
|
870
970
|
/* @__PURE__ */ jsx3("dd", { children: field.value })
|
|
871
971
|
] }, field.label)) }) : null,
|
|
972
|
+
/* @__PURE__ */ jsx3(ToolActions, { presentation, adapter }),
|
|
872
973
|
/* @__PURE__ */ jsx3(TechnicalDetails, { entry })
|
|
873
974
|
] })
|
|
874
975
|
] });
|
|
875
976
|
}
|
|
876
|
-
function ActivityGroup({ entries, state }) {
|
|
877
|
-
if (entries.length === 1) return /* @__PURE__ */ jsx3("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx3(ToolRow, { entry: entries[0], workspace: state.workspace }) });
|
|
977
|
+
function ActivityGroup({ entries, state, adapter }) {
|
|
978
|
+
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 }) });
|
|
878
979
|
const active = entries.some((entry) => entry.status === "pending");
|
|
879
980
|
const [open, setOpen] = useState2(active);
|
|
880
981
|
const id = useId();
|
|
@@ -892,7 +993,7 @@ function ActivityGroup({ entries, state }) {
|
|
|
892
993
|
entries.length
|
|
893
994
|
] })
|
|
894
995
|
] }),
|
|
895
|
-
open ? /* @__PURE__ */ jsx3("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx3(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
|
|
996
|
+
open ? /* @__PURE__ */ jsx3("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx3(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
|
|
896
997
|
] });
|
|
897
998
|
}
|
|
898
999
|
function TaskPlan({ plan }) {
|
package/conversation.mjs
CHANGED
|
@@ -70,10 +70,10 @@ function boundedString(value, max) {
|
|
|
70
70
|
if (typeof value !== "string") return "";
|
|
71
71
|
return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
|
|
72
72
|
}
|
|
73
|
-
function
|
|
73
|
+
function argumentValue(argumentsText) {
|
|
74
74
|
if (!argumentsText) return null;
|
|
75
75
|
try {
|
|
76
|
-
return
|
|
76
|
+
return JSON.parse(argumentsText);
|
|
77
77
|
} catch {
|
|
78
78
|
return null;
|
|
79
79
|
}
|
|
@@ -84,6 +84,33 @@ function firstString(source, keys) {
|
|
|
84
84
|
}
|
|
85
85
|
return "";
|
|
86
86
|
}
|
|
87
|
+
function decodedLiteral(value) {
|
|
88
|
+
if (!value) return "";
|
|
89
|
+
if (value.startsWith('"')) {
|
|
90
|
+
try {
|
|
91
|
+
return JSON.parse(value);
|
|
92
|
+
} catch {
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return value.slice(1, -1).replaceAll("\\n", "\n").replaceAll("\\t", " ").replaceAll("\\r", "\r").replaceAll("\\`", "`").replaceAll("\\'", "'").replaceAll("\\\\", "\\");
|
|
97
|
+
}
|
|
98
|
+
function sourceString(source, keys) {
|
|
99
|
+
if (!source) return "";
|
|
100
|
+
const names = keys.join("|");
|
|
101
|
+
const match = new RegExp(`\\b(?:${names})\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
|
|
102
|
+
return decodedLiteral(match?.[1]);
|
|
103
|
+
}
|
|
104
|
+
function toolEnvelope(entry) {
|
|
105
|
+
const value = argumentValue(entry.arguments);
|
|
106
|
+
const source = typeof value === "string" ? value : "";
|
|
107
|
+
const tools = source ? [...new Set([...source.matchAll(/\btools\.([A-Za-z0-9_]+)/g)].map((match) => match[1]))].slice(0, 8) : [];
|
|
108
|
+
const name = tools.length === 1 ? tools[0] : entry.label ?? "tool";
|
|
109
|
+
return { args: record(value), source, tools, name };
|
|
110
|
+
}
|
|
111
|
+
function patchPath(source) {
|
|
112
|
+
return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]+)/.exec(source)?.[1]?.trim() ?? "";
|
|
113
|
+
}
|
|
87
114
|
function explicitNumber(sources, keys) {
|
|
88
115
|
for (const source of sources) {
|
|
89
116
|
for (const key of keys) {
|
|
@@ -117,7 +144,7 @@ function planItems(args) {
|
|
|
117
144
|
return [{ label: boundedString(label, 300), status: firstString(value, ["status"]) }];
|
|
118
145
|
}).slice(0, 12);
|
|
119
146
|
}
|
|
120
|
-
function editPreview(args, resultText) {
|
|
147
|
+
function editPreview(args, resultText, source) {
|
|
121
148
|
const direct = firstString(args, ["patch", "diff"]);
|
|
122
149
|
if (direct) return direct;
|
|
123
150
|
const oldText = firstString(args, ["old_string"]);
|
|
@@ -128,21 +155,63 @@ function editPreview(args, resultText) {
|
|
|
128
155
|
...newText.split("\n").map((line) => `+ ${line}`)
|
|
129
156
|
].join("\n");
|
|
130
157
|
}
|
|
158
|
+
const patch = /\*\*\* Begin Patch[\s\S]*?\*\*\* End Patch/.exec(source ?? "")?.[0];
|
|
159
|
+
if (patch) return patch;
|
|
131
160
|
return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
|
|
132
161
|
}
|
|
162
|
+
function classifyTool(name, command) {
|
|
163
|
+
const normalized = name.toLocaleLowerCase();
|
|
164
|
+
if (/write_stdin|^wait$/.test(normalized)) return "command";
|
|
165
|
+
if (/update.?plan|todo|checklist|taskcreate|taskupdate/.test(normalized)) return "plan";
|
|
166
|
+
if (/search.?replace|edit|write|patch|replace|create_file|apply_patch/.test(normalized)) return "edit";
|
|
167
|
+
if (/read|view|open_file|list_dir/.test(normalized)) return "read";
|
|
168
|
+
if (/search|find|grep|glob|toolsearch/.test(normalized)) return "search";
|
|
169
|
+
if (/browser|web|fetch|url/.test(normalized)) return "web";
|
|
170
|
+
if (/agent|subagent|sendmessage|delegate|^task$/.test(normalized)) return "agent";
|
|
171
|
+
if (/test|typecheck|lint|build/.test(normalized)) return "test";
|
|
172
|
+
if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return /\b(test|typecheck|lint|build)\b/i.test(command) ? "test" : "command";
|
|
173
|
+
return "other";
|
|
174
|
+
}
|
|
175
|
+
function toolAction(status, category, name, tools) {
|
|
176
|
+
const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
|
|
177
|
+
if (tools.length > 1) return [`Running ${tools.length} actions`, `Ran ${tools.length} actions`, `${tools.length} actions failed`][position];
|
|
178
|
+
const normalized = name.toLocaleLowerCase();
|
|
179
|
+
if (/sendmessage/.test(normalized)) return ["Messaging agent", "Messaged agent", "Agent message failed"][position];
|
|
180
|
+
if (/kill_command_or_subagent/.test(normalized)) return ["Stopping", "Stopped", "Stop failed"][position];
|
|
181
|
+
if (/get_command_or_subagent_output|write_stdin|^wait$/.test(normalized)) return ["Waiting for", "Checked", "Check failed"][position];
|
|
182
|
+
const actions = {
|
|
183
|
+
read: ["Reading", "Read", "Read failed"],
|
|
184
|
+
search: ["Searching", "Searched", "Search failed"],
|
|
185
|
+
edit: ["Editing", "Edited", "Edit failed"],
|
|
186
|
+
command: ["Running command", "Ran command", "Command failed"],
|
|
187
|
+
test: ["Running tests", "Ran tests", "Tests failed"],
|
|
188
|
+
web: ["Browsing", "Browsed", "Browser action failed"],
|
|
189
|
+
agent: ["Starting agent", "Started agent", "Agent failed"],
|
|
190
|
+
plan: ["Updating plan", "Updated plan", "Plan update failed"]
|
|
191
|
+
};
|
|
192
|
+
return actions[category]?.[position] ?? (status === "error" ? `${name} failed` : name.replaceAll(/[_-]+/g, " "));
|
|
193
|
+
}
|
|
133
194
|
function createToolPresentation(entry) {
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
const command = firstString(args, ["command", "cmd"]);
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const
|
|
195
|
+
const envelope = toolEnvelope(entry);
|
|
196
|
+
const args = envelope.args;
|
|
197
|
+
const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.source, ["command", "cmd"]);
|
|
198
|
+
const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
199
|
+
const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.source, ["file_path", "target_file", "target_directory", "path"]) || patchPath(envelope.source);
|
|
200
|
+
const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.source, ["query", "pattern", "q"]);
|
|
201
|
+
const url = firstString(args, ["url"]) || sourceString(envelope.source, ["url", "ref_id"]);
|
|
202
|
+
const subject = firstString(args, ["subject", "description", "summary", "task", "prompt"]) || sourceString(envelope.source, ["subject", "description", "summary", "task", "prompt"]);
|
|
203
|
+
const background = /get_command_or_subagent_output|kill_command_or_subagent/i.test(envelope.name) ? "background task" : /write_stdin|^wait$/i.test(envelope.name) ? "background command" : "";
|
|
204
|
+
const items = planItems(args);
|
|
205
|
+
const taskId = firstString(args, ["taskId", "task_id"]);
|
|
206
|
+
const planTarget = category === "plan" ? items.length ? `${items.length} ${items.length === 1 ? "item" : "items"}` : taskId ? `task ${taskId}` : "" : "";
|
|
207
|
+
const target = path || command || query || url || subject || background || planTarget || (envelope.tools.length > 1 ? `${envelope.tools.length} coordinated actions` : toolTarget(entry.arguments));
|
|
208
|
+
const previewSource = category === "edit" ? editPreview(args, entry.resultText, envelope.source) : entry.resultText ?? "";
|
|
143
209
|
const result = record(entry.resultContent);
|
|
144
210
|
const metadata = record(entry.metadata);
|
|
211
|
+
const resultMetadata = record(result?.metadata);
|
|
145
212
|
return {
|
|
213
|
+
name: boundedString(envelope.name, 120),
|
|
214
|
+
action: boundedString(toolAction(entry.status ?? "completed", category, envelope.name, envelope.tools), 120),
|
|
146
215
|
category,
|
|
147
216
|
detail: toolDetail(category),
|
|
148
217
|
target: boundedString(target, 300),
|
|
@@ -153,12 +222,13 @@ function createToolPresentation(entry) {
|
|
|
153
222
|
subject: boundedString(subject, MAX_TOOL_FIELD_CHARS),
|
|
154
223
|
preview: boundedString(previewSource, MAX_TOOL_PREVIEW_CHARS),
|
|
155
224
|
fields: usefulToolFields(args),
|
|
156
|
-
items
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
225
|
+
items,
|
|
226
|
+
tools: envelope.tools,
|
|
227
|
+
exitCode: explicitNumber([result, resultMetadata, metadata], ["exit_code", "exitCode", "pi_bash_exit_code"]),
|
|
228
|
+
durationMs: explicitNumber([result, resultMetadata, metadata], ["duration_ms", "durationMs", "elapsed_ms", "elapsedMs", "totalDurationMs"]),
|
|
229
|
+
additions: explicitNumber([result, resultMetadata, metadata], ["additions", "lines_added"]),
|
|
230
|
+
deletions: explicitNumber([result, resultMetadata, metadata], ["deletions", "lines_removed"]),
|
|
231
|
+
matches: explicitNumber([result, resultMetadata, metadata], ["matches", "match_count", "result_count"])
|
|
162
232
|
};
|
|
163
233
|
}
|
|
164
234
|
function harnessDisplayName(id) {
|
|
@@ -179,16 +249,9 @@ function groupConversation(entries) {
|
|
|
179
249
|
}
|
|
180
250
|
function toolCategory(entry) {
|
|
181
251
|
if (TOOL_CATEGORIES.has(entry.presentation?.category)) return entry.presentation.category;
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if (/edit|write|patch|replace|create_file/.test(name)) return "edit";
|
|
186
|
-
if (/test|typecheck|lint|build/.test(name)) return "test";
|
|
187
|
-
if (/terminal|bash|shell|command|exec/.test(name)) return /\b(test|typecheck|lint|build)\b/i.test(entry.arguments ?? "") ? "test" : "command";
|
|
188
|
-
if (/browser|web|fetch|url/.test(name)) return "web";
|
|
189
|
-
if (/update.?plan|todo|checklist/.test(name)) return "plan";
|
|
190
|
-
if (/subagent|spawn.?agent|delegate|^task$/.test(name)) return "agent";
|
|
191
|
-
return "other";
|
|
252
|
+
const envelope = toolEnvelope(entry);
|
|
253
|
+
const command = firstString(envelope.args, ["command", "cmd"]) || sourceString(envelope.source, ["command", "cmd"]);
|
|
254
|
+
return classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
|
|
192
255
|
}
|
|
193
256
|
function toolTarget(argumentsText) {
|
|
194
257
|
if (!argumentsText) return "";
|
|
@@ -214,7 +277,8 @@ function activitySummary(entries) {
|
|
|
214
277
|
if (pending) return `${entries.length} actions in progress`;
|
|
215
278
|
if (failed) return `${entries.length} actions \xB7 ${failed} failed`;
|
|
216
279
|
if ([...counts.keys()].every((key) => key === "read" || key === "search")) return `Explored ${entries.length} ${entries.length === 1 ? "item" : "items"}`;
|
|
217
|
-
|
|
280
|
+
const nouns = { read: ["read", "reads"], search: ["search", "searches"], edit: ["edit", "edits"], command: ["command", "commands"], test: ["test run", "test runs"], web: ["web action", "web actions"], agent: ["agent action", "agent actions"], plan: ["plan update", "plan updates"], other: ["action", "actions"] };
|
|
281
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 3).map(([category, count]) => `${count} ${nouns[category][count === 1 ? 0 : 1]}`).join(" \xB7 ");
|
|
218
282
|
}
|
|
219
283
|
|
|
220
284
|
// src/markdown.jsx
|
|
@@ -326,7 +390,8 @@ function ToolIcon({ category }) {
|
|
|
326
390
|
const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
|
|
327
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, {}) });
|
|
328
392
|
}
|
|
329
|
-
function
|
|
393
|
+
function toolAction2(entry, category, presentation) {
|
|
394
|
+
if (presentation?.action) return presentation.action;
|
|
330
395
|
const status = entry.status ?? "completed";
|
|
331
396
|
const actions = {
|
|
332
397
|
read: ["Reading", "Read", "Read failed"],
|
|
@@ -380,6 +445,16 @@ function ToolMetrics({ presentation }) {
|
|
|
380
445
|
].filter(Boolean);
|
|
381
446
|
return metrics.length ? /* @__PURE__ */ jsx2("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx2("span", { children: metric }, metric)) }) : null;
|
|
382
447
|
}
|
|
448
|
+
function PendingElapsed({ now }) {
|
|
449
|
+
const clock = now ?? Date.now;
|
|
450
|
+
const started = useRef(clock());
|
|
451
|
+
const [elapsed, setElapsed] = useState(0);
|
|
452
|
+
useEffect(() => {
|
|
453
|
+
const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
|
|
454
|
+
return () => clearInterval(timer);
|
|
455
|
+
}, [clock]);
|
|
456
|
+
return /* @__PURE__ */ jsx2("small", { class: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
|
|
457
|
+
}
|
|
383
458
|
function LinePreview({ value, kind }) {
|
|
384
459
|
if (!value) return null;
|
|
385
460
|
return /* @__PURE__ */ jsx2("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
|
|
@@ -437,16 +512,31 @@ function ToolPreview({ presentation, entry }) {
|
|
|
437
512
|
presentation.url ? /* @__PURE__ */ jsx2("code", { children: presentation.url }) : null,
|
|
438
513
|
presentation.preview ? /* @__PURE__ */ jsx2("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx2("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
|
|
439
514
|
] });
|
|
440
|
-
if (presentation.detail === "agent") return /* @__PURE__ */
|
|
441
|
-
presentation.subject ? /* @__PURE__ */ jsx2("p", { children: presentation.subject }) : null,
|
|
442
|
-
presentation.preview ? /* @__PURE__ */ jsx2("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx2("small", { children: pending ? "Agent is working" : "No textual handoff returned" })
|
|
443
|
-
] });
|
|
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" }) });
|
|
444
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: [
|
|
445
517
|
/* @__PURE__ */ jsx2("i", { "aria-hidden": "true" }),
|
|
446
518
|
/* @__PURE__ */ jsx2("span", { children: item.label })
|
|
447
519
|
] }, `${item.label}:${index}`)) });
|
|
448
520
|
return presentation.preview ? /* @__PURE__ */ jsx2("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
|
|
449
521
|
}
|
|
522
|
+
function ToolActions({ presentation, adapter }) {
|
|
523
|
+
const [copied, setCopied] = useState(false);
|
|
524
|
+
const reset = useRef(null);
|
|
525
|
+
useEffect(() => () => clearTimeout(reset.current), []);
|
|
526
|
+
if (!adapter?.copyText) return null;
|
|
527
|
+
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
|
+
const copy = async () => {
|
|
529
|
+
await adapter.copyText(action[1]);
|
|
530
|
+
setCopied(true);
|
|
531
|
+
clearTimeout(reset.current);
|
|
532
|
+
reset.current = setTimeout(() => setCopied(false), 1500);
|
|
533
|
+
};
|
|
534
|
+
return action ? /* @__PURE__ */ jsx2("div", { class: "scui-tool-actions", children: /* @__PURE__ */ jsx2("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
|
|
535
|
+
}
|
|
536
|
+
function ToolStack({ tools }) {
|
|
537
|
+
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)) });
|
|
539
|
+
}
|
|
450
540
|
function TechnicalDetails({ entry }) {
|
|
451
541
|
if (!entry.arguments && !entry.resultText) return null;
|
|
452
542
|
return /* @__PURE__ */ jsxs("details", { class: "scui-tool-technical", children: [
|
|
@@ -484,35 +574,42 @@ function TranscriptEntry({ entry, state, adapter }) {
|
|
|
484
574
|
entry.truncated ? /* @__PURE__ */ jsx2("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
|
|
485
575
|
] });
|
|
486
576
|
}
|
|
487
|
-
function ToolRow({ entry, workspace, open = false }) {
|
|
577
|
+
function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
488
578
|
const presentation = entry.presentation ?? createToolPresentation(entry);
|
|
579
|
+
const [expanded, setExpanded] = useState(open || entry.status === "pending");
|
|
580
|
+
useEffect(() => {
|
|
581
|
+
if (entry.status === "pending") setExpanded(true);
|
|
582
|
+
}, [entry.status]);
|
|
489
583
|
const target = compactToolTarget(presentation.target, workspace);
|
|
490
584
|
const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
|
|
491
585
|
const category = presentation.category ?? toolCategory(entry);
|
|
492
586
|
const summary = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
493
587
|
/* @__PURE__ */ jsx2(ToolIcon, { category }),
|
|
494
|
-
/* @__PURE__ */ jsx2("strong", { children:
|
|
588
|
+
/* @__PURE__ */ jsx2("strong", { children: toolAction2(entry, category, presentation) }),
|
|
495
589
|
target ? /* @__PURE__ */ jsx2("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
|
|
496
590
|
/* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
|
|
591
|
+
entry.status === "pending" ? /* @__PURE__ */ jsx2(PendingElapsed, { now: adapter?.now }) : null,
|
|
497
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" }),
|
|
498
593
|
hasDetail ? /* @__PURE__ */ jsx2("span", { class: "scui-tool-chevron", "aria-hidden": "true", children: "\u203A" }) : null
|
|
499
594
|
] });
|
|
500
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 }) });
|
|
501
|
-
return /* @__PURE__ */ jsxs("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open:
|
|
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: [
|
|
502
597
|
/* @__PURE__ */ jsx2("summary", { class: "scui-tool-head", children: summary }),
|
|
503
598
|
/* @__PURE__ */ jsxs("div", { class: "scui-tool-detail", children: [
|
|
504
599
|
/* @__PURE__ */ jsx2(ToolMetrics, { presentation }),
|
|
600
|
+
/* @__PURE__ */ jsx2(ToolStack, { tools: presentation.tools ?? [] }),
|
|
505
601
|
/* @__PURE__ */ jsx2(ToolPreview, { presentation, entry }),
|
|
506
602
|
presentation.fields.length ? /* @__PURE__ */ jsx2("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs("div", { children: [
|
|
507
603
|
/* @__PURE__ */ jsx2("dt", { children: field.label }),
|
|
508
604
|
/* @__PURE__ */ jsx2("dd", { children: field.value })
|
|
509
605
|
] }, field.label)) }) : null,
|
|
606
|
+
/* @__PURE__ */ jsx2(ToolActions, { presentation, adapter }),
|
|
510
607
|
/* @__PURE__ */ jsx2(TechnicalDetails, { entry })
|
|
511
608
|
] })
|
|
512
609
|
] });
|
|
513
610
|
}
|
|
514
|
-
function ActivityGroup({ entries, state }) {
|
|
515
|
-
if (entries.length === 1) return /* @__PURE__ */ jsx2("section", { class: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx2(ToolRow, { entry: entries[0], workspace: state.workspace }) });
|
|
611
|
+
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 }) });
|
|
516
613
|
const active = entries.some((entry) => entry.status === "pending");
|
|
517
614
|
const [open, setOpen] = useState(active);
|
|
518
615
|
const id = useId();
|
|
@@ -530,7 +627,7 @@ function ActivityGroup({ entries, state }) {
|
|
|
530
627
|
entries.length
|
|
531
628
|
] })
|
|
532
629
|
] }),
|
|
533
|
-
open ? /* @__PURE__ */ jsx2("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx2(ToolRow, { entry, workspace: state.workspace }, entry.id)) }) : null
|
|
630
|
+
open ? /* @__PURE__ */ jsx2("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx2(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
|
|
534
631
|
] });
|
|
535
632
|
}
|
|
536
633
|
function TaskPlan({ plan }) {
|