@workerdeck/ui 0.11.0 → 0.13.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.
Files changed (35) hide show
  1. package/build/{SessionPanel-_U8tjX29.mjs → SessionPanel-CKQa4i0Y.mjs} +337 -269
  2. package/build/SessionPanel-CKQa4i0Y.mjs.map +1 -0
  3. package/build/{SessionPanel-CyhygZx_.d.mts → SessionPanel-CZMA44NM.d.mts} +73 -2
  4. package/build/format.d.mts +65 -1
  5. package/build/format.mjs +118 -1
  6. package/build/format.mjs.map +1 -0
  7. package/build/index.d.mts +129 -10
  8. package/build/index.mjs +461 -5
  9. package/build/index.mjs.map +1 -1
  10. package/build/workspace.d.mts +36 -1
  11. package/build/workspace.mjs +16 -2
  12. package/build/workspace.mjs.map +1 -1
  13. package/package.json +4 -4
  14. package/src/components/agent/Composer.tsx +18 -10
  15. package/src/components/agent/EngineIcon.tsx +97 -0
  16. package/src/components/agent/Loader.tsx +11 -46
  17. package/src/components/agent/Message.tsx +10 -6
  18. package/src/components/agent/QuestionPrompt.tsx +1 -1
  19. package/src/components/agent/SessionBrowser.tsx +546 -0
  20. package/src/components/agent/SessionPanel.tsx +89 -14
  21. package/src/components/agent/SessionWorkspace.tsx +45 -0
  22. package/src/components/agent/StatusBar.tsx +9 -2
  23. package/src/components/agent/ToolCallCard.tsx +11 -2
  24. package/src/components/agent/Transcript.tsx +28 -11
  25. package/src/components/agent/line-prompt.tsx +2 -2
  26. package/src/components/agent/pulse.tsx +60 -0
  27. package/src/components/agent/transcript-variant.tsx +62 -0
  28. package/src/components/ui/Menu.tsx +1 -1
  29. package/src/components/ui/Select.tsx +1 -1
  30. package/src/components/ui/Tooltip.tsx +1 -1
  31. package/src/format.ts +1 -0
  32. package/src/index.ts +12 -0
  33. package/src/lib/status.ts +124 -0
  34. package/src/styles/theme.css +45 -15
  35. package/build/SessionPanel-_U8tjX29.mjs.map +0 -1
package/build/index.mjs CHANGED
@@ -1,10 +1,11 @@
1
- import { $ as TooltipProvider, A as permissionModeMeta, B as mentionTrigger, C as TranscriptVariantProvider, Ct as cn, D as PERMISSION_MODES, E as toolIcon, F as ContextDialog, G as ProgressRing, H as PromptArea, I as Composer, J as Spinner, K as Splitter, L as skillPrompt, M as SkillsDialog, N as McpDialog, O as PermissionModeSelect, P as HostFilesDialog, Q as TooltipContent, R as commandTrigger, S as Response, St as buttonVariants, T as isMutatingTool, U as plainTextToSegments, V as usePromptAreaState, W as segmentsToPlainText, X as copyText, Y as CopyButton, Z as Tip, _ as SessionInfoDialog, _t as SelectValue, a as SessionEmptyState, at as DialogRow, b as parseUserQuestions, bt as badgeVariants, c as Message, ct as MenuContent, d as FileCard, dt as MenuTrigger, et as Dialog, f as Conversation, ft as Select, g as STATUS_META, gt as SelectTrigger, h as StatusBar, ht as SelectItemText, i as ToolCallCard, it as DialogHeader, j as ModelSelect, k as permissionModeChoices, l as MessageContent, lt as MenuItem, m as ConversationScrollButton, mt as SelectItem, n as UsageDialog, nt as DialogClose, o as Reasoning, ot as DialogTrigger, p as ConversationContent, pt as SelectContent, q as CodeBlock, r as Transcript, rt as DialogContent, s as PromptTokenText, st as Menu, t as SessionPanel, tt as DialogBody, u as Loader, ut as MenuSeparator, v as QUESTION_BEHAVIORS, vt as Input, w as useTranscriptVariant, x as PermissionPrompt, xt as Button, y as QuestionPrompt, yt as Badge, z as hashtagTrigger } from "./SessionPanel-_U8tjX29.mjs";
1
+ import { $ as Tip, A as SkillsDialog, B as commandTrigger, C as isMutatingTool, Ct as Button, D as permissionModeChoices, E as PermissionModeSelect, F as skillPrompt, G as plainTextToSegments, H as mentionTrigger, I as TranscriptDensityProvider, J as Splitter, K as segmentsToPlainText, L as TranscriptVariantProvider, M as HostFilesDialog, N as ContextDialog, O as permissionModeMeta, P as Composer, Q as copyText, R as useTranscriptDensity, S as Response, St as badgeVariants, T as PERMISSION_MODES, Tt as cn, U as usePromptAreaState, V as hashtagTrigger, W as PromptArea, X as Spinner, Y as CodeBlock, Z as CopyButton, _ as SessionInfoDialog, _t as SelectItemText, a as SessionEmptyState, at as DialogContent, b as parseUserQuestions, bt as Input, c as Message, ct as DialogTrigger, d as FileCard, dt as MenuItem, et as TooltipContent, f as Conversation, ft as MenuSeparator, g as STATUS_META, gt as SelectItem, h as StatusBar, ht as SelectContent, i as ToolCallCard, it as DialogClose, j as McpDialog, k as ModelSelect, l as MessageContent, lt as Menu, m as ConversationScrollButton, mt as Select, n as UsageDialog, nt as Dialog, o as Reasoning, ot as DialogHeader, p as ConversationContent, pt as MenuTrigger, q as ProgressRing, r as Transcript, rt as DialogBody, s as PromptTokenText, st as DialogRow, t as SessionPanel, tt as TooltipProvider, u as Loader, ut as MenuContent, v as QUESTION_BEHAVIORS, vt as SelectTrigger, w as toolIcon, wt as buttonVariants, x as PermissionPrompt, xt as Badge, y as QuestionPrompt, yt as SelectValue, z as useTranscriptVariant } from "./SessionPanel-CKQa4i0Y.mjs";
2
2
  import { a as formatDuration, c as formatRelativeTime, d as rateLimitWindowSeconds, f as toolInputPreview, i as formatCountdown, l as formatTokens, n as formatBytes, o as formatRateLimitWindow, r as formatCost, s as formatRateLimitWindowLong, t as formatAgoPrecise, u as friendlyModel } from "./format-DqR56Y8l.mjs";
