@workerdeck/ui 0.12.0 → 0.15.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 (32) hide show
  1. package/README.md +19 -0
  2. package/build/{SessionPanel-NQ8ksCfj.mjs → SessionPanel-DI1NO4l8.mjs} +223 -163
  3. package/build/SessionPanel-DI1NO4l8.mjs.map +1 -0
  4. package/build/{SessionPanel-Dy9lQrOV.d.mts → SessionPanel-J2U8v88q.d.mts} +86 -8
  5. package/build/index.d.mts +118 -7
  6. package/build/index.mjs +355 -169
  7. package/build/index.mjs.map +1 -1
  8. package/build/workspace.d.mts +13 -1
  9. package/build/workspace.mjs +7 -2
  10. package/build/workspace.mjs.map +1 -1
  11. package/package.json +4 -4
  12. package/src/components/agent/Composer.tsx +112 -37
  13. package/src/components/agent/EngineIcon.tsx +97 -0
  14. package/src/components/agent/Loader.tsx +4 -1
  15. package/src/components/agent/Message.tsx +12 -5
  16. package/src/components/agent/QuestionPrompt.tsx +1 -1
  17. package/src/components/agent/SessionBrowser.tsx +266 -138
  18. package/src/components/agent/SessionPanel.tsx +149 -48
  19. package/src/components/agent/SessionWorkspace.tsx +17 -0
  20. package/src/components/agent/StatusBar.tsx +58 -12
  21. package/src/components/agent/Transcript.tsx +2 -3
  22. package/src/components/agent/line-prompt.tsx +2 -2
  23. package/src/components/agent/transcript-variant.tsx +14 -0
  24. package/src/components/ui/Badge.tsx +6 -1
  25. package/src/components/ui/Empty.tsx +56 -0
  26. package/src/components/ui/Menu.tsx +1 -1
  27. package/src/components/ui/Select.tsx +1 -1
  28. package/src/components/ui/Splitter.tsx +14 -0
  29. package/src/components/ui/Tooltip.tsx +1 -1
  30. package/src/index.ts +11 -1
  31. package/src/styles/theme.css +77 -15
  32. package/build/SessionPanel-NQ8ksCfj.mjs.map +0 -1
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-DI1NO4l8.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
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
- import { Pencil, Search, Trash2, X } from "lucide-react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { BellRing, CircleAlert, CircleSlash, Layers, Moon, PauseCircle, Pencil, Search, SearchX, 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";
@@ -77,6 +77,57 @@ function Toaster() {
77
77
  });
78
78
  }
79
79
  //#endregion
80
+ //#region src/components/ui/Empty.tsx
81
+ /**
82
+ * A view with nothing in it: icon, title, description, and at most one action.
83
+ *
84
+ * Centered and given room, because an empty view is the first thing a new
85
+ * install shows and a flush-left sentence in the top corner reads like a bug
86
+ * report. It lives here rather than in one client because every panel that can
87
+ * be empty should be empty the same way — the extension's views and the
88
+ * dashboard's four sidebars are the same shape of thing.
89
+ *
90
+ * **At most one action, and never one the view header already offers.** Creating
91
+ * a session and adding a gateway are the `+` in the native title bar, exclusively
92
+ * — so those empty states point at it in words rather than growing a second
93
+ * button that does the same thing two inches lower. A button here is for the way
94
+ * out of a state the header has no answer to: clearing a filter, widening a
95
+ * scope.
96
+ */
97
+ function Empty({ icon, title, description, action, onAction }) {
98
+ return /* @__PURE__ */ jsxs("div", {
99
+ className: "flex flex-col items-center gap-2 px-5 py-8 text-center",
100
+ children: [
101
+ /* @__PURE__ */ jsx("div", {
102
+ className: "text-fg-4 opacity-60 [&_svg]:size-7",
103
+ children: icon
104
+ }),
105
+ /* @__PURE__ */ jsx("p", {
106
+ className: "text-body-sm font-medium text-fg-2",
107
+ children: title
108
+ }),
109
+ description ? /* @__PURE__ */ jsx("p", {
110
+ className: "max-w-[26ch] text-balance text-label leading-relaxed text-fg-4",
111
+ children: description
112
+ }) : null,
113
+ action && onAction ? /* @__PURE__ */ jsx(Button, {
114
+ variant: "outline",
115
+ size: "sm",
116
+ className: "mt-1",
117
+ onClick: onAction,
118
+ children: action
119
+ }) : null
120
+ ]
121
+ });
122
+ }
123
+ /** A key or icon named inline in an empty state's description — "use the + above". */
124
+ function EmptyKey({ children }) {
125
+ return /* @__PURE__ */ jsx("span", {
126
+ className: "rounded border border-border px-1 font-mono text-fg-3",
127
+ children
128
+ });
129
+ }
130
+ //#endregion
80
131
  //#region src/components/prompt-area/segment-helpers.ts
