@volter-ai-dev/supercode-ui 0.1.8 → 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.d.ts +1 -0
- package/components.mjs +375 -33
- package/controller.mjs +8 -2
- package/conversation.d.ts +2 -0
- package/conversation.mjs +341 -33
- package/core.d.ts +3 -0
- package/core.mjs +240 -10
- package/embed.mjs +374 -33
- package/index.d.ts +35 -1
- package/messenger.mjs +374 -33
- package/package.json +1 -1
- package/styles.css +12 -1
package/conversation.mjs
CHANGED
|
@@ -59,6 +59,178 @@ var EMPTY_UI_STATE = Object.freeze({
|
|
|
59
59
|
owned: null,
|
|
60
60
|
attachError: null
|
|
61
61
|
});
|
|
62
|
+
var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
|
|
63
|
+
var MAX_TOOL_FIELDS = 8;
|
|
64
|
+
var MAX_TOOL_FIELD_CHARS = 800;
|
|
65
|
+
var MAX_TOOL_PREVIEW_CHARS = 4e3;
|
|
66
|
+
function record(value) {
|
|
67
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
68
|
+
}
|
|
69
|
+
function boundedString(value, max) {
|
|
70
|
+
if (typeof value !== "string") return "";
|
|
71
|
+
return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
|
|
72
|
+
}
|
|
73
|
+
function argumentValue(argumentsText) {
|
|
74
|
+
if (!argumentsText) return null;
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(argumentsText);
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function firstString(source, keys) {
|
|
82
|
+
for (const key of keys) {
|
|
83
|
+
if (typeof source?.[key] === "string" && source[key].trim()) return source[key].trim();
|
|
84
|
+
}
|
|
85
|
+
return "";
|
|
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
|
+
}
|
|
114
|
+
function explicitNumber(sources, keys) {
|
|
115
|
+
for (const source of sources) {
|
|
116
|
+
for (const key of keys) {
|
|
117
|
+
const value = source?.[key];
|
|
118
|
+
const parsed = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
|
|
119
|
+
if (typeof parsed === "number" && Number.isFinite(parsed)) return parsed;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function toolDetail(category) {
|
|
125
|
+
return { read: "file", search: "matches", edit: "diff", command: "terminal", test: "terminal", web: "web", agent: "agent", plan: "plan" }[category] ?? "fields";
|
|
126
|
+
}
|
|
127
|
+
function usefulToolFields(args) {
|
|
128
|
+
if (!args) return [];
|
|
129
|
+
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"]);
|
|
130
|
+
return Object.entries(args).flatMap(([key, value]) => {
|
|
131
|
+
if (hidden.has(key) || value === null || value === void 0) return [];
|
|
132
|
+
const rendered = typeof value === "string" ? value : JSON.stringify(value);
|
|
133
|
+
if (!rendered) return [];
|
|
134
|
+
return [{ label: key.replaceAll(/[_-]+/g, " ").replace(/^./, (letter) => letter.toLocaleUpperCase()), value: boundedString(rendered, MAX_TOOL_FIELD_CHARS) }];
|
|
135
|
+
}).slice(0, MAX_TOOL_FIELDS);
|
|
136
|
+
}
|
|
137
|
+
function planItems(args) {
|
|
138
|
+
const source = Array.isArray(args?.plan) ? args.plan : Array.isArray(args?.todos) ? args.todos : [];
|
|
139
|
+
return source.flatMap((item) => {
|
|
140
|
+
if (typeof item === "string" && item.trim()) return [{ label: boundedString(item.trim(), 300), status: "" }];
|
|
141
|
+
const value = record(item);
|
|
142
|
+
const label = firstString(value, ["step", "title", "content", "text"]);
|
|
143
|
+
if (!label) return [];
|
|
144
|
+
return [{ label: boundedString(label, 300), status: firstString(value, ["status"]) }];
|
|
145
|
+
}).slice(0, 12);
|
|
146
|
+
}
|
|
147
|
+
function editPreview(args, resultText, source) {
|
|
148
|
+
const direct = firstString(args, ["patch", "diff"]);
|
|
149
|
+
if (direct) return direct;
|
|
150
|
+
const oldText = firstString(args, ["old_string"]);
|
|
151
|
+
const newText = firstString(args, ["new_string"]);
|
|
152
|
+
if (oldText || newText) {
|
|
153
|
+
return [
|
|
154
|
+
...oldText.split("\n").map((line) => `- ${line}`),
|
|
155
|
+
...newText.split("\n").map((line) => `+ ${line}`)
|
|
156
|
+
].join("\n");
|
|
157
|
+
}
|
|
158
|
+
const patch = /\*\*\* Begin Patch[\s\S]*?\*\*\* End Patch/.exec(source ?? "")?.[0];
|
|
159
|
+
if (patch) return patch;
|
|
160
|
+
return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
|
|
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
|
+
}
|
|
194
|
+
function createToolPresentation(entry) {
|
|
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 ?? "";
|
|
209
|
+
const result = record(entry.resultContent);
|
|
210
|
+
const metadata = record(entry.metadata);
|
|
211
|
+
const resultMetadata = record(result?.metadata);
|
|
212
|
+
return {
|
|
213
|
+
name: boundedString(envelope.name, 120),
|
|
214
|
+
action: boundedString(toolAction(entry.status ?? "completed", category, envelope.name, envelope.tools), 120),
|
|
215
|
+
category,
|
|
216
|
+
detail: toolDetail(category),
|
|
217
|
+
target: boundedString(target, 300),
|
|
218
|
+
command: boundedString(command, MAX_TOOL_FIELD_CHARS),
|
|
219
|
+
path: boundedString(path, MAX_TOOL_FIELD_CHARS),
|
|
220
|
+
query: boundedString(query, MAX_TOOL_FIELD_CHARS),
|
|
221
|
+
url: boundedString(url, MAX_TOOL_FIELD_CHARS),
|
|
222
|
+
subject: boundedString(subject, MAX_TOOL_FIELD_CHARS),
|
|
223
|
+
preview: boundedString(previewSource, MAX_TOOL_PREVIEW_CHARS),
|
|
224
|
+
fields: usefulToolFields(args),
|
|
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"])
|
|
232
|
+
};
|
|
233
|
+
}
|
|
62
234
|
function harnessDisplayName(id) {
|
|
63
235
|
return HARNESS_NAMES[id] ?? id;
|
|
64
236
|
}
|
|
@@ -76,15 +248,10 @@ function groupConversation(entries) {
|
|
|
76
248
|
return blocks;
|
|
77
249
|
}
|
|
78
250
|
function toolCategory(entry) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (/test|typecheck|lint|build/.test(name)) return "test";
|
|
84
|
-
if (/terminal|bash|shell|command|exec/.test(name)) return /\b(test|typecheck|lint|build)\b/i.test(entry.arguments ?? "") ? "test" : "command";
|
|
85
|
-
if (/browser|web|fetch|url/.test(name)) return "web";
|
|
86
|
-
if (/subagent|spawn|task/.test(name)) return "agent";
|
|
87
|
-
return "other";
|
|
251
|
+
if (TOOL_CATEGORIES.has(entry.presentation?.category)) return entry.presentation.category;
|
|
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 || "");
|
|
88
255
|
}
|
|
89
256
|
function toolTarget(argumentsText) {
|
|
90
257
|
if (!argumentsText) return "";
|
|
@@ -110,7 +277,8 @@ function activitySummary(entries) {
|
|
|
110
277
|
if (pending) return `${entries.length} actions in progress`;
|
|
111
278
|
if (failed) return `${entries.length} actions \xB7 ${failed} failed`;
|
|
112
279
|
if ([...counts.keys()].every((key) => key === "read" || key === "search")) return `Explored ${entries.length} ${entries.length === 1 ? "item" : "items"}`;
|
|
113
|
-
|
|
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 ");
|
|
114
282
|
}
|
|
115
283
|
|
|
116
284
|
// src/markdown.jsx
|
|
@@ -212,6 +380,7 @@ var TOOL_ICONS = {
|
|
|
212
380
|
/* @__PURE__ */ jsx2("circle", { cx: "9", cy: "6", r: "2.5" }),
|
|
213
381
|
/* @__PURE__ */ jsx2("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
|
|
214
382
|
] }),
|
|
383
|
+
plan: () => /* @__PURE__ */ jsx2(Fragment, { children: /* @__PURE__ */ jsx2("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
|
|
215
384
|
other: () => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
216
385
|
/* @__PURE__ */ jsx2("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
|
|
217
386
|
/* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "3.5" })
|
|
@@ -221,7 +390,8 @@ function ToolIcon({ category }) {
|
|
|
221
390
|
const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
|
|
222
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, {}) });
|
|
223
392
|
}
|
|
224
|
-
function
|
|
393
|
+
function toolAction2(entry, category, presentation) {
|
|
394
|
+
if (presentation?.action) return presentation.action;
|
|
225
395
|
const status = entry.status ?? "completed";
|
|
226
396
|
const actions = {
|
|
227
397
|
read: ["Reading", "Read", "Read failed"],
|
|
@@ -230,7 +400,8 @@ function toolAction(entry, category) {
|
|
|
230
400
|
command: ["Running command", "Ran command", "Command failed"],
|
|
231
401
|
test: ["Running tests", "Ran tests", "Tests failed"],
|
|
232
402
|
web: ["Browsing", "Browsed", "Browser action failed"],
|
|
233
|
-
agent: ["Starting agent", "Started agent", "Agent failed"]
|
|
403
|
+
agent: ["Starting agent", "Started agent", "Agent failed"],
|
|
404
|
+
plan: ["Updating plan", "Updated plan", "Plan update failed"]
|
|
234
405
|
};
|
|
235
406
|
const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
|
|
236
407
|
if (actions[category]) return actions[category][position];
|
|
@@ -256,6 +427,138 @@ function argumentRows(argumentsText) {
|
|
|
256
427
|
}
|
|
257
428
|
return [{ key: "arguments", label: "Details", value: argumentsText }];
|
|
258
429
|
}
|
|
430
|
+
function stripAnsi(value) {
|
|
431
|
+
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, "") ?? "";
|
|
432
|
+
}
|
|
433
|
+
function formatDuration(value) {
|
|
434
|
+
if (value === null) return "";
|
|
435
|
+
if (value < 1e3) return `${Math.round(value)}ms`;
|
|
436
|
+
return `${(value / 1e3).toFixed(value < 1e4 ? 1 : 0)}s`;
|
|
437
|
+
}
|
|
438
|
+
function ToolMetrics({ presentation }) {
|
|
439
|
+
const metrics = [
|
|
440
|
+
presentation.matches === null ? "" : `${presentation.matches} ${presentation.matches === 1 ? "match" : "matches"}`,
|
|
441
|
+
presentation.additions === null ? "" : `+${presentation.additions}`,
|
|
442
|
+
presentation.deletions === null ? "" : `\u2212${presentation.deletions}`,
|
|
443
|
+
presentation.exitCode === null ? "" : `exit ${presentation.exitCode}`,
|
|
444
|
+
formatDuration(presentation.durationMs)
|
|
445
|
+
].filter(Boolean);
|
|
446
|
+
return metrics.length ? /* @__PURE__ */ jsx2("div", { class: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx2("span", { children: metric }, metric)) }) : null;
|
|
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
|
+
}
|
|
458
|
+
function LinePreview({ value, kind }) {
|
|
459
|
+
if (!value) return null;
|
|
460
|
+
return /* @__PURE__ */ jsx2("ol", { class: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
|
|
461
|
+
const tone = kind === "diff" ? line.startsWith("+") && !line.startsWith("+++") ? "add" : line.startsWith("-") && !line.startsWith("---") ? "remove" : line.startsWith("@@") ? "hunk" : "plain" : "plain";
|
|
462
|
+
return /* @__PURE__ */ jsxs("li", { "data-tone": tone, children: [
|
|
463
|
+
/* @__PURE__ */ jsx2("span", { children: index + 1 }),
|
|
464
|
+
/* @__PURE__ */ jsx2("code", { children: line || " " })
|
|
465
|
+
] }, index);
|
|
466
|
+
}) });
|
|
467
|
+
}
|
|
468
|
+
function TerminalPreview({ presentation, pending, failed }) {
|
|
469
|
+
return /* @__PURE__ */ jsxs("section", { class: "scui-terminal", children: [
|
|
470
|
+
/* @__PURE__ */ jsxs("header", { children: [
|
|
471
|
+
/* @__PURE__ */ jsxs("span", { "aria-hidden": "true", children: [
|
|
472
|
+
/* @__PURE__ */ jsx2("i", {}),
|
|
473
|
+
/* @__PURE__ */ jsx2("i", {}),
|
|
474
|
+
/* @__PURE__ */ jsx2("i", {})
|
|
475
|
+
] }),
|
|
476
|
+
/* @__PURE__ */ jsx2("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
|
|
477
|
+
] }),
|
|
478
|
+
presentation.preview ? /* @__PURE__ */ jsx2("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs("div", { class: "scui-terminal-wait", children: [
|
|
479
|
+
/* @__PURE__ */ jsx2("i", {}),
|
|
480
|
+
" Waiting for output"
|
|
481
|
+
] }) : /* @__PURE__ */ jsx2("div", { class: "scui-terminal-empty", children: "No output" })
|
|
482
|
+
] });
|
|
483
|
+
}
|
|
484
|
+
function SearchPreview({ presentation }) {
|
|
485
|
+
const lines = stripAnsi(presentation.preview).split("\n").filter(Boolean);
|
|
486
|
+
return /* @__PURE__ */ jsxs("section", { class: "scui-search-preview", children: [
|
|
487
|
+
presentation.query ? /* @__PURE__ */ jsxs("header", { children: [
|
|
488
|
+
/* @__PURE__ */ jsx2("span", { children: "Search" }),
|
|
489
|
+
/* @__PURE__ */ jsx2("code", { children: presentation.query })
|
|
490
|
+
] }) : null,
|
|
491
|
+
lines.length ? /* @__PURE__ */ jsx2("ol", { children: lines.map((line, index) => {
|
|
492
|
+
const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
|
|
493
|
+
return /* @__PURE__ */ jsx2("li", { children: match ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
494
|
+
/* @__PURE__ */ jsx2("code", { children: match[1] }),
|
|
495
|
+
/* @__PURE__ */ jsxs("small", { children: [
|
|
496
|
+
match[2],
|
|
497
|
+
match[3] ? `:${match[3]}` : ""
|
|
498
|
+
] }),
|
|
499
|
+
/* @__PURE__ */ jsx2("span", { children: match[4] })
|
|
500
|
+
] }) : /* @__PURE__ */ jsx2("span", { children: line }) }, index);
|
|
501
|
+
}) }) : /* @__PURE__ */ jsx2("p", { children: "No textual results" })
|
|
502
|
+
] });
|
|
503
|
+
}
|
|
504
|
+
function ToolPreview({ presentation, entry }) {
|
|
505
|
+
const pending = entry.status === "pending";
|
|
506
|
+
const failed = entry.status === "error";
|
|
507
|
+
if (presentation.detail === "terminal") return /* @__PURE__ */ jsx2(TerminalPreview, { presentation, pending, failed });
|
|
508
|
+
if (presentation.detail === "diff") return presentation.preview ? /* @__PURE__ */ jsx2(LinePreview, { value: presentation.preview, kind: "diff" }) : /* @__PURE__ */ jsx2("div", { class: "scui-tool-empty", children: "Edit completed without a textual diff" });
|
|
509
|
+
if (presentation.detail === "file") return presentation.preview ? /* @__PURE__ */ jsx2(LinePreview, { value: presentation.preview, kind: "file" }) : /* @__PURE__ */ jsx2("div", { class: "scui-tool-empty", children: "File contents were not included in this event" });
|
|
510
|
+
if (presentation.detail === "matches") return /* @__PURE__ */ jsx2(SearchPreview, { presentation });
|
|
511
|
+
if (presentation.detail === "web") return /* @__PURE__ */ jsxs("section", { class: "scui-web-preview", children: [
|
|
512
|
+
presentation.url ? /* @__PURE__ */ jsx2("code", { children: presentation.url }) : null,
|
|
513
|
+
presentation.preview ? /* @__PURE__ */ jsx2("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx2("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
|
|
514
|
+
] });
|
|
515
|
+
if (presentation.detail === "agent") return /* @__PURE__ */ jsx2("section", { class: "scui-agent-preview", children: presentation.preview ? /* @__PURE__ */ jsx2("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx2("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
|
|
516
|
+
if (presentation.detail === "plan") return /* @__PURE__ */ jsx2("ol", { class: "scui-plan-preview", children: presentation.items?.map((item, index) => /* @__PURE__ */ jsxs("li", { "data-status": item.status, children: [
|
|
517
|
+
/* @__PURE__ */ jsx2("i", { "aria-hidden": "true" }),
|
|
518
|
+
/* @__PURE__ */ jsx2("span", { children: item.label })
|
|
519
|
+
] }, `${item.label}:${index}`)) });
|
|
520
|
+
return presentation.preview ? /* @__PURE__ */ jsx2("pre", { class: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
|
|
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
|
+
}
|
|
540
|
+
function TechnicalDetails({ entry }) {
|
|
541
|
+
if (!entry.arguments && !entry.resultText) return null;
|
|
542
|
+
return /* @__PURE__ */ jsxs("details", { class: "scui-tool-technical", children: [
|
|
543
|
+
/* @__PURE__ */ jsx2("summary", { children: "Technical details" }),
|
|
544
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
545
|
+
entry.arguments ? /* @__PURE__ */ jsxs("section", { children: [
|
|
546
|
+
/* @__PURE__ */ jsx2("strong", { children: "Native arguments" }),
|
|
547
|
+
/* @__PURE__ */ jsx2("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs("div", { children: [
|
|
548
|
+
/* @__PURE__ */ jsx2("dt", { children: row.label }),
|
|
549
|
+
/* @__PURE__ */ jsx2("dd", { children: /* @__PURE__ */ jsx2("pre", { children: row.value }) })
|
|
550
|
+
] }, row.key)) })
|
|
551
|
+
] }) : null,
|
|
552
|
+
entry.resultText ? /* @__PURE__ */ jsxs("section", { children: [
|
|
553
|
+
/* @__PURE__ */ jsx2("strong", { children: "Native result" }),
|
|
554
|
+
/* @__PURE__ */ jsxs("pre", { "data-error": entry.status === "error", children: [
|
|
555
|
+
entry.resultText,
|
|
556
|
+
entry.truncated ? "\n[truncated]" : ""
|
|
557
|
+
] })
|
|
558
|
+
] }) : null
|
|
559
|
+
] })
|
|
560
|
+
] });
|
|
561
|
+
}
|
|
259
562
|
function TranscriptEntry({ entry, state, adapter }) {
|
|
260
563
|
if (entry.role === "request") return /* @__PURE__ */ jsx2(RequestCard, { entry, adapter, canRespond: state.canRespond });
|
|
261
564
|
if (entry.role === "reasoning") {
|
|
@@ -271,38 +574,42 @@ function TranscriptEntry({ entry, state, adapter }) {
|
|
|
271
574
|
entry.truncated ? /* @__PURE__ */ jsx2("small", { class: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null
|
|
272
575
|
] });
|
|
273
576
|
}
|
|
274
|
-
function ToolRow({ entry, workspace }) {
|
|
275
|
-
const
|
|
276
|
-
const
|
|
277
|
-
|
|
577
|
+
function ToolRow({ entry, workspace, open = false, adapter }) {
|
|
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]);
|
|
583
|
+
const target = compactToolTarget(presentation.target, workspace);
|
|
584
|
+
const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
|
|
585
|
+
const category = presentation.category ?? toolCategory(entry);
|
|
278
586
|
const summary = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
279
587
|
/* @__PURE__ */ jsx2(ToolIcon, { category }),
|
|
280
|
-
/* @__PURE__ */ jsx2("strong", { children:
|
|
281
|
-
target ? /* @__PURE__ */ jsx2("code", { class: "scui-tool-target", title:
|
|
588
|
+
/* @__PURE__ */ jsx2("strong", { children: toolAction2(entry, category, presentation) }),
|
|
589
|
+
target ? /* @__PURE__ */ jsx2("code", { class: "scui-tool-target", title: presentation.target, children: target }) : null,
|
|
282
590
|
/* @__PURE__ */ jsx2("span", { class: "scui-spacer" }),
|
|
591
|
+
entry.status === "pending" ? /* @__PURE__ */ jsx2(PendingElapsed, { now: adapter?.now }) : null,
|
|
283
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" }),
|
|
284
593
|
hasDetail ? /* @__PURE__ */ jsx2("span", { class: "scui-tool-chevron", "aria-hidden": "true", children: "\u203A" }) : null
|
|
285
594
|
] });
|
|
286
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 }) });
|
|
287
|
-
return /* @__PURE__ */ jsxs("details", { class: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: [
|
|
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: [
|
|
288
597
|
/* @__PURE__ */ jsx2("summary", { class: "scui-tool-head", children: summary }),
|
|
289
598
|
/* @__PURE__ */ jsxs("div", { class: "scui-tool-detail", children: [
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
/* @__PURE__ */ jsx2("
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
] })
|
|
300
|
-
] }) : null
|
|
599
|
+
/* @__PURE__ */ jsx2(ToolMetrics, { presentation }),
|
|
600
|
+
/* @__PURE__ */ jsx2(ToolStack, { tools: presentation.tools ?? [] }),
|
|
601
|
+
/* @__PURE__ */ jsx2(ToolPreview, { presentation, entry }),
|
|
602
|
+
presentation.fields.length ? /* @__PURE__ */ jsx2("dl", { class: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs("div", { children: [
|
|
603
|
+
/* @__PURE__ */ jsx2("dt", { children: field.label }),
|
|
604
|
+
/* @__PURE__ */ jsx2("dd", { children: field.value })
|
|
605
|
+
] }, field.label)) }) : null,
|
|
606
|
+
/* @__PURE__ */ jsx2(ToolActions, { presentation, adapter }),
|
|
607
|
+
/* @__PURE__ */ jsx2(TechnicalDetails, { entry })
|
|
301
608
|
] })
|
|
302
609
|
] });
|
|
303
610
|
}
|
|
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 }) });
|
|
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 }) });
|
|
306
613
|
const active = entries.some((entry) => entry.status === "pending");
|
|
307
614
|
const [open, setOpen] = useState(active);
|
|
308
615
|
const id = useId();
|
|
@@ -320,7 +627,7 @@ function ActivityGroup({ entries, state }) {
|
|
|
320
627
|
entries.length
|
|
321
628
|
] })
|
|
322
629
|
] }),
|
|
323
|
-
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
|
|
324
631
|
] });
|
|
325
632
|
}
|
|
326
633
|
function TaskPlan({ plan }) {
|
|
@@ -462,5 +769,6 @@ export {
|
|
|
462
769
|
RequestCard,
|
|
463
770
|
SessionDetails,
|
|
464
771
|
TaskPlan,
|
|
772
|
+
ToolRow,
|
|
465
773
|
TranscriptEntry
|
|
466
774
|
};
|
package/core.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export type {
|
|
|
19
19
|
TranscriptContext,
|
|
20
20
|
TranscriptEntryModel,
|
|
21
21
|
TranscriptRequest,
|
|
22
|
+
ToolCategory,
|
|
23
|
+
ToolPresentationModel,
|
|
22
24
|
UiTone,
|
|
23
25
|
} from './index.js';
|
|
24
26
|
export {
|
|
@@ -27,6 +29,7 @@ export {
|
|
|
27
29
|
activitySummary,
|
|
28
30
|
canContinueHere,
|
|
29
31
|
compactToolTarget,
|
|
32
|
+
createToolPresentation,
|
|
30
33
|
filterSessions,
|
|
31
34
|
groupConversation,
|
|
32
35
|
harnessDisplayName,
|