3
- import { forwardRef } from "react";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
- import { Trash2 } from "lucide-react";
3
+ import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
4
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
+ import { BellRing, CircleAlert, CircleSlash, Moon, PauseCircle, Pencil, Search, Trash2, X } from "lucide-react";
6
6
  import { AlertDialog as AlertDialog$1 } from "@base-ui/react/alert-dialog";
7
7
  import { Toaster as Toaster$1, toast } from "sonner";
8
+ import { STATE_LABELS, STATE_ORDER, adaptersOf, clearFilters, filterRows, groupRows, hasFacetFilter, sessionLabel, subsetSummary } from "@workerdeck/protocol";
8
9
  //#region src/components/ui/Card.tsx
9
10
  function Card({ className, ...props }) {
10
11
  return /* @__PURE__ */ jsx("div", {
@@ -156,6 +157,461 @@ function SessionList({ sessions, activeId, onSelect, onDelete, emptyText = "No s
156
157
  });
157
158
  }
158
159
  //#endregion
159
- export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, Button, Card, CardContent, CardHeader, CardTitle, CodeBlock, Composer, ContextDialog, Conversation, ConversationContent, ConversationScrollButton, CopyButton, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, FileCard, HostFilesDialog, Input, Loader, McpDialog, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, ModelSelect, PERMISSION_MODES, PermissionModeSelect, PermissionPrompt, ProgressRing, PromptArea, PromptTokenText, QUESTION_BEHAVIORS, QuestionPrompt, Reasoning, Response, STATUS_META, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionEmptyState, SessionInfoDialog, SessionList, SessionListItem, SessionPanel, SkillsDialog, Spinner, Splitter, StatusBar, Textarea, Tip, Toaster, ToolCallCard, TooltipContent, TooltipProvider, Transcript, TranscriptVariantProvider, UsageDialog, badgeVariants, buttonVariants, cn, commandTrigger, copyText, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, mentionTrigger, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, rateLimitWindowSeconds, segmentsToPlainText, skillPrompt, toast, toolIcon, toolInputPreview, usePromptAreaState, useTranscriptVariant };
160
+ //#region src/components/agent/SessionBrowser.tsx
161
+ /**
162
+ * How a list row is drawn, in one place, so `SidebarRow` in `web` matches this
163
+ * exactly rather than approximating it — the dashboard's other three sidebars
164
+ * are that component, and a sessions list that hovered differently from the
165
+ * gateways list beside it would read as a different product.
166
+ *
167
+ * Two rules are load-bearing:
168
+ *
169
+ * - **Fill means hover, and only hover.** It stays on the row whether or not
170
+ * the row is selected, because a selected row still has to answer the
171
+ * pointer. Selection gets the gutter instead.
172
+ * - **`ml-0` on the selected row is not cosmetic.** It hands the accent border
173
+ * the 4px the margin was holding, so the text does not shift sideways as a
174
+ * row becomes the selected one. The squared left corners are what let the bar
175
+ * sit flush against the sidebar edge.
176
+ */
177
+ function rowShapeClass(active) {
178
+ return cn("px-2 py-1.5 hover:bg-row-hover", active ? "mr-1 ml-0 rounded-r-md border-l-4 border-l-accent" : "mx-1 rounded-md");
179
+ }
180
+ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelect, onDelete, onRename, emptyState, showControls = true, className }) {
181
+ const visible = useMemo(() => filterRows(rows, config, scope), [
182
+ rows,
183
+ config,
184
+ scope
185
+ ]);
186
+ const groups = useMemo(() => groupRows(visible, config), [visible, config]);
187
+ const subset = subsetSummary(config, scope, visible.length, rows.length);
188
+ const adapters = useMemo(() => adaptersOf(rows), [rows]);
189
+ const gateways = useMemo(() => {
190
+ const seen = /* @__PURE__ */ new Map();
191
+ for (const row of rows) seen.set(row.hostId, row.hostName);
192
+ return [...seen].map(([id, name]) => ({
193
+ id,
194
+ name
195
+ }));
196
+ }, [rows]);
197
+ const set = (patch) => onConfigChange({
198
+ ...config,
199
+ ...patch
200
+ });
201
+ return /* @__PURE__ */ jsxs("div", {
202
+ "data-slot": "session-browser",
203
+ className: cn("flex flex-col gap-3", className),
204
+ children: [
205
+ /* @__PURE__ */ jsxs("div", {
206
+ className: cn("flex flex-col gap-1.5 px-2", !showControls && "hidden"),
207
+ children: [
208
+ /* @__PURE__ */ jsxs("div", {
209
+ className: "relative",
210
+ children: [/* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-fg-4" }), /* @__PURE__ */ jsx(Input, {
211
+ value: config.search,
212
+ onChange: (e) => set({ search: e.target.value }),
213
+ placeholder: "Search sessions",
214
+ "aria-label": "Search sessions",
215
+ className: "pl-8"
216
+ })]
217
+ }),
218
+ /* @__PURE__ */ jsx(FilterRow, {
219
+ label: "State",
220
+ children: /* @__PURE__ */ jsx(FacetSelect, {
221
+ label: "State",
222
+ value: config.states,
223
+ options: STATE_ORDER.map((s) => ({
224
+ value: s,
225
+ label: STATE_LABELS[s]
226
+ })),
227
+ onChange: (states) => set({ states })
228
+ })
229
+ }),
230
+ adapters.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
231
+ label: "Engine",
232
+ children: /* @__PURE__ */ jsx(FacetSelect, {
233
+ label: "Engine",
234
+ value: config.adapters,
235
+ options: adapters.map((a) => ({
236
+ value: a,
237
+ label: a
238
+ })),
239
+ onChange: (adapters) => set({ adapters })
240
+ })
241
+ }) : null,
242
+ gateways.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
243
+ label: "Gateway",
244
+ children: /* @__PURE__ */ jsx(FacetSelect, {
245
+ label: "Gateway",
246
+ value: config.gateways,
247
+ options: gateways.map((g) => ({
248
+ value: g.id,
249
+ label: g.name
250
+ })),
251
+ onChange: (gateways) => set({ gateways })
252
+ })
253
+ }) : null,
254
+ /* @__PURE__ */ jsx(FilterRow, {
255
+ label: "Group",
256
+ children: /* @__PURE__ */ jsx(OneOfSelect, {
257
+ label: "Group",
258
+ value: config.groupBy,
259
+ options: [
260
+ {
261
+ value: "none",
262
+ label: "No grouping"
263
+ },
264
+ {
265
+ value: "state",
266
+ label: "By state"
267
+ },
268
+ {
269
+ value: "adapter",
270
+ label: "By engine"
271
+ },
272
+ ...gateways.length > 1 ? [{
273
+ value: "gateway",
274
+ label: "By gateway"
275
+ }] : []
276
+ ],
277
+ onChange: (groupBy) => set({ groupBy })
278
+ })
279
+ }),
280
+ /* @__PURE__ */ jsx(FilterRow, {
281
+ label: "Sort",
282
+ children: /* @__PURE__ */ jsx(OneOfSelect, {
283
+ label: "Sort",
284
+ value: config.sortBy,
285
+ options: [
286
+ {
287
+ value: "recent",
288
+ label: "Recent"
289
+ },
290
+ {
291
+ value: "name",
292
+ label: "Name"
293
+ },
294
+ {
295
+ value: "state",
296
+ label: "State"
297
+ },
298
+ ...gateways.length > 1 ? [{
299
+ value: "gateway",
300
+ label: "Gateway"
301
+ }] : []
302
+ ],
303
+ onChange: (sortBy) => set({ sortBy })
304
+ })
305
+ })
306
+ ]
307
+ }),
308
+ subset ? /* @__PURE__ */ jsxs("div", {
309
+ className: "flex items-center gap-2 px-3 text-label text-fg-4",
310
+ children: [/* @__PURE__ */ jsxs("span", { children: [
311
+ subset.shown,
312
+ " of ",
313
+ subset.total,
314
+ subset.causes.length ? ` · ${subset.causes.join(" · ")}` : null
315
+ ] }), /* @__PURE__ */ jsx("button", {
316
+ type: "button",
317
+ className: "text-fg-3 underline underline-offset-2 hover:text-fg-1",
318
+ onClick: () => onConfigChange(clearFilters(config)),
319
+ children: "Show all"
320
+ })]
321
+ }) : null,
322
+ rows.length === 0 ? emptyState ?? /* @__PURE__ */ jsx(Empty, { children: "No sessions yet." }) : visible.length === 0 ? /* @__PURE__ */ jsx(Empty, { children: hasFacetFilter(config) ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
323
+ "No sessions match.",
324
+ " ",
325
+ /* @__PURE__ */ jsx("button", {
326
+ type: "button",
327
+ className: "underline underline-offset-2 hover:text-fg-1",
328
+ onClick: () => onConfigChange(clearFilters(config)),
329
+ children: "Clear filters"
330
+ })
331
+ ] }) : "No sessions here." }) : /* @__PURE__ */ jsx("div", {
332
+ className: "flex flex-col gap-4",
333
+ children: groups.map((group) => /* @__PURE__ */ jsxs("div", {
334
+ className: "flex flex-col gap-1",
335
+ children: [config.groupBy !== "none" && group.label ? /* @__PURE__ */ jsxs("div", {
336
+ className: "flex items-baseline gap-2 px-3 text-label font-medium text-fg-4",
337
+ children: [/* @__PURE__ */ jsx("span", {
338
+ className: "uppercase tracking-wide",
339
+ children: group.label
340
+ }), /* @__PURE__ */ jsx("span", {
341
+ className: "text-fg-4/70",
342
+ children: group.rows.length
343
+ })]
344
+ }) : null, group.rows.map((row) => /* @__PURE__ */ jsx(SessionRowItem, {
345
+ row,
346
+ active: row.info.id === activeId,
347
+ showGateway: gateways.length > 1,
348
+ onSelect,
349
+ onDelete,
350
+ onRename
351
+ }, `${row.hostId}:${row.info.id}`))]
352
+ }, group.key))
353
+ })
354
+ ]
355
+ });
356
+ }
357
+ function Empty({ children }) {
358
+ return /* @__PURE__ */ jsx("div", {
359
+ className: "px-3 py-6 text-center text-body-sm text-fg-4",
360
+ children
361
+ });
362
+ }
363
+ function SessionRowItem({ row, active, showGateway, onSelect, onDelete, onRename }) {
364
+ const { info } = row;
365
+ const [editing, setEditing] = useState(false);
366
+ const folder = info.cwd.split("/").filter(Boolean).pop() ?? info.cwd;
367
+ const details = [
368
+ showGateway ? row.hostName : void 0,
369
+ friendlyModel(info.model),
370
+ folder,
371
+ info.profile ? `@${info.profile}` : void 0,
372
+ formatCost(info.totalCostUsd)
373
+ ].filter(Boolean);
374
+ return /* @__PURE__ */ jsxs("div", {
375
+ "data-slot": "session-row",
376
+ "data-active": active || void 0,
377
+ className: cn("group flex cursor-pointer flex-col gap-0.5 text-left transition-colors", rowShapeClass(active === true)),
378
+ children: [/* @__PURE__ */ jsxs("div", {
379
+ className: "flex items-center gap-1.5",
380
+ children: [
381
+ editing && onRename ? /* @__PURE__ */ jsx(NameEditor, {
382
+ initial: info.title ?? "",
383
+ onCommit: (title) => {
384
+ setEditing(false);
385
+ onRename(row, title);
386
+ },
387
+ onCancel: () => setEditing(false)
388
+ }) : /* @__PURE__ */ jsx("button", {
389
+ type: "button",
390
+ onClick: () => onSelect?.(row),
391
+ className: cn("min-w-0 flex-1 truncate text-left text-body-sm outline-none", active ? "font-medium text-fg-1" : "text-fg-2"),
392
+ children: sessionLabel(info)
393
+ }),
394
+ row.unseen > 0 ? /* @__PURE__ */ jsx("span", {
395
+ title: `${row.unseen} new`,
396
+ className: "shrink-0 rounded-full bg-accent px-1.5 text-label text-accent-fg",
397
+ children: row.unseen
398
+ }) : null,
399
+ /* @__PURE__ */ jsx("span", {
400
+ className: "shrink-0 text-label text-fg-4",
401
+ children: formatRelativeTime(info.lastActivityAt ?? info.createdAt)
402
+ }),
403
+ /* @__PURE__ */ jsx(SessionStatusIcon, { row })
404
+ ]
405
+ }), /* @__PURE__ */ jsxs("div", {
406
+ className: "flex items-center gap-1 text-label text-fg-4",
407
+ children: [
408
+ /* @__PURE__ */ jsx("button", {
409
+ type: "button",
410
+ onClick: () => !editing && onSelect?.(row),
411
+ className: "min-w-0 flex-1 truncate text-left font-mono outline-none",
412
+ children: details.join(" · ")
413
+ }),
414
+ onRename && !editing ? /* @__PURE__ */ jsx(Button, {
415
+ variant: "ghost",
416
+ size: "icon-sm",
417
+ "aria-label": "Rename session",
418
+ className: "size-5 shrink-0 opacity-0 transition-opacity group-hover:opacity-100",
419
+ onClick: () => setEditing(true),
420
+ children: /* @__PURE__ */ jsx(Pencil, { className: "size-3 text-fg-3" })
421
+ }) : null,
422
+ onDelete ? /* @__PURE__ */ jsx(Button, {
423
+ variant: "ghost",
424
+ size: "icon-sm",
425
+ "aria-label": "Close session",
426
+ className: "size-5 shrink-0 opacity-0 transition-opacity group-hover:opacity-100",
427
+ onClick: () => onDelete(row),
428
+ children: /* @__PURE__ */ jsx(Trash2, { className: "size-3 text-fg-3" })
429
+ }) : null
430
+ ]
431
+ })]
432
+ });
433
+ }
434
+ /**
435
+ * State as one glyph on the right edge — a ringing bell when it wants a human, a
436
+ * spinner while it works, a moon when it is only sleeping. Replaces the text
437
+ * badge: in a sidebar the word costs more room than it earns, and the states
438
+ * that matter are the two you can recognise without reading.
439
+ */
440
+ function SessionStatusIcon({ row }) {
441
+ const { info } = row;
442
+ if (info.pendingPermissionCount > 0 || info.status === "awaiting_approval") return /* @__PURE__ */ jsx(BellRing, { className: "size-3.5 shrink-0 animate-pulse text-warning" });
443
+ if (info.status === "running" || info.status === "starting") return /* @__PURE__ */ jsx(Spinner, { className: "size-3.5 shrink-0 text-info" });
444
+ switch (info.status) {
445
+ case "failed": return /* @__PURE__ */ jsx(CircleAlert, { className: "size-3.5 shrink-0 text-danger" });
446
+ case "closed": return /* @__PURE__ */ jsx(CircleSlash, { className: "size-3.5 shrink-0 text-fg-4" });
447
+ case "parked": return /* @__PURE__ */ jsx(PauseCircle, { className: "size-3.5 shrink-0 text-fg-3" });
448
+ default: return /* @__PURE__ */ jsx(Moon, { className: "size-3.5 shrink-0 text-fg-4" });
449
+ }
450
+ }
451
+ /**
452
+ * Inline rename. Enter commits, Escape cancels, blur commits — but only a blur
453
+ * that is still inside this document: switching windows must not silently commit,
454
+ * nor kill the editor in the frame it opened.
455
+ */
456
+ function NameEditor({ initial, onCommit, onCancel }) {
457
+ const [value, setValue] = useState(initial);
458
+ const ref = useRef(null);
459
+ useEffect(() => {
460
+ ref.current?.select();
461
+ }, []);
462
+ return /* @__PURE__ */ jsx("input", {
463
+ ref,
464
+ value,
465
+ autoFocus: true,
466
+ "aria-label": "Session name",
467
+ onClick: (e) => e.stopPropagation(),
468
+ onChange: (e) => setValue(e.target.value),
469
+ onBlur: () => document.hasFocus() ? onCommit(value.trim()) : void 0,
470
+ onKeyDown: (e) => {
471
+ if (e.key === "Enter") onCommit(value.trim());
472
+ else if (e.key === "Escape") onCancel();
473
+ e.stopPropagation();
474
+ },
475
+ className: "-my-0.5 min-w-0 flex-1 rounded-sm border border-ring bg-bg px-1 py-0.5 text-body-sm font-medium text-fg-1 outline-none"
476
+ });
477
+ }
478
+ /** A multi-select facet. Empty = no filter, which is why the trigger reads the
479
+ * facet's name rather than "All": nothing is being excluded. */
480
+ /**
481
+ * One labelled control row. The label column is fixed so every control starts
482
+ * on the same x — the thing that makes a stack of them read as a form rather
483
+ * than as five unrelated widgets.
484
+ */
485
+ function FilterRow({ label, children }) {
486
+ return /* @__PURE__ */ jsxs("div", {
487
+ className: "flex items-center gap-2",
488
+ children: [/* @__PURE__ */ jsx("span", {
489
+ "aria-hidden": true,
490
+ className: "w-14 shrink-0 truncate text-label text-fg-3",
491
+ children: label
492
+ }), /* @__PURE__ */ jsx("div", {
493
+ className: "min-w-0 flex-1",
494
+ children
495
+ })]
496
+ });
497
+ }
498
+ function FacetSelect({ label, value, options, onChange }) {
499
+ return /* @__PURE__ */ jsxs("div", {
500
+ className: "flex items-center gap-1",
501
+ children: [/* @__PURE__ */ jsxs(Select, {
502
+ multiple: true,
503
+ value,
504
+ onValueChange: (v) => onChange(v),
505
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
506
+ "aria-label": label,
507
+ className: "min-w-0 flex-1",
508
+ children: /* @__PURE__ */ jsx(SelectValue, { children: value.length === 0 ? "All" : value.length === 1 ? options.find((o) => o.value === value[0])?.label ?? "All" : `${value.length} selected` })
509
+ }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
510
+ value: option.value,
511
+ children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
512
+ }, option.value)) })]
513
+ }), value.length > 0 ? /* @__PURE__ */ jsx(Button, {
514
+ variant: "ghost",
515
+ size: "icon-sm",
516
+ "aria-label": `Clear ${label}`,
517
+ onClick: () => onChange([]),
518
+ children: /* @__PURE__ */ jsx(X, { className: "size-3 text-fg-4" })
519
+ }) : null]
520
+ });
521
+ }
522
+ function OneOfSelect({ label, value, options, onChange }) {
523
+ return /* @__PURE__ */ jsxs(Select, {
524
+ value,
525
+ onValueChange: (v) => onChange(v),
526
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
527
+ "aria-label": label,
528
+ className: "w-full min-w-0",
529
+ children: /* @__PURE__ */ jsx(SelectValue, { children: options.find((o) => o.value === value)?.label ?? label })
530
+ }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
531
+ value: option.value,
532
+ children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
533
+ }, option.value)) })]
534
+ });
535
+ }
536
+ //#endregion
537
+ //#region src/components/agent/EngineIcon.tsx
538
+ /**
539
+ * The engine's own mark, monochrome.
540
+ *
541
+ * Inlined rather than depended on: the React package these come from
542
+ * (`@lobehub/icons`) pulls antd, `@lobehub/ui` and a second copy of
543
+ * lucide-react — an absurd amount of bundle for a few glyphs in a sidebar.
544
+ * These are paths from `@lobehub/icons-static-svg` (MIT, © LobeHub), already
545
+ * `fill="currentColor"` single-path marks, so they take the row's colour like
546
+ * any other glyph and need no light/dark variants.
547
+ *
548
+ * The marks are trademarks of their owners (Anthropic, OpenAI, Google,
549
+ * DeepSeek, Moonshot), used here only to identify which engine a session runs
550
+ * on.
551
+ *
552
+ * Codex is drawn as OpenAI: the session's engine *is* OpenAI's, and OpenAI's
553
+ * mark is the one a person recognises at 12px.
554
+ */
555
+ const PATHS = {
556
+ claude: {
557
+ title: "Claude",
558
+ d: "M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z"
559
+ },
560
+ codex: {
561
+ title: "OpenAI",
562
+ d: "M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z"
563
+ },
564
+ gemini: {
565
+ title: "Gemini",
566
+ d: "M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z"
567
+ },
568
+ deepseek: {
569
+ title: "DeepSeek",
570
+ d: "M23.748 4.482c-.254-.124-.364.113-.512.234-.051.039-.094.09-.137.136-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.156-.708-.311-.955-.65-.172-.241-.219-.51-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.093.172.187.129.323-.082.28-.18.552-.266.833-.055.179-.137.217-.329.14a5.526 5.526 0 01-1.736-1.18c-.857-.828-1.631-1.742-2.597-2.458a11.365 11.365 0 00-.689-.471c-.985-.957.13-1.743.388-1.836.27-.098.093-.432-.779-.428-.872.004-1.67.295-2.687.684a3.055 3.055 0 01-.465.137 9.597 9.597 0 00-2.883-.102c-1.885.21-3.39 1.102-4.497 2.623C.082 8.606-.231 10.684.152 12.85c.403 2.284 1.569 4.175 3.36 5.653 1.858 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.133-.284 4.994-1.86.47.234.962.327 1.78.397.63.059 1.236-.03 1.705-.128.735-.156.684-.837.419-.961-2.155-1.004-1.682-.595-2.113-.926 1.096-1.296 2.746-2.642 3.392-7.003.05-.347.007-.565 0-.845-.004-.17.035-.237.23-.256a4.173 4.173 0 001.545-.475c1.396-.763 1.96-2.015 2.093-3.517.02-.23-.004-.467-.247-.588zM11.581 18c-2.089-1.642-3.102-2.183-3.52-2.16-.392.024-.321.471-.235.763.09.288.207.486.371.739.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.167-1.361-.802-2.5-1.86-3.301-3.307-.774-1.393-1.224-2.887-1.298-4.482-.02-.386.093-.522.477-.592a4.696 4.696 0 011.529-.039c2.132.312 3.946 1.265 5.468 2.774.868.86 1.525 1.887 2.202 2.891.72 1.066 1.494 2.082 2.48 2.914.348.292.625.514.891.677-.802.09-2.14.11-3.054-.614zm1-6.44a.306.306 0 01.415-.287.302.302 0 01.2.288.306.306 0 01-.31.307.303.303 0 01-.304-.308zm3.11 1.596c-.2.081-.399.151-.59.16a1.245 1.245 0 01-.798-.254c-.274-.23-.47-.358-.552-.758a1.73 1.73 0 01.016-.588c.07-.327-.008-.537-.239-.727-.187-.156-.426-.199-.688-.199a.559.559 0 01-.254-.078c-.11-.054-.2-.19-.114-.358.028-.054.16-.186.192-.21.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.391.451.462.576.685.914.176.265.336.537.445.848.067.195-.019.354-.25.452z"
571
+ },
572
+ moonshot: {
573
+ title: "Moonshot",
574
+ d: "M1.052 16.916l9.539 2.552a21.007 21.007 0 00.06 2.033l5.956 1.593a11.997 11.997 0 01-5.586.865l-.18-.016-.044-.004-.084-.009-.094-.01a11.605 11.605 0 01-.157-.02l-.107-.014-.11-.016a11.962 11.962 0 01-.32-.051l-.042-.008-.075-.013-.107-.02-.07-.015-.093-.019-.075-.016-.095-.02-.097-.023-.094-.022-.068-.017-.088-.022-.09-.024-.095-.025-.082-.023-.109-.03-.062-.02-.084-.025-.093-.028-.105-.034-.058-.019-.08-.026-.09-.031-.066-.024a6.293 6.293 0 01-.044-.015l-.068-.025-.101-.037-.057-.022-.08-.03-.087-.035-.088-.035-.079-.032-.095-.04-.063-.028-.063-.027a5.655 5.655 0 01-.041-.018l-.066-.03-.103-.047-.052-.024-.096-.046-.062-.03-.084-.04-.086-.044-.093-.047-.052-.027-.103-.055-.057-.03-.058-.032a6.49 6.49 0 01-.046-.026l-.094-.053-.06-.034-.051-.03-.072-.041-.082-.05-.093-.056-.052-.032-.084-.053-.061-.039-.079-.05-.07-.047-.053-.035a7.785 7.785 0 01-.054-.036l-.044-.03-.044-.03a6.066 6.066 0 01-.04-.028l-.057-.04-.076-.054-.069-.05-.074-.054-.056-.042-.076-.057-.076-.059-.086-.067-.045-.035-.064-.052-.074-.06-.089-.073-.046-.039-.046-.039a7.516 7.516 0 01-.043-.037l-.045-.04-.061-.053-.07-.062-.068-.06-.062-.058-.067-.062-.053-.05-.088-.084a13.28 13.28 0 01-.099-.097l-.029-.028-.041-.042-.069-.07-.05-.051-.05-.053a6.457 6.457 0 01-.168-.179l-.08-.088-.062-.07-.071-.08-.042-.049-.053-.062-.058-.068-.046-.056a7.175 7.175 0 01-.027-.033l-.045-.055-.066-.082-.041-.052-.05-.064-.02-.025a11.99 11.99 0 01-1.44-2.402zm-1.02-5.794l11.353 3.037a20.468 20.468 0 00-.469 2.011l10.817 2.894a12.076 12.076 0 01-1.845 2.005L.657 15.923l-.016-.046-.035-.104a11.965 11.965 0 01-.05-.153l-.007-.023a11.896 11.896 0 01-.207-.741l-.03-.126-.018-.08-.021-.097-.018-.081-.018-.09-.017-.084-.018-.094c-.026-.141-.05-.283-.071-.426l-.017-.118-.011-.083-.013-.102a12.01 12.01 0 01-.019-.161l-.005-.047a12.12 12.12 0 01-.034-2.145zm1.593-5.15l11.948 3.196c-.368.605-.705 1.231-1.01 1.875l11.295 3.022c-.142.82-.368 1.612-.668 2.365l-11.55-3.09L.124 10.26l.015-.1.008-.049.01-.067.015-.087.018-.098c.026-.148.056-.295.088-.442l.028-.124.02-.085.024-.097c.022-.09.045-.18.07-.268l.028-.102.023-.083.03-.1.025-.082.03-.096.026-.082.031-.095a11.896 11.896 0 011.01-2.232zm4.442-4.4L17.352 4.59a20.77 20.77 0 00-1.688 1.721l7.823 2.093c.267.852.442 1.744.513 2.665L2.106 5.213l.045-.065.027-.04.04-.055.046-.065.055-.076.054-.072.064-.086.05-.065.057-.073.055-.07.06-.074.055-.069.065-.077.054-.066.066-.077.053-.06.072-.082.053-.06.067-.074.054-.058.073-.078.058-.06.063-.067.168-.17.1-.098.059-.056.076-.071a12.084 12.084 0 012.272-1.677zM12.017 0h.097l.082.001.069.001.054.002.068.002.046.001.076.003.047.002.06.003.054.002.087.005.105.007.144.011.088.007.044.004.077.008.082.008.047.005.102.012.05.006.108.014.081.01.042.006.065.01.207.032.07.012.065.011.14.026.092.018.11.022.046.01.075.016.041.01L14.7.3l.042.01.065.015.049.012.071.017.096.024.112.03.113.03.113.032.05.015.07.02.078.024.073.023.05.016.05.016.076.025.099.033.102.036.048.017.064.023.093.034.11.041.116.045.1.04.047.02.06.024.041.018.063.026.04.018.057.025.11.048.1.046.074.035.075.036.06.028.092.046.091.045.102.052.053.028.049.026.046.024.06.033.041.022.052.029.088.05.106.06.087.051.057.034.053.032.096.059.088.055.098.062.036.024.064.041.084.056.04.027.062.042.062.043.023.017c.054.037.108.075.161.114l.083.06.065.048.056.043.086.065.082.064.04.03.05.041.086.069.079.065.085.071c.712.6 1.353 1.283 1.909 2.031L7.222.994l.062-.027.065-.028.081-.034.086-.035c.113-.045.227-.09.341-.131l.096-.035.093-.033.084-.03.096-.031c.087-.03.176-.058.264-.085l.091-.027.086-.025.102-.03.085-.023.1-.026L9.04.37l.09-.023.091-.022.095-.022.09-.02.098-.021.091-.02.095-.018.092-.018.1-.018.091-.016.098-.017.092-.014.097-.015.092-.013.102-.013.091-.012.105-.012.09-.01.105-.01c.093-.01.186-.018.28-.024l.106-.008.09-.005.11-.006.093-.004.1-.004.097-.002.099-.002.197-.002z"
575
+ }
576
+ };
577
+ /**
578
+ * Which mark a session wears.
579
+ *
580
+ * The two first-party engines are named directly. A `provider` session is
581
+ * whatever the host wired up, so its *model* is the only thing that says whose
582
+ * it is — sniffed loosely on purpose (`gemini-2.5-pro`, `deepseek-chat`,
583
+ * `kimi-k2`), and falling through to no mark rather than guessing wrong.
584
+ */
585
+ function engineMark(engine, model) {
586
+ if (engine === "claude") return "claude";
587
+ if (engine === "codex") return "codex";
588
+ const id = model?.toLowerCase() ?? "";
589
+ if (!id) return void 0;
590
+ if (id.includes("gemini")) return "gemini";
591
+ if (id.includes("deepseek")) return "deepseek";
592
+ if (id.includes("moonshot") || id.includes("kimi")) return "moonshot";
593
+ if (id.includes("claude")) return "claude";
594
+ if (id.startsWith("gpt") || id.startsWith("o1") || id.startsWith("o3") || id.includes("openai")) return "codex";
595
+ }
596
+ function EngineIcon({ engine, model, className }) {
597
+ const mark = PATHS[engineMark(engine, model) ?? ""];
598
+ if (!mark) return /* @__PURE__ */ jsx("span", {
599
+ "aria-hidden": true,
600
+ title: engine,
601
+ className: cn("shrink-0 text-fg-3", className),
602
+ children: "·"
603
+ });
604
+ return /* @__PURE__ */ jsxs("svg", {
605
+ viewBox: "0 0 24 24",
606
+ fill: "currentColor",
607
+ fillRule: "evenodd",
608
+ role: "img",
609
+ "aria-label": mark.title,
610
+ className: cn("size-3 shrink-0 text-fg-3", className),
611
+ children: [/* @__PURE__ */ jsx("title", { children: mark.title }), /* @__PURE__ */ jsx("path", { d: mark.d })]
612
+ });
613
+ }
614
+ //#endregion
615
+ export { AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, Button, Card, CardContent, CardHeader, CardTitle, CodeBlock, Composer, ContextDialog, Conversation, ConversationContent, ConversationScrollButton, CopyButton, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, EngineIcon, FileCard, HostFilesDialog, Input, Loader, McpDialog, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, ModelSelect, PERMISSION_MODES, PermissionModeSelect, PermissionPrompt, ProgressRing, PromptArea, PromptTokenText, QUESTION_BEHAVIORS, QuestionPrompt, Reasoning, Response, STATUS_META, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionBrowser, SessionEmptyState, SessionInfoDialog, SessionList, SessionListItem, SessionPanel, SessionStatusIcon, SkillsDialog, Spinner, Splitter, StatusBar, Textarea, Tip, Toaster, ToolCallCard, TooltipContent, TooltipProvider, Transcript, TranscriptDensityProvider, TranscriptVariantProvider, UsageDialog, badgeVariants, buttonVariants, cn, commandTrigger, copyText, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, mentionTrigger, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, rateLimitWindowSeconds, rowShapeClass, segmentsToPlainText, skillPrompt, toast, toolIcon, toolInputPreview, usePromptAreaState, useTranscriptDensity, useTranscriptVariant };
160
616
 
161
617
  //# sourceMappingURL=index.mjs.map