@volter-ai-dev/supercode-ui 0.1.70 → 0.1.72

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.
Files changed (59) hide show
  1. package/README.md +61 -1
  2. package/activity.mjs +5 -1235
  3. package/chunks/chunk-2FG7VKIW.mjs +201 -0
  4. package/chunks/chunk-4XUMCWPC.mjs +29 -0
  5. package/chunks/chunk-E65I2I2L.mjs +120 -0
  6. package/chunks/chunk-IL5T2AST.mjs +842 -0
  7. package/chunks/chunk-LOP6XOON.mjs +671 -0
  8. package/chunks/chunk-LS6JBXNT.mjs +1237 -0
  9. package/chunks/chunk-SJ3YTA6Z.mjs +316 -0
  10. package/chunks/chunk-TKTOVDXB.mjs +139 -0
  11. package/chunks/chunk-V3UM7H7W.mjs +328 -0
  12. package/chunks/chunk-WRK5TBX3.mjs +224 -0
  13. package/chunks/chunk-ZLYHUYE2.mjs +62 -0
  14. package/components.d.ts +3 -0
  15. package/components.mjs +59 -3766
  16. package/composer.mjs +8 -580
  17. package/conversation.mjs +16 -1373
  18. package/embed.mjs +15 -3681
  19. package/icon.mjs +3 -58
  20. package/index.d.ts +25 -0
  21. package/logo.mjs +5 -87
  22. package/messenger.d.ts +3 -0
  23. package/messenger.mjs +21 -3677
  24. package/package.json +22 -3
  25. package/react/activity.mjs +5 -1235
  26. package/react/chunks/chunk-7ES5FSLG.mjs +316 -0
  27. package/react/chunks/chunk-LS6JBXNT.mjs +1237 -0
  28. package/react/chunks/chunk-LYRIQE5M.mjs +29 -0
  29. package/react/chunks/chunk-NJC6S2AW.mjs +201 -0
  30. package/react/chunks/chunk-OINC7LV7.mjs +62 -0
  31. package/react/chunks/chunk-QL6QEYPK.mjs +842 -0
  32. package/react/chunks/chunk-UGL6AB2K.mjs +120 -0
  33. package/react/chunks/chunk-UKHDCPME.mjs +328 -0
  34. package/react/chunks/chunk-UKMTRNJN.mjs +671 -0
  35. package/react/chunks/chunk-VFOVJ4S3.mjs +139 -0
  36. package/react/chunks/chunk-YK7SJ6EH.mjs +224 -0
  37. package/react/components.mjs +59 -3766
  38. package/react/composer.mjs +8 -580
  39. package/react/conversation.mjs +16 -1373
  40. package/react/icon.mjs +3 -58
  41. package/react/index.d.ts +25 -0
  42. package/react/logo.mjs +5 -87
  43. package/react/messenger.d.ts +3 -0
  44. package/react/messenger.mjs +21 -3677
  45. package/react/sessions.mjs +9 -519
  46. package/react/settings.mjs +9 -425
  47. package/react/subagents.mjs +8 -1546
  48. package/react/supervision-components.mjs +1354 -0
  49. package/react/supervision.d.ts +36 -0
  50. package/sessions.mjs +9 -519
  51. package/settings.mjs +9 -425
  52. package/source-inventory.d.ts +240 -0
  53. package/source-inventory.mjs +367 -0
  54. package/styles.css +104 -0
  55. package/subagents.mjs +8 -1546
  56. package/supervision-components.d.ts +36 -0
  57. package/supervision-components.mjs +1354 -0
  58. package/supervision.d.ts +242 -0
  59. package/supervision.mjs +349 -0
