@workerdeck/ui 0.12.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.
package/build/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import { $ as Tip, A as PermissionModeSelect, B as commandTrigger, C as TranscriptDensityProvider, Ct as Button, D as isMutatingTool, E as useTranscriptVariant, F as McpDialog, G as plainTextToSegments, H as mentionTrigger, I as HostFilesDialog, J as Splitter, K as segmentsToPlainText, L as ContextDialog, M as permissionModeMeta, N as ModelSelect, O as toolIcon, P as SkillsDialog, Q as copyText, R as Composer, S as Response, St as badgeVariants, T as useTranscriptDensity, 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 permissionModeChoices, k as PERMISSION_MODES, 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 TranscriptVariantProvider, wt as buttonVariants, x as PermissionPrompt, xt as Badge, y as QuestionPrompt, yt as SelectValue, z as skillPrompt } from "./SessionPanel-NQ8ksCfj.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
3
  import { forwardRef, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
- import { Pencil, Search, Trash2, X } from "lucide-react";
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
8
  import { STATE_LABELS, STATE_ORDER, adaptersOf, clearFilters, filterRows, groupRows, hasFacetFilter, sessionLabel, subsetSummary } from "@workerdeck/protocol";
@@ -158,7 +158,26 @@ function SessionList({ sessions, activeId, onSelect, onDelete, emptyText = "No s
158
158
  }
159
159
  //#endregion
160
160
  //#region src/components/agent/SessionBrowser.tsx
161
- function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelect, onDelete, onRename, emptyState, className }) {
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 }) {
162
181
  const visible = useMemo(() => filterRows(rows, config, scope), [
163
182
  rows,
164
183
  config,
@@ -184,10 +203,10 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
184
203
  className: cn("flex flex-col gap-3", className),
185
204
  children: [
186
205
  /* @__PURE__ */ jsxs("div", {
187
- className: "flex flex-wrap items-center gap-2",
206
+ className: cn("flex flex-col gap-1.5 px-2", !showControls && "hidden"),
188
207
  children: [
189
208
  /* @__PURE__ */ jsxs("div", {
190
- className: "relative min-w-48 flex-1",
209
+ className: "relative",
191
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, {
192
211
  value: config.search,
193
212
  onChange: (e) => set({ search: e.target.value }),
@@ -196,83 +215,98 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
196
215
  className: "pl-8"
197
216
  })]
198
217
  }),
199
- /* @__PURE__ */ jsx(FacetSelect, {
218
+ /* @__PURE__ */ jsx(FilterRow, {
200
219
  label: "State",
201
- value: config.states,
202
- options: STATE_ORDER.map((s) => ({
203
- value: s,
204
- label: STATE_LABELS[s]
205
- })),
206
- onChange: (states) => set({ states })
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
+ })
207
229
  }),
208
- adapters.length > 1 ? /* @__PURE__ */ jsx(FacetSelect, {
230
+ adapters.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
209
231
  label: "Engine",
210
- value: config.adapters,
211
- options: adapters.map((a) => ({
212
- value: a,
213
- label: a
214
- })),
215
- onChange: (adapters) => set({ adapters })
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
+ })
216
241
  }) : null,
217
- gateways.length > 1 ? /* @__PURE__ */ jsx(FacetSelect, {
242
+ gateways.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
218
243
  label: "Gateway",
219
- value: config.gateways,
220
- options: gateways.map((g) => ({
221
- value: g.id,
222
- label: g.name
223
- })),
224
- onChange: (gateways) => set({ gateways })
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
+ })
225
253
  }) : null,
226
- /* @__PURE__ */ jsx(OneOfSelect, {
254
+ /* @__PURE__ */ jsx(FilterRow, {
227
255
  label: "Group",
228
- value: config.groupBy,
229
- options: [
230
- {
231
- value: "none",
232
- label: "No grouping"
233
- },
234
- {
235
- value: "state",
236
- label: "By state"
237
- },
238
- {
239
- value: "adapter",
240
- label: "By engine"
241
- },
242
- ...gateways.length > 1 ? [{
243
- value: "gateway",
244
- label: "By gateway"
245
- }] : []
246
- ],
247
- onChange: (groupBy) => set({ groupBy })
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
+ })
248
279
  }),
249
- /* @__PURE__ */ jsx(OneOfSelect, {
280
+ /* @__PURE__ */ jsx(FilterRow, {
250
281
  label: "Sort",
251
- value: config.sortBy,
252
- options: [
253
- {
254
- value: "recent",
255
- label: "Recent"
256
- },
257
- {
258
- value: "name",
259
- label: "Name"
260
- },
261
- {
262
- value: "state",
263
- label: "State"
264
- },
265
- ...gateways.length > 1 ? [{
266
- value: "gateway",
267
- label: "Gateway"
268
- }] : []
269
- ],
270
- onChange: (sortBy) => set({ sortBy })
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
+ })
271
305
  })
272
306
  ]
