@aphrody/m3-ai 3.3.0
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/LICENSE.spaceui +21 -0
- package/README.md +98 -0
- package/dist/ChatComposer.d.ts +45 -0
- package/dist/ChatComposer.d.ts.map +1 -0
- package/dist/InlineBranchCard.d.ts +13 -0
- package/dist/InlineBranchCard.d.ts.map +1 -0
- package/dist/InlineWorkerCard.d.ts +19 -0
- package/dist/InlineWorkerCard.d.ts.map +1 -0
- package/dist/Markdown.d.ts +16 -0
- package/dist/Markdown.d.ts.map +1 -0
- package/dist/MessageBubble.d.ts +13 -0
- package/dist/MessageBubble.d.ts.map +1 -0
- package/dist/ModelSelector.d.ts +43 -0
- package/dist/ModelSelector.d.ts.map +1 -0
- package/dist/TaskCreateForm.d.ts +19 -0
- package/dist/TaskCreateForm.d.ts.map +1 -0
- package/dist/TaskDetail.d.ts +17 -0
- package/dist/TaskDetail.d.ts.map +1 -0
- package/dist/TaskList.d.ts +19 -0
- package/dist/TaskList.d.ts.map +1 -0
- package/dist/TaskPriorityIcon.d.ts +10 -0
- package/dist/TaskPriorityIcon.d.ts.map +1 -0
- package/dist/TaskRow.d.ts +21 -0
- package/dist/TaskRow.d.ts.map +1 -0
- package/dist/TaskStatusIcon.d.ts +10 -0
- package/dist/TaskStatusIcon.d.ts.map +1 -0
- package/dist/ToolCall.d.ts +13 -0
- package/dist/ToolCall.d.ts.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2227 -0
- package/dist/index.js.map +1 -0
- package/dist/internal.d.ts +44 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +66 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2227 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { forwardRef, useState, useMemo, useRef, useEffect, useId, useCallback } from 'react';
|
|
3
|
+
import { clsx } from 'clsx';
|
|
4
|
+
import { AnimatePresence, motion } from 'motion/react';
|
|
5
|
+
import { usePopover, Popover, SelectPill, Icon, CircleButton, Button, DropdownMenu, Collapsible, CollapsibleTrigger, CollapsibleContent, Select, SelectOption, Input, TextArea } from '@aphrody/m3-primitives';
|
|
6
|
+
import { m3Easings, m3Durations } from '@aphrody/m3-motion';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
import ReactMarkdown from 'react-markdown';
|
|
9
|
+
import remarkGfm from 'remark-gfm';
|
|
10
|
+
import rehypeRaw from 'rehype-raw';
|
|
11
|
+
|
|
12
|
+
// src/types.ts
|
|
13
|
+
var TASK_STATUS_ORDER = [
|
|
14
|
+
"in_progress",
|
|
15
|
+
"ready",
|
|
16
|
+
"pending_approval",
|
|
17
|
+
"backlog",
|
|
18
|
+
"done"
|
|
19
|
+
];
|
|
20
|
+
var TASK_STATUS_LABEL = {
|
|
21
|
+
in_progress: "In Progress",
|
|
22
|
+
ready: "Ready",
|
|
23
|
+
pending_approval: "Pending Approval",
|
|
24
|
+
backlog: "Backlog",
|
|
25
|
+
done: "Done"
|
|
26
|
+
};
|
|
27
|
+
var TASK_PRIORITY_LABEL = {
|
|
28
|
+
critical: "Critical",
|
|
29
|
+
high: "High",
|
|
30
|
+
medium: "Medium",
|
|
31
|
+
low: "Low"
|
|
32
|
+
};
|
|
33
|
+
function tryParseJson(text) {
|
|
34
|
+
if (!text || text.trim().length === 0) return null;
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(text);
|
|
37
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
38
|
+
return parsed;
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function isErrorResult(text, parsed) {
|
|
46
|
+
if (parsed?.error) return true;
|
|
47
|
+
if (parsed?.status === "error") return true;
|
|
48
|
+
if (parsed?.success === false) return true;
|
|
49
|
+
if (typeof parsed?.exit_code === "number" && parsed.exit_code !== 0) return true;
|
|
50
|
+
const lower = text.toLowerCase();
|
|
51
|
+
return lower.startsWith("error:") || lower.startsWith("error -") || lower.startsWith("failed:") || lower.startsWith("toolset error:");
|
|
52
|
+
}
|
|
53
|
+
function pairTranscriptSteps(steps) {
|
|
54
|
+
const items = [];
|
|
55
|
+
const resultsById = /* @__PURE__ */ new Map();
|
|
56
|
+
for (const step of steps) {
|
|
57
|
+
if (step.type === "tool_result") {
|
|
58
|
+
resultsById.set(step.call_id, { name: step.name, text: step.text });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const step of steps) {
|
|
62
|
+
if (step.type === "action") {
|
|
63
|
+
for (const content of step.content) {
|
|
64
|
+
if (content.type === "text") {
|
|
65
|
+
items.push({ kind: "text", text: content.text });
|
|
66
|
+
} else if (content.type === "tool_call") {
|
|
67
|
+
const result = resultsById.get(content.id);
|
|
68
|
+
const parsedArgs = tryParseJson(content.args);
|
|
69
|
+
const parsedResult = result ? tryParseJson(result.text) : null;
|
|
70
|
+
const hasError = result ? isErrorResult(result.text, parsedResult) : false;
|
|
71
|
+
items.push({
|
|
72
|
+
kind: "tool",
|
|
73
|
+
pair: {
|
|
74
|
+
id: content.id,
|
|
75
|
+
name: content.name,
|
|
76
|
+
argsRaw: content.args,
|
|
77
|
+
args: parsedArgs,
|
|
78
|
+
resultRaw: result?.text ?? null,
|
|
79
|
+
result: parsedResult,
|
|
80
|
+
status: result ? hasError ? "error" : "completed" : "running"
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return items;
|
|
88
|
+
}
|
|
89
|
+
var focusRing = "outline-none focus-visible:outline-3 focus-visible:outline-secondary focus-visible:outline-offset-2";
|
|
90
|
+
var expandMotion = {
|
|
91
|
+
initial: { height: 0, opacity: 0 },
|
|
92
|
+
animate: {
|
|
93
|
+
height: "auto",
|
|
94
|
+
opacity: 1,
|
|
95
|
+
transition: { duration: m3Durations.medium2, ease: m3Easings.emphasizedDecelerate }
|
|
96
|
+
},
|
|
97
|
+
exit: {
|
|
98
|
+
height: 0,
|
|
99
|
+
opacity: 0,
|
|
100
|
+
transition: { duration: m3Durations.short4, ease: m3Easings.emphasizedAccelerate }
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
function CircularIndicator({
|
|
104
|
+
size = 16,
|
|
105
|
+
className,
|
|
106
|
+
label = "Loading"
|
|
107
|
+
}) {
|
|
108
|
+
const stroke = size <= 16 ? 2 : size <= 24 ? 3 : 4;
|
|
109
|
+
const r = (size - stroke) / 2;
|
|
110
|
+
const c = 2 * Math.PI * r;
|
|
111
|
+
return /* @__PURE__ */ jsx(
|
|
112
|
+
"span",
|
|
113
|
+
{
|
|
114
|
+
role: "progressbar",
|
|
115
|
+
"aria-label": label,
|
|
116
|
+
className: clsx("m3-circular-indicator inline-flex shrink-0 text-primary", className),
|
|
117
|
+
style: { width: size, height: size },
|
|
118
|
+
children: /* @__PURE__ */ jsx(
|
|
119
|
+
"svg",
|
|
120
|
+
{
|
|
121
|
+
width: size,
|
|
122
|
+
height: size,
|
|
123
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
124
|
+
className: "animate-spin",
|
|
125
|
+
"aria-hidden": "true",
|
|
126
|
+
children: /* @__PURE__ */ jsx(
|
|
127
|
+
"circle",
|
|
128
|
+
{
|
|
129
|
+
cx: size / 2,
|
|
130
|
+
cy: size / 2,
|
|
131
|
+
r,
|
|
132
|
+
fill: "none",
|
|
133
|
+
stroke: "currentColor",
|
|
134
|
+
strokeWidth: stroke,
|
|
135
|
+
strokeLinecap: "round",
|
|
136
|
+
strokeDasharray: `${c * 0.7} ${c}`
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
var chipTones = {
|
|
145
|
+
primary: "bg-primary-container text-on-primary-container",
|
|
146
|
+
success: "bg-success-container text-on-success-container",
|
|
147
|
+
error: "bg-error-container text-on-error-container",
|
|
148
|
+
warning: "bg-warning-container text-on-warning-container",
|
|
149
|
+
neutral: "border border-outline-variant text-on-surface-variant"
|
|
150
|
+
};
|
|
151
|
+
function StatusChip({
|
|
152
|
+
tone,
|
|
153
|
+
icon,
|
|
154
|
+
children,
|
|
155
|
+
className
|
|
156
|
+
}) {
|
|
157
|
+
return /* @__PURE__ */ jsxs(
|
|
158
|
+
"span",
|
|
159
|
+
{
|
|
160
|
+
className: clsx(
|
|
161
|
+
"inline-flex h-6 shrink-0 items-center gap-1 rounded-small px-2 text-label-medium",
|
|
162
|
+
chipTones[tone],
|
|
163
|
+
className
|
|
164
|
+
),
|
|
165
|
+
children: [
|
|
166
|
+
icon,
|
|
167
|
+
children
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
var toolRenderers = {
|
|
173
|
+
browser_launch: {
|
|
174
|
+
summary(pair) {
|
|
175
|
+
const headless = pair.args?.headless;
|
|
176
|
+
return headless === false ? "Launch browser (visible)" : "Launch browser";
|
|
177
|
+
},
|
|
178
|
+
resultView(pair) {
|
|
179
|
+
if (!pair.resultRaw) return null;
|
|
180
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: "Browser session started" });
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
browser_navigate: {
|
|
184
|
+
summary(pair) {
|
|
185
|
+
const url = pair.args?.url;
|
|
186
|
+
return url ? truncate(String(url), 60) : null;
|
|
187
|
+
},
|
|
188
|
+
resultView(pair) {
|
|
189
|
+
if (!pair.result) return /* @__PURE__ */ jsx(ResultText, { text: pair.resultRaw });
|
|
190
|
+
const title = pair.result.title;
|
|
191
|
+
const url = pair.result.url;
|
|
192
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 px-3 py-2", children: [
|
|
193
|
+
title && /* @__PURE__ */ jsxs("p", { className: "text-body-small text-on-surface-variant", children: [
|
|
194
|
+
/* @__PURE__ */ jsx("span", { className: "text-outline", children: "Title: " }),
|
|
195
|
+
title
|
|
196
|
+
] }),
|
|
197
|
+
url && /* @__PURE__ */ jsx("p", { className: "font-code text-body-small text-outline", children: truncate(url, 80) })
|
|
198
|
+
] });
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
browser_snapshot: {
|
|
202
|
+
summary(pair) {
|
|
203
|
+
if (!pair.resultRaw) return "Taking snapshot...";
|
|
204
|
+
const matches = pair.resultRaw.match(/\[\d+\]/g);
|
|
205
|
+
const count = matches?.length ?? 0;
|
|
206
|
+
return count > 0 ? `${count} interactive element${count !== 1 ? "s" : ""}` : "Page snapshot";
|
|
207
|
+
},
|
|
208
|
+
resultView(pair) {
|
|
209
|
+
if (!pair.resultRaw) return null;
|
|
210
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 20 });
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
browser_click: {
|
|
214
|
+
summary(pair) {
|
|
215
|
+
const index = pair.args?.index;
|
|
216
|
+
return index !== void 0 ? `Click element [${index}]` : "Click";
|
|
217
|
+
},
|
|
218
|
+
resultView(pair) {
|
|
219
|
+
if (!pair.resultRaw) return null;
|
|
220
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: pair.resultRaw });
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
browser_type: {
|
|
224
|
+
summary(pair) {
|
|
225
|
+
const index = pair.args?.index;
|
|
226
|
+
const hasSecret = pair.args?.secret !== void 0;
|
|
227
|
+
const text = pair.args?.text;
|
|
228
|
+
if (hasSecret) {
|
|
229
|
+
return index !== void 0 ? `Type secret into [${index}]` : "Type secret";
|
|
230
|
+
}
|
|
231
|
+
if (text) {
|
|
232
|
+
const display = truncate(String(text), 30);
|
|
233
|
+
return index !== void 0 ? `Type "${display}" into [${index}]` : `Type "${display}"`;
|
|
234
|
+
}
|
|
235
|
+
return index !== void 0 ? `Type into [${index}]` : "Type";
|
|
236
|
+
},
|
|
237
|
+
resultView(pair) {
|
|
238
|
+
if (!pair.resultRaw) return null;
|
|
239
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: pair.resultRaw });
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
browser_press_key: {
|
|
243
|
+
summary(pair) {
|
|
244
|
+
const key = pair.args?.key;
|
|
245
|
+
return key ? `Press ${key}` : "Press key";
|
|
246
|
+
},
|
|
247
|
+
resultView(pair) {
|
|
248
|
+
if (!pair.resultRaw) return null;
|
|
249
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: pair.resultRaw });
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
browser_screenshot: {
|
|
253
|
+
summary() {
|
|
254
|
+
return "Capture screenshot";
|
|
255
|
+
},
|
|
256
|
+
resultView(pair) {
|
|
257
|
+
if (!pair.resultRaw) return null;
|
|
258
|
+
if (pair.result?.base64) {
|
|
259
|
+
const mimeType = pair.result.mime_type ?? "image/png";
|
|
260
|
+
return /* @__PURE__ */ jsx("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx(
|
|
261
|
+
"img",
|
|
262
|
+
{
|
|
263
|
+
src: `data:${mimeType};base64,${pair.result.base64}`,
|
|
264
|
+
alt: "Browser screenshot",
|
|
265
|
+
className: "max-h-60 rounded-extra-small border border-outline-variant object-contain"
|
|
266
|
+
}
|
|
267
|
+
) });
|
|
268
|
+
}
|
|
269
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: truncate(pair.resultRaw, 100) });
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
browser_evaluate: {
|
|
273
|
+
summary(pair) {
|
|
274
|
+
const expression = pair.args?.expression;
|
|
275
|
+
return expression ? truncate(String(expression), 50) : "Evaluate JS";
|
|
276
|
+
},
|
|
277
|
+
argsView(pair) {
|
|
278
|
+
const expression = pair.args?.expression;
|
|
279
|
+
if (!expression) return null;
|
|
280
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: [
|
|
281
|
+
/* @__PURE__ */ jsx("p", { className: "mb-1 text-body-small font-medium text-outline", children: "JavaScript" }),
|
|
282
|
+
/* @__PURE__ */ jsx("pre", { className: "max-h-40 overflow-auto font-code text-body-small text-on-surface-variant", children: String(expression) })
|
|
283
|
+
] });
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
browser_tab_open: {
|
|
287
|
+
summary(pair) {
|
|
288
|
+
const url = pair.args?.url;
|
|
289
|
+
return url ? `Open tab: ${truncate(String(url), 50)}` : "Open new tab";
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
browser_tab_list: {
|
|
293
|
+
summary() {
|
|
294
|
+
return "List tabs";
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
browser_tab_close: {
|
|
298
|
+
summary(pair) {
|
|
299
|
+
const tabId = pair.args?.tab_id;
|
|
300
|
+
return tabId !== void 0 ? `Close tab ${tabId}` : "Close tab";
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
browser_close: {
|
|
304
|
+
summary() {
|
|
305
|
+
return "Close browser";
|
|
306
|
+
},
|
|
307
|
+
resultView(pair) {
|
|
308
|
+
if (!pair.resultRaw) return null;
|
|
309
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: "Browser session closed" });
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
shell: {
|
|
313
|
+
summary(pair) {
|
|
314
|
+
const command = pair.args?.command;
|
|
315
|
+
if (!command) return null;
|
|
316
|
+
if (pair.result && typeof pair.result.exit_code === "number") {
|
|
317
|
+
const code = pair.result.exit_code;
|
|
318
|
+
const cmdStr = truncate(String(command), 50);
|
|
319
|
+
return code === 0 ? cmdStr : `${cmdStr} (exit ${code})`;
|
|
320
|
+
}
|
|
321
|
+
return truncate(String(command), 60);
|
|
322
|
+
},
|
|
323
|
+
argsView(pair) {
|
|
324
|
+
const command = pair.args?.command;
|
|
325
|
+
if (!command) return null;
|
|
326
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: /* @__PURE__ */ jsxs("pre", { className: "max-h-40 overflow-auto font-code text-body-small text-on-surface-variant", children: [
|
|
327
|
+
/* @__PURE__ */ jsx("span", { className: "select-none text-outline", children: "$ " }),
|
|
328
|
+
String(command)
|
|
329
|
+
] }) });
|
|
330
|
+
},
|
|
331
|
+
resultView(pair) {
|
|
332
|
+
if (!pair.resultRaw) return null;
|
|
333
|
+
return /* @__PURE__ */ jsx(ShellResultView, { pair });
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
file_read: {
|
|
337
|
+
summary(pair) {
|
|
338
|
+
if (pair.title) return pair.title;
|
|
339
|
+
const path = pair.args?.path;
|
|
340
|
+
return path ? truncate(String(path), 60) : null;
|
|
341
|
+
},
|
|
342
|
+
argsView(pair) {
|
|
343
|
+
const path = pair.args?.path;
|
|
344
|
+
if (!path) return null;
|
|
345
|
+
const offset = pair.args?.offset;
|
|
346
|
+
const limit = pair.args?.limit;
|
|
347
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: /* @__PURE__ */ jsxs("p", { className: "font-code text-body-small text-on-surface-variant", children: [
|
|
348
|
+
String(path),
|
|
349
|
+
offset ? ` (from line ${offset})` : "",
|
|
350
|
+
limit ? ` (${limit} lines)` : ""
|
|
351
|
+
] }) });
|
|
352
|
+
},
|
|
353
|
+
resultView(pair) {
|
|
354
|
+
if (!pair.resultRaw) return null;
|
|
355
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 30 });
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
file_write: {
|
|
359
|
+
summary(pair) {
|
|
360
|
+
if (pair.title) return pair.title;
|
|
361
|
+
const path = pair.args?.path;
|
|
362
|
+
return path ? truncate(String(path), 60) : null;
|
|
363
|
+
},
|
|
364
|
+
argsView(pair) {
|
|
365
|
+
const path = pair.args?.path;
|
|
366
|
+
const content = pair.args?.content;
|
|
367
|
+
if (!path && !content) return null;
|
|
368
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: [
|
|
369
|
+
!!path && /* @__PURE__ */ jsx("p", { className: "mb-1 font-code text-body-small text-on-surface-variant", children: String(path) }),
|
|
370
|
+
!!content && /* @__PURE__ */ jsx("pre", { className: "max-h-40 overflow-auto font-code text-body-small text-outline", children: truncate(String(content), 2e3) })
|
|
371
|
+
] });
|
|
372
|
+
},
|
|
373
|
+
resultView(pair) {
|
|
374
|
+
if (!pair.resultRaw) return null;
|
|
375
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: truncate(pair.resultRaw, 100) });
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
file_edit: {
|
|
379
|
+
summary(pair) {
|
|
380
|
+
if (pair.title) return pair.title;
|
|
381
|
+
const path = pair.args?.path;
|
|
382
|
+
return path ? truncate(String(path), 60) : null;
|
|
383
|
+
},
|
|
384
|
+
argsView(pair) {
|
|
385
|
+
const path = pair.args?.path;
|
|
386
|
+
const oldStr = pair.args?.old_string;
|
|
387
|
+
const newStr = pair.args?.new_string;
|
|
388
|
+
if (!path) return null;
|
|
389
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: [
|
|
390
|
+
/* @__PURE__ */ jsx("p", { className: "mb-1 font-code text-body-small text-on-surface-variant", children: String(path) }),
|
|
391
|
+
!!oldStr && /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
392
|
+
/* @__PURE__ */ jsx("p", { className: "text-body-small font-medium text-error", children: "Old" }),
|
|
393
|
+
/* @__PURE__ */ jsx("pre", { className: "max-h-20 overflow-auto font-code text-body-small text-error", children: truncate(String(oldStr), 500) })
|
|
394
|
+
] }),
|
|
395
|
+
!!newStr && /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
396
|
+
/* @__PURE__ */ jsx("p", { className: "text-body-small font-medium text-success", children: "New" }),
|
|
397
|
+
/* @__PURE__ */ jsx("pre", { className: "max-h-20 overflow-auto font-code text-body-small text-success", children: truncate(String(newStr), 500) })
|
|
398
|
+
] })
|
|
399
|
+
] });
|
|
400
|
+
},
|
|
401
|
+
resultView(pair) {
|
|
402
|
+
if (!pair.resultRaw) return null;
|
|
403
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: truncate(pair.resultRaw, 100) });
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
file_list: {
|
|
407
|
+
summary(pair) {
|
|
408
|
+
if (pair.title) return pair.title;
|
|
409
|
+
const path = pair.args?.path;
|
|
410
|
+
return path ? truncate(String(path), 60) : null;
|
|
411
|
+
},
|
|
412
|
+
resultView(pair) {
|
|
413
|
+
if (!pair.resultRaw) return null;
|
|
414
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 30 });
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
exec: {
|
|
418
|
+
summary(pair) {
|
|
419
|
+
const program = pair.args?.program;
|
|
420
|
+
const cmdArgs = pair.args?.args;
|
|
421
|
+
if (!program) return null;
|
|
422
|
+
const parts = [String(program)];
|
|
423
|
+
if (Array.isArray(cmdArgs)) {
|
|
424
|
+
for (const arg of cmdArgs) parts.push(String(arg));
|
|
425
|
+
}
|
|
426
|
+
const full = parts.join(" ");
|
|
427
|
+
if (pair.result && typeof pair.result.exit_code === "number") {
|
|
428
|
+
const code = pair.result.exit_code;
|
|
429
|
+
const cmdStr = truncate(full, 50);
|
|
430
|
+
return code === 0 ? cmdStr : `${cmdStr} (exit ${code})`;
|
|
431
|
+
}
|
|
432
|
+
return truncate(full, 60);
|
|
433
|
+
},
|
|
434
|
+
argsView(pair) {
|
|
435
|
+
const program = pair.args?.program;
|
|
436
|
+
if (!program) return null;
|
|
437
|
+
const parts = [String(program)];
|
|
438
|
+
const cmdArgs = pair.args?.args;
|
|
439
|
+
if (Array.isArray(cmdArgs)) {
|
|
440
|
+
for (const arg of cmdArgs) parts.push(String(arg));
|
|
441
|
+
}
|
|
442
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: /* @__PURE__ */ jsxs("pre", { className: "max-h-40 overflow-auto font-code text-body-small text-on-surface-variant", children: [
|
|
443
|
+
/* @__PURE__ */ jsx("span", { className: "select-none text-outline", children: "$ " }),
|
|
444
|
+
parts.join(" ")
|
|
445
|
+
] }) });
|
|
446
|
+
},
|
|
447
|
+
resultView(pair) {
|
|
448
|
+
if (!pair.resultRaw) return null;
|
|
449
|
+
return /* @__PURE__ */ jsx(ShellResultView, { pair });
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
set_status: {
|
|
453
|
+
summary(pair) {
|
|
454
|
+
const kind = pair.args?.kind;
|
|
455
|
+
const message = pair.args?.message;
|
|
456
|
+
if (kind === "outcome") {
|
|
457
|
+
return message ? `Outcome: ${truncate(String(message), 50)}` : "Outcome set";
|
|
458
|
+
}
|
|
459
|
+
return message ? truncate(String(message), 60) : null;
|
|
460
|
+
},
|
|
461
|
+
resultView() {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
// OpenCode tools
|
|
466
|
+
read: {
|
|
467
|
+
summary(pair) {
|
|
468
|
+
if (pair.title) return pair.title;
|
|
469
|
+
const filePath = pair.args?.filePath ?? pair.args?.file_path;
|
|
470
|
+
return filePath ? truncate(String(filePath), 60) : null;
|
|
471
|
+
},
|
|
472
|
+
argsView(pair) {
|
|
473
|
+
const filePath = pair.args?.filePath ?? pair.args?.file_path;
|
|
474
|
+
if (!filePath) return null;
|
|
475
|
+
const offset = pair.args?.offset;
|
|
476
|
+
const limit = pair.args?.limit;
|
|
477
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: /* @__PURE__ */ jsxs("p", { className: "font-code text-body-small text-on-surface-variant", children: [
|
|
478
|
+
String(filePath),
|
|
479
|
+
offset ? ` (from line ${offset})` : "",
|
|
480
|
+
limit ? ` (${limit} lines)` : ""
|
|
481
|
+
] }) });
|
|
482
|
+
},
|
|
483
|
+
resultView(pair) {
|
|
484
|
+
if (!pair.resultRaw) return null;
|
|
485
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 30 });
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
write: {
|
|
489
|
+
summary(pair) {
|
|
490
|
+
if (pair.title) return pair.title;
|
|
491
|
+
const filePath = pair.args?.filePath ?? pair.args?.file_path;
|
|
492
|
+
return filePath ? truncate(String(filePath), 60) : null;
|
|
493
|
+
},
|
|
494
|
+
argsView(pair) {
|
|
495
|
+
const filePath = pair.args?.filePath ?? pair.args?.file_path;
|
|
496
|
+
const content = pair.args?.content;
|
|
497
|
+
if (!filePath && !content) return null;
|
|
498
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: [
|
|
499
|
+
!!filePath && /* @__PURE__ */ jsx("p", { className: "mb-1 font-code text-body-small text-on-surface-variant", children: String(filePath) }),
|
|
500
|
+
!!content && /* @__PURE__ */ jsx("pre", { className: "max-h-40 overflow-auto font-code text-body-small text-outline", children: truncate(String(content), 2e3) })
|
|
501
|
+
] });
|
|
502
|
+
},
|
|
503
|
+
resultView(pair) {
|
|
504
|
+
if (!pair.resultRaw) return null;
|
|
505
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: truncate(pair.resultRaw, 100) });
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
edit: {
|
|
509
|
+
summary(pair) {
|
|
510
|
+
if (pair.title) return pair.title;
|
|
511
|
+
const filePath = pair.args?.filePath ?? pair.args?.file_path;
|
|
512
|
+
return filePath ? truncate(String(filePath), 60) : null;
|
|
513
|
+
},
|
|
514
|
+
argsView(pair) {
|
|
515
|
+
const filePath = pair.args?.filePath ?? pair.args?.file_path;
|
|
516
|
+
const oldStr = pair.args?.oldString ?? pair.args?.old_string;
|
|
517
|
+
const newStr = pair.args?.newString ?? pair.args?.new_string;
|
|
518
|
+
if (!filePath) return null;
|
|
519
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: [
|
|
520
|
+
/* @__PURE__ */ jsx("p", { className: "mb-1 font-code text-body-small text-on-surface-variant", children: String(filePath) }),
|
|
521
|
+
!!oldStr && /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
522
|
+
/* @__PURE__ */ jsx("p", { className: "text-body-small font-medium text-error", children: "Old" }),
|
|
523
|
+
/* @__PURE__ */ jsx("pre", { className: "max-h-20 overflow-auto font-code text-body-small text-error", children: truncate(String(oldStr), 500) })
|
|
524
|
+
] }),
|
|
525
|
+
!!newStr && /* @__PURE__ */ jsxs("div", { className: "mt-1", children: [
|
|
526
|
+
/* @__PURE__ */ jsx("p", { className: "text-body-small font-medium text-success", children: "New" }),
|
|
527
|
+
/* @__PURE__ */ jsx("pre", { className: "max-h-20 overflow-auto font-code text-body-small text-success", children: truncate(String(newStr), 500) })
|
|
528
|
+
] })
|
|
529
|
+
] });
|
|
530
|
+
},
|
|
531
|
+
resultView(pair) {
|
|
532
|
+
if (!pair.resultRaw) return null;
|
|
533
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: truncate(pair.resultRaw, 100) });
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
bash: {
|
|
537
|
+
summary(pair) {
|
|
538
|
+
if (pair.title) return pair.title;
|
|
539
|
+
const command = pair.args?.command;
|
|
540
|
+
if (!command) return null;
|
|
541
|
+
if (pair.result && typeof pair.result.exit_code === "number") {
|
|
542
|
+
const code = pair.result.exit_code;
|
|
543
|
+
const cmdStr = truncate(String(command), 50);
|
|
544
|
+
return code === 0 ? cmdStr : `${cmdStr} (exit ${code})`;
|
|
545
|
+
}
|
|
546
|
+
return truncate(String(command), 60);
|
|
547
|
+
},
|
|
548
|
+
argsView(pair) {
|
|
549
|
+
const command = pair.args?.command;
|
|
550
|
+
if (!command) return null;
|
|
551
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: /* @__PURE__ */ jsxs("pre", { className: "max-h-40 overflow-auto font-code text-body-small text-on-surface-variant", children: [
|
|
552
|
+
/* @__PURE__ */ jsx("span", { className: "select-none text-outline", children: "$ " }),
|
|
553
|
+
String(command)
|
|
554
|
+
] }) });
|
|
555
|
+
},
|
|
556
|
+
resultView(pair) {
|
|
557
|
+
if (!pair.resultRaw) return null;
|
|
558
|
+
return /* @__PURE__ */ jsx(ShellResultView, { pair });
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
glob: {
|
|
562
|
+
summary(pair) {
|
|
563
|
+
if (pair.title) return pair.title;
|
|
564
|
+
const pattern = pair.args?.pattern;
|
|
565
|
+
return pattern ? truncate(String(pattern), 60) : null;
|
|
566
|
+
},
|
|
567
|
+
resultView(pair) {
|
|
568
|
+
if (!pair.resultRaw) return null;
|
|
569
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 20 });
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
grep: {
|
|
573
|
+
summary(pair) {
|
|
574
|
+
if (pair.title) return pair.title;
|
|
575
|
+
const pattern = pair.args?.pattern;
|
|
576
|
+
const include = pair.args?.include;
|
|
577
|
+
if (pattern && include) {
|
|
578
|
+
return `/${pattern}/ in ${include}`;
|
|
579
|
+
}
|
|
580
|
+
return pattern ? `/${truncate(String(pattern), 40)}/` : null;
|
|
581
|
+
},
|
|
582
|
+
resultView(pair) {
|
|
583
|
+
if (!pair.resultRaw) return null;
|
|
584
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 20 });
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
webfetch: {
|
|
588
|
+
summary(pair) {
|
|
589
|
+
if (pair.title) return pair.title;
|
|
590
|
+
const url = pair.args?.url;
|
|
591
|
+
return url ? truncate(String(url), 60) : null;
|
|
592
|
+
},
|
|
593
|
+
resultView(pair) {
|
|
594
|
+
if (!pair.resultRaw) return null;
|
|
595
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 20 });
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
read_skill: {
|
|
599
|
+
summary(pair) {
|
|
600
|
+
if (pair.title) return pair.title;
|
|
601
|
+
const name = pair.args?.name;
|
|
602
|
+
return name ? String(name) : null;
|
|
603
|
+
},
|
|
604
|
+
resultView(pair) {
|
|
605
|
+
if (!pair.resultRaw) return null;
|
|
606
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 30 });
|
|
607
|
+
}
|
|
608
|
+
},
|
|
609
|
+
web_search: {
|
|
610
|
+
summary(pair) {
|
|
611
|
+
if (pair.title) return pair.title;
|
|
612
|
+
const query = pair.args?.query;
|
|
613
|
+
const resultCount = pair.result?.result_count ?? (Array.isArray(pair.result?.results) ? pair.result.results.length : null);
|
|
614
|
+
const queryStr = query ? truncate(String(query), 50) : null;
|
|
615
|
+
if (queryStr && resultCount != null) {
|
|
616
|
+
return `${queryStr} (${resultCount} result${resultCount !== 1 ? "s" : ""})`;
|
|
617
|
+
}
|
|
618
|
+
return queryStr;
|
|
619
|
+
},
|
|
620
|
+
argsView(pair) {
|
|
621
|
+
const query = pair.args?.query;
|
|
622
|
+
if (!query) return null;
|
|
623
|
+
const count = pair.args?.count;
|
|
624
|
+
const freshness = pair.args?.freshness;
|
|
625
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: [
|
|
626
|
+
/* @__PURE__ */ jsxs("p", { className: "text-body-small text-on-surface-variant", children: [
|
|
627
|
+
/* @__PURE__ */ jsx("span", { className: "select-none text-outline", children: "Search: " }),
|
|
628
|
+
String(query)
|
|
629
|
+
] }),
|
|
630
|
+
!!(count || freshness) && /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-body-small text-outline", children: [
|
|
631
|
+
count ? `${count} results` : "",
|
|
632
|
+
count && freshness ? " \xB7 " : "",
|
|
633
|
+
freshness ? `${freshness}` : ""
|
|
634
|
+
] })
|
|
635
|
+
] });
|
|
636
|
+
},
|
|
637
|
+
resultView(pair) {
|
|
638
|
+
if (!pair.resultRaw) return null;
|
|
639
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 20 });
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
spacebot_docs: {
|
|
643
|
+
summary(pair) {
|
|
644
|
+
if (pair.title) return pair.title;
|
|
645
|
+
const action = pair.args?.action;
|
|
646
|
+
const docId = pair.args?.doc_id;
|
|
647
|
+
if (action === "read" && docId) {
|
|
648
|
+
return truncate(String(docId), 50);
|
|
649
|
+
}
|
|
650
|
+
return action ? String(action) : "list";
|
|
651
|
+
},
|
|
652
|
+
argsView(pair) {
|
|
653
|
+
const action = pair.args?.action;
|
|
654
|
+
const docId = pair.args?.doc_id;
|
|
655
|
+
const query = pair.args?.query;
|
|
656
|
+
if (!action && !docId) return null;
|
|
657
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: [
|
|
658
|
+
!!docId && /* @__PURE__ */ jsx("p", { className: "font-code text-body-small text-on-surface-variant", children: String(docId) }),
|
|
659
|
+
!!query && /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-body-small text-outline", children: [
|
|
660
|
+
"filter: ",
|
|
661
|
+
String(query)
|
|
662
|
+
] })
|
|
663
|
+
] });
|
|
664
|
+
},
|
|
665
|
+
resultView(pair) {
|
|
666
|
+
if (!pair.resultRaw) return null;
|
|
667
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 30 });
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
todowrite: {
|
|
671
|
+
summary(pair) {
|
|
672
|
+
if (pair.title) return pair.title;
|
|
673
|
+
return "Update tasks";
|
|
674
|
+
},
|
|
675
|
+
resultView() {
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
task: {
|
|
680
|
+
summary(pair) {
|
|
681
|
+
if (pair.title) return pair.title;
|
|
682
|
+
const description = pair.args?.description;
|
|
683
|
+
return description ? truncate(String(description), 60) : null;
|
|
684
|
+
},
|
|
685
|
+
resultView(pair) {
|
|
686
|
+
if (!pair.resultRaw) return null;
|
|
687
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 20 });
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
var defaultRenderer = {
|
|
692
|
+
summary(pair) {
|
|
693
|
+
if (!pair.argsRaw || pair.argsRaw === "{}") return null;
|
|
694
|
+
return truncate(pair.argsRaw, 60);
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
function getRenderer(name) {
|
|
698
|
+
return toolRenderers[name] ?? defaultRenderer;
|
|
699
|
+
}
|
|
700
|
+
function ResultLine({ text }) {
|
|
701
|
+
return /* @__PURE__ */ jsx("p", { className: "px-3 py-2 text-body-small text-on-surface-variant", children: text });
|
|
702
|
+
}
|
|
703
|
+
function ResultText({ text }) {
|
|
704
|
+
if (!text) return null;
|
|
705
|
+
return /* @__PURE__ */ jsx("pre", { className: "max-h-60 overflow-auto whitespace-pre-wrap px-3 py-2 font-code text-body-small text-on-surface-variant", children: text });
|
|
706
|
+
}
|
|
707
|
+
function CollapsiblePre({ text, maxLines = 20 }) {
|
|
708
|
+
const [expanded, setExpanded] = useState(false);
|
|
709
|
+
const lines = text.split("\n");
|
|
710
|
+
const needsCollapse = lines.length > maxLines;
|
|
711
|
+
const displayText = needsCollapse && !expanded ? lines.slice(0, maxLines).join("\n") + "\n..." : text;
|
|
712
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
713
|
+
/* @__PURE__ */ jsx("pre", { className: "max-h-80 overflow-auto whitespace-pre-wrap px-3 py-2 font-code text-body-small text-on-surface-variant", children: displayText }),
|
|
714
|
+
needsCollapse && /* @__PURE__ */ jsxs(
|
|
715
|
+
"button",
|
|
716
|
+
{
|
|
717
|
+
type: "button",
|
|
718
|
+
onClick: () => setExpanded(!expanded),
|
|
719
|
+
className: clsx(
|
|
720
|
+
"flex h-8 w-full items-center justify-center gap-1 border-t border-outline-variant px-3 text-label-medium text-primary",
|
|
721
|
+
"transition-colors duration-200 ease-standard hover:bg-primary/8 active:bg-primary/10",
|
|
722
|
+
focusRing
|
|
723
|
+
),
|
|
724
|
+
children: [
|
|
725
|
+
/* @__PURE__ */ jsx(
|
|
726
|
+
Icon,
|
|
727
|
+
{
|
|
728
|
+
name: "expand_more",
|
|
729
|
+
size: 18,
|
|
730
|
+
className: clsx(
|
|
731
|
+
"transition-transform duration-200 ease-standard",
|
|
732
|
+
expanded && "rotate-180"
|
|
733
|
+
)
|
|
734
|
+
}
|
|
735
|
+
),
|
|
736
|
+
expanded ? "Show less" : `Show all ${lines.length} lines`
|
|
737
|
+
]
|
|
738
|
+
}
|
|
739
|
+
)
|
|
740
|
+
] });
|
|
741
|
+
}
|
|
742
|
+
function ShellResultView({ pair }) {
|
|
743
|
+
const r = pair.result;
|
|
744
|
+
if (!r || typeof r.exit_code !== "number") {
|
|
745
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 30 });
|
|
746
|
+
}
|
|
747
|
+
const exitCode = r.exit_code;
|
|
748
|
+
const stdout = typeof r.stdout === "string" ? r.stdout : "";
|
|
749
|
+
const stderr = typeof r.stderr === "string" ? r.stderr : "";
|
|
750
|
+
const hasStdout = stdout.trim().length > 0;
|
|
751
|
+
const hasStderr = stderr.trim().length > 0;
|
|
752
|
+
const isError = exitCode !== 0;
|
|
753
|
+
if (!hasStdout && !hasStderr && exitCode === 0) {
|
|
754
|
+
return /* @__PURE__ */ jsx(ResultLine, { text: "Completed with no output" });
|
|
755
|
+
}
|
|
756
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
757
|
+
isError && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 border-b border-outline-variant px-3 py-1.5", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex h-6 items-center rounded-small bg-error px-2 font-code text-label-medium text-on-error", children: [
|
|
758
|
+
"exit ",
|
|
759
|
+
exitCode
|
|
760
|
+
] }) }),
|
|
761
|
+
hasStdout && /* @__PURE__ */ jsx("div", { className: hasStderr ? "border-b border-outline-variant" : "", children: /* @__PURE__ */ jsx(CollapsiblePre, { text: stdout.replace(/\n$/, ""), maxLines: 30 }) }),
|
|
762
|
+
hasStderr && /* @__PURE__ */ jsxs("div", { children: [
|
|
763
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5 px-3 pt-2 pb-0.5", children: /* @__PURE__ */ jsx("span", { className: clsx("text-label-medium", isError ? "text-error" : "text-warning"), children: "stderr" }) }),
|
|
764
|
+
/* @__PURE__ */ jsx(
|
|
765
|
+
"pre",
|
|
766
|
+
{
|
|
767
|
+
className: clsx(
|
|
768
|
+
"max-h-40 overflow-auto whitespace-pre-wrap px-3 pb-2 font-code text-body-small",
|
|
769
|
+
isError ? "text-error" : "text-warning"
|
|
770
|
+
),
|
|
771
|
+
children: stderr.replace(/\n$/, "")
|
|
772
|
+
}
|
|
773
|
+
)
|
|
774
|
+
] })
|
|
775
|
+
] });
|
|
776
|
+
}
|
|
777
|
+
var STATUS_ICONS = {
|
|
778
|
+
running: "pending",
|
|
779
|
+
completed: "check_circle",
|
|
780
|
+
error: "error"
|
|
781
|
+
};
|
|
782
|
+
var STATUS_COLORS = {
|
|
783
|
+
running: "text-primary",
|
|
784
|
+
completed: "text-success",
|
|
785
|
+
error: "text-error"
|
|
786
|
+
};
|
|
787
|
+
var STATUS_LABELS = {
|
|
788
|
+
running: "Running",
|
|
789
|
+
completed: "Completed",
|
|
790
|
+
error: "Error"
|
|
791
|
+
};
|
|
792
|
+
function toolIcon(name) {
|
|
793
|
+
if (name.startsWith("browser_")) return "language";
|
|
794
|
+
if (name.startsWith("file_") || name === "read" || name === "write" || name === "edit") {
|
|
795
|
+
return "description";
|
|
796
|
+
}
|
|
797
|
+
if (name === "shell" || name === "exec" || name === "bash") return "terminal";
|
|
798
|
+
if (name === "glob" || name === "grep" || name === "web_search") return "search";
|
|
799
|
+
if (name === "webfetch") return "language";
|
|
800
|
+
if (name === "set_status") return "schedule";
|
|
801
|
+
return "build";
|
|
802
|
+
}
|
|
803
|
+
function formatToolName(name) {
|
|
804
|
+
const overrides = {
|
|
805
|
+
webfetch: "Web Fetch",
|
|
806
|
+
todowrite: "Todo",
|
|
807
|
+
read_skill: "Read Skill",
|
|
808
|
+
web_search: "Web Search",
|
|
809
|
+
spacebot_docs: "Docs"
|
|
810
|
+
};
|
|
811
|
+
if (overrides[name]) return overrides[name];
|
|
812
|
+
const stripped = name.replace(/^browser_/, "").replace(/^file_/, "").replace(/^tab_/, "Tab ");
|
|
813
|
+
return stripped.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
814
|
+
}
|
|
815
|
+
function toolCategory(name) {
|
|
816
|
+
if (name.startsWith("browser_")) return "Browser";
|
|
817
|
+
if (name.startsWith("file_")) return "File";
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
function ToolCall({ pair, defaultExpanded = false, className }) {
|
|
821
|
+
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
822
|
+
const bodyId = useId();
|
|
823
|
+
const renderer = getRenderer(pair.name);
|
|
824
|
+
const summary = renderer.summary(pair);
|
|
825
|
+
const category = toolCategory(pair.name);
|
|
826
|
+
const displayName = formatToolName(pair.name);
|
|
827
|
+
const isError = pair.status === "error";
|
|
828
|
+
const args = expanded ? renderArgs(pair, renderer) : null;
|
|
829
|
+
const result = expanded ? renderResult(pair, renderer) : null;
|
|
830
|
+
return /* @__PURE__ */ jsxs(
|
|
831
|
+
"div",
|
|
832
|
+
{
|
|
833
|
+
"data-status": pair.status,
|
|
834
|
+
className: clsx(
|
|
835
|
+
"m3-tool-call min-w-0 overflow-hidden rounded-medium border bg-surface-container-low text-on-surface",
|
|
836
|
+
isError ? "border-error" : "border-outline-variant",
|
|
837
|
+
className
|
|
838
|
+
),
|
|
839
|
+
children: [
|
|
840
|
+
/* @__PURE__ */ jsxs(
|
|
841
|
+
"button",
|
|
842
|
+
{
|
|
843
|
+
type: "button",
|
|
844
|
+
onClick: () => setExpanded(!expanded),
|
|
845
|
+
"aria-expanded": expanded,
|
|
846
|
+
"aria-controls": bodyId,
|
|
847
|
+
className: clsx(
|
|
848
|
+
"flex min-h-10 w-full items-center gap-2 rounded-medium px-3 py-2 text-left",
|
|
849
|
+
"transition-colors duration-200 ease-standard hover:bg-on-surface/8 active:bg-on-surface/10",
|
|
850
|
+
focusRing
|
|
851
|
+
),
|
|
852
|
+
children: [
|
|
853
|
+
/* @__PURE__ */ jsx(
|
|
854
|
+
"span",
|
|
855
|
+
{
|
|
856
|
+
className: clsx(
|
|
857
|
+
"flex size-5 shrink-0 items-center justify-center",
|
|
858
|
+
STATUS_COLORS[pair.status]
|
|
859
|
+
),
|
|
860
|
+
children: pair.status === "running" ? /* @__PURE__ */ jsx(CircularIndicator, { size: 16, label: "Running" }) : /* @__PURE__ */ jsx(
|
|
861
|
+
Icon,
|
|
862
|
+
{
|
|
863
|
+
name: STATUS_ICONS[pair.status],
|
|
864
|
+
size: 18,
|
|
865
|
+
filled: true,
|
|
866
|
+
label: STATUS_LABELS[pair.status]
|
|
867
|
+
}
|
|
868
|
+
)
|
|
869
|
+
}
|
|
870
|
+
),
|
|
871
|
+
/* @__PURE__ */ jsx(Icon, { name: toolIcon(pair.name), size: 18, className: "shrink-0 text-on-surface-variant" }),
|
|
872
|
+
category && /* @__PURE__ */ jsx("span", { className: "text-label-medium text-outline", children: category }),
|
|
873
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-label-large text-on-surface", children: displayName }),
|
|
874
|
+
summary && !expanded ? /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-body-small text-on-surface-variant", children: summary }) : /* @__PURE__ */ jsx("span", { className: "flex-1" }),
|
|
875
|
+
isError && /* @__PURE__ */ jsx(StatusChip, { tone: "error", className: "h-5 px-1.5 text-label-small", children: "error" }),
|
|
876
|
+
/* @__PURE__ */ jsx(
|
|
877
|
+
Icon,
|
|
878
|
+
{
|
|
879
|
+
name: "expand_more",
|
|
880
|
+
size: 20,
|
|
881
|
+
className: clsx(
|
|
882
|
+
"shrink-0 text-on-surface-variant transition-transform duration-300 ease-emphasized",
|
|
883
|
+
expanded && "rotate-180"
|
|
884
|
+
)
|
|
885
|
+
}
|
|
886
|
+
)
|
|
887
|
+
]
|
|
888
|
+
}
|
|
889
|
+
),
|
|
890
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: expanded ? /* @__PURE__ */ jsx(motion.div, { id: bodyId, ...expandMotion, className: "overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-outline-variant px-3 py-3", children: [
|
|
891
|
+
args,
|
|
892
|
+
result != null && result !== false ? /* @__PURE__ */ jsx(
|
|
893
|
+
"div",
|
|
894
|
+
{
|
|
895
|
+
className: clsx(
|
|
896
|
+
"m3-tool-result overflow-hidden rounded-small",
|
|
897
|
+
isError ? "bg-error-container text-on-error-container [&_.text-on-surface-variant]:text-on-error-container [&_.text-outline]:text-on-error-container/80" : "bg-surface-container-highest text-on-surface-variant"
|
|
898
|
+
),
|
|
899
|
+
children: result
|
|
900
|
+
}
|
|
901
|
+
) : null
|
|
902
|
+
] }) }, "body") : null })
|
|
903
|
+
]
|
|
904
|
+
}
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
function renderArgs(pair, renderer) {
|
|
908
|
+
if (renderer.argsView) {
|
|
909
|
+
const custom = renderer.argsView(pair);
|
|
910
|
+
if (custom) return custom;
|
|
911
|
+
}
|
|
912
|
+
if (pair.args && Object.keys(pair.args).length > 0) {
|
|
913
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5", children: Object.entries(pair.args).map(([key, value]) => /* @__PURE__ */ jsxs("p", { className: "font-code text-body-small", children: [
|
|
914
|
+
/* @__PURE__ */ jsxs("span", { className: "text-outline", children: [
|
|
915
|
+
key,
|
|
916
|
+
": "
|
|
917
|
+
] }),
|
|
918
|
+
/* @__PURE__ */ jsx("span", { className: "text-on-surface-variant", children: formatArgValue(key, value) })
|
|
919
|
+
] }, key)) }) });
|
|
920
|
+
}
|
|
921
|
+
if (pair.argsRaw && pair.argsRaw !== "{}" && pair.argsRaw.trim().length > 0) {
|
|
922
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-small bg-surface-container-highest px-3 py-2", children: /* @__PURE__ */ jsx("pre", { className: "max-h-40 overflow-auto font-code text-body-small text-on-surface-variant", children: pair.argsRaw }) });
|
|
923
|
+
}
|
|
924
|
+
return null;
|
|
925
|
+
}
|
|
926
|
+
function renderResult(pair, renderer) {
|
|
927
|
+
if (pair.status === "running") {
|
|
928
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 text-body-small text-on-surface-variant", children: [
|
|
929
|
+
/* @__PURE__ */ jsx(CircularIndicator, { size: 14, label: "Running" }),
|
|
930
|
+
"Running..."
|
|
931
|
+
] });
|
|
932
|
+
}
|
|
933
|
+
if (renderer.resultView) {
|
|
934
|
+
const custom = renderer.resultView(pair);
|
|
935
|
+
if (custom !== void 0) return custom;
|
|
936
|
+
}
|
|
937
|
+
if (!pair.resultRaw) return null;
|
|
938
|
+
if (pair.result && Object.keys(pair.result).length > 0) {
|
|
939
|
+
return /* @__PURE__ */ jsx("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0.5", children: Object.entries(pair.result).map(([key, value]) => /* @__PURE__ */ jsxs("p", { className: "font-code text-body-small", children: [
|
|
940
|
+
/* @__PURE__ */ jsxs("span", { className: "text-outline", children: [
|
|
941
|
+
key,
|
|
942
|
+
": "
|
|
943
|
+
] }),
|
|
944
|
+
/* @__PURE__ */ jsx("span", { className: "text-on-surface-variant", children: typeof value === "string" ? truncate(value, 200) : JSON.stringify(value) })
|
|
945
|
+
] }, key)) }) });
|
|
946
|
+
}
|
|
947
|
+
return /* @__PURE__ */ jsx(CollapsiblePre, { text: pair.resultRaw, maxLines: 20 });
|
|
948
|
+
}
|
|
949
|
+
function formatArgValue(key, value) {
|
|
950
|
+
if (key === "secret" && typeof value === "string") {
|
|
951
|
+
return "***";
|
|
952
|
+
}
|
|
953
|
+
if (typeof value === "string") {
|
|
954
|
+
return truncate(value, 100);
|
|
955
|
+
}
|
|
956
|
+
if (typeof value === "boolean" || typeof value === "number") {
|
|
957
|
+
return String(value);
|
|
958
|
+
}
|
|
959
|
+
return JSON.stringify(value);
|
|
960
|
+
}
|
|
961
|
+
function truncate(text, maxLen) {
|
|
962
|
+
if (text.length <= maxLen) return text;
|
|
963
|
+
return text.slice(0, maxLen) + "...";
|
|
964
|
+
}
|
|
965
|
+
var bodyClass = {
|
|
966
|
+
small: "text-body-small",
|
|
967
|
+
medium: "text-body-medium",
|
|
968
|
+
large: "text-body-large"
|
|
969
|
+
};
|
|
970
|
+
function m3Components(size) {
|
|
971
|
+
const body = bodyClass[size];
|
|
972
|
+
return {
|
|
973
|
+
h1: ({ node: _node, className, children, ...props }) => /* @__PURE__ */ jsx(
|
|
974
|
+
"h1",
|
|
975
|
+
{
|
|
976
|
+
className: clsx("mt-4 mb-2 text-headline-small text-on-surface first:mt-0", className),
|
|
977
|
+
...props,
|
|
978
|
+
children
|
|
979
|
+
}
|
|
980
|
+
),
|
|
981
|
+
h2: ({ node: _node, className, children, ...props }) => /* @__PURE__ */ jsx(
|
|
982
|
+
"h2",
|
|
983
|
+
{
|
|
984
|
+
className: clsx("mt-4 mb-2 text-title-large text-on-surface first:mt-0", className),
|
|
985
|
+
...props,
|
|
986
|
+
children
|
|
987
|
+
}
|
|
988
|
+
),
|
|
989
|
+
h3: ({ node: _node, className, children, ...props }) => /* @__PURE__ */ jsx(
|
|
990
|
+
"h3",
|
|
991
|
+
{
|
|
992
|
+
className: clsx("mt-3 mb-1.5 text-title-medium text-on-surface first:mt-0", className),
|
|
993
|
+
...props,
|
|
994
|
+
children
|
|
995
|
+
}
|
|
996
|
+
),
|
|
997
|
+
h4: ({ node: _node, className, children, ...props }) => /* @__PURE__ */ jsx(
|
|
998
|
+
"h4",
|
|
999
|
+
{
|
|
1000
|
+
className: clsx("mt-3 mb-1 text-title-small text-on-surface first:mt-0", className),
|
|
1001
|
+
...props,
|
|
1002
|
+
children
|
|
1003
|
+
}
|
|
1004
|
+
),
|
|
1005
|
+
h5: ({ node: _node, className, children, ...props }) => /* @__PURE__ */ jsx(
|
|
1006
|
+
"h5",
|
|
1007
|
+
{
|
|
1008
|
+
className: clsx("mt-3 mb-1 text-title-small text-on-surface-variant first:mt-0", className),
|
|
1009
|
+
...props,
|
|
1010
|
+
children
|
|
1011
|
+
}
|
|
1012
|
+
),
|
|
1013
|
+
h6: ({ node: _node, className, children, ...props }) => /* @__PURE__ */ jsx(
|
|
1014
|
+
"h6",
|
|
1015
|
+
{
|
|
1016
|
+
className: clsx("mt-3 mb-1 text-label-large text-on-surface-variant first:mt-0", className),
|
|
1017
|
+
...props,
|
|
1018
|
+
children
|
|
1019
|
+
}
|
|
1020
|
+
),
|
|
1021
|
+
p: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx("p", { className: clsx("my-2 first:mt-0 last:mb-0", body, className), ...props }),
|
|
1022
|
+
a: ({ node: _node, className, children, ...props }) => /* @__PURE__ */ jsx(
|
|
1023
|
+
"a",
|
|
1024
|
+
{
|
|
1025
|
+
className: clsx(
|
|
1026
|
+
"text-primary underline underline-offset-2 hover:decoration-2",
|
|
1027
|
+
"rounded-extra-small outline-none focus-visible:outline-3 focus-visible:outline-secondary focus-visible:outline-offset-2",
|
|
1028
|
+
className
|
|
1029
|
+
),
|
|
1030
|
+
...props,
|
|
1031
|
+
children
|
|
1032
|
+
}
|
|
1033
|
+
),
|
|
1034
|
+
strong: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx("strong", { className: clsx("font-semibold text-on-surface", className), ...props }),
|
|
1035
|
+
ul: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx(
|
|
1036
|
+
"ul",
|
|
1037
|
+
{
|
|
1038
|
+
className: clsx("my-2 list-disc pl-6 marker:text-on-surface-variant", body, className),
|
|
1039
|
+
...props
|
|
1040
|
+
}
|
|
1041
|
+
),
|
|
1042
|
+
ol: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx(
|
|
1043
|
+
"ol",
|
|
1044
|
+
{
|
|
1045
|
+
className: clsx("my-2 list-decimal pl-6 marker:text-on-surface-variant", body, className),
|
|
1046
|
+
...props
|
|
1047
|
+
}
|
|
1048
|
+
),
|
|
1049
|
+
li: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx("li", { className: clsx("my-1", className), ...props }),
|
|
1050
|
+
blockquote: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx(
|
|
1051
|
+
"blockquote",
|
|
1052
|
+
{
|
|
1053
|
+
className: clsx(
|
|
1054
|
+
"my-3 border-l-4 border-outline-variant pl-4 text-on-surface-variant",
|
|
1055
|
+
className
|
|
1056
|
+
),
|
|
1057
|
+
...props
|
|
1058
|
+
}
|
|
1059
|
+
),
|
|
1060
|
+
code: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx(
|
|
1061
|
+
"code",
|
|
1062
|
+
{
|
|
1063
|
+
className: clsx(
|
|
1064
|
+
"rounded-extra-small bg-surface-container-highest px-1 py-0.5 font-code text-[0.9em] text-on-surface",
|
|
1065
|
+
className
|
|
1066
|
+
),
|
|
1067
|
+
...props
|
|
1068
|
+
}
|
|
1069
|
+
),
|
|
1070
|
+
pre: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx(
|
|
1071
|
+
"pre",
|
|
1072
|
+
{
|
|
1073
|
+
className: clsx(
|
|
1074
|
+
"my-3 overflow-x-auto rounded-small bg-surface-container-highest p-3 font-code text-body-small text-on-surface",
|
|
1075
|
+
"[&_code]:bg-transparent [&_code]:p-0 [&_code]:text-[length:inherit]",
|
|
1076
|
+
className
|
|
1077
|
+
),
|
|
1078
|
+
...props
|
|
1079
|
+
}
|
|
1080
|
+
),
|
|
1081
|
+
hr: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx("hr", { className: clsx("my-4 border-outline-variant", className), ...props }),
|
|
1082
|
+
table: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx("div", { className: "my-3 overflow-x-auto rounded-small border border-outline-variant", children: /* @__PURE__ */ jsx("table", { className: clsx("w-full border-collapse", body, className), ...props }) }),
|
|
1083
|
+
thead: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx("thead", { className: clsx("bg-surface-container", className), ...props }),
|
|
1084
|
+
th: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx(
|
|
1085
|
+
"th",
|
|
1086
|
+
{
|
|
1087
|
+
className: clsx(
|
|
1088
|
+
"border-b border-outline-variant px-3 py-2 text-left text-title-small text-on-surface",
|
|
1089
|
+
className
|
|
1090
|
+
),
|
|
1091
|
+
...props
|
|
1092
|
+
}
|
|
1093
|
+
),
|
|
1094
|
+
td: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx(
|
|
1095
|
+
"td",
|
|
1096
|
+
{
|
|
1097
|
+
className: clsx("border-t border-outline-variant px-3 py-2 text-on-surface", className),
|
|
1098
|
+
...props
|
|
1099
|
+
}
|
|
1100
|
+
),
|
|
1101
|
+
img: ({ node: _node, className, alt, ...props }) => /* @__PURE__ */ jsx(
|
|
1102
|
+
"img",
|
|
1103
|
+
{
|
|
1104
|
+
className: clsx("my-2 max-w-full rounded-medium", className),
|
|
1105
|
+
alt: alt ?? "",
|
|
1106
|
+
...props
|
|
1107
|
+
}
|
|
1108
|
+
),
|
|
1109
|
+
input: ({ node: _node, className, ...props }) => /* @__PURE__ */ jsx("input", { className: clsx("mr-2 accent-primary", className), ...props })
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
var Markdown = forwardRef(
|
|
1113
|
+
({ content, className, size = "medium", allowHtml = false }, ref) => {
|
|
1114
|
+
return /* @__PURE__ */ jsx(
|
|
1115
|
+
"div",
|
|
1116
|
+
{
|
|
1117
|
+
ref,
|
|
1118
|
+
className: clsx("markdown min-w-0 text-on-surface", bodyClass[size], className),
|
|
1119
|
+
children: /* @__PURE__ */ jsx(
|
|
1120
|
+
ReactMarkdown,
|
|
1121
|
+
{
|
|
1122
|
+
remarkPlugins: [remarkGfm],
|
|
1123
|
+
rehypePlugins: allowHtml ? [rehypeRaw] : void 0,
|
|
1124
|
+
components: m3Components(size),
|
|
1125
|
+
children: content
|
|
1126
|
+
}
|
|
1127
|
+
)
|
|
1128
|
+
}
|
|
1129
|
+
);
|
|
1130
|
+
}
|
|
1131
|
+
);
|
|
1132
|
+
Markdown.displayName = "Markdown";
|
|
1133
|
+
function MessageBubble({
|
|
1134
|
+
content,
|
|
1135
|
+
isUser,
|
|
1136
|
+
isStreaming = false,
|
|
1137
|
+
onCopy,
|
|
1138
|
+
className
|
|
1139
|
+
}) {
|
|
1140
|
+
return /* @__PURE__ */ jsxs(
|
|
1141
|
+
"div",
|
|
1142
|
+
{
|
|
1143
|
+
className: clsx("group flex flex-col py-2", isUser ? "items-end" : "items-start", className),
|
|
1144
|
+
children: [
|
|
1145
|
+
/* @__PURE__ */ jsx(
|
|
1146
|
+
"div",
|
|
1147
|
+
{
|
|
1148
|
+
className: clsx(
|
|
1149
|
+
"min-w-0",
|
|
1150
|
+
isUser ? "max-w-[80%] rounded-large rounded-br-extra-small bg-secondary-container px-4 py-2.5 text-body-large text-on-secondary-container" : "w-full max-w-full bg-transparent text-body-large text-on-surface"
|
|
1151
|
+
),
|
|
1152
|
+
"aria-busy": isStreaming || void 0,
|
|
1153
|
+
children: isUser ? /* @__PURE__ */ jsx("div", { className: "whitespace-pre-wrap break-words", children: content }) : /* @__PURE__ */ jsx(Markdown, { content, size: "large", className: "break-words" })
|
|
1154
|
+
}
|
|
1155
|
+
),
|
|
1156
|
+
!isUser && onCopy ? /* @__PURE__ */ jsx("div", { className: "mt-1 flex opacity-0 transition-opacity duration-200 ease-standard group-focus-within:opacity-100 group-hover:opacity-100", children: /* @__PURE__ */ jsx(
|
|
1157
|
+
CircleButton,
|
|
1158
|
+
{
|
|
1159
|
+
icon: "content_copy",
|
|
1160
|
+
variant: "standard",
|
|
1161
|
+
size: "sm",
|
|
1162
|
+
onClick: () => onCopy(content),
|
|
1163
|
+
"aria-label": isStreaming ? "Copy Streaming Message" : "Copy Message",
|
|
1164
|
+
title: isStreaming ? "Copy streaming message" : "Copy message"
|
|
1165
|
+
}
|
|
1166
|
+
) }) : null
|
|
1167
|
+
]
|
|
1168
|
+
}
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
function stripExcessWhitespace(text) {
|
|
1172
|
+
return text.replace(/ {3,}/g, " ");
|
|
1173
|
+
}
|
|
1174
|
+
function statusTone(status) {
|
|
1175
|
+
switch (status) {
|
|
1176
|
+
case "running":
|
|
1177
|
+
return "primary";
|
|
1178
|
+
case "completed":
|
|
1179
|
+
return "success";
|
|
1180
|
+
case "failed":
|
|
1181
|
+
case "error":
|
|
1182
|
+
case "cancelled":
|
|
1183
|
+
return "error";
|
|
1184
|
+
default:
|
|
1185
|
+
return "neutral";
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
function InlineWorkerCard({
|
|
1189
|
+
title,
|
|
1190
|
+
status,
|
|
1191
|
+
toolCallCount,
|
|
1192
|
+
liveStatus,
|
|
1193
|
+
transcript,
|
|
1194
|
+
isTranscriptLoading,
|
|
1195
|
+
onCopyLogs,
|
|
1196
|
+
onCancel,
|
|
1197
|
+
className,
|
|
1198
|
+
defaultExpanded = false
|
|
1199
|
+
}) {
|
|
1200
|
+
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
1201
|
+
const contentId = useId();
|
|
1202
|
+
const items = useMemo(() => pairTranscriptSteps(transcript), [transcript]);
|
|
1203
|
+
const isRunning = status === "running";
|
|
1204
|
+
const isDone = status === "completed";
|
|
1205
|
+
const tone = statusTone(status);
|
|
1206
|
+
return /* @__PURE__ */ jsxs("div", { className: clsx("group flex min-w-0 flex-col items-start", className), children: [
|
|
1207
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 max-w-full overflow-hidden rounded-medium bg-surface-container text-on-surface", children: [
|
|
1208
|
+
/* @__PURE__ */ jsxs(
|
|
1209
|
+
"button",
|
|
1210
|
+
{
|
|
1211
|
+
type: "button",
|
|
1212
|
+
onClick: () => setExpanded((v) => !v),
|
|
1213
|
+
"aria-expanded": expanded,
|
|
1214
|
+
"aria-controls": contentId,
|
|
1215
|
+
className: clsx(
|
|
1216
|
+
"flex w-full items-start gap-3 rounded-medium px-4 py-3 text-left transition-colors duration-200 ease-standard",
|
|
1217
|
+
"hover:bg-on-surface/8 active:bg-on-surface/10",
|
|
1218
|
+
focusRing
|
|
1219
|
+
),
|
|
1220
|
+
children: [
|
|
1221
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-8 shrink-0 items-center justify-center", children: isRunning ? /* @__PURE__ */ jsx(CircularIndicator, { size: 20, label: "Worker running" }) : isDone ? /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-success-container text-on-success-container", children: /* @__PURE__ */ jsx(Icon, { name: "check_circle", size: 18, filled: true }) }) : tone === "error" ? /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-error-container text-on-error-container", children: /* @__PURE__ */ jsx(Icon, { name: "error", size: 18, filled: true }) }) : /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-surface-container-highest text-on-surface-variant", children: /* @__PURE__ */ jsx(Icon, { name: "build", size: 18 }) }) }),
|
|
1222
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1223
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1224
|
+
/* @__PURE__ */ jsx("div", { className: "line-clamp-2 min-w-0 flex-1 text-title-small text-on-surface", children: title }),
|
|
1225
|
+
/* @__PURE__ */ jsx(StatusChip, { tone, children: status })
|
|
1226
|
+
] }),
|
|
1227
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2 text-body-small text-on-surface-variant", children: [
|
|
1228
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1229
|
+
toolCallCount,
|
|
1230
|
+
" tool calls"
|
|
1231
|
+
] }),
|
|
1232
|
+
liveStatus ? /* @__PURE__ */ jsx("span", { className: "truncate text-outline", children: liveStatus }) : null
|
|
1233
|
+
] })
|
|
1234
|
+
] }),
|
|
1235
|
+
/* @__PURE__ */ jsx(
|
|
1236
|
+
Icon,
|
|
1237
|
+
{
|
|
1238
|
+
name: "expand_more",
|
|
1239
|
+
size: 20,
|
|
1240
|
+
className: clsx(
|
|
1241
|
+
"mt-1.5 shrink-0 text-on-surface-variant transition-transform duration-300 ease-emphasized",
|
|
1242
|
+
expanded ? "rotate-180" : ""
|
|
1243
|
+
)
|
|
1244
|
+
}
|
|
1245
|
+
)
|
|
1246
|
+
]
|
|
1247
|
+
}
|
|
1248
|
+
),
|
|
1249
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: expanded ? /* @__PURE__ */ jsx(
|
|
1250
|
+
motion.div,
|
|
1251
|
+
{
|
|
1252
|
+
id: contentId,
|
|
1253
|
+
...expandMotion,
|
|
1254
|
+
className: "overflow-hidden",
|
|
1255
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 border-t border-outline-variant px-4 py-3", children: isTranscriptLoading ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-body-small text-on-surface-variant", children: [
|
|
1256
|
+
/* @__PURE__ */ jsx(CircularIndicator, { size: 16, label: "Loading transcript" }),
|
|
1257
|
+
"Loading worker transcript..."
|
|
1258
|
+
] }) : items.length > 0 ? items.map(
|
|
1259
|
+
(item) => item.kind === "tool" ? /* @__PURE__ */ jsx(ToolCall, { pair: item.pair }, item.pair.id) : /* @__PURE__ */ jsx(
|
|
1260
|
+
Markdown,
|
|
1261
|
+
{
|
|
1262
|
+
content: stripExcessWhitespace(item.text),
|
|
1263
|
+
size: "small",
|
|
1264
|
+
className: "text-on-surface-variant"
|
|
1265
|
+
},
|
|
1266
|
+
`text-${item.text}`
|
|
1267
|
+
)
|
|
1268
|
+
) : /* @__PURE__ */ jsx("div", { className: "text-body-small text-on-surface-variant", children: "No tool calls yet." }) })
|
|
1269
|
+
},
|
|
1270
|
+
"transcript"
|
|
1271
|
+
) : null })
|
|
1272
|
+
] }),
|
|
1273
|
+
(onCopyLogs || onCancel && isRunning) && /* @__PURE__ */ jsxs("div", { className: "mt-1 flex gap-1 opacity-0 transition-opacity duration-200 ease-standard group-focus-within:opacity-100 group-hover:opacity-100", children: [
|
|
1274
|
+
onCopyLogs && /* @__PURE__ */ jsxs(Button, { variant: "text", size: "xs", onClick: onCopyLogs, title: "Copy logs", children: [
|
|
1275
|
+
/* @__PURE__ */ jsx(Icon, { name: "content_copy", size: 18 }),
|
|
1276
|
+
"Copy"
|
|
1277
|
+
] }),
|
|
1278
|
+
onCancel && isRunning && /* @__PURE__ */ jsxs(Button, { variant: "text", size: "xs", onClick: onCancel, title: "Cancel", children: [
|
|
1279
|
+
/* @__PURE__ */ jsx(Icon, { name: "stop", size: 18 }),
|
|
1280
|
+
"Cancel"
|
|
1281
|
+
] })
|
|
1282
|
+
] })
|
|
1283
|
+
] });
|
|
1284
|
+
}
|
|
1285
|
+
function InlineBranchCard({
|
|
1286
|
+
description,
|
|
1287
|
+
completedAt,
|
|
1288
|
+
conclusion,
|
|
1289
|
+
className,
|
|
1290
|
+
defaultExpanded = false
|
|
1291
|
+
}) {
|
|
1292
|
+
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
1293
|
+
const isRunning = !completedAt;
|
|
1294
|
+
const contentId = useId();
|
|
1295
|
+
const canExpand = !!conclusion;
|
|
1296
|
+
return /* @__PURE__ */ jsx("div", { className: clsx("group flex min-w-0 flex-col items-start", className), children: /* @__PURE__ */ jsxs("div", { className: "min-w-0 max-w-full overflow-hidden rounded-medium bg-surface-container text-on-surface", children: [
|
|
1297
|
+
/* @__PURE__ */ jsxs(
|
|
1298
|
+
"button",
|
|
1299
|
+
{
|
|
1300
|
+
type: "button",
|
|
1301
|
+
onClick: () => canExpand && setExpanded((v) => !v),
|
|
1302
|
+
"aria-expanded": canExpand ? expanded : void 0,
|
|
1303
|
+
"aria-controls": canExpand ? contentId : void 0,
|
|
1304
|
+
className: clsx(
|
|
1305
|
+
"flex w-full items-start gap-3 rounded-medium px-4 py-3 text-left transition-colors duration-200 ease-standard",
|
|
1306
|
+
canExpand && "hover:bg-on-surface/8 active:bg-on-surface/10",
|
|
1307
|
+
focusRing
|
|
1308
|
+
),
|
|
1309
|
+
children: [
|
|
1310
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-8 shrink-0 items-center justify-center", children: isRunning ? /* @__PURE__ */ jsx(CircularIndicator, { size: 20, label: "Thinking" }) : /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-primary-container text-on-primary-container", children: /* @__PURE__ */ jsx(Icon, { name: "alt_route", size: 18 }) }) }),
|
|
1311
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 self-center", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
1312
|
+
/* @__PURE__ */ jsx("div", { className: "line-clamp-2 min-w-0 flex-1 text-title-small text-on-surface", children: description }),
|
|
1313
|
+
/* @__PURE__ */ jsx(StatusChip, { tone: isRunning ? "primary" : "success", children: isRunning ? "thinking" : "done" })
|
|
1314
|
+
] }) }),
|
|
1315
|
+
canExpand && /* @__PURE__ */ jsx(
|
|
1316
|
+
Icon,
|
|
1317
|
+
{
|
|
1318
|
+
name: "expand_more",
|
|
1319
|
+
size: 20,
|
|
1320
|
+
className: clsx(
|
|
1321
|
+
"mt-1.5 shrink-0 text-on-surface-variant transition-transform duration-300 ease-emphasized",
|
|
1322
|
+
expanded ? "rotate-180" : ""
|
|
1323
|
+
)
|
|
1324
|
+
}
|
|
1325
|
+
)
|
|
1326
|
+
]
|
|
1327
|
+
}
|
|
1328
|
+
),
|
|
1329
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: expanded && conclusion ? /* @__PURE__ */ jsx(
|
|
1330
|
+
motion.div,
|
|
1331
|
+
{
|
|
1332
|
+
id: contentId,
|
|
1333
|
+
...expandMotion,
|
|
1334
|
+
className: "overflow-hidden",
|
|
1335
|
+
children: /* @__PURE__ */ jsx("div", { className: "border-t border-outline-variant px-4 py-3", children: /* @__PURE__ */ jsx(Markdown, { content: conclusion, size: "small", className: "text-on-surface-variant" }) })
|
|
1336
|
+
},
|
|
1337
|
+
"conclusion"
|
|
1338
|
+
) : null })
|
|
1339
|
+
] }) });
|
|
1340
|
+
}
|
|
1341
|
+
function groupModelsByProvider(models, search = "") {
|
|
1342
|
+
const q = search.trim().toLowerCase();
|
|
1343
|
+
const filtered = q ? models.filter((m) => m.name.toLowerCase().includes(q) || m.provider.toLowerCase().includes(q)) : models;
|
|
1344
|
+
return filtered.reduce(
|
|
1345
|
+
(acc, model) => {
|
|
1346
|
+
if (!acc[model.provider]) acc[model.provider] = [];
|
|
1347
|
+
acc[model.provider].push(model);
|
|
1348
|
+
return acc;
|
|
1349
|
+
},
|
|
1350
|
+
{}
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
function ModelOptionList({ grouped, value, onSelect, className }) {
|
|
1354
|
+
const providers = Object.entries(grouped);
|
|
1355
|
+
return /* @__PURE__ */ jsxs(
|
|
1356
|
+
"div",
|
|
1357
|
+
{
|
|
1358
|
+
role: "listbox",
|
|
1359
|
+
"aria-label": "Models",
|
|
1360
|
+
className: clsx("flex flex-col", className),
|
|
1361
|
+
children: [
|
|
1362
|
+
providers.map(([provider, providerModels], groupIndex) => /* @__PURE__ */ jsxs(
|
|
1363
|
+
"div",
|
|
1364
|
+
{
|
|
1365
|
+
role: "group",
|
|
1366
|
+
"aria-label": provider,
|
|
1367
|
+
className: clsx(groupIndex > 0 && "mt-1 border-t border-outline-variant pt-1"),
|
|
1368
|
+
children: [
|
|
1369
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 pt-2 pb-1 text-title-small text-on-surface-variant", children: provider }),
|
|
1370
|
+
providerModels.map((model) => {
|
|
1371
|
+
const selected = model.id === value;
|
|
1372
|
+
return /* @__PURE__ */ jsxs(
|
|
1373
|
+
"button",
|
|
1374
|
+
{
|
|
1375
|
+
type: "button",
|
|
1376
|
+
role: "option",
|
|
1377
|
+
"aria-selected": selected,
|
|
1378
|
+
onClick: () => onSelect(model.id),
|
|
1379
|
+
className: clsx(
|
|
1380
|
+
"flex min-h-12 w-full items-center gap-3 px-3 py-2 text-left",
|
|
1381
|
+
"transition-colors duration-200 ease-standard",
|
|
1382
|
+
selected ? "bg-secondary-container text-on-secondary-container" : "text-on-surface hover:bg-on-surface/8 active:bg-on-surface/10",
|
|
1383
|
+
focusRing,
|
|
1384
|
+
"focus-visible:outline-offset-[-3px]"
|
|
1385
|
+
),
|
|
1386
|
+
children: [
|
|
1387
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1388
|
+
/* @__PURE__ */ jsx("div", { className: "truncate text-label-large", children: model.name }),
|
|
1389
|
+
model.context_window || model.capabilities?.length ? /* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-1", children: [
|
|
1390
|
+
model.context_window ? /* @__PURE__ */ jsxs(
|
|
1391
|
+
"span",
|
|
1392
|
+
{
|
|
1393
|
+
className: clsx(
|
|
1394
|
+
"text-body-small",
|
|
1395
|
+
selected ? "text-on-secondary-container" : "text-on-surface-variant"
|
|
1396
|
+
),
|
|
1397
|
+
children: [
|
|
1398
|
+
model.context_window.toLocaleString(),
|
|
1399
|
+
" tokens"
|
|
1400
|
+
]
|
|
1401
|
+
}
|
|
1402
|
+
) : null,
|
|
1403
|
+
model.capabilities?.map((capability) => /* @__PURE__ */ jsx(
|
|
1404
|
+
"span",
|
|
1405
|
+
{
|
|
1406
|
+
className: clsx(
|
|
1407
|
+
"inline-flex h-5 items-center rounded-small border border-outline-variant px-1.5 text-label-small",
|
|
1408
|
+
selected ? "text-on-secondary-container" : "text-on-surface-variant"
|
|
1409
|
+
),
|
|
1410
|
+
children: capability
|
|
1411
|
+
},
|
|
1412
|
+
capability
|
|
1413
|
+
))
|
|
1414
|
+
] }) : null
|
|
1415
|
+
] }),
|
|
1416
|
+
selected && /* @__PURE__ */ jsx(Icon, { name: "check", size: 20, className: "shrink-0" })
|
|
1417
|
+
]
|
|
1418
|
+
},
|
|
1419
|
+
model.id
|
|
1420
|
+
);
|
|
1421
|
+
})
|
|
1422
|
+
]
|
|
1423
|
+
},
|
|
1424
|
+
provider
|
|
1425
|
+
)),
|
|
1426
|
+
providers.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-3 text-center text-body-small text-on-surface-variant", children: "No models found" })
|
|
1427
|
+
]
|
|
1428
|
+
}
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
function ModelSearchField({
|
|
1432
|
+
value,
|
|
1433
|
+
onChange,
|
|
1434
|
+
placeholder
|
|
1435
|
+
}) {
|
|
1436
|
+
const inputRef = useRef(null);
|
|
1437
|
+
useEffect(() => {
|
|
1438
|
+
inputRef.current?.focus();
|
|
1439
|
+
}, []);
|
|
1440
|
+
return /* @__PURE__ */ jsx("div", { className: "px-2 pb-2", children: /* @__PURE__ */ jsxs("label", { className: "flex h-10 items-center gap-2 rounded-full bg-surface-container-high px-3 text-on-surface-variant focus-within:bg-surface-container-highest", children: [
|
|
1441
|
+
/* @__PURE__ */ jsx(Icon, { name: "search", size: 20, className: "shrink-0" }),
|
|
1442
|
+
/* @__PURE__ */ jsx(
|
|
1443
|
+
"input",
|
|
1444
|
+
{
|
|
1445
|
+
ref: inputRef,
|
|
1446
|
+
value,
|
|
1447
|
+
onChange: (event) => onChange(event.target.value),
|
|
1448
|
+
placeholder,
|
|
1449
|
+
"aria-label": placeholder,
|
|
1450
|
+
className: "min-w-0 flex-1 bg-transparent text-body-large text-on-surface outline-none placeholder:text-on-surface-variant"
|
|
1451
|
+
}
|
|
1452
|
+
)
|
|
1453
|
+
] }) });
|
|
1454
|
+
}
|
|
1455
|
+
var ModelSelector = forwardRef(
|
|
1456
|
+
({
|
|
1457
|
+
models,
|
|
1458
|
+
value,
|
|
1459
|
+
onChange,
|
|
1460
|
+
placeholder = "Select model...",
|
|
1461
|
+
searchPlaceholder = "Search models...",
|
|
1462
|
+
variant,
|
|
1463
|
+
size,
|
|
1464
|
+
popover: externalPopover,
|
|
1465
|
+
className,
|
|
1466
|
+
disabled
|
|
1467
|
+
}, ref) => {
|
|
1468
|
+
const internalPopover = usePopover();
|
|
1469
|
+
const popover = externalPopover ?? internalPopover;
|
|
1470
|
+
const [search, setSearch] = useState("");
|
|
1471
|
+
const selectedModel = models.find((m) => m.id === value);
|
|
1472
|
+
const grouped = useMemo(() => groupModelsByProvider(models, search), [models, search]);
|
|
1473
|
+
return /* @__PURE__ */ jsxs(
|
|
1474
|
+
Popover.Root,
|
|
1475
|
+
{
|
|
1476
|
+
open: popover.open,
|
|
1477
|
+
onOpenChange: (open) => {
|
|
1478
|
+
popover.setOpen(open);
|
|
1479
|
+
if (!open) setSearch("");
|
|
1480
|
+
},
|
|
1481
|
+
children: [
|
|
1482
|
+
/* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
1483
|
+
SelectPill,
|
|
1484
|
+
{
|
|
1485
|
+
ref,
|
|
1486
|
+
variant,
|
|
1487
|
+
size,
|
|
1488
|
+
disabled,
|
|
1489
|
+
"aria-haspopup": "listbox",
|
|
1490
|
+
className: clsx("w-full", className),
|
|
1491
|
+
children: selectedModel?.name ?? placeholder
|
|
1492
|
+
}
|
|
1493
|
+
) }),
|
|
1494
|
+
/* @__PURE__ */ jsxs(
|
|
1495
|
+
Popover.Content,
|
|
1496
|
+
{
|
|
1497
|
+
align: "end",
|
|
1498
|
+
sideOffset: 8,
|
|
1499
|
+
style: { width: 280 },
|
|
1500
|
+
className: "overflow-hidden rounded-extra-small! py-2",
|
|
1501
|
+
children: [
|
|
1502
|
+
/* @__PURE__ */ jsx(ModelSearchField, { value: search, onChange: setSearch, placeholder: searchPlaceholder }),
|
|
1503
|
+
/* @__PURE__ */ jsx("div", { className: "max-h-[320px] overflow-y-auto", children: /* @__PURE__ */ jsx(
|
|
1504
|
+
ModelOptionList,
|
|
1505
|
+
{
|
|
1506
|
+
grouped,
|
|
1507
|
+
value,
|
|
1508
|
+
onSelect: (id) => {
|
|
1509
|
+
onChange(id);
|
|
1510
|
+
popover.setOpen(false);
|
|
1511
|
+
setSearch("");
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
) })
|
|
1515
|
+
]
|
|
1516
|
+
}
|
|
1517
|
+
)
|
|
1518
|
+
]
|
|
1519
|
+
}
|
|
1520
|
+
);
|
|
1521
|
+
}
|
|
1522
|
+
);
|
|
1523
|
+
ModelSelector.displayName = "ModelSelector";
|
|
1524
|
+
var iconButtonEnter = {
|
|
1525
|
+
initial: { scale: 0.6, opacity: 0 },
|
|
1526
|
+
animate: {
|
|
1527
|
+
scale: 1,
|
|
1528
|
+
opacity: 1,
|
|
1529
|
+
transition: { duration: m3Durations.short4, ease: m3Easings.emphasizedDecelerate }
|
|
1530
|
+
},
|
|
1531
|
+
exit: {
|
|
1532
|
+
scale: 0.6,
|
|
1533
|
+
opacity: 0,
|
|
1534
|
+
transition: { duration: m3Durations.short3, ease: m3Easings.emphasizedAccelerate }
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
function ChatComposer({
|
|
1538
|
+
draft,
|
|
1539
|
+
onDraftChange,
|
|
1540
|
+
onSend,
|
|
1541
|
+
placeholder = "Ask something...",
|
|
1542
|
+
heading,
|
|
1543
|
+
isSending = false,
|
|
1544
|
+
projectSelector,
|
|
1545
|
+
modelSelector,
|
|
1546
|
+
onOpenVoice,
|
|
1547
|
+
toolbarExtra,
|
|
1548
|
+
onStop,
|
|
1549
|
+
className
|
|
1550
|
+
}) {
|
|
1551
|
+
const canSend = !isSending && draft.trim().length > 0;
|
|
1552
|
+
const showStop = isSending && !!onStop;
|
|
1553
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1554
|
+
heading && /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center gap-2 px-1 text-title-small text-on-surface-variant", children: [
|
|
1555
|
+
/* @__PURE__ */ jsx(Icon, { name: "auto_awesome", size: 18, filled: true, className: "text-primary" }),
|
|
1556
|
+
heading
|
|
1557
|
+
] }),
|
|
1558
|
+
/* @__PURE__ */ jsxs(
|
|
1559
|
+
"div",
|
|
1560
|
+
{
|
|
1561
|
+
className: clsx(
|
|
1562
|
+
"m3-chat-composer rounded-extra-large bg-surface-container-high px-4 pt-3 pb-2 text-on-surface",
|
|
1563
|
+
"transition-colors duration-200 ease-standard focus-within:bg-surface-container-highest",
|
|
1564
|
+
className
|
|
1565
|
+
),
|
|
1566
|
+
children: [
|
|
1567
|
+
/* @__PURE__ */ jsx(
|
|
1568
|
+
"textarea",
|
|
1569
|
+
{
|
|
1570
|
+
value: draft,
|
|
1571
|
+
onChange: (event) => onDraftChange(event.target.value),
|
|
1572
|
+
onKeyDown: (event) => {
|
|
1573
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
1574
|
+
event.preventDefault();
|
|
1575
|
+
onSend();
|
|
1576
|
+
}
|
|
1577
|
+
},
|
|
1578
|
+
placeholder,
|
|
1579
|
+
"aria-label": placeholder,
|
|
1580
|
+
rows: 2,
|
|
1581
|
+
className: "block w-full resize-none border-0 bg-transparent px-1 text-body-large text-on-surface caret-primary outline-none placeholder:text-on-surface-variant focus:outline-none focus:ring-0"
|
|
1582
|
+
}
|
|
1583
|
+
),
|
|
1584
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center justify-between gap-2", children: [
|
|
1585
|
+
projectSelector ? /* @__PURE__ */ jsx("div", { className: "w-[210px]", children: /* @__PURE__ */ jsxs(
|
|
1586
|
+
Popover.Root,
|
|
1587
|
+
{
|
|
1588
|
+
open: projectSelector.popover.open,
|
|
1589
|
+
onOpenChange: projectSelector.popover.setOpen,
|
|
1590
|
+
children: [
|
|
1591
|
+
/* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(SelectPill, { className: "w-full", "aria-haspopup": "listbox", children: projectSelector.value }) }),
|
|
1592
|
+
/* @__PURE__ */ jsx(
|
|
1593
|
+
Popover.Content,
|
|
1594
|
+
{
|
|
1595
|
+
align: "start",
|
|
1596
|
+
sideOffset: 8,
|
|
1597
|
+
className: "min-w-[210px] overflow-hidden rounded-extra-small! py-2",
|
|
1598
|
+
children: /* @__PURE__ */ jsx(
|
|
1599
|
+
"div",
|
|
1600
|
+
{
|
|
1601
|
+
role: "listbox",
|
|
1602
|
+
"aria-label": "Projects",
|
|
1603
|
+
children: projectSelector.options.map((option) => {
|
|
1604
|
+
const selected = option === projectSelector.value;
|
|
1605
|
+
return /* @__PURE__ */ jsxs(
|
|
1606
|
+
"button",
|
|
1607
|
+
{
|
|
1608
|
+
type: "button",
|
|
1609
|
+
role: "option",
|
|
1610
|
+
"aria-selected": selected,
|
|
1611
|
+
onClick: () => {
|
|
1612
|
+
projectSelector.onChange(option);
|
|
1613
|
+
projectSelector.popover.setOpen(false);
|
|
1614
|
+
},
|
|
1615
|
+
className: clsx(
|
|
1616
|
+
"flex h-12 w-full items-center gap-3 px-3 text-left text-label-large",
|
|
1617
|
+
"transition-colors duration-200 ease-standard",
|
|
1618
|
+
selected ? "bg-secondary-container text-on-secondary-container" : "text-on-surface hover:bg-on-surface/8",
|
|
1619
|
+
focusRing,
|
|
1620
|
+
"focus-visible:outline-offset-[-3px]"
|
|
1621
|
+
),
|
|
1622
|
+
children: [
|
|
1623
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: option }),
|
|
1624
|
+
selected && /* @__PURE__ */ jsx(Icon, { name: "check", size: 20 })
|
|
1625
|
+
]
|
|
1626
|
+
},
|
|
1627
|
+
option
|
|
1628
|
+
);
|
|
1629
|
+
})
|
|
1630
|
+
}
|
|
1631
|
+
)
|
|
1632
|
+
}
|
|
1633
|
+
)
|
|
1634
|
+
]
|
|
1635
|
+
}
|
|
1636
|
+
) }) : /* @__PURE__ */ jsx("div", {}),
|
|
1637
|
+
/* @__PURE__ */ jsxs(motion.div, { layout: true, className: "flex items-center gap-1", children: [
|
|
1638
|
+
modelSelector && /* @__PURE__ */ jsx("div", { className: "w-[180px]", children: /* @__PURE__ */ jsx(
|
|
1639
|
+
ModelSelector,
|
|
1640
|
+
{
|
|
1641
|
+
models: modelSelector.options,
|
|
1642
|
+
value: modelSelector.value,
|
|
1643
|
+
onChange: modelSelector.onChange,
|
|
1644
|
+
size: "md"
|
|
1645
|
+
}
|
|
1646
|
+
) }),
|
|
1647
|
+
toolbarExtra,
|
|
1648
|
+
onOpenVoice && /* @__PURE__ */ jsx(
|
|
1649
|
+
CircleButton,
|
|
1650
|
+
{
|
|
1651
|
+
icon: "mic",
|
|
1652
|
+
variant: "standard",
|
|
1653
|
+
onClick: onOpenVoice,
|
|
1654
|
+
disabled: isSending,
|
|
1655
|
+
"aria-label": "Open Voice Input"
|
|
1656
|
+
}
|
|
1657
|
+
),
|
|
1658
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "popLayout", children: showStop ? /* @__PURE__ */ jsx(
|
|
1659
|
+
motion.button,
|
|
1660
|
+
{
|
|
1661
|
+
type: "button",
|
|
1662
|
+
...iconButtonEnter,
|
|
1663
|
+
onClick: onStop,
|
|
1664
|
+
"aria-label": "Stop",
|
|
1665
|
+
className: clsx(
|
|
1666
|
+
"flex size-10 shrink-0 items-center justify-center rounded-full bg-primary text-on-primary",
|
|
1667
|
+
"transition-colors duration-200 ease-standard hover:bg-primary/92 active:bg-primary/90",
|
|
1668
|
+
focusRing
|
|
1669
|
+
),
|
|
1670
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "stop", size: 24, filled: true })
|
|
1671
|
+
},
|
|
1672
|
+
"stop"
|
|
1673
|
+
) : canSend ? /* @__PURE__ */ jsx(
|
|
1674
|
+
motion.button,
|
|
1675
|
+
{
|
|
1676
|
+
type: "button",
|
|
1677
|
+
...iconButtonEnter,
|
|
1678
|
+
onClick: onSend,
|
|
1679
|
+
"aria-label": "Send",
|
|
1680
|
+
className: clsx(
|
|
1681
|
+
"flex size-10 shrink-0 items-center justify-center rounded-full bg-primary text-on-primary",
|
|
1682
|
+
"transition-colors duration-200 ease-standard hover:bg-primary/92 active:bg-primary/90",
|
|
1683
|
+
focusRing
|
|
1684
|
+
),
|
|
1685
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "arrow_upward", size: 24 })
|
|
1686
|
+
},
|
|
1687
|
+
"send"
|
|
1688
|
+
) : null })
|
|
1689
|
+
] })
|
|
1690
|
+
] })
|
|
1691
|
+
]
|
|
1692
|
+
}
|
|
1693
|
+
)
|
|
1694
|
+
] });
|
|
1695
|
+
}
|
|
1696
|
+
var config = {
|
|
1697
|
+
done: { icon: "check_circle", filled: true, color: "text-success" },
|
|
1698
|
+
in_progress: { icon: "clock_loader_40", filled: true, color: "text-primary" },
|
|
1699
|
+
ready: { icon: "radio_button_checked", filled: false, color: "text-primary" },
|
|
1700
|
+
pending_approval: { icon: "schedule", filled: false, color: "text-warning" },
|
|
1701
|
+
backlog: { icon: "radio_button_unchecked", filled: false, color: "text-outline" }
|
|
1702
|
+
};
|
|
1703
|
+
function TaskStatusIcon({ status, size = 16, className, label }) {
|
|
1704
|
+
const { icon, filled, color } = config[status];
|
|
1705
|
+
return /* @__PURE__ */ jsx(
|
|
1706
|
+
Icon,
|
|
1707
|
+
{
|
|
1708
|
+
name: icon,
|
|
1709
|
+
size,
|
|
1710
|
+
filled,
|
|
1711
|
+
label: label ?? TASK_STATUS_LABEL[status],
|
|
1712
|
+
"data-status": status,
|
|
1713
|
+
className: clsx(color, className)
|
|
1714
|
+
}
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
var config2 = {
|
|
1718
|
+
critical: { icon: "priority_high", filled: true, color: "text-error" },
|
|
1719
|
+
high: { icon: "keyboard_double_arrow_up", filled: false, color: "text-warning" },
|
|
1720
|
+
medium: { icon: "drag_handle", filled: false, color: "text-primary" },
|
|
1721
|
+
low: { icon: "keyboard_arrow_down", filled: false, color: "text-outline" }
|
|
1722
|
+
};
|
|
1723
|
+
function TaskPriorityIcon({ priority, size = 14, className, label }) {
|
|
1724
|
+
const { icon, filled, color } = config2[priority];
|
|
1725
|
+
return /* @__PURE__ */ jsx(
|
|
1726
|
+
Icon,
|
|
1727
|
+
{
|
|
1728
|
+
name: icon,
|
|
1729
|
+
size,
|
|
1730
|
+
filled,
|
|
1731
|
+
weight: 600,
|
|
1732
|
+
label: label ?? `${TASK_PRIORITY_LABEL[priority]} priority`,
|
|
1733
|
+
"data-priority": priority,
|
|
1734
|
+
className: clsx(color, className)
|
|
1735
|
+
}
|
|
1736
|
+
);
|
|
1737
|
+
}
|
|
1738
|
+
var TASK_ROW_GRID = "20px 18px 72px 1fr 56px 96px 40px";
|
|
1739
|
+
var TASK_ROW_HEIGHT = 48;
|
|
1740
|
+
function TaskRow({
|
|
1741
|
+
task,
|
|
1742
|
+
onClick,
|
|
1743
|
+
isActive,
|
|
1744
|
+
resolveAgentName,
|
|
1745
|
+
onStatusChange,
|
|
1746
|
+
onDelete,
|
|
1747
|
+
className
|
|
1748
|
+
}) {
|
|
1749
|
+
const completedSubtasks = task.subtasks.filter((s) => s.completed).length;
|
|
1750
|
+
const assigneeName = resolveAgentName?.(task.assigned_agent_id) ?? task.assigned_agent_id;
|
|
1751
|
+
const hasActions = onStatusChange || onDelete;
|
|
1752
|
+
const isRowInteractive = typeof onClick === "function";
|
|
1753
|
+
const handleRowKeyDown = (e) => {
|
|
1754
|
+
if (e.repeat) return;
|
|
1755
|
+
if (e.key === "Enter") {
|
|
1756
|
+
e.preventDefault();
|
|
1757
|
+
onClick?.(task);
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
const handleRowKeyUp = (e) => {
|
|
1761
|
+
if (e.repeat) return;
|
|
1762
|
+
if (e.key === " ") {
|
|
1763
|
+
e.preventDefault();
|
|
1764
|
+
onClick?.(task);
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
const rowClassName = clsx(
|
|
1768
|
+
"task-row group grid w-full items-center border-b border-outline-variant text-left",
|
|
1769
|
+
"transition-colors duration-200 ease-standard",
|
|
1770
|
+
focusRing,
|
|
1771
|
+
"focus-visible:outline-offset-[-3px]",
|
|
1772
|
+
isActive ? "bg-secondary-container text-on-secondary-container" : "bg-transparent text-on-surface hover:bg-on-surface/8",
|
|
1773
|
+
isRowInteractive && !isActive && "active:bg-on-surface/10",
|
|
1774
|
+
className
|
|
1775
|
+
);
|
|
1776
|
+
const rowStyle = {
|
|
1777
|
+
gridTemplateColumns: TASK_ROW_GRID,
|
|
1778
|
+
minHeight: TASK_ROW_HEIGHT,
|
|
1779
|
+
paddingLeft: 16,
|
|
1780
|
+
paddingRight: 8,
|
|
1781
|
+
gap: 12
|
|
1782
|
+
};
|
|
1783
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1784
|
+
/* @__PURE__ */ jsx(TaskStatusIcon, { status: task.status, size: 20 }),
|
|
1785
|
+
/* @__PURE__ */ jsx(TaskPriorityIcon, { priority: task.priority, size: 18 }),
|
|
1786
|
+
/* @__PURE__ */ jsxs(
|
|
1787
|
+
"span",
|
|
1788
|
+
{
|
|
1789
|
+
className: clsx(
|
|
1790
|
+
"truncate font-code text-body-small",
|
|
1791
|
+
isActive ? "text-on-secondary-container" : "text-on-surface-variant"
|
|
1792
|
+
),
|
|
1793
|
+
children: [
|
|
1794
|
+
"SPC-",
|
|
1795
|
+
task.task_number
|
|
1796
|
+
]
|
|
1797
|
+
}
|
|
1798
|
+
),
|
|
1799
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-body-large", children: task.title }),
|
|
1800
|
+
/* @__PURE__ */ jsx(
|
|
1801
|
+
"span",
|
|
1802
|
+
{
|
|
1803
|
+
className: clsx(
|
|
1804
|
+
"text-right text-body-small",
|
|
1805
|
+
isActive ? "text-on-secondary-container" : "text-on-surface-variant"
|
|
1806
|
+
),
|
|
1807
|
+
children: task.subtasks.length > 0 ? `${completedSubtasks}/${task.subtasks.length}` : ""
|
|
1808
|
+
}
|
|
1809
|
+
),
|
|
1810
|
+
/* @__PURE__ */ jsx(
|
|
1811
|
+
"span",
|
|
1812
|
+
{
|
|
1813
|
+
className: clsx(
|
|
1814
|
+
"truncate text-right text-body-small",
|
|
1815
|
+
isActive ? "text-on-secondary-container" : "text-on-surface-variant"
|
|
1816
|
+
),
|
|
1817
|
+
children: assigneeName
|
|
1818
|
+
}
|
|
1819
|
+
),
|
|
1820
|
+
/* @__PURE__ */ jsx("span", { className: "flex items-center justify-center", children: hasActions ? /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
|
|
1821
|
+
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
1822
|
+
"button",
|
|
1823
|
+
{
|
|
1824
|
+
type: "button",
|
|
1825
|
+
"aria-label": "Task Actions",
|
|
1826
|
+
onClick: (e) => e.stopPropagation(),
|
|
1827
|
+
onKeyDown: (e) => {
|
|
1828
|
+
if (e.key === "Enter" || e.key === " ") e.stopPropagation();
|
|
1829
|
+
},
|
|
1830
|
+
className: clsx(
|
|
1831
|
+
"flex size-8 items-center justify-center rounded-full text-on-surface-variant",
|
|
1832
|
+
"opacity-0 transition-[opacity,background-color] duration-200 ease-standard",
|
|
1833
|
+
"hover:bg-on-surface/8 active:bg-on-surface/10",
|
|
1834
|
+
"group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 data-popup-open:opacity-100",
|
|
1835
|
+
focusRing
|
|
1836
|
+
),
|
|
1837
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "more_vert", size: 20 })
|
|
1838
|
+
}
|
|
1839
|
+
) }),
|
|
1840
|
+
/* @__PURE__ */ jsxs(DropdownMenu.Content, { align: "end", sideOffset: 4, children: [
|
|
1841
|
+
onStatusChange && TASK_STATUS_ORDER.filter((s) => s !== task.status).map((s) => /* @__PURE__ */ jsxs(
|
|
1842
|
+
DropdownMenu.Item,
|
|
1843
|
+
{
|
|
1844
|
+
onClick: (e) => {
|
|
1845
|
+
e.stopPropagation();
|
|
1846
|
+
onStatusChange(task, s);
|
|
1847
|
+
},
|
|
1848
|
+
children: [
|
|
1849
|
+
/* @__PURE__ */ jsx(TaskStatusIcon, { status: s, size: 20, label: "" }),
|
|
1850
|
+
/* @__PURE__ */ jsx("span", { children: TASK_STATUS_LABEL[s] })
|
|
1851
|
+
]
|
|
1852
|
+
},
|
|
1853
|
+
s
|
|
1854
|
+
)),
|
|
1855
|
+
onStatusChange && onDelete && /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
|
|
1856
|
+
onDelete && /* @__PURE__ */ jsxs(
|
|
1857
|
+
DropdownMenu.Item,
|
|
1858
|
+
{
|
|
1859
|
+
onClick: (e) => {
|
|
1860
|
+
e.stopPropagation();
|
|
1861
|
+
onDelete(task);
|
|
1862
|
+
},
|
|
1863
|
+
className: "text-error",
|
|
1864
|
+
children: [
|
|
1865
|
+
/* @__PURE__ */ jsx(Icon, { name: "delete", size: 20 }),
|
|
1866
|
+
/* @__PURE__ */ jsx("span", { children: "Delete" })
|
|
1867
|
+
]
|
|
1868
|
+
}
|
|
1869
|
+
)
|
|
1870
|
+
] })
|
|
1871
|
+
] }) : null })
|
|
1872
|
+
] });
|
|
1873
|
+
if (!isRowInteractive) {
|
|
1874
|
+
return /* @__PURE__ */ jsx("div", { "aria-current": isActive ? "true" : void 0, className: rowClassName, style: rowStyle, children: content });
|
|
1875
|
+
}
|
|
1876
|
+
return /* @__PURE__ */ jsx(
|
|
1877
|
+
"div",
|
|
1878
|
+
{
|
|
1879
|
+
role: "button",
|
|
1880
|
+
tabIndex: 0,
|
|
1881
|
+
"aria-current": isActive ? "true" : void 0,
|
|
1882
|
+
onClick: () => onClick(task),
|
|
1883
|
+
onKeyDown: handleRowKeyDown,
|
|
1884
|
+
onKeyUp: handleRowKeyUp,
|
|
1885
|
+
className: rowClassName,
|
|
1886
|
+
style: rowStyle,
|
|
1887
|
+
children: content
|
|
1888
|
+
}
|
|
1889
|
+
);
|
|
1890
|
+
}
|
|
1891
|
+
var GRID_STYLE = {
|
|
1892
|
+
gridTemplateColumns: TASK_ROW_GRID,
|
|
1893
|
+
paddingLeft: 16,
|
|
1894
|
+
paddingRight: 8,
|
|
1895
|
+
gap: 12
|
|
1896
|
+
};
|
|
1897
|
+
function TaskList({
|
|
1898
|
+
tasks,
|
|
1899
|
+
groups = TASK_STATUS_ORDER,
|
|
1900
|
+
collapsedGroups,
|
|
1901
|
+
onToggleGroup,
|
|
1902
|
+
activeTaskId,
|
|
1903
|
+
onTaskClick,
|
|
1904
|
+
onStatusChange,
|
|
1905
|
+
onDelete,
|
|
1906
|
+
resolveAgentName,
|
|
1907
|
+
className
|
|
1908
|
+
}) {
|
|
1909
|
+
const grouped = useMemo(() => {
|
|
1910
|
+
const map = /* @__PURE__ */ new Map();
|
|
1911
|
+
for (const status of groups) map.set(status, []);
|
|
1912
|
+
for (const task of tasks) {
|
|
1913
|
+
const bucket = map.get(task.status);
|
|
1914
|
+
if (bucket) bucket.push(task);
|
|
1915
|
+
}
|
|
1916
|
+
return map;
|
|
1917
|
+
}, [tasks, groups]);
|
|
1918
|
+
return /* @__PURE__ */ jsxs("div", { className: clsx("flex flex-col bg-surface text-on-surface", className), children: [
|
|
1919
|
+
/* @__PURE__ */ jsxs(
|
|
1920
|
+
"div",
|
|
1921
|
+
{
|
|
1922
|
+
className: "grid items-center border-b border-outline-variant text-label-medium text-on-surface-variant",
|
|
1923
|
+
style: { ...GRID_STYLE, height: 32 },
|
|
1924
|
+
children: [
|
|
1925
|
+
/* @__PURE__ */ jsx("span", {}),
|
|
1926
|
+
/* @__PURE__ */ jsx("span", {}),
|
|
1927
|
+
/* @__PURE__ */ jsx("span", { children: "ID" }),
|
|
1928
|
+
/* @__PURE__ */ jsx("span", { children: "Title" }),
|
|
1929
|
+
/* @__PURE__ */ jsx("span", { className: "text-right", children: "Subs" }),
|
|
1930
|
+
/* @__PURE__ */ jsx("span", { className: "text-right", children: "Assignee" }),
|
|
1931
|
+
/* @__PURE__ */ jsx("span", {})
|
|
1932
|
+
]
|
|
1933
|
+
}
|
|
1934
|
+
),
|
|
1935
|
+
groups.map((status) => {
|
|
1936
|
+
const items = grouped.get(status) ?? [];
|
|
1937
|
+
const isOpen = !collapsedGroups?.has(status);
|
|
1938
|
+
return /* @__PURE__ */ jsxs(Collapsible, { open: isOpen, onOpenChange: () => onToggleGroup?.(status), children: [
|
|
1939
|
+
/* @__PURE__ */ jsxs(
|
|
1940
|
+
CollapsibleTrigger,
|
|
1941
|
+
{
|
|
1942
|
+
className: clsx(
|
|
1943
|
+
"grid w-full items-center rounded-none border-b border-outline-variant bg-surface-container-low",
|
|
1944
|
+
"text-title-small text-on-surface transition-colors duration-200 ease-standard",
|
|
1945
|
+
"hover:bg-on-surface/8 active:bg-on-surface/10",
|
|
1946
|
+
focusRing,
|
|
1947
|
+
"focus-visible:outline-offset-[-3px]"
|
|
1948
|
+
),
|
|
1949
|
+
style: { ...GRID_STYLE, height: 40 },
|
|
1950
|
+
children: [
|
|
1951
|
+
/* @__PURE__ */ jsx("span", { className: "flex items-center justify-center text-on-surface-variant", children: /* @__PURE__ */ jsx(
|
|
1952
|
+
Icon,
|
|
1953
|
+
{
|
|
1954
|
+
name: "chevron_right",
|
|
1955
|
+
size: 20,
|
|
1956
|
+
className: clsx(
|
|
1957
|
+
"shrink-0 transition-transform duration-300 ease-emphasized",
|
|
1958
|
+
isOpen && "rotate-90"
|
|
1959
|
+
)
|
|
1960
|
+
}
|
|
1961
|
+
) }),
|
|
1962
|
+
/* @__PURE__ */ jsx("span", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(TaskStatusIcon, { status, size: 18, label: "" }) }),
|
|
1963
|
+
/* @__PURE__ */ jsxs("span", { className: "col-span-5 flex items-center gap-1.5 text-left", children: [
|
|
1964
|
+
TASK_STATUS_LABEL[status],
|
|
1965
|
+
/* @__PURE__ */ jsxs("span", { className: "text-body-small text-on-surface-variant", children: [
|
|
1966
|
+
"(",
|
|
1967
|
+
items.length,
|
|
1968
|
+
")"
|
|
1969
|
+
] })
|
|
1970
|
+
] })
|
|
1971
|
+
]
|
|
1972
|
+
}
|
|
1973
|
+
),
|
|
1974
|
+
/* @__PURE__ */ jsx(CollapsibleContent, { children: items.length > 0 ? items.map((task) => /* @__PURE__ */ jsx(
|
|
1975
|
+
TaskRow,
|
|
1976
|
+
{
|
|
1977
|
+
task,
|
|
1978
|
+
isActive: task.id === activeTaskId,
|
|
1979
|
+
onClick: onTaskClick,
|
|
1980
|
+
onStatusChange,
|
|
1981
|
+
onDelete,
|
|
1982
|
+
resolveAgentName
|
|
1983
|
+
},
|
|
1984
|
+
task.id
|
|
1985
|
+
)) : /* @__PURE__ */ jsx("div", { className: "border-b border-outline-variant px-4 py-3 text-body-small text-on-surface-variant", children: "No tasks" }) })
|
|
1986
|
+
] }, status);
|
|
1987
|
+
})
|
|
1988
|
+
] });
|
|
1989
|
+
}
|
|
1990
|
+
function formatDate(iso) {
|
|
1991
|
+
return new Date(iso).toLocaleDateString(void 0, {
|
|
1992
|
+
year: "numeric",
|
|
1993
|
+
month: "short",
|
|
1994
|
+
day: "numeric",
|
|
1995
|
+
hour: "2-digit",
|
|
1996
|
+
minute: "2-digit"
|
|
1997
|
+
});
|
|
1998
|
+
}
|
|
1999
|
+
function Property({ label, children }) {
|
|
2000
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [
|
|
2001
|
+
/* @__PURE__ */ jsx("span", { className: "text-label-medium text-on-surface-variant", children: label }),
|
|
2002
|
+
/* @__PURE__ */ jsx("span", { className: "flex min-h-8 items-center gap-1.5 text-body-medium text-on-surface", children })
|
|
2003
|
+
] });
|
|
2004
|
+
}
|
|
2005
|
+
function TaskDetail({
|
|
2006
|
+
task,
|
|
2007
|
+
resolveAgentName,
|
|
2008
|
+
onStatusChange,
|
|
2009
|
+
onSubtaskToggle,
|
|
2010
|
+
onDelete,
|
|
2011
|
+
onClose,
|
|
2012
|
+
className
|
|
2013
|
+
}) {
|
|
2014
|
+
const ownerName = resolveAgentName?.(task.owner_agent_id) ?? task.owner_agent_id;
|
|
2015
|
+
const assigneeName = resolveAgentName?.(task.assigned_agent_id) ?? task.assigned_agent_id;
|
|
2016
|
+
const completedCount = task.subtasks.filter((s) => s.completed).length;
|
|
2017
|
+
return /* @__PURE__ */ jsxs("div", { className: clsx("flex flex-col gap-6 bg-surface p-6 text-on-surface", className), children: [
|
|
2018
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
2019
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2020
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-2", children: [
|
|
2021
|
+
/* @__PURE__ */ jsx(TaskStatusIcon, { status: task.status, size: 20 }),
|
|
2022
|
+
/* @__PURE__ */ jsx(TaskPriorityIcon, { priority: task.priority, size: 18 }),
|
|
2023
|
+
/* @__PURE__ */ jsxs("span", { className: "font-code text-body-small text-on-surface-variant", children: [
|
|
2024
|
+
"SPC-",
|
|
2025
|
+
task.task_number
|
|
2026
|
+
] })
|
|
2027
|
+
] }),
|
|
2028
|
+
onClose && /* @__PURE__ */ jsx(CircleButton, { icon: "close", variant: "standard", onClick: onClose, "aria-label": "Close" })
|
|
2029
|
+
] }),
|
|
2030
|
+
/* @__PURE__ */ jsx("h2", { className: "text-headline-small text-on-surface", children: task.title })
|
|
2031
|
+
] }),
|
|
2032
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-6 gap-y-4 medium:grid-cols-4", children: [
|
|
2033
|
+
/* @__PURE__ */ jsx(Property, { label: "Status", children: onStatusChange ? /* @__PURE__ */ jsx(
|
|
2034
|
+
Select,
|
|
2035
|
+
{
|
|
2036
|
+
value: task.status,
|
|
2037
|
+
size: "md",
|
|
2038
|
+
onChange: (value) => onStatusChange(task, value),
|
|
2039
|
+
children: TASK_STATUS_ORDER.map((s) => /* @__PURE__ */ jsx(SelectOption, { value: s, children: TASK_STATUS_LABEL[s] }, s))
|
|
2040
|
+
}
|
|
2041
|
+
) : TASK_STATUS_LABEL[task.status] }),
|
|
2042
|
+
/* @__PURE__ */ jsxs(Property, { label: "Priority", children: [
|
|
2043
|
+
/* @__PURE__ */ jsx(TaskPriorityIcon, { priority: task.priority, size: 18, label: "" }),
|
|
2044
|
+
TASK_PRIORITY_LABEL[task.priority]
|
|
2045
|
+
] }),
|
|
2046
|
+
/* @__PURE__ */ jsx(Property, { label: "Owner", children: /* @__PURE__ */ jsx("span", { className: "truncate", children: ownerName }) }),
|
|
2047
|
+
/* @__PURE__ */ jsx(Property, { label: "Assigned", children: /* @__PURE__ */ jsx("span", { className: "truncate", children: assigneeName }) })
|
|
2048
|
+
] }),
|
|
2049
|
+
task.subtasks.length > 0 && /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-2", children: [
|
|
2050
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2051
|
+
/* @__PURE__ */ jsx("h3", { className: "text-title-small text-on-surface", children: "Subtasks" }),
|
|
2052
|
+
/* @__PURE__ */ jsxs("span", { className: "text-body-small text-on-surface-variant", children: [
|
|
2053
|
+
completedCount,
|
|
2054
|
+
"/",
|
|
2055
|
+
task.subtasks.length
|
|
2056
|
+
] })
|
|
2057
|
+
] }),
|
|
2058
|
+
/* @__PURE__ */ jsx("ul", { className: "m-0 list-none overflow-hidden rounded-medium border border-outline-variant p-0", children: task.subtasks.map((subtask, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
2059
|
+
"button",
|
|
2060
|
+
{
|
|
2061
|
+
type: "button",
|
|
2062
|
+
role: "checkbox",
|
|
2063
|
+
"aria-checked": subtask.completed,
|
|
2064
|
+
onClick: () => onSubtaskToggle?.(task, i, !subtask.completed),
|
|
2065
|
+
className: clsx(
|
|
2066
|
+
"flex min-h-12 w-full items-center gap-4 px-4 py-2 text-left text-body-large",
|
|
2067
|
+
"transition-colors duration-200 ease-standard hover:bg-on-surface/8 active:bg-on-surface/10",
|
|
2068
|
+
focusRing,
|
|
2069
|
+
"focus-visible:outline-offset-[-3px]",
|
|
2070
|
+
i > 0 && "border-t border-outline-variant"
|
|
2071
|
+
),
|
|
2072
|
+
children: [
|
|
2073
|
+
/* @__PURE__ */ jsx(
|
|
2074
|
+
"span",
|
|
2075
|
+
{
|
|
2076
|
+
className: clsx(
|
|
2077
|
+
"flex size-[18px] shrink-0 items-center justify-center rounded-[2px] transition-colors duration-200 ease-standard",
|
|
2078
|
+
subtask.completed ? "bg-primary text-on-primary" : "border-2 border-on-surface-variant"
|
|
2079
|
+
),
|
|
2080
|
+
children: subtask.completed && /* @__PURE__ */ jsx(Icon, { name: "check", size: 16, weight: 700 })
|
|
2081
|
+
}
|
|
2082
|
+
),
|
|
2083
|
+
/* @__PURE__ */ jsx(
|
|
2084
|
+
"span",
|
|
2085
|
+
{
|
|
2086
|
+
className: clsx(
|
|
2087
|
+
"min-w-0 flex-1",
|
|
2088
|
+
subtask.completed ? "text-on-surface-variant line-through" : "text-on-surface"
|
|
2089
|
+
),
|
|
2090
|
+
children: subtask.title
|
|
2091
|
+
}
|
|
2092
|
+
)
|
|
2093
|
+
]
|
|
2094
|
+
}
|
|
2095
|
+
) }, subtask.title)) })
|
|
2096
|
+
] }),
|
|
2097
|
+
/* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-2", children: [
|
|
2098
|
+
/* @__PURE__ */ jsx("h3", { className: "text-title-small text-on-surface", children: "Description" }),
|
|
2099
|
+
task.description ? /* @__PURE__ */ jsx(Markdown, { content: task.description, size: "medium" }) : /* @__PURE__ */ jsx("p", { className: "text-body-medium text-on-surface-variant", children: "No description" })
|
|
2100
|
+
] }),
|
|
2101
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 text-body-small text-on-surface-variant", children: [
|
|
2102
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2103
|
+
"Created ",
|
|
2104
|
+
formatDate(task.created_at)
|
|
2105
|
+
] }),
|
|
2106
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2107
|
+
"Updated ",
|
|
2108
|
+
formatDate(task.updated_at)
|
|
2109
|
+
] }),
|
|
2110
|
+
task.completed_at && /* @__PURE__ */ jsxs("span", { children: [
|
|
2111
|
+
"Completed ",
|
|
2112
|
+
formatDate(task.completed_at)
|
|
2113
|
+
] })
|
|
2114
|
+
] }),
|
|
2115
|
+
(onStatusChange || onDelete) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
2116
|
+
onStatusChange && task.status === "pending_approval" && /* @__PURE__ */ jsx(Button, { variant: "filled", size: "lg", onClick: () => onStatusChange(task, "ready"), children: "Approve" }),
|
|
2117
|
+
onStatusChange && task.status === "backlog" && /* @__PURE__ */ jsx(Button, { variant: "filled", size: "lg", onClick: () => onStatusChange(task, "in_progress"), children: "Execute" }),
|
|
2118
|
+
onStatusChange && (task.status === "in_progress" || task.status === "ready") && /* @__PURE__ */ jsx(Button, { variant: "filled", size: "lg", onClick: () => onStatusChange(task, "done"), children: "Mark Done" }),
|
|
2119
|
+
onStatusChange && task.status === "done" && /* @__PURE__ */ jsx(Button, { variant: "text", size: "lg", onClick: () => onStatusChange(task, "ready"), children: "Reopen" }),
|
|
2120
|
+
onDelete && /* @__PURE__ */ jsxs(
|
|
2121
|
+
"button",
|
|
2122
|
+
{
|
|
2123
|
+
type: "button",
|
|
2124
|
+
onClick: () => onDelete(task),
|
|
2125
|
+
className: clsx(
|
|
2126
|
+
"inline-flex h-10 items-center justify-center gap-2 rounded-full px-3 text-label-large text-error",
|
|
2127
|
+
"transition-colors duration-200 ease-standard hover:bg-error/8 active:bg-error/10",
|
|
2128
|
+
focusRing
|
|
2129
|
+
),
|
|
2130
|
+
children: [
|
|
2131
|
+
/* @__PURE__ */ jsx(Icon, { name: "delete", size: 18 }),
|
|
2132
|
+
"Delete"
|
|
2133
|
+
]
|
|
2134
|
+
}
|
|
2135
|
+
)
|
|
2136
|
+
] })
|
|
2137
|
+
] });
|
|
2138
|
+
}
|
|
2139
|
+
var PRIORITIES = ["critical", "high", "medium", "low"];
|
|
2140
|
+
function TaskCreateForm({
|
|
2141
|
+
onSubmit,
|
|
2142
|
+
onCancel,
|
|
2143
|
+
defaultPriority = "medium",
|
|
2144
|
+
isSubmitting,
|
|
2145
|
+
className
|
|
2146
|
+
}) {
|
|
2147
|
+
const [title, setTitle] = useState("");
|
|
2148
|
+
const [description, setDescription] = useState("");
|
|
2149
|
+
const [priority, setPriority] = useState(defaultPriority);
|
|
2150
|
+
const titleInputId = useId();
|
|
2151
|
+
const descriptionInputId = useId();
|
|
2152
|
+
const titleInputRef = useRef(null);
|
|
2153
|
+
useEffect(() => {
|
|
2154
|
+
titleInputRef.current?.focus();
|
|
2155
|
+
}, []);
|
|
2156
|
+
const canSubmit = title.trim().length > 0 && !isSubmitting;
|
|
2157
|
+
const handleSubmit = useCallback(() => {
|
|
2158
|
+
if (!canSubmit) return;
|
|
2159
|
+
onSubmit({ title: title.trim(), description: description.trim(), priority });
|
|
2160
|
+
setTitle("");
|
|
2161
|
+
setDescription("");
|
|
2162
|
+
setPriority(defaultPriority);
|
|
2163
|
+
}, [canSubmit, onSubmit, title, description, priority, defaultPriority]);
|
|
2164
|
+
return /* @__PURE__ */ jsxs(
|
|
2165
|
+
"div",
|
|
2166
|
+
{
|
|
2167
|
+
className: clsx(
|
|
2168
|
+
"flex flex-col gap-3 rounded-medium bg-surface-container-low p-4 text-on-surface",
|
|
2169
|
+
className
|
|
2170
|
+
),
|
|
2171
|
+
children: [
|
|
2172
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2173
|
+
/* @__PURE__ */ jsx("label", { htmlFor: titleInputId, className: "sr-only", children: "Task Title" }),
|
|
2174
|
+
/* @__PURE__ */ jsx(
|
|
2175
|
+
Input,
|
|
2176
|
+
{
|
|
2177
|
+
ref: titleInputRef,
|
|
2178
|
+
id: titleInputId,
|
|
2179
|
+
type: "text",
|
|
2180
|
+
size: "lg",
|
|
2181
|
+
value: title,
|
|
2182
|
+
onChange: (e) => setTitle(e.target.value),
|
|
2183
|
+
onKeyDown: (e) => {
|
|
2184
|
+
if (e.key === "Enter") handleSubmit();
|
|
2185
|
+
if (e.key === "Escape") onCancel?.();
|
|
2186
|
+
},
|
|
2187
|
+
placeholder: "Task title...",
|
|
2188
|
+
className: "min-w-0 flex-1",
|
|
2189
|
+
disabled: isSubmitting
|
|
2190
|
+
}
|
|
2191
|
+
),
|
|
2192
|
+
/* @__PURE__ */ jsx(
|
|
2193
|
+
Select,
|
|
2194
|
+
{
|
|
2195
|
+
value: priority,
|
|
2196
|
+
size: "lg",
|
|
2197
|
+
onChange: (value) => setPriority(value),
|
|
2198
|
+
disabled: isSubmitting,
|
|
2199
|
+
children: PRIORITIES.map((p) => /* @__PURE__ */ jsx(SelectOption, { value: p, children: TASK_PRIORITY_LABEL[p] }, p))
|
|
2200
|
+
}
|
|
2201
|
+
)
|
|
2202
|
+
] }),
|
|
2203
|
+
/* @__PURE__ */ jsx("label", { htmlFor: descriptionInputId, className: "sr-only", children: "Description" }),
|
|
2204
|
+
/* @__PURE__ */ jsx(
|
|
2205
|
+
TextArea,
|
|
2206
|
+
{
|
|
2207
|
+
id: descriptionInputId,
|
|
2208
|
+
value: description,
|
|
2209
|
+
onChange: (e) => setDescription(e.target.value),
|
|
2210
|
+
placeholder: "Description (optional)",
|
|
2211
|
+
rows: 2,
|
|
2212
|
+
className: "w-full resize-none",
|
|
2213
|
+
disabled: isSubmitting
|
|
2214
|
+
}
|
|
2215
|
+
),
|
|
2216
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
|
|
2217
|
+
onCancel && /* @__PURE__ */ jsx(Button, { variant: "text", size: "lg", onClick: onCancel, disabled: isSubmitting, children: "Cancel" }),
|
|
2218
|
+
/* @__PURE__ */ jsx(Button, { variant: "filled", size: "lg", disabled: !canSubmit, onClick: handleSubmit, children: "Create" })
|
|
2219
|
+
] })
|
|
2220
|
+
]
|
|
2221
|
+
}
|
|
2222
|
+
);
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
export { ChatComposer, InlineBranchCard, InlineWorkerCard, Markdown, MessageBubble, ModelOptionList, ModelSelector, TASK_PRIORITY_LABEL, TASK_STATUS_LABEL, TASK_STATUS_ORDER, TaskCreateForm, TaskDetail, TaskList, TaskPriorityIcon, TaskRow, TaskStatusIcon, ToolCall, groupModelsByProvider, isErrorResult, pairTranscriptSteps, tryParseJson };
|
|
2226
|
+
//# sourceMappingURL=index.js.map
|
|
2227
|
+
//# sourceMappingURL=index.js.map
|