@@ -1,1376 +1,19 @@
1
- // src/conversation.jsx
2
- import { Fragment as Fragment3 } from "react";
3
- import { useEffect as useEffect3, useId, useLayoutEffect, useRef as useRef3, useState as useState2 } from "react";
4
-
5
- // core.mjs
6
- var HARNESS_NAMES = Object.freeze({
7
- "claude-code": "Claude Code",
8
- codex: "Codex",
9
- gemini: "Gemini CLI",
10
- goose: "Goose",
11
- opencode: "OpenCode",
12
- pi: "Pi",
13
- grok: "Grok"
14
- });
15
- var DEFAULT_LABELS = Object.freeze({
16
- chats: "Chats",
17
- newChat: "New chat",
18
- searchChats: "Search chats",
19
- askAgent: "Ask your agent\u2026",
20
- attachContext: "Attach files or images",
21
- continueHere: "Continue here",
22
- continueWithTerminal: "Continue with terminal",
23
- joinLive: "Join live",
24
- forkHere: "Fork here"
25
- });
26
- var EMPTY_UI_STATE = Object.freeze({
27
- pill: Object.freeze({ tone: "off", label: "connecting\u2026" }),
28
- startup: "connecting",
29
- transcript: Object.freeze([]),
30
- busy: false,
31
- operation: null,
32
- needsInput: false,
33
- harness: "",
34
- mode: "none",
35
- strategy: null,
36
- participant: Object.freeze({ kind: "local-user", label: null, origin: null }),
37
- workspaceRef: Object.freeze({ kind: "none", value: null }),
38
- mirror: null,
39
- holder: null,
40
- canSend: false,
41
- canSteer: false,
42
- canResume: false,
43
- supportsResume: false,
44
- continuationModes: Object.freeze([]),
45
- canBranch: false,
46
- supportsBranch: false,
47
- canAttach: false,
48
- supportsAttach: false,
49
- canDetach: false,
50
- canOpenTerminal: false,
51
- canExport: false,
52
- canReduce: false,
53
- canInterrupt: false,
54
- canRespond: false,
55
- canConfigureSettings: false,
56
- messaging: null,
57
- workspace: "",
58
- taskPlan: Object.freeze({ source: "none", items: Object.freeze([]), residueCount: 0, observedAt: null }),
59
- semantics: Object.freeze({ fidelity: null, residue: Object.freeze([]), residueCount: 0, parseErrors: 0, rawRecords: 0, subagents: Object.freeze([]) }),
60
- terminalHandoff: null,
61
- exportBackTarget: null,
62
- exportReceipt: null,
63
- reductionReceipt: null,
64
- interopSettings: null,
65
- interopSettingsError: null,
66
- harnessAuthentication: null,
67
- error: null,
68
- recoverable: false,
69
- harnesses: Object.freeze([]),
70
- history: Object.freeze({ sessionLimit: 0, hasMoreSessions: false, transcriptLimit: 120, hasEarlier: false }),
71
- savedDraft: "",
72
- attention: Object.freeze([]),
73
- sessions: Object.freeze([]),
74
- subagentInspector: null,
75
- attached: null,
76
- owned: null,
77
- attachError: null,
78
- agentPackage: null,
79
- contributions: Object.freeze([]),
80
- agentPackageError: null,
81
- agentPackageCapabilityState: null,
82
- agentPackageCapabilityError: null
83
- });
84
- var TOOL_CATEGORIES = /* @__PURE__ */ new Set(["read", "search", "edit", "command", "test", "web", "agent", "plan", "other"]);
85
- var MAX_TOOL_FIELDS = 8;
86
- var MAX_TOOL_FIELD_CHARS = 800;
87
- var MAX_TOOL_PREVIEW_CHARS = 4e3;
88
- function record(value) {
89
- return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
90
- }
91
- function boundedString(value, max = 2e3) {
92
- if (typeof value !== "string") return "";
93
- return value.length <= max ? value : `${value.slice(0, max)}\u2026`;
94
- }
95
- function argumentValue(argumentsText) {
96
- if (!argumentsText) return null;
97
- try {
98
- return JSON.parse(argumentsText);
99
- } catch {
100
- return null;
101
- }
102
- }
103
- function firstString(source, keys) {
104
- for (const key of keys) {
105
- if (typeof source?.[key] === "string" && source[key].trim()) return source[key].trim();
106
- }
107
- return "";
108
- }
109
- function decodedLiteral(value) {
110
- if (!value) return "";
111
- if (value.startsWith('"')) {
112
- try {
113
- return JSON.parse(value);
114
- } catch {
115
- return "";
116
- }
117
- }
118
- return value.slice(1, -1).replaceAll("\\n", "\n").replaceAll("\\t", " ").replaceAll("\\r", "\r").replaceAll("\\`", "`").replaceAll("\\'", "'").replaceAll("\\\\", "\\");
119
- }
120
- function sourceString(source, keys) {
121
- if (!source) return "";
122
- const names = keys.join("|");
123
- const match = new RegExp(`(?:^|[,{\\s])["']?(?:${names})["']?\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
124
- return decodedLiteral(match?.[1]);
125
- }
126
- function assignedString(source, keys) {
127
- if (!source) return "";
128
- const names = keys.join("|");
129
- const match = new RegExp(`\\b(?:${names})\\s*=\\s*("(?:\\\\.|[^"\\\\])*"|'(?:\\\\.|[^'\\\\])*'|\`(?:\\\\.|[^\`\\\\])*\`)`).exec(source);
130
- return decodedLiteral(match?.[1]);
131
- }
132
- function callArgumentSource(source, open) {
133
- let depth = 1;
134
- let quote = "";
135
- let escaped = false;
136
- let lineComment = false;
137
- let blockComment = false;
138
- for (let index = open + 1; index < source.length; index += 1) {
139
- const char = source[index];
140
- const next = source[index + 1];
141
- if (lineComment) {
142
- if (char === "\n") lineComment = false;
143
- continue;
144
- }
145
- if (blockComment) {
146
- if (char === "*" && next === "/") {
147
- blockComment = false;
148
- index += 1;
149
- }
150
- continue;
151
- }
152
- if (quote) {
153
- if (escaped) escaped = false;
154
- else if (char === "\\") escaped = true;
155
- else if (char === quote) quote = "";
156
- continue;
157
- }
158
- if (char === "/" && next === "/") {
159
- lineComment = true;
160
- index += 1;
161
- continue;
162
- }
163
- if (char === "/" && next === "*") {
164
- blockComment = true;
165
- index += 1;
166
- continue;
167
- }
168
- if (char === '"' || char === "'" || char === "`") {
169
- quote = char;
170
- continue;
171
- }
172
- if (char === "(") depth += 1;
173
- else if (char === ")" && (depth -= 1) === 0) return source.slice(open + 1, index);
174
- }
175
- return source.slice(open + 1);
176
- }
177
- function toolCalls(source) {
178
- const calls = [];
179
- let quote = "";
180
- let escaped = false;
181
- let lineComment = false;
182
- let blockComment = false;
183
- for (let index = 0; index < source.length && calls.length < 8; index += 1) {
184
- const char = source[index];
185
- const next = source[index + 1];
186
- if (lineComment) {
187
- if (char === "\n") lineComment = false;
188
- continue;
189
- }
190
- if (blockComment) {
191
- if (char === "*" && next === "/") {
192
- blockComment = false;
193
- index += 1;
194
- }
195
- continue;
196
- }
197
- if (quote) {
198
- if (escaped) escaped = false;
199
- else if (char === "\\") escaped = true;
200
- else if (char === quote) quote = "";
201
- continue;
202
- }
203
- if (char === "/" && next === "/") {
204
- lineComment = true;
205
- index += 1;
206
- continue;
207
- }
208
- if (char === "/" && next === "*") {
209
- blockComment = true;
210
- index += 1;
211
- continue;
212
- }
213
- if (char === '"' || char === "'" || char === "`") {
214
- quote = char;
215
- continue;
216
- }
217
- if (!source.startsWith("tools.", index) || /[A-Za-z0-9_$]/.test(source[index - 1] ?? "")) continue;
218
- const nameStart = index + 6;
219
- let nameEnd = nameStart;
220
- while (/[A-Za-z0-9_$]/.test(source[nameEnd] ?? "")) nameEnd += 1;
221
- let open = nameEnd;
222
- while (/\s/.test(source[open] ?? "")) open += 1;
223
- if (nameEnd === nameStart || source[open] !== "(") continue;
224
- calls.push({ name: source.slice(nameStart, nameEnd), arguments: callArgumentSource(source, open) });
225
- index = open;
226
- }
227
- return calls;
228
- }
229
- function toolEnvelope(entry) {
230
- const value = argumentValue(entry.arguments);
231
- const source = typeof value === "string" ? value : value === null ? entry.arguments ?? "" : "";
232
- const calls = source ? toolCalls(source) : [];
233
- const tools = [...new Set(calls.map((call) => call.name))];
234
- const name = tools.length === 1 ? tools[0] : entry.label ?? "tool";
235
- return { args: record(value), source, callSource: calls[0]?.arguments ?? "", tools, name };
236
- }
237
- function patchPath(source) {
238
- return /\*\*\* (?:Update|Add|Delete) File:\s*([^\r\n]*?)(?=\\[nr]|[\r\n]|$)/.exec(source)?.[1]?.trim() ?? "";
239
- }
240
- function explicitNumber(sources, keys) {
241
- for (const source of sources) {
242
- for (const key of keys) {
243
- const value = source?.[key];
244
- const parsed = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
245
- if (typeof parsed === "number" && Number.isFinite(parsed)) return parsed;
246
- }
247
- }
248
- return null;
249
- }
250
- function toolDetail(category) {
251
- return { read: "file", search: "matches", edit: "diff", command: "terminal", test: "terminal", web: "web", agent: "agent", plan: "plan" }[category] ?? "fields";
252
- }
253
- function usefulToolFields(args) {
254
- if (!args) return [];
255
- 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"]);
256
- return Object.entries(args).flatMap(([key, value]) => {
257
- if (hidden.has(key) || value === null || value === void 0) return [];
258
- const rendered = typeof value === "string" ? value : JSON.stringify(value);
259
- if (!rendered) return [];
260
- return [{ label: key.replaceAll(/[_-]+/g, " ").replace(/^./, (letter) => letter.toLocaleUpperCase()), value: boundedString(rendered, MAX_TOOL_FIELD_CHARS) }];
261
- }).slice(0, MAX_TOOL_FIELDS);
262
- }
263
- function planItems(args) {
264
- const source = Array.isArray(args?.plan) ? args.plan : Array.isArray(args?.todos) ? args.todos : [];
265
- return source.flatMap((item) => {
266
- if (typeof item === "string" && item.trim()) return [{ label: boundedString(item.trim(), 300), status: "" }];
267
- const value = record(item);
268
- const label = firstString(value, ["step", "title", "content", "text"]);
269
- if (!label) return [];
270
- return [{ label: boundedString(label, 300), status: firstString(value, ["status"]) }];
271
- }).slice(0, 12);
272
- }
273
- function agentItems(name, resultText) {
274
- if (!/list.?agents/i.test(name)) return [];
275
- return (resultText ?? "").split("\n").flatMap((line) => {
276
- const parts = line.trim().split(/\s+·\s+/).filter(Boolean);
277
- return parts.length > 1 ? [{ label: boundedString(parts[0], 120), status: boundedString(parts.slice(1).join(" \xB7 "), 180) }] : [];
278
- }).slice(0, 12);
279
- }
280
- function editPreview(args, resultText, source) {
281
- const direct = firstString(args, ["patch", "diff"]);
282
- if (direct) return direct;
283
- const oldText = firstString(args, ["old_string"]);
284
- const newText = firstString(args, ["new_string"]);
285
- if (oldText || newText) {
286
- return [
287
- ...oldText.split("\n").map((line) => `- ${line}`),
288
- ...newText.split("\n").map((line) => `+ ${line}`)
289
- ].join("\n");
290
- }
291
- const patch = /\*\*\* Begin Patch[\s\S]*?\*\*\* End Patch/.exec(source ?? "")?.[0];
292
- if (patch) return patch;
293
- return /^(?:diff --git|@@ |--- |\+\+\+ )/m.test(resultText ?? "") ? resultText : "";
294
- }
295
- function toolResultEnvelope(resultText) {
296
- const match = /^Script (?:completed|failed)\r?\nWall time ([0-9.]+) seconds\r?\nOutput:\r?\n([\s\S]*)$/.exec(resultText ?? "");
297
- if (!match) {
298
- try {
299
- const value = JSON.parse(resultText ?? "");
300
- const object = record(value);
301
- return {
302
- preview: typeof value === "string" ? value : firstString(object, ["output", "message", "text", "summary", "result"]) || resultText || "",
303
- value: object,
304
- durationMs: null
305
- };
306
- } catch {
307
- return { preview: resultText ?? "", value: null, durationMs: null };
308
- }
309
- }
310
- const durationMs = Number(match[1]) * 1e3;
311
- try {
312
- const value = record(JSON.parse(match[2]));
313
- return {
314
- preview: typeof value?.output === "string" ? value.output : match[2],
315
- value,
316
- durationMs: Number.isFinite(durationMs) ? durationMs : null
317
- };
318
- } catch {
319
- return { preview: match[2], value: null, durationMs: Number.isFinite(durationMs) ? durationMs : null };
320
- }
321
- }
322
- function semanticAgentPreview(name, status, outcome) {
323
- const normalized = name.toLocaleLowerCase();
324
- if (status === "error") return outcome.preview;
325
- if (/^(?:agent|task)$|spawn.?agent/.test(normalized) && outcome.preview) return "Agent is working in the background.";
326
- if (/send.?message|followup.?task/.test(normalized) && outcome.preview) {
327
- return /resumed from transcript|resumedAgentId/i.test(outcome.preview) ? "Agent resumed in the background." : "Message delivered.";
328
- }
329
- return outcome.preview;
330
- }
331
- function verificationCommand(command) {
332
- let shell = "";
333
- let quote = "";
334
- let escaped = false;
335
- for (const char of command) {
336
- if (escaped) {
337
- escaped = false;
338
- shell += quote ? " " : char;
339
- continue;
340
- }
341
- if (char === "\\") {
342
- escaped = true;
343
- shell += quote ? " " : char;
344
- continue;
345
- }
346
- if (quote) {
347
- if (char === quote) quote = "";
348
- shell += " ";
349
- continue;
350
- }
351
- if (char === '"' || char === "'" || char === "`") {
352
- quote = char;
353
- shell += " ";
354
- continue;
355
- }
356
- shell += char;
357
- }
358
- return /(?:^|[;&|]\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|typecheck|lint|build)|cargo\s+(?:test|clippy|build|check|fmt)|npx\s+(?:vitest|tsc|eslint|playwright)|pytest\b|go\s+test\b)/i.test(shell);
359
- }
360
- function classifyTool(name, command) {
361
- const normalized = name.toLocaleLowerCase();
362
- if (/write_stdin|^wait$/.test(normalized)) return "command";
363
- if (/update.?plan|todo|checklist|taskcreate|taskupdate|create.?goal|update.?goal/.test(normalized)) return "plan";
364
- if (/search.?replace|edit|write|patch|replace|create_file|apply_patch/.test(normalized)) return "edit";
365
- if (/read|view|open_file|list_dir/.test(normalized)) return "read";
366
- if (/web.?search|web.?fetch|fetch.?url/.test(normalized)) return "web";
367
- if (/search|find|grep|glob|toolsearch/.test(normalized)) return "search";
368
- if (/browser|web|fetch|url/.test(normalized)) return "web";
369
- if (/agent|subagent|send.?message|delegate|followup.?task|taskstop|taskoutput|^task$/.test(normalized)) return "agent";
370
- if (/test|typecheck|lint|build/.test(normalized)) return "test";
371
- if (/terminal|bash|shell|command|exec|write_stdin|^wait$/.test(normalized)) return verificationCommand(command) ? "test" : "command";
372
- return "other";
373
- }
374
- function toolAction(status, category, name, tools) {
375
- const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
376
- if (tools.length > 1) return [`Running ${tools.length} actions`, `Ran ${tools.length} actions`, `${tools.length} actions failed`][position];
377
- const normalized = name.toLocaleLowerCase();
378
- if (/send.?message|followup.?task/.test(normalized)) return ["Messaging agent", "Messaged agent", "Agent message failed"][position];
379
- if (/taskstop|interrupt.?agent|kill_command_or_subagent/.test(normalized)) return ["Stopping agent", "Stopped agent", "Stop failed"][position];
380
- if (/list.?agents|taskoutput|wait.?agent/.test(normalized)) return ["Checking agents", "Checked agents", "Agent check failed"][position];
381
- if (/get_command_or_subagent_output|write_stdin|^wait$/.test(normalized)) return ["Waiting for", "Checked", "Check failed"][position];
382
- if (/web.?search/.test(normalized)) return ["Searching web", "Searched web", "Web search failed"][position];
383
- if (/web.?fetch|fetch.?url/.test(normalized)) return ["Fetching page", "Fetched page", "Page fetch failed"][position];
384
- if (/^skill$|use.?skill|load.?skill/.test(normalized)) return ["Loading skill", "Loaded skill", "Skill load failed"][position];
385
- if (/taskcreate/.test(normalized)) return ["Adding task", "Added task", "Task creation failed"][position];
386
- if (/taskupdate/.test(normalized)) return ["Updating task", "Updated task", "Task update failed"][position];
387
- if (/create.?goal/.test(normalized)) return ["Creating goal", "Created goal", "Goal creation failed"][position];
388
- if (/update.?goal/.test(normalized)) return ["Updating goal", "Updated goal", "Goal update failed"][position];
389
- const actions = {
390
- read: ["Reading", "Read", "Read failed"],
391
- search: ["Searching", "Searched", "Search failed"],
392
- edit: ["Editing", "Edited", "Edit failed"],
393
- command: ["Running command", "Ran command", "Command failed"],
394
- test: ["Running tests", "Ran tests", "Tests failed"],
395
- web: ["Browsing", "Browsed", "Browser action failed"],
396
- agent: ["Starting agent", "Started agent", "Agent failed"],
397
- plan: ["Updating plan", "Updated plan", "Plan update failed"]
398
- };
399
- return actions[category]?.[position] ?? (status === "error" ? `${name} failed` : name.replaceAll(/[_-]+/g, " "));
400
- }
401
- function createToolPresentation(entry) {
402
- const envelope = toolEnvelope(entry);
403
- const args = envelope.args;
404
- const outcome = toolResultEnvelope(entry.resultText);
405
- const patchSource = assignedString(envelope.source, ["patch"]) || envelope.source;
406
- const command = firstString(args, ["command", "cmd"]) || sourceString(envelope.callSource, ["command", "cmd"]);
407
- const category = classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
408
- const path = firstString(args, ["file_path", "target_file", "target_directory", "path"]) || sourceString(envelope.callSource, ["file_path", "target_file", "target_directory", "path"]) || patchPath(patchSource);
409
- const query = firstString(args, ["query", "pattern"]) || sourceString(envelope.callSource, ["query", "pattern", "q"]);
410
- const url = firstString(args, ["url"]) || sourceString(envelope.callSource, ["url", "ref_id"]);
411
- const subject = firstString(args, ["subject", "description", "summary", "task", "objective", "prompt"]) || sourceString(envelope.callSource, ["subject", "description", "summary", "task", "objective", "prompt"]);
412
- const agentTarget = category === "agent" ? firstString(record(outcome.value), ["command", "name"]) || firstString(args, ["target", "task_name", "taskId", "task_id", "agentId", "agent_id", "resume", "team_name"]) || sourceString(envelope.callSource, ["target", "task_name", "taskId", "task_id", "agentId", "agent_id", "resume", "team_name"]) : "";
413
- const skillTarget = /^skill$|use.?skill|load.?skill/i.test(envelope.name) ? firstString(args, ["skill", "name"]) || sourceString(envelope.callSource, ["skill", "name"]) : "";
414
- 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" : "";
415
- const items = category === "agent" ? agentItems(envelope.name, outcome.preview) : planItems(args);
416
- const taskId = firstString(args, ["taskId", "task_id"]);
417
- const planTarget = category === "plan" ? items.length ? `${items.length} ${items.length === 1 ? "item" : "items"}` : taskId ? `task ${taskId}` : "" : "";
418
- const target = path || command || query || url || subject || agentTarget || skillTarget || background || planTarget || (envelope.tools.length > 1 ? `${envelope.tools.length} coordinated actions` : toolTarget(entry.arguments));
419
- const previewSource = category === "edit" ? editPreview(args, outcome.preview, patchSource) : category === "agent" ? semanticAgentPreview(envelope.name, entry.status ?? "completed", outcome) : outcome.preview;
420
- const result = record(entry.resultContent);
421
- const metadata = record(entry.metadata);
422
- const resultMetadata = record(result?.metadata);
423
- return {
424
- name: boundedString(envelope.name, 120),
425
- action: boundedString(toolAction(entry.status ?? "completed", category, envelope.name, envelope.tools), 120),
426
- category,
427
- detail: toolDetail(category),
428
- target: boundedString(target, 300),
429
- command: boundedString(command, MAX_TOOL_FIELD_CHARS),
430
- path: boundedString(path, MAX_TOOL_FIELD_CHARS),
431
- query: boundedString(query, MAX_TOOL_FIELD_CHARS),
432
- url: boundedString(url, MAX_TOOL_FIELD_CHARS),
433
- subject: boundedString(subject, MAX_TOOL_FIELD_CHARS),
434
- preview: boundedString(previewSource, MAX_TOOL_PREVIEW_CHARS),
435
- fields: usefulToolFields(args),
436
- items,
437
- tools: envelope.tools,
438
- exitCode: explicitNumber([outcome.value, result, resultMetadata, metadata], ["exit_code", "exitCode", "pi_bash_exit_code"]),
439
- durationMs: explicitNumber([outcome.value, result, resultMetadata, metadata], ["duration_ms", "durationMs", "elapsed_ms", "elapsedMs", "totalDurationMs"]) ?? outcome.durationMs,
440
- additions: explicitNumber([result, resultMetadata, metadata], ["additions", "lines_added"]),
441
- deletions: explicitNumber([result, resultMetadata, metadata], ["deletions", "lines_removed"]),
442
- matches: explicitNumber([result, resultMetadata, metadata], ["matches", "match_count", "result_count"])
443
- };
444
- }
445
- function harnessDisplayName(id) {
446
- return HARNESS_NAMES[id] ?? id;
447
- }
448
- var ACTIVITY_PRIORITY = Object.freeze({
449
- "needs-input": 70,
450
- failed: 60,
451
- working: 50,
452
- unseen: 40,
453
- finished: 30,
454
- running: 20,
455
- recent: 10,
456
- idle: 0
457
- });
458
- function groupConversation(entries) {
459
- const blocks = [];
460
- for (const entry of entries) {
461
- if (entry.role !== "tool") {
462
- blocks.push({ kind: "entry", id: entry.id, entry });
463
- continue;
464
- }
465
- const previous = blocks.at(-1);
466
- if (previous?.kind === "activity") previous.entries.push(entry);
467
- else blocks.push({ kind: "activity", id: `activity:${entry.id}`, entries: [entry] });
468
- }
469
- return blocks;
470
- }
471
- function toolCategory(entry) {
472
- if (TOOL_CATEGORIES.has(entry.presentation?.category)) return entry.presentation.category;
473
- const envelope = toolEnvelope(entry);
474
- const command = firstString(envelope.args, ["command", "cmd"]) || sourceString(envelope.source, ["command", "cmd"]);
475
- return classifyTool(envelope.name, command || envelope.source || entry.arguments || "");
476
- }
477
- function toolTarget(argumentsText) {
478
- if (!argumentsText) return "";
479
- try {
480
- const args = JSON.parse(argumentsText);
481
- for (const key of ["file_path", "target_file", "path", "command", "cmd", "query", "pattern", "url"]) {
482
- if (typeof args?.[key] === "string") return args[key];
483
- }
484
- } catch {
485
- return argumentsText.length > 120 ? `${argumentsText.slice(0, 117)}\u2026` : argumentsText;
486
- }
487
- return "";
488
- }
489
- function compactToolTarget(target, workspace) {
490
- const prefix = workspace && !workspace.endsWith("/") ? `${workspace}/` : workspace;
491
- return prefix && target.startsWith(prefix) ? target.slice(prefix.length) : target;
492
- }
493
- function activitySummary(entries) {
494
- const counts = /* @__PURE__ */ new Map();
495
- for (const entry of entries) counts.set(toolCategory(entry), (counts.get(toolCategory(entry)) ?? 0) + 1);
496
- const failed = entries.filter((entry) => entry.status === "error").length;
497
- const pending = entries.filter((entry) => entry.status === "pending").length;
498
- if (pending) return `${entries.length} actions in progress`;
499
- if (failed) return `${entries.length} actions \xB7 ${failed} failed`;
500
- if ([...counts.keys()].every((key) => key === "read" || key === "search")) return `Explored ${entries.length} ${entries.length === 1 ? "item" : "items"}`;
501
- 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"] };
502
- 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 ");
503
- }
504
-
505
- // src/markdown.jsx
506
- import MarkdownIt from "markdown-it";
507
- import { useEffect, useMemo, useRef } from "react";
508
- import { jsx } from "react/jsx-runtime";
509
- var markdown = new MarkdownIt({ html: false, linkify: true, breaks: false });
510
- var LANGUAGE_LABELS = {
511
- bash: "Shell",
512
- css: "CSS",
513
- html: "HTML",
514
- js: "JavaScript",
515
- javascript: "JavaScript",
516
- jsx: "JSX",
517
- md: "Markdown",
518
- markdown: "Markdown",
519
- py: "Python",
520
- python: "Python",
521
- rs: "Rust",
522
- rust: "Rust",
523
- sh: "Shell",
524
- shell: "Shell",
525
- ts: "TypeScript",
526
- tsx: "TSX",
527
- yaml: "YAML",
528
- yml: "YAML",
529
- json: "JSON",
530
- jsonc: "JSONC",
531
- sql: "SQL",
532
- xml: "XML"
533
- };
534
- var COPY_ICON = '<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="5" width="8" height="8" rx="1.5"></rect><path d="M3 10.5V4.25C3 3.56 3.56 3 4.25 3h6.25"></path></svg>';
535
- function languageLabel(info) {
536
- const language = info.trim().split(/\s+/, 1)[0]?.toLocaleLowerCase() ?? "";
537
- if (!language) return "Code";
538
- return LANGUAGE_LABELS[language] ?? language.toLocaleUpperCase();
539
- }
540
- function frameCode(render, tokens, index, options, env, self) {
541
- const label = markdown.utils.escapeHtml(languageLabel(tokens[index]?.info ?? ""));
542
- const body = render(tokens, index, options, env, self).replace(
543
- "<pre>",
544
- `<pre tabindex="0" role="region" aria-label="${label} code">`
545
- );
546
- return `<div class="scui-code-block"><div class="scui-code-head"><span>${label}</span><button class="scui-code-copy" type="button" aria-label="Copy code" title="Copy code">${COPY_ICON}<span>Copy</span></button></div>${body}</div>`;
547
- }
548
- for (const kind of ["fence", "code_block"]) {
549
- const render = markdown.renderer.rules[kind];
550
- markdown.renderer.rules[kind] = (tokens, index, options, env, self) => frameCode(render, tokens, index, options, env, self);
551
- }
552
- var defaultLinkOpen = markdown.renderer.rules.link_open;
553
- markdown.renderer.rules.link_open = (tokens, index, options, env, self) => {
554
- tokens[index]?.attrSet("target", "_blank");
555
- tokens[index]?.attrSet("rel", "noreferrer noopener");
556
- return defaultLinkOpen ? defaultLinkOpen(tokens, index, options, env, self) : self.renderToken(tokens, index, options);
557
- };
558
- function setCopyState(button, status) {
559
- const labels = {
560
- idle: ["Copy code", "Copy"],
561
- copied: ["Code copied", "Copied"],
562
- failed: ["Copy failed \xB7 retry", "Retry"]
563
- };
564
- const [label, visible] = labels[status];
565
- button.dataset.status = status;
566
- button.setAttribute("aria-label", label);
567
- button.setAttribute("title", label);
568
- const text = button.querySelector("span");
569
- if (text) text.textContent = visible;
570
- }
571
- function Markdown({ value, copyText }) {
572
- const html = useMemo(() => markdown.render(value), [value]);
573
- const resets = useRef(/* @__PURE__ */ new Map());
574
- useEffect(() => () => {
575
- for (const timer of resets.current.values()) clearTimeout(timer);
576
- resets.current.clear();
577
- }, []);
578
- const copyCode = async (event) => {
579
- const button = event.target.closest?.(".scui-code-copy");
580
- if (!button || !event.currentTarget.contains(button) || !copyText) return;
581
- const code = button.closest(".scui-code-block")?.querySelector("pre code");
582
- if (!code) return;
583
- button.disabled = true;
584
- try {
585
- await copyText(code.textContent ?? "");
586
- setCopyState(button, "copied");
587
- } catch {
588
- setCopyState(button, "failed");
589
- } finally {
590
- button.disabled = false;
591
- }
592
- clearTimeout(resets.current.get(button));
593
- const timer = setTimeout(() => {
594
- if (button.isConnected) setCopyState(button, "idle");
595
- resets.current.delete(button);
596
- }, 1500);
597
- resets.current.set(button, timer);
598
- };
599
- return /* @__PURE__ */ jsx("div", { className: "scui-markdown", "data-copyable": Boolean(copyText), onClick: copyCode, dangerouslySetInnerHTML: { __html: html } });
600
- }
601
-
602
- // src/memory.js
603
- var MEMORY_LIMIT = 100;
604
- var registry = /* @__PURE__ */ new Set();
605
- function uiMemory() {
606
- const map = /* @__PURE__ */ new Map();
607
- registry.add(map);
608
- return map;
609
- }
610
- function boundedSet(map, key, value) {
611
- map.delete(key);
612
- map.set(key, value);
613
- while (map.size > MEMORY_LIMIT) map.delete(map.keys().next().value);
614
- }
615
-
616
- // src/icon.jsx
617
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
618
- var ICONS = {
619
- agents: () => /* @__PURE__ */ jsxs(Fragment, { children: [
620
- /* @__PURE__ */ jsx2("circle", { cx: "6", cy: "6.5", r: "2" }),
621
- /* @__PURE__ */ jsx2("path", { d: "M2.75 13c.45-2 1.55-3 3.25-3s2.8 1 3.25 3" }),
622
- /* @__PURE__ */ jsx2("circle", { cx: "12.25", cy: "7", r: "1.5" }),
623
- /* @__PURE__ */ jsx2("path", { d: "M10.5 10.75c1.95-.65 3.45.1 4 2.25" })
624
- ] }),
625
- attach: () => /* @__PURE__ */ jsx2("path", { d: "M6.25 9.75 10.6 5.4a2.1 2.1 0 0 1 2.97 2.97l-5.4 5.4a3.3 3.3 0 0 1-4.67-4.66l5.52-5.52" }),
626
- back: () => /* @__PURE__ */ jsx2("path", { d: "m11.5 4.5-4.5 4.5 4.5 4.5" }),
627
- check: () => /* @__PURE__ */ jsx2("path", { d: "m4 9 3.25 3.25L14 5.5" }),
628
- chevron: () => /* @__PURE__ */ jsx2("path", { d: "m7 4.5 4.5 4.5L7 13.5" }),
629
- close: () => /* @__PURE__ */ jsxs(Fragment, { children: [
630
- /* @__PURE__ */ jsx2("path", { d: "m4.75 4.75 8.5 8.5" }),
631
- /* @__PURE__ */ jsx2("path", { d: "m13.25 4.75-8.5 8.5" })
632
- ] }),
633
- compose: () => /* @__PURE__ */ jsxs(Fragment, { children: [
634
- /* @__PURE__ */ jsx2("path", { d: "M11.75 3.75 14.25 6.25 7 13.5l-3.25.75.75-3.25 7.25-7.25Z" }),
635
- /* @__PURE__ */ jsx2("path", { d: "m10.5 5 2.5 2.5" })
636
- ] }),
637
- copy: () => /* @__PURE__ */ jsxs(Fragment, { children: [
638
- /* @__PURE__ */ jsx2("rect", { x: "5", y: "5", width: "8", height: "8", rx: "1.5" }),
639
- /* @__PURE__ */ jsx2("path", { d: "M3 10.5V4.25C3 3.56 3.56 3 4.25 3h6.25" })
640
- ] }),
641
- down: () => /* @__PURE__ */ jsxs(Fragment, { children: [
642
- /* @__PURE__ */ jsx2("path", { d: "M9 3.5v10" }),
643
- /* @__PURE__ */ jsx2("path", { d: "m4.75 9.5 4.25 4 4.25-4" })
644
- ] }),
645
- image: () => /* @__PURE__ */ jsxs(Fragment, { children: [
646
- /* @__PURE__ */ jsx2("rect", { x: "3", y: "3.5", width: "12", height: "11", rx: "1.75" }),
647
- /* @__PURE__ */ jsx2("circle", { cx: "6.5", cy: "7", r: "1.25" }),
648
- /* @__PURE__ */ jsx2("path", { d: "m4.5 13 3.25-3 2.1 1.85 1.65-1.5L14 13" })
649
- ] }),
650
- menu: () => /* @__PURE__ */ jsxs(Fragment, { children: [
651
- /* @__PURE__ */ jsx2("circle", { cx: "4", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
652
- /* @__PURE__ */ jsx2("circle", { cx: "9", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" }),
653
- /* @__PURE__ */ jsx2("circle", { cx: "14", cy: "9", r: "1.25", fill: "currentColor", stroke: "none" })
654
- ] }),
655
- plus: () => /* @__PURE__ */ jsxs(Fragment, { children: [
656
- /* @__PURE__ */ jsx2("path", { d: "M9 3.5v11" }),
657
- /* @__PURE__ */ jsx2("path", { d: "M3.5 9h11" })
658
- ] }),
659
- search: () => /* @__PURE__ */ jsxs(Fragment, { children: [
660
- /* @__PURE__ */ jsx2("circle", { cx: "7.75", cy: "7.75", r: "4.25" }),
661
- /* @__PURE__ */ jsx2("path", { d: "m11 11 3.5 3.5" })
662
- ] }),
663
- send: () => /* @__PURE__ */ jsxs(Fragment, { children: [
664
- /* @__PURE__ */ jsx2("path", { d: "M9 14.5v-11" }),
665
- /* @__PURE__ */ jsx2("path", { d: "m4.75 7.75 4.25-4.25 4.25 4.25" })
666
- ] }),
667
- stop: () => /* @__PURE__ */ jsx2("rect", { x: "4.5", y: "4.5", width: "9", height: "9", rx: "1.5", fill: "currentColor", stroke: "none" })
668
- };
669
- function UiIcon({ name, size = 16, class: className = "" }) {
670
- const Glyph = ICONS[name];
671
- if (!Glyph) return null;
672
- return /* @__PURE__ */ jsx2("svg", { className: `scui-icon ${className}`, style: { "--scui-icon-size": `${size}px` }, viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx2(Glyph, {}) });
673
- }
674
-
675
- // src/context.jsx
676
- import { useEffect as useEffect2, useRef as useRef2, useState } from "react";
677
- import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
678
- var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
679
- var MAX_RESOLVED_IMAGE_BYTES = 16 * 1024 * 1024;
680
- function imageFilename(label) {
681
- const value = label.trim().replace(/[\\/:*?"<>|]+/g, "-");
682
- return value || "image";
683
- }
684
- function ImageViewer({ items, index, adapter, onChange, onClose }) {
685
- const dialog = useRef2(null);
686
- const reset = useRef2(null);
687
- const resolutions = useRef2(/* @__PURE__ */ new Map());
688
- const alive = useRef2(true);
689
- const [, redraw] = useState(0);
690
- const [copyState, setCopyState2] = useState("idle");
691
- const item = items[index];
692
- const key = item?.reference ?? item?.url ?? `${item?.id ?? ""}:${index}`;
693
- const resolution = item?.url ? null : resolutions.current.get(key);
694
- const imageUrl = item?.url ?? (resolution?.status === "ready" ? resolution.url : null);
695
- const remote = imageUrl?.startsWith("http://") || imageUrl?.startsWith("https://");
696
- const resolve = (candidate, force = false) => {
697
- if (candidate?.url || !candidate?.reference || !adapter?.resolveImage) return;
698
- const candidateKey = candidate.reference;
699
- const current = resolutions.current.get(candidateKey);
700
- if (!force && (current?.status === "loading" || current?.status === "ready")) return;
701
- if (current?.url) URL.revokeObjectURL(current.url);
702
- resolutions.current.set(candidateKey, { status: "loading" });
703
- redraw((value) => value + 1);
704
- Promise.resolve().then(() => adapter.resolveImage(candidate)).then((blob) => {
705
- if (!(blob instanceof Blob) || !blob.type.startsWith("image/")) throw new Error("The host returned an invalid image.");
706
- if (blob.size > MAX_RESOLVED_IMAGE_BYTES) throw new Error("This image is too large to preview safely.");
707
- if (!alive.current) return;
708
- const url = URL.createObjectURL(blob);
709
- resolutions.current.set(candidateKey, { status: "ready", url });
710
- redraw((value) => value + 1);
711
- }).catch((error) => {
712
- if (!alive.current) return;
713
- resolutions.current.set(candidateKey, {
714
- status: "error",
715
- message: error instanceof Error && error.message ? error.message : "Could not load this image."
716
- });
717
- redraw((value) => value + 1);
718
- });
719
- };
720
- useEffect2(() => {
721
- alive.current = true;
722
- if (!dialog.current?.open) dialog.current?.showModal();
723
- return () => {
724
- alive.current = false;
725
- clearTimeout(reset.current);
726
- for (const value of resolutions.current.values()) if (value.url) URL.revokeObjectURL(value.url);
727
- resolutions.current.clear();
728
- };
729
- }, []);
730
- useEffect2(() => {
731
- clearTimeout(reset.current);
732
- setCopyState2("idle");
733
- resolve(item);
734
- }, [index, item?.reference]);
735
- if (!item || !item.url && (!item.reference || !adapter?.resolveImage)) return null;
736
- const move = (amount) => onChange((index + amount + items.length) % items.length);
737
- const copy = async () => {
738
- try {
739
- await adapter.copyText(imageUrl);
740
- setCopyState2("copied");
741
- } catch {
742
- setCopyState2("failed");
743
- }
744
- clearTimeout(reset.current);
745
- reset.current = setTimeout(() => setCopyState2("idle"), 1500);
746
- };
747
- const close = () => dialog.current?.close();
748
- return /* @__PURE__ */ jsxs2(
749
- "dialog",
750
- {
751
- ref: dialog,
752
- className: "scui-image-viewer",
753
- "aria-label": `Image preview: ${item.label}`,
754
- onClose,
755
- onClick: (event) => {
756
- if (event.target === event.currentTarget) close();
757
- },
758
- onKeyDown: (event) => {
759
- if (items.length < 2 || !["ArrowLeft", "ArrowRight"].includes(event.key)) return;
760
- event.preventDefault();
761
- move(event.key === "ArrowLeft" ? -1 : 1);
762
- },
763
- children: [
764
- /* @__PURE__ */ jsxs2("header", { children: [
765
- /* @__PURE__ */ jsxs2("span", { children: [
766
- /* @__PURE__ */ jsx3("strong", { children: item.label }),
767
- items.length > 1 ? /* @__PURE__ */ jsxs2("small", { children: [
768
- index + 1,
769
- " of ",
770
- items.length
771
- ] }) : null
772
- ] }),
773
- /* @__PURE__ */ jsxs2("nav", { "aria-label": "Image actions", children: [
774
- remote && adapter?.copyText ? /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": copyState === "copied" ? "Image link copied" : copyState === "failed" ? "Could not copy image link" : "Copy image link", title: "Copy image link", "data-status": copyState, onClick: copy, children: /* @__PURE__ */ jsx3(UiIcon, { name: copyState === "copied" ? "check" : "copy", size: 16 }) }) : null,
775
- imageUrl ? remote ? /* @__PURE__ */ jsx3("a", { href: imageUrl, target: "_blank", rel: "noreferrer", "aria-label": "Open original image", title: "Open original image", children: /* @__PURE__ */ jsx3(UiIcon, { name: "image", size: 16 }) }) : /* @__PURE__ */ jsx3("a", { href: imageUrl, download: imageFilename(item.label), "aria-label": "Download image", title: "Download image", children: /* @__PURE__ */ jsx3(UiIcon, { name: "down", size: 16 }) }) : null,
776
- /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": "Close image preview", title: "Close", onClick: close, children: /* @__PURE__ */ jsx3(UiIcon, { name: "close", size: 17 }) })
777
- ] })
778
- ] }),
779
- /* @__PURE__ */ jsxs2("figure", { children: [
780
- imageUrl ? /* @__PURE__ */ jsx3("img", { src: imageUrl, alt: item.label }) : resolution?.status === "error" ? /* @__PURE__ */ jsxs2("div", { className: "scui-image-resolution", role: "alert", children: [
781
- /* @__PURE__ */ jsx3(UiIcon, { name: "image", size: 28 }),
782
- /* @__PURE__ */ jsx3("strong", { children: "Could not load image" }),
783
- /* @__PURE__ */ jsx3("small", { children: resolution.message }),
784
- /* @__PURE__ */ jsx3("button", { type: "button", onClick: () => resolve(item, true), children: "Retry" })
785
- ] }) : /* @__PURE__ */ jsxs2("div", { className: "scui-image-resolution", role: "status", children: [
786
- /* @__PURE__ */ jsx3("i", { className: "scui-control-spinner" }),
787
- /* @__PURE__ */ jsx3("strong", { children: "Loading image\u2026" }),
788
- /* @__PURE__ */ jsx3("small", { children: "The original stays out of the transcript payload." })
789
- ] }),
790
- items.length > 1 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
791
- /* @__PURE__ */ jsx3("button", { type: "button", className: "scui-image-previous", "aria-label": "Previous image", onClick: () => move(-1), children: /* @__PURE__ */ jsx3(UiIcon, { name: "chevron", size: 19 }) }),
792
- /* @__PURE__ */ jsx3("button", { type: "button", className: "scui-image-next", "aria-label": "Next image", onClick: () => move(1), children: /* @__PURE__ */ jsx3(UiIcon, { name: "chevron", size: 19 }) })
793
- ] }) : null
794
- ] })
795
- ]
796
- }
797
- );
798
- }
799
- function MessageImages({ items, adapter }) {
800
- const [active, setActive] = useState(null);
801
- const opener = useRef2(null);
802
- if (!items?.length) return null;
803
- const viewable = items.filter((item) => item.url || item.reference && adapter?.resolveImage);
804
- const close = () => {
805
- setActive(null);
806
- requestAnimationFrame(() => opener.current?.focus({ preventScroll: true }));
807
- };
808
- return /* @__PURE__ */ jsxs2(Fragment2, { children: [
809
- /* @__PURE__ */ jsx3("div", { className: "scui-message-images", "aria-label": "Message images", children: items.map((item, index) => item.url ? /* @__PURE__ */ jsx3("button", { type: "button", "aria-label": `View image ${item.label}`, onClick: (event) => {
810
- opener.current = event.currentTarget;
811
- setActive(viewable.indexOf(item));
812
- }, children: /* @__PURE__ */ jsx3("img", { src: item.url, alt: "" }) }, item.id ?? `${item.label}:${index}`) : item.reference && adapter?.resolveImage ? /* @__PURE__ */ jsxs2("button", { type: "button", "data-lazy": "true", "aria-label": `Load image ${item.label}`, onClick: (event) => {
813
- opener.current = event.currentTarget;
814
- setActive(viewable.indexOf(item));
815
- }, children: [
816
- /* @__PURE__ */ jsx3(UiIcon, { name: "image", size: 16 }),
817
- /* @__PURE__ */ jsxs2("span", { children: [
818
- /* @__PURE__ */ jsx3("strong", { children: item.label }),
819
- /* @__PURE__ */ jsx3("small", { children: "Load preview" })
820
- ] })
821
- ] }, item.id ?? `${item.label}:${index}`) : /* @__PURE__ */ jsxs2("span", { "data-unavailable": "true", children: [
822
- /* @__PURE__ */ jsx3(UiIcon, { name: "image", size: 14 }),
823
- /* @__PURE__ */ jsxs2("span", { children: [
824
- /* @__PURE__ */ jsx3("strong", { children: item.label }),
825
- /* @__PURE__ */ jsx3("small", { children: "Preview unavailable" })
826
- ] })
827
- ] }, item.id ?? `${item.label}:${index}`)) }),
828
- active !== null && viewable[active] ? /* @__PURE__ */ jsx3(ImageViewer, { items: viewable, index: active, adapter, onChange: setActive, onClose: close }) : null
829
- ] });
830
- }
831
-
832
- // src/conversation.jsx
833
- import { Fragment as Fragment4, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
834
- function LoadingStatus({ state, compact = false }) {
835
- const copy = {
836
- connecting: ["Connecting to coding agents", "Checking installed harnesses and capabilities.", 0],
837
- starting: [`Starting ${harnessDisplayName(state.harness) || "coding agent"}`, "Opening a controlled session in this workspace.", 1],
838
- discovering: ["Loading recent sessions", "Scanning native session stores without loading full transcripts.", 2],
839
- ready: ["Ready", "Coding sessions are up to date.", 3]
840
- }[state.startup];
841
- return /* @__PURE__ */ jsxs3("div", { className: `scui-loading${compact ? " scui-loading-compact" : ""}`, role: "status", "aria-busy": state.startup !== "ready", children: [
842
- /* @__PURE__ */ jsx4("span", { className: "scui-orbit", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("i", {}) }),
843
- /* @__PURE__ */ jsxs3("span", { className: "scui-loading-copy", children: [
844
- /* @__PURE__ */ jsx4("strong", { children: copy[0] }),
845
- /* @__PURE__ */ jsx4("small", { children: copy[1] })
846
- ] }),
847
- /* @__PURE__ */ jsx4("span", { className: "scui-progress", "aria-hidden": "true", children: [1, 2, 3].map((step) => /* @__PURE__ */ jsx4("i", { "data-progress": step <= copy[2] ? "done" : step === copy[2] + 1 ? "current" : "waiting" }, step)) })
848
- ] });
849
- }
850
- function RequestCard({ entry, adapter, canRespond }) {
851
- const request = entry.request;
852
- if (!request) return null;
853
- if (request.status === "responded") {
854
- return /* @__PURE__ */ jsxs3("div", { className: "scui-request-done", children: [
855
- "\u2713 Request answered \xB7 ",
856
- request.resolution?.name ?? request.requestKind
857
- ] });
858
- }
859
- return /* @__PURE__ */ jsxs3("section", { className: "scui-request", role: "alert", "aria-label": `${request.requestKind} needs input`, children: [
860
- /* @__PURE__ */ jsx4("strong", { children: "Agent needs input" }),
861
- /* @__PURE__ */ jsx4(Markdown, { value: request.payloadText || entry.text, copyText: adapter?.copyText }),
862
- /* @__PURE__ */ jsxs3("div", { className: "scui-request-actions", children: [
863
- request.options.map((option) => /* @__PURE__ */ jsx4("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: option.optionId }), children: option.name }, option.optionId)),
864
- request.cancellable ? /* @__PURE__ */ jsx4("button", { type: "button", disabled: !canRespond, onClick: () => adapter.onIntent({ action: "respond", requestId: request.requestId, optionId: null }), children: "Cancel" }) : null
865
- ] })
866
- ] });
867
- }
868
- function ContextDisclosure({ context }) {
869
- if (!context?.length) return null;
870
- return /* @__PURE__ */ jsxs3("details", { className: "scui-context", children: [
871
- /* @__PURE__ */ jsxs3("summary", { children: [
872
- "Context \xB7 ",
873
- context.length
874
- ] }),
875
- /* @__PURE__ */ jsx4("div", { children: context.map((item, index) => /* @__PURE__ */ jsxs3("p", { children: [
876
- /* @__PURE__ */ jsx4("strong", { children: item.label }),
877
- /* @__PURE__ */ jsx4("span", { children: item.detail })
878
- ] }, item.id ?? index)) })
879
- ] });
880
- }
881
- function MessageMeta({ entry, adapter }) {
882
- const [copyState, setCopyState2] = useState2("idle");
883
- const reset = useRef3(null);
884
- useEffect3(() => () => clearTimeout(reset.current), []);
885
- const date = entry.ts === null ? null : new Date(entry.ts);
886
- const validDate = date && Number.isFinite(date.valueOf()) ? date : null;
887
- if (!validDate && (!adapter?.copyText || !entry.text)) return null;
888
- const copy = async () => {
889
- try {
890
- await adapter.copyText(entry.text);
891
- setCopyState2("copied");
892
- } catch {
893
- setCopyState2("failed");
894
- }
895
- clearTimeout(reset.current);
896
- reset.current = setTimeout(() => setCopyState2("idle"), 1500);
897
- };
898
- const copyLabel = copyState === "copied" ? "Message copied" : copyState === "failed" ? "Copy failed \xB7 retry" : "Copy message";
899
- return /* @__PURE__ */ jsxs3("footer", { className: "scui-message-meta", children: [
900
- validDate ? /* @__PURE__ */ jsx4("time", { dateTime: validDate.toISOString(), title: validDate.toLocaleString(), children: validDate.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }) : null,
901
- adapter?.copyText && entry.text ? /* @__PURE__ */ jsx4("button", { type: "button", "aria-label": copyLabel, title: copyLabel, onClick: copy, "data-status": copyState, children: /* @__PURE__ */ jsx4(UiIcon, { name: "copy", size: 13 }) }) : null
902
- ] });
903
- }
904
- var TOOL_ICONS = {
905
- read: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
906
- /* @__PURE__ */ jsx4("path", { d: "M5 2.75h7.25L15 5.5v7.75A1.75 1.75 0 0 1 13.25 15h-8.5A1.75 1.75 0 0 1 3 13.25v-8.5A2 2 0 0 1 5 2.75Z" }),
907
- /* @__PURE__ */ jsx4("path", { d: "M12 2.9v3h2.85M6 9h6M6 12h4" })
908
- ] }),
909
- search: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
910
- /* @__PURE__ */ jsx4("circle", { cx: "8", cy: "8", r: "4.5" }),
911
- /* @__PURE__ */ jsx4("path", { d: "m11.5 11.5 3 3" })
912
- ] }),
913
- edit: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
914
- /* @__PURE__ */ jsx4("path", { d: "m11.75 3.25 3 3-8.5 8.5-3.75.75.75-3.75 8.5-8.5Z" }),
915
- /* @__PURE__ */ jsx4("path", { d: "m10 5 3 3" })
916
- ] }),
917
- command: () => /* @__PURE__ */ jsx4(Fragment4, { children: /* @__PURE__ */ jsx4("path", { d: "m3 5 3 3-3 3M8 12h6" }) }),
918
- test: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
919
- /* @__PURE__ */ jsx4("path", { d: "M6 2.5v3L3 12a2 2 0 0 0 1.8 3h8.4a2 2 0 0 0 1.8-3l-3-6.5v-3M5 9h8" }),
920
- /* @__PURE__ */ jsx4("path", { d: "M5 2.5h8" })
921
- ] }),
922
- web: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
923
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "6.5" }),
924
- /* @__PURE__ */ jsx4("path", { d: "M2.75 9h12.5M9 2.5c2 1.8 3 4 3 6.5s-1 4.7-3 6.5c-2-1.8-3-4-3-6.5s1-4.7 3-6.5Z" })
925
- ] }),
926
- agent: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
927
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "6", r: "2.5" }),
928
- /* @__PURE__ */ jsx4("path", { d: "M4 15c.4-3 2-4.5 5-4.5s4.6 1.5 5 4.5" })
929
- ] }),
930
- plan: () => /* @__PURE__ */ jsx4(Fragment4, { children: /* @__PURE__ */ jsx4("path", { d: "m3 5 1 1 2-2M3 9l1 1 2-2M3 13l1 1 2-2M8 5h7M8 9h7M8 13h7" }) }),
931
- other: () => /* @__PURE__ */ jsxs3(Fragment4, { children: [
932
- /* @__PURE__ */ jsx4("path", { d: "M9 2.5v3M9 12.5v3M2.5 9h3M12.5 9h3" }),
933
- /* @__PURE__ */ jsx4("circle", { cx: "9", cy: "9", r: "3.5" })
934
- ] })
935
- };
936
- function ToolIcon({ category }) {
937
- const Glyph = TOOL_ICONS[category] ?? TOOL_ICONS.other;
938
- return /* @__PURE__ */ jsx4("svg", { className: "scui-tool-icon", viewBox: "0 0 18 18", fill: "none", stroke: "currentColor", strokeWidth: "1.35", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx4(Glyph, {}) });
939
- }
940
- function toolAction2(entry, category, presentation) {
941
- if (presentation?.action) return presentation.action;
942
- const status = entry.status ?? "completed";
943
- const actions = {
944
- read: ["Reading", "Read", "Read failed"],
945
- search: ["Searching", "Searched", "Search failed"],
946
- edit: ["Editing", "Edited", "Edit failed"],
947
- command: ["Running command", "Ran command", "Command failed"],
948
- test: ["Running tests", "Ran tests", "Tests failed"],
949
- web: ["Browsing", "Browsed", "Browser action failed"],
950
- agent: ["Starting agent", "Started agent", "Agent failed"],
951
- plan: ["Updating plan", "Updated plan", "Plan update failed"]
952
- };
953
- const position = status === "pending" ? 0 : status === "error" ? 2 : 1;
954
- if (actions[category]) return actions[category][position];
955
- const label = entry.label?.split(/__|\//).at(-1)?.replaceAll(/[_-]+/g, " ") || "Tool";
956
- return status === "error" ? `${label} failed` : label;
957
- }
958
- function argumentLabel(key) {
959
- const labels = { cmd: "Command", command: "Command", cwd: "Working directory", file_path: "File", target_file: "File", path: "Path", query: "Query", pattern: "Pattern", url: "URL" };
960
- return labels[key] ?? key.replaceAll(/[_-]+/g, " ").replace(/^./, (letter) => letter.toLocaleUpperCase());
961
- }
962
- function argumentRows(argumentsText) {
963
- if (!argumentsText) return [];
964
- try {
965
- const value = JSON.parse(argumentsText);
966
- if (value && typeof value === "object" && !Array.isArray(value)) {
967
- return Object.entries(value).map(([key, item]) => ({
968
- key,
969
- label: argumentLabel(key),
970
- value: typeof item === "string" ? item : JSON.stringify(item, null, 2)
971
- }));
972
- }
973
- } catch {
974
- }
975
- return [{ key: "arguments", label: "Details", value: argumentsText }];
976
- }
977
- function stripAnsi(value) {
978
- 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, "") ?? "";
979
- }
980
- function formatDuration(value) {
981
- if (value === null) return "";
982
- if (value < 1e3) return `${Math.round(value)}ms`;
983
- return `${(value / 1e3).toFixed(value < 1e4 ? 1 : 0)}s`;
984
- }
985
- function ToolMetrics({ presentation }) {
986
- const metrics = [
987
- presentation.matches === null ? "" : `${presentation.matches} ${presentation.matches === 1 ? "match" : "matches"}`,
988
- presentation.additions === null ? "" : `+${presentation.additions}`,
989
- presentation.deletions === null ? "" : `\u2212${presentation.deletions}`,
990
- presentation.exitCode === null ? "" : `exit ${presentation.exitCode}`,
991
- formatDuration(presentation.durationMs)
992
- ].filter(Boolean);
993
- return metrics.length ? /* @__PURE__ */ jsx4("div", { className: "scui-tool-metrics", children: metrics.map((metric) => /* @__PURE__ */ jsx4("span", { children: metric }, metric)) }) : null;
994
- }
995
- function PendingElapsed({ now }) {
996
- const clock = now ?? Date.now;
997
- const started = useRef3(clock());
998
- const [elapsed, setElapsed] = useState2(0);
999
- useEffect3(() => {
1000
- const timer = setInterval(() => setElapsed(Math.max(0, clock() - started.current)), 1e3);
1001
- return () => clearInterval(timer);
1002
- }, [clock]);
1003
- return /* @__PURE__ */ jsx4("small", { className: "scui-tool-elapsed", children: elapsed < 1e3 ? "now" : formatDuration(elapsed) });
1004
- }
1005
- function LinePreview({ value, kind }) {
1006
- if (!value) return null;
1007
- return /* @__PURE__ */ jsx4("ol", { className: "scui-code-preview", "data-kind": kind, children: stripAnsi(value).split("\n").map((line, index) => {
1008
- const tone = kind === "diff" ? line.startsWith("+") && !line.startsWith("+++") ? "add" : line.startsWith("-") && !line.startsWith("---") ? "remove" : line.startsWith("@@") ? "hunk" : "plain" : "plain";
1009
- return /* @__PURE__ */ jsxs3("li", { "data-tone": tone, children: [
1010
- /* @__PURE__ */ jsx4("span", { children: index + 1 }),
1011
- /* @__PURE__ */ jsx4("code", { children: line || " " })
1012
- ] }, index);
1013
- }) });
1014
- }
1015
- function TerminalPreview({ presentation, pending, failed }) {
1016
- return /* @__PURE__ */ jsxs3("section", { className: "scui-terminal", children: [
1017
- /* @__PURE__ */ jsxs3("header", { children: [
1018
- /* @__PURE__ */ jsxs3("span", { "aria-hidden": "true", children: [
1019
- /* @__PURE__ */ jsx4("i", {}),
1020
- /* @__PURE__ */ jsx4("i", {}),
1021
- /* @__PURE__ */ jsx4("i", {})
1022
- ] }),
1023
- /* @__PURE__ */ jsx4("code", { children: presentation.command ? `$ ${presentation.command}` : "Terminal" })
1024
- ] }),
1025
- presentation.preview ? /* @__PURE__ */ jsx4("pre", { "data-error": failed, children: stripAnsi(presentation.preview) }) : pending ? /* @__PURE__ */ jsxs3("div", { className: "scui-terminal-wait", children: [
1026
- /* @__PURE__ */ jsx4("i", {}),
1027
- " Waiting for output"
1028
- ] }) : /* @__PURE__ */ jsx4("div", { className: "scui-terminal-empty", children: "No output" })
1029
- ] });
1030
- }
1031
- function SearchPreview({ presentation }) {
1032
- const lines = stripAnsi(presentation.preview).split("\n").filter(Boolean);
1033
- return /* @__PURE__ */ jsxs3("section", { className: "scui-search-preview", children: [
1034
- presentation.query ? /* @__PURE__ */ jsxs3("header", { children: [
1035
- /* @__PURE__ */ jsx4("span", { children: "Search" }),
1036
- /* @__PURE__ */ jsx4("code", { children: presentation.query })
1037
- ] }) : null,
1038
- lines.length ? /* @__PURE__ */ jsx4("ol", { children: lines.map((line, index) => {
1039
- const match = /^(.*?):(\d+)(?::(\d+))?:(.*)$/.exec(line);
1040
- return /* @__PURE__ */ jsx4("li", { children: match ? /* @__PURE__ */ jsxs3(Fragment4, { children: [
1041
- /* @__PURE__ */ jsx4("code", { children: match[1] }),
1042
- /* @__PURE__ */ jsxs3("small", { children: [
1043
- match[2],
1044
- match[3] ? `:${match[3]}` : ""
1045
- ] }),
1046
- /* @__PURE__ */ jsx4("span", { children: match[4] })
1047
- ] }) : /* @__PURE__ */ jsx4("span", { children: line }) }, index);
1048
- }) }) : /* @__PURE__ */ jsx4("p", { children: "No textual results" })
1049
- ] });
1050
- }
1051
- function ToolPreview({ presentation, entry }) {
1052
- const pending = entry.status === "pending";
1053
- const failed = entry.status === "error";
1054
- if (presentation.detail === "terminal") return /* @__PURE__ */ jsx4(TerminalPreview, { presentation, pending, failed });
1055
- if (presentation.detail === "diff") return presentation.preview ? /* @__PURE__ */ jsx4(LinePreview, { value: presentation.preview, kind: "diff" }) : /* @__PURE__ */ jsx4("div", { className: "scui-tool-empty", children: "Edit completed without a textual diff" });
1056
- if (presentation.detail === "file") return presentation.preview ? /* @__PURE__ */ jsx4(LinePreview, { value: presentation.preview, kind: "file" }) : /* @__PURE__ */ jsx4("div", { className: "scui-tool-empty", children: "File contents were not included in this event" });
1057
- if (presentation.detail === "matches") return /* @__PURE__ */ jsx4(SearchPreview, { presentation });
1058
- if (presentation.detail === "web") return /* @__PURE__ */ jsxs3("section", { className: "scui-web-preview", children: [
1059
- presentation.url ? /* @__PURE__ */ jsx4("code", { children: presentation.url }) : null,
1060
- presentation.preview ? /* @__PURE__ */ jsx4("p", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx4("small", { children: pending ? "Waiting for the page" : "No page summary returned" })
1061
- ] });
1062
- if (presentation.detail === "agent") return /* @__PURE__ */ jsx4("section", { className: "scui-agent-preview", children: presentation.items?.length ? /* @__PURE__ */ jsx4("ol", { className: "scui-agent-roster", children: presentation.items.map((item, index) => /* @__PURE__ */ jsxs3("li", { children: [
1063
- /* @__PURE__ */ jsx4("strong", { children: item.label }),
1064
- /* @__PURE__ */ jsx4("small", { children: item.status })
1065
- ] }, `${item.label}:${index}`)) }) : presentation.preview ? /* @__PURE__ */ jsx4("pre", { children: stripAnsi(presentation.preview) }) : /* @__PURE__ */ jsx4("small", { children: pending ? "Agent is working" : "No textual handoff returned" }) });
1066
- if (presentation.detail === "plan") return /* @__PURE__ */ jsx4("ol", { className: "scui-plan-preview", children: presentation.items?.map((item, index) => /* @__PURE__ */ jsxs3("li", { "data-status": item.status, children: [
1067
- /* @__PURE__ */ jsx4("i", { "aria-hidden": "true" }),
1068
- /* @__PURE__ */ jsx4("span", { children: item.label })
1069
- ] }, `${item.label}:${index}`)) });
1070
- return presentation.preview ? /* @__PURE__ */ jsx4("pre", { className: "scui-tool-output", "data-error": failed, children: stripAnsi(presentation.preview) }) : null;
1071
- }
1072
- function ToolActions({ presentation, adapter }) {
1073
- const [copied, setCopied] = useState2(false);
1074
- const reset = useRef3(null);
1075
- useEffect3(() => () => clearTimeout(reset.current), []);
1076
- if (!adapter?.copyText) return null;
1077
- 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;
1078
- const copy = async () => {
1079
- await adapter.copyText(action[1]);
1080
- setCopied(true);
1081
- clearTimeout(reset.current);
1082
- reset.current = setTimeout(() => setCopied(false), 1500);
1083
- };
1084
- return action ? /* @__PURE__ */ jsx4("div", { className: "scui-tool-actions", children: /* @__PURE__ */ jsx4("button", { type: "button", onClick: copy, children: copied ? "Copied" : action[0] }) }) : null;
1085
- }
1086
- function ToolStack({ tools }) {
1087
- if (tools.length < 2) return null;
1088
- return /* @__PURE__ */ jsx4("div", { className: "scui-tool-stack", "aria-label": "Coordinated tools", children: tools.map((tool) => /* @__PURE__ */ jsx4("span", { children: tool.replaceAll("__", " \xB7 ").replaceAll("_", " ") }, tool)) });
1089
- }
1090
- function TechnicalDetails({ entry }) {
1091
- if (!entry.arguments && !entry.resultText) return null;
1092
- return /* @__PURE__ */ jsxs3("details", { className: "scui-tool-technical", children: [
1093
- /* @__PURE__ */ jsx4("summary", { children: "Technical details" }),
1094
- /* @__PURE__ */ jsxs3("div", { children: [
1095
- entry.arguments ? /* @__PURE__ */ jsxs3("section", { children: [
1096
- /* @__PURE__ */ jsx4("strong", { children: "Native arguments" }),
1097
- /* @__PURE__ */ jsx4("dl", { children: argumentRows(entry.arguments).map((row) => /* @__PURE__ */ jsxs3("div", { children: [
1098
- /* @__PURE__ */ jsx4("dt", { children: row.label }),
1099
- /* @__PURE__ */ jsx4("dd", { children: /* @__PURE__ */ jsx4("pre", { children: row.value }) })
1100
- ] }, row.key)) })
1101
- ] }) : null,
1102
- entry.resultText ? /* @__PURE__ */ jsxs3("section", { children: [
1103
- /* @__PURE__ */ jsx4("strong", { children: "Native result" }),
1104
- /* @__PURE__ */ jsxs3("pre", { "data-error": entry.status === "error", children: [
1105
- entry.resultText,
1106
- entry.truncated ? "\n[truncated]" : ""
1107
- ] })
1108
- ] }) : null
1109
- ] })
1110
- ] });
1111
- }
1112
- function TranscriptEntry({ entry, state, adapter }) {
1113
- if (entry.role === "opaque") {
1114
- return /* @__PURE__ */ jsxs3("article", { className: "scui-message scui-opaque", "data-role": "opaque", "data-kind": entry.kind, "aria-label": "Unrecognized entry", children: [
1115
- /* @__PURE__ */ jsxs3("div", { className: "scui-notice", "data-code": "opaque-entry", children: [
1116
- "Unrecognized entry kind ",
1117
- /* @__PURE__ */ jsx4("code", { children: entry.kind }),
1118
- " \u2014 kept as-is, nothing dropped"
1119
- ] }),
1120
- entry.text ? /* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText }) : null,
1121
- entry.raw ? /* @__PURE__ */ jsxs3("details", { className: "scui-tool-technical", children: [
1122
- /* @__PURE__ */ jsx4("summary", { children: "Technical details" }),
1123
- /* @__PURE__ */ jsx4("div", { children: /* @__PURE__ */ jsxs3("section", { children: [
1124
- /* @__PURE__ */ jsx4("strong", { children: "Raw entry" }),
1125
- /* @__PURE__ */ jsxs3("pre", { children: [
1126
- entry.raw,
1127
- entry.truncated ? "\n[truncated]" : ""
1128
- ] })
1129
- ] }) })
1130
- ] }) : null
1131
- ] });
1132
- }
1133
- if (entry.role === "request") return /* @__PURE__ */ jsx4(RequestCard, { entry, adapter, canRespond: state.canRespond });
1134
- if (entry.role === "reasoning") {
1135
- return /* @__PURE__ */ jsxs3("details", { className: "scui-reasoning", open: entry.streaming, children: [
1136
- /* @__PURE__ */ jsx4("summary", { children: entry.streaming ? "Reasoning\u2026" : "Reasoning" }),
1137
- /* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText })
1138
- ] });
1139
- }
1140
- if (entry.role === "notice" || entry.role === "system") return /* @__PURE__ */ jsx4("div", { className: "scui-notice", "data-code": entry.code, children: entry.text });
1141
- return /* @__PURE__ */ jsxs3("article", { className: "scui-message", "data-role": entry.role, "aria-label": `${entry.role === "user" ? "Your" : "Assistant"} message`, children: [
1142
- /* @__PURE__ */ jsx4(MessageImages, { items: entry.images, adapter }),
1143
- /* @__PURE__ */ jsx4(Markdown, { value: entry.text, copyText: adapter?.copyText }),
1144
- /* @__PURE__ */ jsx4(ContextDisclosure, { context: entry.context }),
1145
- entry.truncated ? /* @__PURE__ */ jsx4("small", { className: "scui-truncated", children: "Entry truncated by host \xB7 load native session for the complete value" }) : null,
1146
- /* @__PURE__ */ jsx4(MessageMeta, { entry, adapter })
1147
- ] });
1148
- }
1149
- function ToolRow({ entry, workspace, open = false, adapter }) {
1150
- const presentation = entry.presentation ?? createToolPresentation(entry);
1151
- const [expanded, setExpanded] = useState2(open || entry.status === "pending");
1152
- useEffect3(() => {
1153
- if (entry.status === "pending") setExpanded(true);
1154
- }, [entry.status]);
1155
- const target = compactToolTarget(presentation.target, workspace);
1156
- const hasDetail = Boolean(entry.arguments || entry.resultText || presentation.preview || presentation.fields.length);
1157
- const category = presentation.category ?? toolCategory(entry);
1158
- const summary = /* @__PURE__ */ jsxs3(Fragment4, { children: [
1159
- /* @__PURE__ */ jsx4(ToolIcon, { category }),
1160
- /* @__PURE__ */ jsx4("strong", { children: toolAction2(entry, category, presentation) }),
1161
- target ? /* @__PURE__ */ jsx4("code", { className: "scui-tool-target", title: presentation.target, children: target }) : null,
1162
- /* @__PURE__ */ jsx4("span", { className: "scui-spacer" }),
1163
- entry.status === "pending" ? /* @__PURE__ */ jsx4(PendingElapsed, { now: adapter?.now }) : null,
1164
- /* @__PURE__ */ jsx4("span", { className: "scui-tool-status", role: "status", "data-status": entry.status ?? "completed", "aria-label": entry.status ?? "completed", children: entry.status === "pending" ? /* @__PURE__ */ jsx4("i", {}) : /* @__PURE__ */ jsx4(UiIcon, { name: entry.status === "error" ? "close" : "check", size: 12 }) }),
1165
- hasDetail ? /* @__PURE__ */ jsx4(UiIcon, { name: "chevron", size: 14, className: "scui-tool-chevron" }) : null
1166
- ] });
1167
- if (!hasDetail) return /* @__PURE__ */ jsx4("div", { className: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, children: /* @__PURE__ */ jsx4("div", { className: "scui-tool-head", children: summary }) });
1168
- return /* @__PURE__ */ jsxs3("details", { className: "scui-tool", "data-status": entry.status ?? "completed", "data-category": category, open: expanded, onToggle: (event) => setExpanded(event.currentTarget.open), children: [
1169
- /* @__PURE__ */ jsx4("summary", { className: "scui-tool-head", children: summary }),
1170
- /* @__PURE__ */ jsxs3("div", { className: "scui-tool-detail", children: [
1171
- /* @__PURE__ */ jsx4(ToolMetrics, { presentation }),
1172
- /* @__PURE__ */ jsx4(ToolStack, { tools: presentation.tools ?? [] }),
1173
- /* @__PURE__ */ jsx4(ToolPreview, { presentation, entry }),
1174
- presentation.fields.length ? /* @__PURE__ */ jsx4("dl", { className: "scui-tool-fields", children: presentation.fields.map((field) => /* @__PURE__ */ jsxs3("div", { children: [
1175
- /* @__PURE__ */ jsx4("dt", { children: field.label }),
1176
- /* @__PURE__ */ jsx4("dd", { children: field.value })
1177
- ] }, field.label)) }) : null,
1178
- /* @__PURE__ */ jsx4(ToolActions, { presentation, adapter }),
1179
- /* @__PURE__ */ jsx4(TechnicalDetails, { entry })
1180
- ] })
1181
- ] });
1182
- }
1183
- function ActivityGroup({ entries, state, adapter }) {
1184
- const active = entries.some((entry) => entry.status === "pending");
1185
- const [open, setOpen] = useState2(active);
1186
- const id = useId();
1187
- useEffect3(() => {
1188
- if (active) setOpen(true);
1189
- }, [active]);
1190
- if (entries.length === 1) return /* @__PURE__ */ jsx4("section", { className: "scui-activity", "data-single": "true", children: /* @__PURE__ */ jsx4(ToolRow, { entry: entries[0], workspace: state.workspace, adapter }) });
1191
- return /* @__PURE__ */ jsxs3("section", { className: "scui-activity", children: [
1192
- /* @__PURE__ */ jsxs3("button", { className: "scui-activity-head", type: "button", "aria-expanded": open, "aria-controls": id, onClick: () => setOpen((value) => !value), children: [
1193
- /* @__PURE__ */ jsx4("span", { className: "scui-fold", "data-open": open, children: /* @__PURE__ */ jsx4(UiIcon, { name: "chevron", size: 14 }) }),
1194
- /* @__PURE__ */ jsx4("strong", { children: activitySummary(entries) }),
1195
- /* @__PURE__ */ jsx4("span", { className: "scui-spacer" }),
1196
- /* @__PURE__ */ jsxs3("small", { children: [
1197
- entries.filter((entry) => entry.status !== "pending").length,
1198
- "/",
1199
- entries.length
1200
- ] })
1201
- ] }),
1202
- open ? /* @__PURE__ */ jsx4("div", { id, children: entries.map((entry) => /* @__PURE__ */ jsx4(ToolRow, { entry, workspace: state.workspace, adapter }, entry.id)) }) : null
1203
- ] });
1204
- }
1205
- function TaskPlan({ plan }) {
1206
- if (!plan.items.length) return null;
1207
- const complete = plan.items.filter((item) => item.status === "completed" || item.status === "cancelled").length;
1208
- return /* @__PURE__ */ jsxs3("details", { className: "scui-plan", children: [
1209
- /* @__PURE__ */ jsxs3("summary", { children: [
1210
- /* @__PURE__ */ jsx4("span", { children: "Plan" }),
1211
- /* @__PURE__ */ jsxs3("small", { children: [
1212
- complete,
1213
- "/",
1214
- plan.items.length
1215
- ] })
1216
- ] }),
1217
- /* @__PURE__ */ jsx4("ol", { tabIndex: 0, "aria-label": "Task plan steps", children: plan.items.map((item) => /* @__PURE__ */ jsxs3("li", { "data-status": item.status, children: [
1218
- /* @__PURE__ */ jsx4("i", { "aria-hidden": "true" }),
1219
- " ",
1220
- /* @__PURE__ */ jsx4("span", { children: item.title })
1221
- ] }, item.id)) })
1222
- ] });
1223
- }
1224
- function SessionDetails({ semantics }) {
1225
- if (!semantics.fidelity && !semantics.residueCount && !semantics.parseErrors && !semantics.subagents.length) return null;
1226
- return /* @__PURE__ */ jsxs3("details", { className: "scui-details", children: [
1227
- /* @__PURE__ */ jsx4("summary", { children: "Session details" }),
1228
- /* @__PURE__ */ jsxs3("div", { children: [
1229
- semantics.fidelity ? /* @__PURE__ */ jsxs3("p", { children: [
1230
- /* @__PURE__ */ jsx4("strong", { children: "Fidelity" }),
1231
- /* @__PURE__ */ jsx4("span", { children: semantics.fidelity.replaceAll("_", " ") })
1232
- ] }) : null,
1233
- /* @__PURE__ */ jsxs3("p", { children: [
1234
- /* @__PURE__ */ jsx4("strong", { children: "Native records" }),
1235
- /* @__PURE__ */ jsx4("span", { children: semantics.rawRecords })
1236
- ] }),
1237
- semantics.residueCount ? /* @__PURE__ */ jsxs3("p", { children: [
1238
- /* @__PURE__ */ jsx4("strong", { children: "Residue" }),
1239
- /* @__PURE__ */ jsxs3("span", { children: [
1240
- semantics.residueCount,
1241
- " retained"
1242
- ] })
1243
- ] }) : null,
1244
- semantics.parseErrors ? /* @__PURE__ */ jsxs3("p", { children: [
1245
- /* @__PURE__ */ jsx4("strong", { children: "Parse diagnostics" }),
1246
- /* @__PURE__ */ jsx4("span", { children: semantics.parseErrors })
1247
- ] }) : null,
1248
- semantics.subagents.map((agent) => /* @__PURE__ */ jsxs3("p", { children: [
1249
- /* @__PURE__ */ jsxs3("strong", { children: [
1250
- agent.source,
1251
- " subagent"
1252
- ] }),
1253
- /* @__PURE__ */ jsxs3("span", { children: [
1254
- agent.messages,
1255
- " messages \xB7 ",
1256
- agent.fidelity.replaceAll("_", " ")
1257
- ] })
1258
- ] }, agent.id))
1259
- ] })
1260
- ] });
1261
- }
1262
- var conversationMemory = uiMemory();
1263
- function ConversationAnnouncements({ state }) {
1264
- const previousBusy = useRef3(state.busy);
1265
- const [announcement, setAnnouncement] = useState2("");
1266
- useEffect3(() => {
1267
- if (previousBusy.current && !state.busy && !state.error) {
1268
- setAnnouncement(`${harnessDisplayName(state.harness) || "Coding agent"} finished working`);
1269
- }
1270
- previousBusy.current = state.busy;
1271
- }, [state.busy, state.error, state.harness]);
1272
- return /* @__PURE__ */ jsx4("span", { className: "scui-sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true", children: announcement });
1273
- }
1274
- function Conversation({ state, adapter, components = {}, slots = {}, memoryKey = state.attached?.key || `${state.harness}:${state.workspace}`, pending = null, unreadAfterMessages = null }) {
1275
- const scroller = useRef3(null);
1276
- const remembered = conversationMemory.get(memoryKey) ?? { top: null, atBottom: true };
1277
- const [atBottom, setAtBottom] = useState2(remembered.atBottom);
1278
- const earlierAnchor = useRef3(null);
1279
- const restored = useRef3(false);
1280
- const blocks = groupConversation(state.transcript);
1281
- const unreadBoundary = useRef3(Number.isSafeInteger(unreadAfterMessages) && unreadAfterMessages >= 0 ? unreadAfterMessages : null);
1282
- const unreadBlock = unreadBoundary.current === null ? -1 : blocks.findIndex((block) => {
1283
- const entries = block.kind === "activity" ? block.entries : [block.entry];
1284
- return entries.some((entry) => Number.isSafeInteger(entry.messageIndex) && entry.messageIndex > unreadBoundary.current);
1285
- });
1286
- const Entry = components.TranscriptEntry ?? TranscriptEntry;
1287
- const Group = components.ActivityGroup ?? ActivityGroup;
1288
- const Plan = components.TaskPlan ?? TaskPlan;
1289
- const Before = slots.beforeConversation;
1290
- const After = slots.afterConversation;
1291
- const Empty = slots.emptyConversation;
1292
- const remember = (value) => boundedSet(conversationMemory, memoryKey, value);
1293
- const pendingMessage = typeof pending === "string" ? { text: pending, status: "sending" } : pending;
1294
- const pin = () => {
1295
- if (!scroller.current) return;
1296
- scroller.current.scrollTop = scroller.current.scrollHeight;
1297
- setAtBottom(true);
1298
- remember({ top: scroller.current.scrollTop, atBottom: true });
1299
- };
1300
- useLayoutEffect(() => {
1301
- const element = scroller.current;
1302
- if (!element) return;
1303
- const anchor = earlierAnchor.current;
1304
- if (anchor) {
1305
- if (state.operation === "loadEarlier") anchor.seenOperation = true;
1306
- const prepended = state.transcript.length > anchor.entries && state.transcript[0]?.id !== anchor.firstId;
1307
- if (prepended) {
1308
- element.scrollTop = anchor.top + (element.scrollHeight - anchor.height);
1309
- earlierAnchor.current = null;
1310
- remember({ top: element.scrollTop, atBottom: false });
1311
- return;
1312
- }
1313
- if (state.error || anchor.seenOperation && state.operation !== "loadEarlier") earlierAnchor.current = null;
1314
- }
1315
- if (!restored.current) {
1316
- restored.current = true;
1317
- if (remembered.top !== null && !remembered.atBottom) element.scrollTop = remembered.top;
1318
- else pin();
1319
- } else if (atBottom) pin();
1320
- }, [memoryKey, state.transcript, state.busy, state.operation, state.error, pendingMessage?.text, pendingMessage?.status]);
1321
- return /* @__PURE__ */ jsxs3("div", { className: "scui-conversation-wrap", children: [
1322
- /* @__PURE__ */ jsx4(ConversationAnnouncements, { state }),
1323
- /* @__PURE__ */ jsx4("div", { className: "scui-conversation", ref: scroller, tabIndex: 0, "aria-label": "Conversation", onScroll: (event) => {
1324
- const element = event.currentTarget;
1325
- const bottom = element.scrollHeight - element.scrollTop - element.clientHeight <= 64;
1326
- setAtBottom(bottom);
1327
- remember({ top: element.scrollTop, atBottom: bottom });
1328
- }, children: /* @__PURE__ */ jsxs3("div", { children: [
1329
- Before ? /* @__PURE__ */ jsx4(Before, { state, adapter, value: null }) : null,
1330
- /* @__PURE__ */ jsx4(Plan, { plan: state.taskPlan, value: state.taskPlan, state, adapter }),
1331
- /* @__PURE__ */ jsx4(SessionDetails, { semantics: state.semantics }),
1332
- state.history.hasEarlier ? /* @__PURE__ */ jsx4("button", { className: "scui-load", type: "button", disabled: Boolean(state.operation), onClick: () => {
1333
- const element = scroller.current;
1334
- if (element) earlierAnchor.current = { height: element.scrollHeight, top: element.scrollTop, entries: state.transcript.length, firstId: state.transcript[0]?.id, seenOperation: false };
1335
- setAtBottom(false);
1336
- adapter.onIntent({ action: "loadEarlier" });
1337
- }, children: "Load earlier messages" }) : null,
1338
- !blocks.length && state.startup !== "ready" ? /* @__PURE__ */ jsx4(LoadingStatus, { state }) : null,
1339
- !blocks.length && state.startup === "ready" ? Empty ? /* @__PURE__ */ jsx4(Empty, { state, adapter, value: null }) : /* @__PURE__ */ jsx4("div", { className: "scui-empty", children: state.error ?? (state.harness ? `${harnessDisplayName(state.harness)} is listening. Say something.` : "No transcript yet.") }) : null,
1340
- blocks.map((block, index) => /* @__PURE__ */ jsxs3(Fragment3, { children: [
1341
- index === unreadBlock ? /* @__PURE__ */ jsx4("div", { className: "scui-unread-divider", role: "separator", "aria-label": "New messages", children: /* @__PURE__ */ jsx4("span", { children: "New" }) }) : null,
1342
- block.kind === "activity" ? /* @__PURE__ */ jsx4(Group, { value: block.entries, entries: block.entries, state, adapter }) : /* @__PURE__ */ jsx4(Entry, { value: block.entry, entry: block.entry, state, adapter })
1343
- ] }, block.id)),
1344
- pendingMessage ? /* @__PURE__ */ jsxs3("article", { className: "scui-message scui-pending", "data-role": "user", "data-status": pendingMessage.status, "aria-label": "Your pending message", children: [
1345
- /* @__PURE__ */ jsx4(MessageImages, { items: pendingMessage.images, adapter }),
1346
- /* @__PURE__ */ jsx4(Markdown, { value: pendingMessage.text, copyText: adapter?.copyText }),
1347
- /* @__PURE__ */ jsx4(ContextDisclosure, { context: pendingMessage.context }),
1348
- /* @__PURE__ */ jsxs3("footer", { children: [
1349
- /* @__PURE__ */ jsx4("small", { children: pendingMessage.status === "failed" ? "Not sent" : "Sending\u2026" }),
1350
- pendingMessage.status === "failed" ? /* @__PURE__ */ jsxs3("span", { children: [
1351
- /* @__PURE__ */ jsx4("button", { type: "button", onClick: pendingMessage.onRetry, children: "Retry" }),
1352
- /* @__PURE__ */ jsx4("button", { type: "button", onClick: pendingMessage.onEdit, children: "Edit" })
1353
- ] }) : null
1354
- ] })
1355
- ] }) : null,
1356
- state.busy ? /* @__PURE__ */ jsxs3("div", { className: "scui-working", role: "status", children: [
1357
- /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "\u2726" }),
1358
- /* @__PURE__ */ jsx4("i", {}),
1359
- /* @__PURE__ */ jsx4("i", {}),
1360
- /* @__PURE__ */ jsx4("i", {}),
1361
- /* @__PURE__ */ jsxs3("small", { children: [
1362
- harnessDisplayName(state.harness),
1363
- " is working"
1364
- ] })
1365
- ] }) : null,
1366
- After ? /* @__PURE__ */ jsx4(After, { state, adapter, value: null }) : null
1367
- ] }) }),
1368
- !atBottom ? /* @__PURE__ */ jsxs3("button", { className: "scui-latest", type: "button", onClick: pin, children: [
1369
- /* @__PURE__ */ jsx4(UiIcon, { name: "down", size: 13 }),
1370
- " Latest"
1371
- ] }) : null
1372
- ] });
1373
- }
1
+ import {
2
+ ActivityGroup,
3
+ Conversation,
4
+ LoadingStatus,
5
+ RequestCard,
6
+ SessionDetails,
7
+ TaskPlan,
8
+ ToolRow,
9
+ TranscriptEntry
10
+ } from "./chunks/chunk-UKMTRNJN.mjs";
11
+ import {
12
+ ImageViewer,
13
+ MessageImages
14
+ } from "./chunks/chunk-UKHDCPME.mjs";
15
+ import "./chunks/chunk-LS6JBXNT.mjs";
16
+ import "./chunks/chunk-OINC7LV7.mjs";
1374
17
  export {
1375
18
  ActivityGroup,
1376
19
  Conversation,