273
307
  }),
274
308
  subset ? /* @__PURE__ */ jsxs("div", {
275
- className: "flex items-center gap-2 text-label text-fg-4",
309
+ className: "flex items-center gap-2 px-3 text-label text-fg-4",
276
310
  children: [/* @__PURE__ */ jsxs("span", { children: [
277
311
  subset.shown,
278
312
  " of ",
@@ -299,7 +333,7 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
299
333
  children: groups.map((group) => /* @__PURE__ */ jsxs("div", {
300
334
  className: "flex flex-col gap-1",
301
335
  children: [config.groupBy !== "none" && group.label ? /* @__PURE__ */ jsxs("div", {
302
- className: "flex items-baseline gap-2 px-2.5 text-label font-medium text-fg-4",
336
+ className: "flex items-baseline gap-2 px-3 text-label font-medium text-fg-4",
303
337
  children: [/* @__PURE__ */ jsx("span", {
304
338
  className: "uppercase tracking-wide",
305
339
  children: group.label
@@ -322,98 +356,99 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
322
356
  }
323
357
  function Empty({ children }) {
324
358
  return /* @__PURE__ */ jsx("div", {
325
- className: "px-2.5 py-6 text-center text-body-sm text-fg-4",
359
+ className: "px-3 py-6 text-center text-body-sm text-fg-4",
326
360
  children
327
361
  });
328
362
  }
329
363
  function SessionRowItem({ row, active, showGateway, onSelect, onDelete, onRename }) {
330
364
  const { info } = row;
331
- const meta = STATUS_META[info.status];
332
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);
333
374
  return /* @__PURE__ */ jsxs("div", {
334
375
  "data-slot": "session-row",
335
376
  "data-active": active || void 0,
336
- className: cn("group flex w-full items-center gap-2 rounded-md border border-transparent px-2.5 py-2 text-left transition-colors", active ? "border-border bg-surface" : "hover:bg-surface-hover"),
337
- children: [
338
- /* @__PURE__ */ jsxs("div", {
339
- className: "min-w-0 flex-1",
340
- children: [/* @__PURE__ */ jsxs("div", {
341
- className: "flex items-center gap-2",
342
- children: [
343
- editing && onRename ? /* @__PURE__ */ jsx(NameEditor, {
344
- initial: info.title ?? "",
345
- onCommit: (title) => {
346
- setEditing(false);
347
- onRename(row, title);
348
- },
349
- onCancel: () => setEditing(false)
350
- }) : /* @__PURE__ */ jsx("button", {
351
- type: "button",
352
- onClick: () => onSelect?.(row),
353
- className: "min-w-0 truncate text-left text-body-sm font-medium text-fg-1 outline-none",
354
- children: sessionLabel(info)
355
- }),
356
- /* @__PURE__ */ jsx(Badge, {
357
- variant: meta.variant,
358
- dot: true,
359
- className: "shrink-0",
360
- children: meta.label
361
- }),
362
- row.unseen > 0 ? /* @__PURE__ */ jsx(Badge, {
363
- variant: "accent",
364
- className: "shrink-0",
365
- title: `${row.unseen} new`,
366
- children: row.unseen
367
- }) : null
368
- ]
369
- }), /* @__PURE__ */ jsxs("button", {
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", {
370
409
  type: "button",
371
410
  onClick: () => !editing && onSelect?.(row),
372
- className: "mt-0.5 flex w-full items-center gap-2 text-left font-mono text-label text-fg-4 outline-none",
373
- children: [
374
- /* @__PURE__ */ jsx("span", {
375
- className: "truncate",
376
- children: info.cwd
377
- }),
378
- showGateway ? /* @__PURE__ */ jsx("span", {
379
- className: "shrink-0",
380
- children: row.hostName
381
- }) : null,
382
- info.profile ? /* @__PURE__ */ jsxs("span", {
383
- className: "shrink-0",
384
- children: ["@", info.profile]
385
- }) : null,
386
- /* @__PURE__ */ jsx("span", {
387
- className: "shrink-0",
388
- children: formatCost(info.totalCostUsd)
389
- }),
390
- /* @__PURE__ */ jsx("span", {
391
- className: "shrink-0",
392
- children: formatRelativeTime(info.lastActivityAt ?? info.createdAt)
393
- })
394
- ]
395
- })]
396
- }),
397
- onRename && !editing ? /* @__PURE__ */ jsx(Button, {
398
- variant: "ghost",
399
- size: "icon-sm",
400
- "aria-label": "Rename session",
401
- className: "opacity-0 transition-opacity group-hover:opacity-100",
402
- onClick: () => setEditing(true),
403
- children: /* @__PURE__ */ jsx(Pencil, { className: "size-3.5 text-fg-3" })
404
- }) : null,
405
- onDelete ? /* @__PURE__ */ jsx(Button, {
406
- variant: "ghost",
407
- size: "icon-sm",
408
- "aria-label": "Close session",
409
- className: "opacity-0 transition-opacity group-hover:opacity-100",
410
- onClick: () => onDelete(row),
411
- children: /* @__PURE__ */ jsx(Trash2, { className: "size-3.5 text-fg-3" })
412
- }) : null
413
- ]
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
+ })]
414
432
  });
415
433
  }
416
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
+ /**
417
452
  * Inline rename. Enter commits, Escape cancels, blur commits — but only a blur
418
453
  * that is still inside this document: switching windows must not silently commit,
419
454
  * nor kill the editor in the frame it opened.
@@ -442,6 +477,24 @@ function NameEditor({ initial, onCommit, onCancel }) {
442
477
  }
443
478
  /** A multi-select facet. Empty = no filter, which is why the trigger reads the
444
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
+ }
445
498
  function FacetSelect({ label, value, options, onChange }) {
446
499
  return /* @__PURE__ */ jsxs("div", {
447
500
  className: "flex items-center gap-1",
@@ -451,8 +504,8 @@ function FacetSelect({ label, value, options, onChange }) {
451
504
  onValueChange: (v) => onChange(v),
452
505
  children: [/* @__PURE__ */ jsx(SelectTrigger, {
453
506
  "aria-label": label,
454
- className: "min-w-28",
455
- children: /* @__PURE__ */ jsx(SelectValue, { children: value.length === 0 ? label : value.length === 1 ? options.find((o) => o.value === value[0])?.label ?? label : `${label} · ${value.length}` })
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` })
456
509
  }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
457
510
  value: option.value,
458
511
  children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
@@ -472,7 +525,7 @@ function OneOfSelect({ label, value, options, onChange }) {
472
525
  onValueChange: (v) => onChange(v),
473
526
  children: [/* @__PURE__ */ jsx(SelectTrigger, {
474
527
  "aria-label": label,
475
- className: "min-w-28",
528
+ className: "w-full min-w-0",
476
529
  children: /* @__PURE__ */ jsx(SelectValue, { children: options.find((o) => o.value === value)?.label ?? label })
477
530
  }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
478
531
  value: option.value,
@@ -481,6 +534,84 @@ function OneOfSelect({ label, value, options, onChange }) {
481
534
  });
482
535
  }
483
536
  //#endregion
484
- 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, SessionBrowser, SessionEmptyState, SessionInfoDialog, SessionList, SessionListItem, SessionPanel, 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, segmentsToPlainText, skillPrompt, toast, toolIcon, toolInputPreview, usePromptAreaState, useTranscriptDensity, useTranscriptVariant };
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 };
485
616
 
486
617
  //# sourceMappingURL=index.mjs.map