81
132
  /** Returns `true` when the segment array is empty or contains only whitespace text. */
82
133
  function isSegmentsEmpty(segments) {
@@ -158,7 +209,26 @@ function SessionList({ sessions, activeId, onSelect, onDelete, emptyText = "No s
158
209
  }
159
210
  //#endregion
160
211
  //#region src/components/agent/SessionBrowser.tsx
161
- function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelect, onDelete, onRename, emptyState, className }) {
212
+ /**
213
+ * How a list row is drawn, in one place, so `SidebarRow` in `web` matches this
214
+ * exactly rather than approximating it — the dashboard's other three sidebars
215
+ * are that component, and a sessions list that hovered differently from the
216
+ * gateways list beside it would read as a different product.
217
+ *
218
+ * Two rules are load-bearing:
219
+ *
220
+ * - **Fill means hover, and only hover.** It stays on the row whether or not
221
+ * the row is selected, because a selected row still has to answer the
222
+ * pointer. Selection gets the gutter instead.
223
+ * - **`ml-0` on the selected row is not cosmetic.** It hands the accent border
224
+ * the 4px the margin was holding, so the text does not shift sideways as a
225
+ * row becomes the selected one. The squared left corners are what let the bar
226
+ * sit flush against the sidebar edge.
227
+ */
228
+ function rowShapeClass(active) {
229
+ 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");
230
+ }
231
+ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelect, onDelete, onRename, emptyState, showControls = true, className }) {
162
232
  const visible = useMemo(() => filterRows(rows, config, scope), [
163
233
  rows,
164
234
  config,
@@ -184,10 +254,10 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
184
254
  className: cn("flex flex-col gap-3", className),
185
255
  children: [
186
256
  /* @__PURE__ */ jsxs("div", {
187
- className: "flex flex-wrap items-center gap-2",
257
+ className: cn("flex flex-col gap-1.5 px-2", !showControls && "hidden"),
188
258
  children: [
189
259
  /* @__PURE__ */ jsxs("div", {
190
- className: "relative min-w-48 flex-1",
260
+ className: "relative",
191
261
  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
262
  value: config.search,
193
263
  onChange: (e) => set({ search: e.target.value }),
@@ -196,83 +266,98 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
196
266
  className: "pl-8"
197
267
  })]
198
268
  }),
199
- /* @__PURE__ */ jsx(FacetSelect, {
269
+ /* @__PURE__ */ jsx(FilterRow, {
200
270
  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 })
271
+ children: /* @__PURE__ */ jsx(FacetSelect, {
272
+ label: "State",
273
+ value: config.states,
274
+ options: STATE_ORDER.map((s) => ({
275
+ value: s,
276
+ label: STATE_LABELS[s]
277
+ })),
278
+ onChange: (states) => set({ states })
279
+ })
207
280
  }),
208
- adapters.length > 1 ? /* @__PURE__ */ jsx(FacetSelect, {
281
+ adapters.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
209
282
  label: "Engine",
210
- value: config.adapters,
211
- options: adapters.map((a) => ({
212
- value: a,
213
- label: a
214
- })),
215
- onChange: (adapters) => set({ adapters })
283
+ children: /* @__PURE__ */ jsx(FacetSelect, {
284
+ label: "Engine",
285
+ value: config.adapters,
286
+ options: adapters.map((a) => ({
287
+ value: a,
288
+ label: a
289
+ })),
290
+ onChange: (adapters) => set({ adapters })
291
+ })
216
292
  }) : null,
217
- gateways.length > 1 ? /* @__PURE__ */ jsx(FacetSelect, {
293
+ gateways.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
218
294
  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 })
295
+ children: /* @__PURE__ */ jsx(FacetSelect, {
296
+ label: "Gateway",
297
+ value: config.gateways,
298
+ options: gateways.map((g) => ({
299
+ value: g.id,
300
+ label: g.name
301
+ })),
302
+ onChange: (gateways) => set({ gateways })
303
+ })
225
304
  }) : null,
226
- /* @__PURE__ */ jsx(OneOfSelect, {
305
+ /* @__PURE__ */ jsx(FilterRow, {
227
306
  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 })
307
+ children: /* @__PURE__ */ jsx(OneOfSelect, {
308
+ label: "Group",
309
+ value: config.groupBy,
310
+ options: [
311
+ {
312
+ value: "none",
313
+ label: "No grouping"
314
+ },
315
+ {
316
+ value: "state",
317
+ label: "By state"
318
+ },
319
+ {
320
+ value: "adapter",
321
+ label: "By engine"
322
+ },
323
+ ...gateways.length > 1 ? [{
324
+ value: "gateway",
325
+ label: "By gateway"
326
+ }] : []
327
+ ],
328
+ onChange: (groupBy) => set({ groupBy })
329
+ })
248
330
  }),
249
- /* @__PURE__ */ jsx(OneOfSelect, {
331
+ /* @__PURE__ */ jsx(FilterRow, {
250
332
  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 })
333
+ children: /* @__PURE__ */ jsx(OneOfSelect, {
334
+ label: "Sort",
335
+ value: config.sortBy,
336
+ options: [
337
+ {
338
+ value: "recent",
339
+ label: "Recent"
340
+ },
341
+ {
342
+ value: "name",
343
+ label: "Name"
344
+ },
345
+ {
346
+ value: "state",
347
+ label: "State"
348
+ },
349
+ ...gateways.length > 1 ? [{
350
+ value: "gateway",
351
+ label: "Gateway"
352
+ }] : []
353
+ ],
354
+ onChange: (sortBy) => set({ sortBy })
355
+ })
271
356
  })
272
357
  ]
273
358
  }),
274
359
  subset ? /* @__PURE__ */ jsxs("div", {
275
- className: "flex items-center gap-2 text-label text-fg-4",
360
+ className: "flex items-center gap-2 px-3 text-label text-fg-4",
276
361
  children: [/* @__PURE__ */ jsxs("span", { children: [
277
362
  subset.shown,
278
363
  " of ",
@@ -285,21 +370,25 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
285
370
  children: "Show all"
286
371
  })]
287
372
  }) : null,
288
- 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: [
289
- "No sessions match.",
290
- " ",
291
- /* @__PURE__ */ jsx("button", {
292
- type: "button",
293
- className: "underline underline-offset-2 hover:text-fg-1",
294
- onClick: () => onConfigChange(clearFilters(config)),
295
- children: "Clear filters"
296
- })
297
- ] }) : "No sessions here." }) : /* @__PURE__ */ jsx("div", {
373
+ rows.length === 0 ? emptyState ?? /* @__PURE__ */ jsx(Empty, {
374
+ icon: /* @__PURE__ */ jsx(Layers, {}),
375
+ title: "No sessions yet"
376
+ }) : visible.length === 0 ? hasFacetFilter(config) ? /* @__PURE__ */ jsx(Empty, {
377
+ icon: /* @__PURE__ */ jsx(SearchX, {}),
378
+ title: "No matches",
379
+ description: "No session matches the current search and filters.",
380
+ action: "Clear filters",
381
+ onAction: () => onConfigChange(clearFilters(config))
382
+ }) : /* @__PURE__ */ jsx(Empty, {
383
+ icon: /* @__PURE__ */ jsx(Layers, {}),
384
+ title: "Nothing here",
385
+ description: "No session to show."
386
+ }) : /* @__PURE__ */ jsx("div", {
298
387
  className: "flex flex-col gap-4",
299
388
  children: groups.map((group) => /* @__PURE__ */ jsxs("div", {
300
389
  className: "flex flex-col gap-1",
301
390
  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",
391
+ className: "flex items-baseline gap-2 px-3 text-label font-medium text-fg-4",
303
392
  children: [/* @__PURE__ */ jsx("span", {
304
393
  className: "uppercase tracking-wide",
305
394
  children: group.label
@@ -320,100 +409,101 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, onSelec
320
409
  ]
321
410
  });
322
411
  }
323
- function Empty({ children }) {
324
- return /* @__PURE__ */ jsx("div", {
325
- className: "px-2.5 py-6 text-center text-body-sm text-fg-4",
326
- children
327
- });
328
- }
329
412
  function SessionRowItem({ row, active, showGateway, onSelect, onDelete, onRename }) {
330
413
  const { info } = row;
331
- const meta = STATUS_META[info.status];
332
414
  const [editing, setEditing] = useState(false);
415
+ const folder = info.cwd.split("/").filter(Boolean).pop() ?? info.cwd;
416
+ const details = [
417
+ showGateway ? row.hostName : void 0,
418
+ friendlyModel(info.model),
419
+ folder,
420
+ info.profile ? `@${info.profile}` : void 0,
421
+ formatCost(info.totalCostUsd)
422
+ ].filter(Boolean);
333
423
  return /* @__PURE__ */ jsxs("div", {
334
424
  "data-slot": "session-row",
335
425
  "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", {
426
+ onClick: () => !editing && onSelect?.(row),
427
+ className: cn("group flex cursor-pointer flex-col gap-0.5 text-left transition-colors", rowShapeClass(active === true)),
428
+ children: [/* @__PURE__ */ jsxs("div", {
429
+ className: "flex items-center gap-1.5",
430
+ children: [
431
+ editing && onRename ? /* @__PURE__ */ jsx(NameEditor, {
432
+ initial: info.title ?? "",
433
+ onCommit: (title) => {
434
+ setEditing(false);
435
+ onRename(row, title);
436
+ },
437
+ onCancel: () => setEditing(false)
438
+ }) : /* @__PURE__ */ jsx("button", {
370
439
  type: "button",
371
- 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
- ]
440
+ className: cn("min-w-0 flex-1 truncate text-left text-body-sm outline-none", active ? "font-medium text-fg-1" : "text-fg-2"),
441
+ children: sessionLabel(info)
442
+ }),
443
+ row.unseen > 0 ? /* @__PURE__ */ jsx("span", {
444
+ title: `${row.unseen} new`,
445
+ className: "shrink-0 rounded-full bg-accent px-1.5 text-label text-accent-fg",
446
+ children: row.unseen
447
+ }) : null,
448
+ /* @__PURE__ */ jsx("span", {
449
+ className: "shrink-0 text-label text-fg-4",
450
+ children: formatRelativeTime(info.lastActivityAt ?? info.createdAt)
451
+ }),
452
+ /* @__PURE__ */ jsx(SessionStatusIcon, { row })
453
+ ]
454
+ }), /* @__PURE__ */ jsxs("div", {
455
+ className: "flex items-center gap-1 text-label text-fg-4",
456
+ children: [
457
+ /* @__PURE__ */ jsx("button", {
458
+ type: "button",
459
+ tabIndex: -1,
460
+ className: "min-w-0 flex-1 truncate text-left font-mono outline-none",
461
+ children: details.join(" · ")
462
+ }),
463
+ onRename && !editing ? /* @__PURE__ */ jsx(Button, {
464
+ variant: "ghost",
465
+ size: "icon-sm",
466
+ "aria-label": "Rename session",
467
+ className: "size-5 shrink-0 opacity-0 transition-opacity group-hover:opacity-100",
468
+ onClick: (e) => {
469
+ e.stopPropagation();
470
+ setEditing(true);
471
+ },
472
+ children: /* @__PURE__ */ jsx(Pencil, { className: "size-3 text-fg-3" })
473
+ }) : null,
474
+ onDelete ? /* @__PURE__ */ jsx(Button, {
475
+ variant: "ghost",
476
+ size: "icon-sm",
477
+ "aria-label": "Close session",
478
+ className: "size-5 shrink-0 opacity-0 transition-opacity group-hover:opacity-100",
479
+ onClick: (e) => {
480
+ e.stopPropagation();
481
+ onDelete(row);
482
+ },
483
+ children: /* @__PURE__ */ jsx(Trash2, { className: "size-3 text-fg-3" })
484
+ }) : null
485
+ ]
486
+ })]
414
487
  });
415
488
  }
416
489
  /**
490
+ * State as one glyph on the right edge — a ringing bell when it wants a human, a
491
+ * spinner while it works, a moon when it is only sleeping. Replaces the text
492
+ * badge: in a sidebar the word costs more room than it earns, and the states
493
+ * that matter are the two you can recognise without reading.
494
+ */
495
+ function SessionStatusIcon({ row }) {
496
+ const { info } = row;
497
+ if (info.pendingPermissionCount > 0 || info.status === "awaiting_approval") return /* @__PURE__ */ jsx(BellRing, { className: "size-3.5 shrink-0 animate-pulse text-warning" });
498
+ if (info.status === "running" || info.status === "starting") return /* @__PURE__ */ jsx(Spinner, { className: "size-3.5 shrink-0 text-info" });
499
+ switch (info.status) {
500
+ case "failed": return /* @__PURE__ */ jsx(CircleAlert, { className: "size-3.5 shrink-0 text-danger" });
501
+ case "closed": return /* @__PURE__ */ jsx(CircleSlash, { className: "size-3.5 shrink-0 text-fg-4" });
502
+ case "parked": return /* @__PURE__ */ jsx(PauseCircle, { className: "size-3.5 shrink-0 text-fg-3" });
503
+ default: return /* @__PURE__ */ jsx(Moon, { className: "size-3.5 shrink-0 text-fg-4" });
504
+ }
505
+ }
506
+ /**
417
507
  * Inline rename. Enter commits, Escape cancels, blur commits — but only a blur
418
508
  * that is still inside this document: switching windows must not silently commit,
419
509
  * nor kill the editor in the frame it opened.
@@ -442,6 +532,24 @@ function NameEditor({ initial, onCommit, onCancel }) {
442
532
  }
443
533
  /** A multi-select facet. Empty = no filter, which is why the trigger reads the
444
534
  * facet's name rather than "All": nothing is being excluded. */
535
+ /**
536
+ * One labelled control row. The label column is fixed so every control starts
537
+ * on the same x — the thing that makes a stack of them read as a form rather
538
+ * than as five unrelated widgets.
539
+ */
540
+ function FilterRow({ label, children }) {
541
+ return /* @__PURE__ */ jsxs("div", {
542
+ className: "flex items-center gap-2",
543
+ children: [/* @__PURE__ */ jsx("span", {
544
+ "aria-hidden": true,
545
+ className: "w-14 shrink-0 truncate text-label text-fg-3",
546
+ children: label
547
+ }), /* @__PURE__ */ jsx("div", {
548
+ className: "min-w-0 flex-1",
549
+ children
550
+ })]
551
+ });
552
+ }
445
553
  function FacetSelect({ label, value, options, onChange }) {
446
554
  return /* @__PURE__ */ jsxs("div", {
447
555
  className: "flex items-center gap-1",
@@ -451,8 +559,8 @@ function FacetSelect({ label, value, options, onChange }) {
451
559
  onValueChange: (v) => onChange(v),
452
560
  children: [/* @__PURE__ */ jsx(SelectTrigger, {
453
561
  "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}` })
562
+ className: "min-w-0 flex-1",
563
+ 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
564
  }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
457
565
  value: option.value,
458
566
  children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
@@ -472,7 +580,7 @@ function OneOfSelect({ label, value, options, onChange }) {
472
580
  onValueChange: (v) => onChange(v),
473
581
  children: [/* @__PURE__ */ jsx(SelectTrigger, {
474
582
  "aria-label": label,
475
- className: "min-w-28",
583
+ className: "w-full min-w-0",
476
584
  children: /* @__PURE__ */ jsx(SelectValue, { children: options.find((o) => o.value === value)?.label ?? label })
477
585
  }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
478
586
  value: option.value,
@@ -481,6 +589,84 @@ function OneOfSelect({ label, value, options, onChange }) {
481
589
  });
482
590
  }
483
591
  //#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 };
592
+ //#region src/components/agent/EngineIcon.tsx
593
+ /**
594
+ * The engine's own mark, monochrome.
595
+ *
596
+ * Inlined rather than depended on: the React package these come from
597
+ * (`@lobehub/icons`) pulls antd, `@lobehub/ui` and a second copy of
598
+ * lucide-react — an absurd amount of bundle for a few glyphs in a sidebar.
599
+ * These are paths from `@lobehub/icons-static-svg` (MIT, © LobeHub), already
600
+ * `fill="currentColor"` single-path marks, so they take the row's colour like
601
+ * any other glyph and need no light/dark variants.
602
+ *
603
+ * The marks are trademarks of their owners (Anthropic, OpenAI, Google,
604
+ * DeepSeek, Moonshot), used here only to identify which engine a session runs
605
+ * on.
606
+ *
607
+ * Codex is drawn as OpenAI: the session's engine *is* OpenAI's, and OpenAI's
608
+ * mark is the one a person recognises at 12px.
609
+ */
610
+ const PATHS = {
611
+ claude: {
612
+ title: "Claude",
613
+ 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"
614
+ },
615
+ codex: {
616
+ title: "OpenAI",
617
+ 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"
618
+ },
619
+ gemini: {
620
+ title: "Gemini",
621
+ 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"
622
+ },
623
+ deepseek: {
624
+ title: "DeepSeek",
625
+ 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"
626
+ },
627
+ moonshot: {
628
+ title: "Moonshot",
629
+ 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"
630
+ }
631
+ };
632
+ /**
633
+ * Which mark a session wears.
634
+ *
635
+ * The two first-party engines are named directly. A `provider` session is
636
+ * whatever the host wired up, so its *model* is the only thing that says whose
637
+ * it is — sniffed loosely on purpose (`gemini-2.5-pro`, `deepseek-chat`,
638
+ * `kimi-k2`), and falling through to no mark rather than guessing wrong.
639
+ */
640
+ function engineMark(engine, model) {
641
+ if (engine === "claude") return "claude";
642
+ if (engine === "codex") return "codex";
643
+ const id = model?.toLowerCase() ?? "";
644
+ if (!id) return void 0;
645
+ if (id.includes("gemini")) return "gemini";
646
+ if (id.includes("deepseek")) return "deepseek";
647
+ if (id.includes("moonshot") || id.includes("kimi")) return "moonshot";
648
+ if (id.includes("claude")) return "claude";
649
+ if (id.startsWith("gpt") || id.startsWith("o1") || id.startsWith("o3") || id.includes("openai")) return "codex";
650
+ }
651
+ function EngineIcon({ engine, model, className }) {
652
+ const mark = PATHS[engineMark(engine, model) ?? ""];
653
+ if (!mark) return /* @__PURE__ */ jsx("span", {
654
+ "aria-hidden": true,
655
+ title: engine,
656
+ className: cn("shrink-0 text-fg-3", className),
657
+ children: "·"
658
+ });
659
+ return /* @__PURE__ */ jsxs("svg", {
660
+ viewBox: "0 0 24 24",
661
+ fill: "currentColor",
662
+ fillRule: "evenodd",
663
+ role: "img",
664
+ "aria-label": mark.title,
665
+ className: cn("size-3 shrink-0 text-fg-3", className),
666
+ children: [/* @__PURE__ */ jsx("title", { children: mark.title }), /* @__PURE__ */ jsx("path", { d: mark.d })]
667
+ });
668
+ }
669
+ //#endregion
670
+ 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, Empty, EmptyKey, 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
671
 
486
672
  //# sourceMappingURL=index.mjs.map