@workerdeck/ui 3.0.1 → 3.1.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 (55) hide show
  1. package/build/{SessionPanel-C1bU4yTM.d.mts → SessionPanel-BNNc8grK.d.mts} +9 -7
  2. package/build/index.d.mts +153 -45
  3. package/build/index.mjs +501 -226
  4. package/build/index.mjs.map +1 -1
  5. package/build/scoped.css +15 -6
  6. package/build/{use-path-links-BEWxt0ZM.mjs → use-path-links-C6Fh5zdx.mjs} +1926 -2086
  7. package/build/use-path-links-C6Fh5zdx.mjs.map +1 -0
  8. package/build/workspace.d.mts +1 -1
  9. package/build/workspace.mjs +1 -1
  10. package/package.json +4 -4
  11. package/src/components/agent/ApprovalPrompts.tsx +87 -0
  12. package/src/components/agent/Composer.tsx +25 -47
  13. package/src/components/agent/ContextDialog.tsx +75 -67
  14. package/src/components/agent/FrameStrip.tsx +74 -0
  15. package/src/components/agent/HostFilesDialog.tsx +3 -2
  16. package/src/components/agent/McpDialog.tsx +112 -78
  17. package/src/components/agent/PermissionPrompt.tsx +13 -22
  18. package/src/components/agent/QuestionPrompt.tsx +6 -41
  19. package/src/components/agent/Scrubber.tsx +6 -75
  20. package/src/components/agent/SessionBrowser.tsx +125 -214
  21. package/src/components/agent/SessionFilters.tsx +266 -0
  22. package/src/components/agent/SessionInfoDialog.tsx +47 -63
  23. package/src/components/agent/SessionItem.tsx +27 -7
  24. package/src/components/agent/SessionPanel.tsx +244 -488
  25. package/src/components/agent/SessionSteps.tsx +54 -11
  26. package/src/components/agent/ShellStrip.tsx +27 -43
  27. package/src/components/agent/SubagentStrip.tsx +13 -30
  28. package/src/components/agent/Transcript.tsx +13 -0
  29. package/src/components/agent/TranscriptItemView.tsx +6 -36
  30. package/src/components/agent/composer-commands.ts +80 -1
  31. package/src/components/agent/markdown-image.tsx +49 -1
  32. package/src/components/agent/scrubber-marks.ts +33 -11
  33. package/src/components/agent/scrubber-peek.tsx +122 -0
  34. package/src/components/agent/session-panel-providers.tsx +41 -0
  35. package/src/components/agent/shell-actions.tsx +36 -1
  36. package/src/components/agent/use-catch-up.ts +20 -0
  37. package/src/components/agent/use-frame.ts +88 -0
  38. package/src/components/agent/use-host-image.ts +81 -0
  39. package/src/components/agent/use-shell-frame.ts +12 -70
  40. package/src/components/agent/use-subagent-frame.ts +19 -75
  41. package/src/components/prompt-area/prompt-area-engine.ts +21 -20
  42. package/src/components/prompt-area/prompt-area-list-ops.ts +12 -15
  43. package/src/components/terminal/PermissionPrompt.tsx +19 -32
  44. package/src/components/terminal/QuestionPrompt.tsx +10 -46
  45. package/src/components/terminal/TerminalTranscript.tsx +3 -86
  46. package/src/components/terminal/items.tsx +5 -43
  47. package/src/components/terminal/scrubber.tsx +25 -272
  48. package/src/components/ui/Popover.tsx +29 -0
  49. package/src/components/ui/Select.tsx +25 -0
  50. package/src/index.ts +46 -8
  51. package/src/lib/file-link.ts +3 -16
  52. package/src/lib/permission-prompt.ts +57 -0
  53. package/src/lib/question-answers.ts +65 -0
  54. package/build/use-path-links-BEWxt0ZM.mjs.map +0 -1
  55. package/src/components/prompt-area/use-markdown-mode.ts +0 -103
package/build/index.mjs CHANGED
@@ -1,11 +1,12 @@
1
- import { $ as shellAgentWriteLabel, $t as Tip, At as isMutatingTool, B as SkillsDialog, Bt as hashtagTrigger, C as SessionInfoDialog, Cn as Badge, Ct as AgentWriteIcon, D as QuestionPrompt, Dn as cn, Dt as PromptTokenText, E as QUESTION_BEHAVIORS, En as buttonVariants, Et as useAffordances, F as PERMISSION_MODES, Ft as mergeComposerRows, G as TaskList, Gt as plainTextToSegments, H as HostFilesDialog, Ht as mentionTrigger, I as PermissionModeSelect, It as rankComposerRows, J as Composer, Jt as Splitter, K as ContextDialog, Kt as segmentsToPlainText, L as permissionModeChoices, Lt as rankPeerSessions, M as SubagentStrip, Mt as TranscriptVariantProvider, N as PermissionPrompt, Nt as useTranscriptVariant, O as parseUserQuestions, Ot as SessionNamesProvider, P as Response, Pt as matchClientCommand, Q as SHELL_KILL_GLYPH, Qt as copyText, R as permissionModeMeta, Rt as skillPrompt, S as STATUS_META, Sn as Input, St as Row, T as TerminalPermissionPrompt, Tn as Button, Tt as WithActions, Ut as usePromptAreaState, V as McpDialog, Vt as launchTrigger, W as TasksDialog, Wt as PromptArea, X as SHELL_AGENT_WRITE_NOTE, Xt as Spinner, Y as TerminalSurface, Yt as CodeBlock, Z as SHELL_GLYPH, Zt as CopyButton, _ as Loader, _n as SelectItemText, _t as TerminalDiff, a as UsageDialog, an as DialogContent, at as ShellActionsProvider, b as ConversationScrollButton, bn as PortalScope, bt as Blank, c as Transcript, cn as DialogTrigger, ct as useToolTitle, d as Message, dn as MenuItem, dt as ImageViewerProvider, en as TooltipContent, et as shellGrantable, f as MessageContent, fn as MenuSeparator, ft as ViewableImage, g as SessionEmptyState, gn as SelectItem, gt as parseFileLink, h as TerminalTranscript, hn as SelectContent, ht as useFileLinks, i as SessionPanel, in as DialogClose, it as shellTitle, j as ShellStrip, jt as toolIcon, k as useShellFrame, kt as SkillNamesProvider, l as ToolCallCard, ln as Menu, lt as TerminalMarkdown, m as TerminalItemView, mn as Select, mt as FileLinkProvider, n as usePathLinks, nn as Dialog, nt as shellInfoLabel, o as UsageMeters, on as DialogHeader, ot as useShellActions, p as FileCard, pn as MenuTrigger, pt as useOpenImage, q as contextNote, qt as ProgressRing, r as matchPath, rn as DialogBody, rt as shellInfoStatusText, s as useMinuteClock, sn as DialogRow, st as ToolTitleProvider, t as resolveAgainstCwd, tn as TooltipProvider, tt as shellInfoFailed, u as Reasoning, un as MenuContent, ut as ImageViewer, v as Conversation, vn as SelectTrigger, vt as previewPatch, w as TerminalQuestionPrompt, wn as badgeVariants, wt as CopyAction, x as StatusBar, xn as Textarea, xt as Ink, y as ConversationContent, yn as SelectValue, yt as Band, z as ModelSelect, zt as commandTrigger } from "./use-path-links-BEWxt0ZM.mjs";
1
+ import { $ as ShellActionsProvider, $t as Spinner, A as PermissionPrompt, An as buttonVariants, At as PromptTokenText, B as ModelSelect, Bt as rankPeerSessions, C as SessionInfoDialog, Cn as SelectValue, Ct as Blank, D as QUESTION_BEHAVIORS, Dn as Badge, Dt as CopyAction, E as TerminalPermissionPrompt, En as Input, Et as AgentWriteIcon, F as SubagentStrip, Ft as TranscriptVariantProvider, G as useMcpPanel, Gt as mentionTrigger, H as McpDialog, Ht as commandTrigger, I as PERMISSION_MODES, It as useTranscriptVariant, J as ContextDialog, Jt as plainTextToSegments, K as HostFilesDialog, Kt as usePromptAreaState, L as PermissionModeSelect, Lt as matchClientCommand, M as useShellFrame, Mt as SkillNamesProvider, Nt as isMutatingTool, O as QuestionPrompt, On as badgeVariants, Ot as WithActions, P as ShellStrip, Pt as toolIcon, Q as TerminalSurface, Qt as CodeBlock, R as permissionModeChoices, Rt as mergeComposerRows, S as STATUS_META, Sn as SelectTrigger, St as Band, T as TerminalQuestionPrompt, Tn as Textarea, Tt as Row, U as McpPanel, Ut as hashtagTrigger, V as SkillsDialog, Vt as skillPrompt, W as McpPanelActions, Wt as launchTrigger, X as contextNote, Xt as ProgressRing, Y as ContextPanel, Yt as segmentsToPlainText, Z as Composer, Zt as Splitter, _ as Loader, _n as OptionSelect, _t as FileLinkProvider, a as UsageDialog, an as Dialog, at as shellGrantable, b as ConversationScrollButton, bn as SelectItem, bt as TerminalDiff, c as TerminalTranscript, cn as DialogContent, ct as shellInfoStatusText, d as Reasoning, dn as DialogTrigger, dt as useToolTitle, en as CopyButton, et as useShellActions, f as Message, fn as Menu, ft as TerminalMarkdown, g as SessionEmptyState, gn as MenuTrigger, gt as useOpenImage, h as TerminalItemView, hn as MenuSeparator, ht as ViewableImage, i as SessionPanel, in as TooltipProvider, it as shellAgentWriteLabel, j as Response, jn as cn, jt as SessionNamesProvider, k as parseUserQuestions, kn as Button, kt as useAffordances, l as Transcript, ln as DialogHeader, lt as shellTitle, m as FileCard, mn as MenuItem, mt as ImageViewerProvider, n as usePathLinks, nn as Tip, nt as SHELL_GLYPH, o as UsageMeters, on as DialogBody, ot as shellInfoFailed, p as MessageContent, pn as MenuContent, pt as ImageViewer, qt as PromptArea, r as matchPath, rn as TooltipContent, rt as SHELL_KILL_GLYPH, s as useMinuteClock, sn as DialogClose, st as shellInfoLabel, t as resolveAgainstCwd, tn as copyText, tt as SHELL_AGENT_WRITE_NOTE, u as ToolCallCard, un as DialogRow, ut as ToolTitleProvider, v as Conversation, vn as Select, vt as useFileLinks, w as SessionInfoPanel, wn as PortalScope, wt as Ink, x as StatusBar, xn as SelectItemText, xt as previewPatch, y as ConversationContent, yn as SelectContent, yt as parseFileLink, z as permissionModeMeta, zt as rankComposerRows } from "./use-path-links-C6Fh5zdx.mjs";
2
2
  import { C as rateLimitWindowSeconds, S as friendlyModel, _ as formatDuration, b as formatRelativeTime, c as tightestWindow, g as formatCountdown, h as formatCost, i as meterSeverity, m as formatBytes, o as modelLabel, p as formatAgoPrecise, r as meterColorClass, s as statusPresentation, t as contextSeverity, u as windowLabel, v as formatRateLimitWindow, w as toolInputPreview, x as formatTokens, y as formatRateLimitWindowLong } from "./status-kmsBhuFG.mjs";
3
3
  import { Fragment, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
- import { Anchor, ArrowRight, Atom, Beaker, BellRing, Bike, Binary, Blocks, Bot, Box, Brain, Briefcase, Brush, Bug, Building2, Cable, Camera, Car, Cat, Check, ChevronDown, CircleAlert, CircleSlash, CircuitBoard, Cloud, Code, Coffee, Cog, Compass, Container, Cpu, CreditCard, Database, Diamond, Dog, Eraser, Feather, Film, Flame, FlaskConical, Folder, Gamepad2, Gauge, Gem, Ghost, Gift, GitBranch, Globe, GraduationCap, Hammer, Hexagon, House, Image, Key, Landmark, Laptop, Layers, Leaf, Library, Lightbulb, Lock, Mail, Map as Map$1, MessageCircle, Mic, Monitor, Moon, Mountain, Music, Network, Newspaper, Notebook, Orbit, Package, Palette, PauseCircle, PenTool, Pencil, Phone, PiggyBank, Plane, Plug, Puzzle, Radar, Radio, Receipt, Rocket, Ruler, Satellite, Scale, Scissors, Search, SearchX, Server, Shield, Ship, ShoppingCart, Signal, Smartphone, Sparkles, Sprout, Square, Star, Sun, Table, Tag, Target, Telescope, Terminal, TestTube, Trash2, TreePine, Trophy, Truck, Umbrella, Users, Wallet, Wand, Waves, Webhook, Wifi, Wrench, X, Zap } from "lucide-react";
5
+ import { Anchor, ArrowRight, Atom, Beaker, BellRing, Bike, Binary, Blocks, Bot, Box, Brain, Briefcase, Brush, Bug, Building2, Cable, Camera, Car, Cat, Check, ChevronDown, Circle, CircleAlert, CircleSlash, CircuitBoard, Cloud, Code, Coffee, Cog, Compass, Container, Cpu, CreditCard, Database, Diamond, Dog, Eraser, Feather, Film, Filter, Flame, FlaskConical, Folder, FolderOpen, Gamepad2, Gauge, Gem, Ghost, Gift, GitBranch, Globe, GraduationCap, Hammer, Hexagon, House, Image, Key, Landmark, Laptop, Layers, Leaf, Library, Lightbulb, Lock, Mail, Map as Map$1, MessageCircle, Mic, Monitor, Moon, Mountain, Music, Network, Newspaper, Notebook, Orbit, Package, Palette, PauseCircle, PenTool, Pencil, Phone, PiggyBank, Plane, Plug, Puzzle, Radar, Radio, Receipt, Rocket, Ruler, Satellite, Scale, Scissors, Search, SearchX, Server, Shield, Ship, ShoppingCart, Signal, Smartphone, Sparkles, Sprout, Square, Star, Sun, Table, Tag, Target, Telescope, Terminal, TestTube, Trash2, TreePine, Trophy, Truck, Umbrella, Users, Wallet, Wand, Waves, Webhook, Wifi, Wrench, X, Zap } from "lucide-react";
6
6
  import { AlertDialog as AlertDialog$1 } from "@base-ui/react/alert-dialog";
7
+ import { Popover as Popover$1 } from "@base-ui/react/popover";
7
8
  import { Toaster as Toaster$1, toast } from "sonner";
8
- import { STATE_LABELS, STATE_ORDER, adaptersOf, clearFilters, filterRows, groupRows, hasFacetFilter, isAgentRecord, projectLabel, projectName, projectSubpath, projectsOf, promotedShells, sessionLabel, subagentLabel, subsetSummary, visibleSubagents } from "@workerdeck/protocol";
9
+ import { STATE_LABELS, STATE_ORDER, adaptersOf, clearFilters, displayCustomized, displayedTasks, facetFilterCount, filterRows, groupRows, hasFacetFilter, isAgentRecord, projectLabel, projectName, projectSubpath, projectsOf, scopeActive, sessionLabel, subagentLabel, subsetSummary, taskSummary, visibleShells, visibleSubagents, visibleTasks } from "@workerdeck/protocol";
9
10
  //#region src/components/ui/Card.tsx
10
11
  function Card({ className, ...props }) {
11
12
  return /* @__PURE__ */ jsx("div", {
@@ -52,6 +53,21 @@ const AlertDialogDescription = ({ className, ...props }) => /* @__PURE__ */ jsx(
52
53
  ...props
53
54
  });
54
55
  //#endregion
56
+ //#region src/components/ui/Popover.tsx
57
+ const Popover = Popover$1.Root;
58
+ const PopoverTrigger = Popover$1.Trigger;
59
+ const PopoverContent = ({ className, align = "end", side = "bottom", sideOffset = 6, ...props }) => /* @__PURE__ */ jsx(Popover$1.Portal, { children: /* @__PURE__ */ jsx(PortalScope, { children: /* @__PURE__ */ jsx(Popover$1.Positioner, {
60
+ align,
61
+ side,
62
+ sideOffset,
63
+ className: "isolate z-80 outline-none",
64
+ children: /* @__PURE__ */ jsx(Popover$1.Popup, {
65
+ "data-slot": "popover-content",
66
+ className: cn("rounded-md border border-border bg-surface p-2 text-fg-1 shadow-(--shadow-lg) outline-none", "transition-[opacity,transform] duration-(--motion-base)", "data-starting-style:scale-95 data-starting-style:opacity-0", "data-ending-style:scale-95 data-ending-style:opacity-0", className),
67
+ ...props
68
+ })
69
+ }) }) });
70
+ //#endregion
55
71
  //#region src/components/ui/Sonner.tsx
56
72
  function Toaster() {
57
73
  return /* @__PURE__ */ jsx(Toaster$1, {
@@ -196,6 +212,102 @@ function TerminalStatusLine({ className, state, rateLimits, connection, onOpenSt
196
212
  });
197
213
  }
198
214
  //#endregion
215
+ //#region src/components/agent/TaskList.tsx
216
+ function TaskList({ tasks, showCompleted, onShowCompletedChange, onSelectTask, className }) {
217
+ const summary = taskSummary(tasks);
218
+ const shown = visibleTasks(tasks, showCompleted);
219
+ const hidden = tasks.length - shown.length;
220
+ return /* @__PURE__ */ jsxs("div", {
221
+ className: cn("flex flex-col", className),
222
+ children: [/* @__PURE__ */ jsxs("div", {
223
+ className: "flex items-baseline justify-between gap-4 pb-1.5",
224
+ children: [/* @__PURE__ */ jsxs("span", {
225
+ className: "text-label text-fg-3",
226
+ children: [
227
+ summary.done,
228
+ " of ",
229
+ summary.total,
230
+ " done",
231
+ summary.failed > 0 ? ` · ${summary.failed} failed` : ""
232
+ ]
233
+ }), summary.done > 0 && onShowCompletedChange ? /* @__PURE__ */ jsx("button", {
234
+ type: "button",
235
+ onClick: () => onShowCompletedChange(!showCompleted),
236
+ className: "shrink-0 rounded-[4px] px-1 py-0.5 text-label text-fg-4 outline-none hover:bg-row-hover hover:text-fg-2",
237
+ children: showCompleted ? "Hide completed" : `Show completed (${summary.done})`
238
+ }) : null]
239
+ }), shown.length === 0 ? /* @__PURE__ */ jsx("p", {
240
+ className: "py-6 text-center text-body-sm text-fg-4",
241
+ children: tasks.length === 0 ? "No tasks yet - a checklist appears once the agent plans one." : `${hidden} completed, all hidden.`
242
+ }) : /* @__PURE__ */ jsx("div", {
243
+ className: "flex flex-col",
244
+ children: shown.map((task) => /* @__PURE__ */ jsx(TaskRow, {
245
+ task,
246
+ onSelect: onSelectTask
247
+ }, task.key))
248
+ })]
249
+ });
250
+ }
251
+ function TaskRow({ task, onSelect }) {
252
+ const pressable = onSelect !== void 0 && task.toolUseId !== void 0;
253
+ const body = task.state === "failed" ? "text-danger" : task.state === "done" ? "text-fg-4" : "text-fg-2";
254
+ const row = /* @__PURE__ */ jsxs(Fragment$1, { children: [
255
+ /* @__PURE__ */ jsx(TaskIcon, { state: task.state }),
256
+ /* @__PURE__ */ jsx("span", {
257
+ className: cn("min-w-0 flex-1 truncate text-left", task.state === "done" ? "line-through" : void 0),
258
+ children: task.label
259
+ }),
260
+ task.detail ? /* @__PURE__ */ jsx("span", {
261
+ className: "shrink-0 tabular-nums text-fg-4",
262
+ children: task.detail
263
+ }) : null,
264
+ pressable ? /* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5 shrink-0 text-fg-4" }) : null
265
+ ] });
266
+ const className = cn("flex w-full items-center gap-1.5 rounded-[4px] px-1.5 py-1 text-body-sm outline-none", body);
267
+ if (!pressable) return /* @__PURE__ */ jsx("div", {
268
+ className,
269
+ children: row
270
+ });
271
+ return /* @__PURE__ */ jsx("button", {
272
+ type: "button",
273
+ title: task.label,
274
+ onClick: () => onSelect(task),
275
+ className: cn(className, "hover:bg-row-active"),
276
+ children: row
277
+ });
278
+ }
279
+ function TaskIcon({ state }) {
280
+ switch (state) {
281
+ case "running": return /* @__PURE__ */ jsx(Spinner, { className: "size-[13px] shrink-0" });
282
+ case "failed": return /* @__PURE__ */ jsx(CircleAlert, { className: "size-[13px] shrink-0" });
283
+ case "done": return /* @__PURE__ */ jsx(Check, { className: "size-[13px] shrink-0" });
284
+ default: return /* @__PURE__ */ jsx(Circle, { className: "size-[13px] shrink-0 text-fg-4" });
285
+ }
286
+ }
287
+ //#endregion
288
+ //#region src/components/agent/TasksDialog.tsx
289
+ function TasksDialog({ tasks, showCompleted, onShowCompletedChange, onSelectTask, open, onOpenChange, className }) {
290
+ return /* @__PURE__ */ jsx(Dialog, {
291
+ open,
292
+ onOpenChange,
293
+ children: /* @__PURE__ */ jsxs(DialogContent, {
294
+ className,
295
+ children: [/* @__PURE__ */ jsx(DialogHeader, {
296
+ title: "Tasks",
297
+ description: "The agent's checklist and the tasks it has spawned"
298
+ }), /* @__PURE__ */ jsx(DialogBody, { children: /* @__PURE__ */ jsx(TaskList, {
299
+ tasks,
300
+ showCompleted,
301
+ onShowCompletedChange,
302
+ onSelectTask: onSelectTask ? (task) => {
303
+ onOpenChange(false);
304
+ onSelectTask(task);
305
+ } : void 0
306
+ }) })]
307
+ })
308
+ });
309
+ }
310
+ //#endregion
199
311
  //#region src/components/agent/SessionList.tsx
200
312
  function SessionListItem({ session, active, onSelect, onDelete, className }) {
201
313
  const meta = STATUS_META[session.status];
@@ -395,6 +507,287 @@ function ProjectIcon({ icon, src, name, className }) {
395
507
  return /* @__PURE__ */ jsx(Glyph, { className: cn("inline-block size-3 shrink-0", className) });
396
508
  }
397
509
  //#endregion
510
+ //#region src/components/agent/SessionFilters.tsx
511
+ const STEP_DISPLAY_OPTIONS = [
512
+ {
513
+ value: "all",
514
+ label: "All"
515
+ },
516
+ {
517
+ value: "active",
518
+ label: "Active"
519
+ },
520
+ {
521
+ value: "none",
522
+ label: "Hide"
523
+ }
524
+ ];
525
+ function SessionFilters({ config, onConfigChange, rows, scope, gateways: gatewaysProp, className }) {
526
+ const adapters = useMemo(() => adaptersOf(rows), [rows]);
527
+ const projects = useMemo(() => projectsOf(rows), [rows]);
528
+ const gateways = useMemo(() => {
529
+ if (gatewaysProp) return gatewaysProp;
530
+ const seen = /* @__PURE__ */ new Map();
531
+ for (const row of rows) seen.set(row.hostId, row.hostName);
532
+ return [...seen].map(([id, name]) => ({
533
+ id,
534
+ name
535
+ }));
536
+ }, [rows, gatewaysProp]);
537
+ const set = (patch) => onConfigChange({
538
+ ...config,
539
+ ...patch
540
+ });
541
+ return /* @__PURE__ */ jsxs("div", {
542
+ "data-slot": "session-filters",
543
+ className: cn("flex flex-col gap-3", className),
544
+ children: [
545
+ /* @__PURE__ */ jsxs(Section, {
546
+ title: "Filter",
547
+ children: [
548
+ scope ? /* @__PURE__ */ jsx(FilterRow, {
549
+ label: "Scope",
550
+ children: /* @__PURE__ */ jsx(OptionSelect, {
551
+ className: "w-full min-w-0",
552
+ label: "Scope",
553
+ value: config.scoped ? "scoped" : "all",
554
+ options: [{
555
+ value: "scoped",
556
+ label: scope.label
557
+ }, {
558
+ value: "all",
559
+ label: "All folders"
560
+ }],
561
+ onChange: (value) => set({ scoped: value === "scoped" })
562
+ })
563
+ }) : null,
564
+ /* @__PURE__ */ jsx(FilterRow, {
565
+ label: "State",
566
+ children: /* @__PURE__ */ jsx(FacetSelect, {
567
+ label: "State",
568
+ value: config.states,
569
+ options: STATE_ORDER.map((s) => ({
570
+ value: s,
571
+ label: STATE_LABELS[s]
572
+ })),
573
+ onChange: (states) => set({ states })
574
+ })
575
+ }),
576
+ adapters.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
577
+ label: "Engine",
578
+ children: /* @__PURE__ */ jsx(FacetSelect, {
579
+ label: "Engine",
580
+ value: config.adapters,
581
+ options: adapters.map((a) => ({
582
+ value: a,
583
+ label: a
584
+ })),
585
+ onChange: (next) => set({ adapters: next })
586
+ })
587
+ }) : null,
588
+ gateways.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
589
+ label: "Gateway",
590
+ children: /* @__PURE__ */ jsx(FacetSelect, {
591
+ label: "Gateway",
592
+ value: config.gateways,
593
+ options: gateways.map((g) => ({
594
+ value: g.id,
595
+ label: g.name
596
+ })),
597
+ onChange: (next) => set({ gateways: next })
598
+ })
599
+ }) : null,
600
+ projects.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
601
+ label: "Project",
602
+ children: /* @__PURE__ */ jsx(FacetSelect, {
603
+ label: "Project",
604
+ value: config.projects ?? [],
605
+ options: projects.map((p) => ({
606
+ value: p.key,
607
+ label: p.label
608
+ })),
609
+ onChange: (next) => set({ projects: next })
610
+ })
611
+ }) : null
612
+ ]
613
+ }),
614
+ /* @__PURE__ */ jsxs(Section, {
615
+ title: "Layout",
616
+ children: [/* @__PURE__ */ jsx(FilterRow, {
617
+ label: "Group",
618
+ children: /* @__PURE__ */ jsx(OptionSelect, {
619
+ className: "w-full min-w-0",
620
+ label: "Group",
621
+ value: config.groupBy,
622
+ options: [
623
+ {
624
+ value: "none",
625
+ label: "No grouping"
626
+ },
627
+ {
628
+ value: "state",
629
+ label: "By state"
630
+ },
631
+ {
632
+ value: "adapter",
633
+ label: "By engine"
634
+ },
635
+ ...projects.length > 1 ? [{
636
+ value: "project",
637
+ label: "By project"
638
+ }] : [],
639
+ ...gateways.length > 1 ? [{
640
+ value: "gateway",
641
+ label: "By gateway"
642
+ }] : []
643
+ ],
644
+ onChange: (groupBy) => set({ groupBy })
645
+ })
646
+ }), /* @__PURE__ */ jsx(FilterRow, {
647
+ label: "Sort",
648
+ children: /* @__PURE__ */ jsx(OptionSelect, {
649
+ className: "w-full min-w-0",
650
+ label: "Sort",
651
+ value: config.sortBy,
652
+ options: [
653
+ {
654
+ value: "recent",
655
+ label: "Recent"
656
+ },
657
+ {
658
+ value: "name",
659
+ label: "Name"
660
+ },
661
+ {
662
+ value: "state",
663
+ label: "State"
664
+ },
665
+ ...projects.length > 1 ? [{
666
+ value: "project",
667
+ label: "Project"
668
+ }] : [],
669
+ ...gateways.length > 1 ? [{
670
+ value: "gateway",
671
+ label: "Gateway"
672
+ }] : []
673
+ ],
674
+ onChange: (sortBy) => set({ sortBy })
675
+ })
676
+ })]
677
+ }),
678
+ /* @__PURE__ */ jsxs(Section, {
679
+ title: "Show under each session",
680
+ children: [
681
+ /* @__PURE__ */ jsx(FilterRow, {
682
+ label: "Agents",
683
+ children: /* @__PURE__ */ jsx(StepDisplayControl, {
684
+ label: "Agents",
685
+ value: config.subagents,
686
+ onChange: (subagents) => set({ subagents })
687
+ })
688
+ }),
689
+ /* @__PURE__ */ jsx(FilterRow, {
690
+ label: "Shells",
691
+ children: /* @__PURE__ */ jsx(StepDisplayControl, {
692
+ label: "Shells",
693
+ value: config.shells ?? "active",
694
+ onChange: (shells) => set({ shells })
695
+ })
696
+ }),
697
+ /* @__PURE__ */ jsx(FilterRow, {
698
+ label: "Tasks",
699
+ children: /* @__PURE__ */ jsx(StepDisplayControl, {
700
+ label: "Tasks",
701
+ value: config.tasks ?? "active",
702
+ onChange: (tasks) => set({ tasks })
703
+ })
704
+ })
705
+ ]
706
+ })
707
+ ]
708
+ });
709
+ }
710
+ function SessionFiltersButton({ open, onOpenChange, className, ...props }) {
711
+ const count = facetFilterCount(props.config);
712
+ const engaged = count > 0 || displayCustomized(props.config);
713
+ return /* @__PURE__ */ jsxs(Popover, {
714
+ open,
715
+ onOpenChange,
716
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, { render: /* @__PURE__ */ jsx(Button, {
717
+ variant: "ghost",
718
+ size: "icon-sm",
719
+ "aria-label": count > 0 ? `Filters (${count} active)` : "Filters",
720
+ title: count > 0 ? `${count} filter${count === 1 ? "" : "s"} active` : "Filters",
721
+ className,
722
+ children: /* @__PURE__ */ jsx(Filter, { className: cn("size-3.5", engaged && "fill-current text-fg-1") })
723
+ }) }), /* @__PURE__ */ jsx(PopoverContent, {
724
+ className: "w-80",
725
+ children: /* @__PURE__ */ jsx(SessionFilters, { ...props })
726
+ })]
727
+ });
728
+ }
729
+ function StepDisplayControl({ label, value, onChange }) {
730
+ return /* @__PURE__ */ jsx("div", {
731
+ role: "radiogroup",
732
+ "aria-label": label,
733
+ className: "flex w-full rounded-md border border-border p-px",
734
+ children: STEP_DISPLAY_OPTIONS.map((option) => /* @__PURE__ */ jsx("button", {
735
+ type: "button",
736
+ role: "radio",
737
+ "aria-checked": option.value === value,
738
+ onClick: () => onChange(option.value),
739
+ className: cn("min-w-0 flex-1 truncate rounded-[4px] px-1.5 py-0.5 text-label outline-none transition-colors", "focus-visible:ring-2 focus-visible:ring-ring", option.value === value ? "bg-row-selected text-fg-1" : "text-fg-3 hover:bg-row-hover hover:text-fg-1"),
740
+ children: option.label
741
+ }, option.value))
742
+ });
743
+ }
744
+ function Section({ title, children }) {
745
+ return /* @__PURE__ */ jsxs("div", {
746
+ className: "flex flex-col gap-1.5",
747
+ children: [/* @__PURE__ */ jsx("div", {
748
+ className: "text-label font-medium uppercase tracking-wide text-fg-4",
749
+ children: title
750
+ }), children]
751
+ });
752
+ }
753
+ function FilterRow({ label, children }) {
754
+ return /* @__PURE__ */ jsxs("div", {
755
+ className: "flex items-center gap-2",
756
+ children: [/* @__PURE__ */ jsx("span", {
757
+ "aria-hidden": true,
758
+ className: "w-16 shrink-0 truncate text-label text-fg-3",
759
+ children: label
760
+ }), /* @__PURE__ */ jsx("div", {
761
+ className: "min-w-0 flex-1",
762
+ children
763
+ })]
764
+ });
765
+ }
766
+ function FacetSelect({ label, value, options, onChange }) {
767
+ return /* @__PURE__ */ jsxs("div", {
768
+ className: "flex items-center gap-1",
769
+ children: [/* @__PURE__ */ jsxs(Select, {
770
+ multiple: true,
771
+ value,
772
+ onValueChange: (v) => onChange(v),
773
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
774
+ "aria-label": label,
775
+ className: "min-w-0 flex-1",
776
+ children: /* @__PURE__ */ jsx(SelectValue, { children: value.length === 0 ? "All" : value.length === 1 ? options.find((o) => o.value === value[0])?.label ?? "All" : `${value.length} selected` })
777
+ }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
778
+ value: option.value,
779
+ children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
780
+ }, option.value)) })]
781
+ }), value.length > 0 ? /* @__PURE__ */ jsx(Button, {
782
+ variant: "ghost",
783
+ size: "icon-sm",
784
+ "aria-label": `Clear ${label}`,
785
+ onClick: () => onChange([]),
786
+ children: /* @__PURE__ */ jsx(X, { className: "size-3 text-fg-4" })
787
+ }) : null]
788
+ });
789
+ }
790
+ //#endregion
398
791
  //#region src/components/agent/ContextRing.tsx
399
792
  function ContextRing({ usage, engine, size = 11, className }) {
400
793
  if (usage === void 0) return null;
@@ -513,7 +906,7 @@ function SessionStatusIcon({ row, className }) {
513
906
  }
514
907
  //#endregion
515
908
  //#region src/components/agent/SessionSteps.tsx
516
- function sessionSteps(info, onSelect, show = "all", shells) {
909
+ function sessionSteps(info, onSelect, show = "all", shells, tasks) {
517
910
  const agents = visibleSubagents(info, show).filter(isAgentRecord).map((sub) => ({
518
911
  key: sub.toolUseId,
519
912
  kind: "agent",
@@ -524,9 +917,31 @@ function sessionSteps(info, onSelect, show = "all", shells) {
524
917
  title: `${subagentLabel(sub)} · ${sub.toolCount} tool${sub.toolCount === 1 ? "" : "s"}`,
525
918
  onSelect: () => onSelect(sub.toolUseId)
526
919
  }));
527
- if (shells === void 0) return agents;
920
+ const taskSteps = tasks === void 0 ? [] : displayedTasks(info, tasks.show).map((task) => taskStep(task, tasks));
921
+ if (shells === void 0) return [...agents, ...taskSteps];
528
922
  const grants = info.shellAgentWrite !== void 0;
529
- return [...agents, ...promotedShells(info, shells.now).map((shell) => shellStep(shell, shells, grants))];
923
+ const shellSteps = visibleShells(info, shells.show ?? "active", shells.now).map((shell) => shellStep(shell, shells, grants));
924
+ return [
925
+ ...agents,
926
+ ...taskSteps,
927
+ ...shellSteps
928
+ ];
929
+ }
930
+ function taskStep(task, options) {
931
+ const stalled = task.source === "checklist" && task.state === "running" && !options.live;
932
+ const toolUseId = task.toolUseId;
933
+ return {
934
+ key: task.key,
935
+ kind: "task",
936
+ label: task.label,
937
+ noun: "task",
938
+ state: stalled ? "pending" : task.state,
939
+ detail: task.detail,
940
+ title: stalled ? `${task.label} · left in progress` : task.label,
941
+ onSelect: () => options.onSelect(task),
942
+ onKill: task.stoppable && toolUseId !== void 0 && options.onStop ? () => options.onStop?.(toolUseId) : void 0,
943
+ killLabel: "Stop this task"
944
+ };
530
945
  }
531
946
  function shellStep(shell, options, grants) {
532
947
  const status = shellInfoStatusText(shell);
@@ -541,6 +956,7 @@ function shellStep(shell, options, grants) {
541
956
  title: `${shellTitle(shell)} · ${status}`,
542
957
  onSelect: () => options.onSelect(shell.id),
543
958
  onKill: running && options.onKill ? () => options.onKill?.(shell.id) : void 0,
959
+ killLabel: "Kill this shell",
544
960
  agentWrite: grants && options.onAgentWrite && shellGrantable(shell) ? {
545
961
  granted: shell.agentWrite === true,
546
962
  label: shellAgentWriteLabel(shell),
@@ -556,7 +972,7 @@ function stepState(status) {
556
972
  }
557
973
  }
558
974
  function StepRow({ step, active = false, onSelect }) {
559
- const body = step.state === "failed" ? "text-danger" : step.kind === "shell" ? "text-[var(--wd-shell-accent)]" : "text-success";
975
+ const body = step.state === "failed" ? "text-danger" : step.kind === "shell" ? "text-[var(--wd-shell-accent)]" : step.kind === "task" ? step.state === "pending" ? "text-fg-4" : "text-fg-2" : "text-success";
560
976
  return /* @__PURE__ */ jsxs("div", {
561
977
  className: cn("flex w-full items-center rounded-[4px] pr-1.5", active ? "bg-row-selected" : "hover:bg-row-active", body),
562
978
  children: [
@@ -579,7 +995,7 @@ function StepRow({ step, active = false, onSelect }) {
579
995
  className: "shrink-0 tabular-nums text-fg-4",
580
996
  children: step.detail
581
997
  }) : null,
582
- step.kind === "shell" ? null : /* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5 shrink-0 text-fg-4" })
998
+ step.kind === "agent" ? /* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5 shrink-0 text-fg-4" }) : null
583
999
  ]
584
1000
  }),
585
1001
  step.agentWrite ? /* @__PURE__ */ jsx("button", {
@@ -599,8 +1015,8 @@ function StepRow({ step, active = false, onSelect }) {
599
1015
  }) : null,
600
1016
  step.onKill ? /* @__PURE__ */ jsx("button", {
601
1017
  type: "button",
602
- "aria-label": `Kill ${step.label}`,
603
- title: "Kill this shell",
1018
+ "aria-label": `${step.kind === "task" ? "Stop" : "Kill"} ${step.label}`,
1019
+ title: step.killLabel,
604
1020
  onClick: (e) => {
605
1021
  e.stopPropagation();
606
1022
  step.onKill?.();
@@ -619,6 +1035,7 @@ function StepIcon({ step }) {
619
1035
  switch (step.state) {
620
1036
  case "running": return /* @__PURE__ */ jsx(Spinner, { className: "size-[11px] shrink-0" });
621
1037
  case "failed": return /* @__PURE__ */ jsx(CircleAlert, { className: "size-[11px] shrink-0" });
1038
+ case "pending": return /* @__PURE__ */ jsx(Circle, { className: "size-[11px] shrink-0" });
622
1039
  default: return /* @__PURE__ */ jsx(Check, { className: "size-[11px] shrink-0" });
623
1040
  }
624
1041
  }
@@ -629,7 +1046,7 @@ const NO_MODIFIERS = {
629
1046
  ctrl: false,
630
1047
  alt: false
631
1048
  };
632
- function SessionItem({ row, active = false, activeStepKey, showGateway, showProject = true, projectIcons, subagents = "active", onSelect, onSelectSubagent, onSelectShell, onKillShell, onShellAgentWrite, now, onRename, renameOn = "doubleClick", editing, onEditingChange, actions, className }) {
1049
+ function SessionItem({ row, active = false, activeStepKey, showGateway, showProject = true, projectIcons, subagents = "active", shells = "active", tasks = "active", onSelect, onSelectSubagent, onSelectTask, onStopTask, onSelectShell, onKillShell, onShellAgentWrite, now, onRename, renameOn = "doubleClick", editing, onEditingChange, actions, className }) {
633
1050
  const { info } = row;
634
1051
  const [ownEditing, setOwnEditing] = useState(false);
635
1052
  const isEditing = editing ?? ownEditing;
@@ -666,9 +1083,15 @@ function SessionItem({ row, active = false, activeStepKey, showGateway, showProj
666
1083
  for (const extra of extras) parts.push(/* @__PURE__ */ jsx("span", { children: extra }, extra));
667
1084
  const steps = sessionSteps(info, (toolUseId) => onSelectSubagent ? onSelectSubagent(toolUseId) : onSelect?.(NO_MODIFIERS), subagents, {
668
1085
  now: now ?? Date.now(),
1086
+ show: shells,
669
1087
  onSelect: (shellId) => onSelectShell ? onSelectShell(shellId) : onSelect?.(NO_MODIFIERS),
670
1088
  onKill: onKillShell,
671
1089
  onAgentWrite: onShellAgentWrite
1090
+ }, {
1091
+ show: tasks,
1092
+ live: info.status === "running" || info.status === "starting" || info.status === "awaiting_approval",
1093
+ onSelect: (task) => onSelectTask ? onSelectTask(task) : onSelect?.(NO_MODIFIERS),
1094
+ onStop: onStopTask
672
1095
  });
673
1096
  const holdsOpenStep = steps.some((s) => s.key === activeStepKey);
674
1097
  return /* @__PURE__ */ jsxs("div", {
@@ -805,7 +1228,7 @@ function NameEditor({ initial, onCommit, onCancel }) {
805
1228
  function rowShapeClass(active) {
806
1229
  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");
807
1230
  }
808
- function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeSubagentId, activeShellId, now, onSelect, onDelete, onRename, onClearContext, onSelectSubagent, onSelectShell, onKillShell, onShellAgentWrite, emptyState, showControls = true, projectIcons, className }) {
1231
+ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeSubagentId, activeShellId, now, isActive = (row) => row.info.id === activeId, rowActions, gatewayCount, showSubset = true, onSelect, onDelete, onRename, onClearContext, onSelectSubagent, onSelectTask, onStopTask, onSelectShell, onKillShell, onShellAgentWrite, emptyState, showControls = true, showSearch = showControls, autoFocusSearch, projectIcons, className }) {
809
1232
  const visible = useMemo(() => filterRows(rows, config, scope), [
810
1233
  rows,
811
1234
  config,
@@ -813,16 +1236,7 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
813
1236
  ]);
814
1237
  const groups = useMemo(() => groupRows(visible, config), [visible, config]);
815
1238
  const subset = subsetSummary(config, scope, visible.length, rows.length);
816
- const adapters = useMemo(() => adaptersOf(rows), [rows]);
817
- const projects = useMemo(() => projectsOf(rows), [rows]);
818
- const gateways = useMemo(() => {
819
- const seen = /* @__PURE__ */ new Map();
820
- for (const row of rows) seen.set(row.hostId, row.hostName);
821
- return [...seen].map(([id, name]) => ({
822
- id,
823
- name
824
- }));
825
- }, [rows]);
1239
+ const rowGateways = useMemo(() => new Set(rows.map((row) => row.hostId)).size, [rows]);
826
1240
  const set = (patch) => onConfigChange({
827
1241
  ...config,
828
1242
  ...patch
@@ -831,152 +1245,20 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
831
1245
  "data-slot": "session-browser",
832
1246
  className: cn("flex flex-col gap-3", className),
833
1247
  children: [
834
- /* @__PURE__ */ jsxs("div", {
835
- className: cn("flex flex-col gap-1.5 px-2", !showControls && "hidden"),
836
- children: [
837
- /* @__PURE__ */ jsxs("div", {
838
- className: "relative",
839
- 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, {
840
- value: config.search,
841
- onChange: (e) => set({ search: e.target.value }),
842
- placeholder: "Search sessions",
843
- "aria-label": "Search sessions",
844
- className: "pl-8"
845
- })]
846
- }),
847
- /* @__PURE__ */ jsx(FilterRow, {
848
- label: "State",
849
- children: /* @__PURE__ */ jsx(FacetSelect, {
850
- label: "State",
851
- value: config.states,
852
- options: STATE_ORDER.map((s) => ({
853
- value: s,
854
- label: STATE_LABELS[s]
855
- })),
856
- onChange: (states) => set({ states })
857
- })
858
- }),
859
- adapters.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
860
- label: "Engine",
861
- children: /* @__PURE__ */ jsx(FacetSelect, {
862
- label: "Engine",
863
- value: config.adapters,
864
- options: adapters.map((a) => ({
865
- value: a,
866
- label: a
867
- })),
868
- onChange: (adapters) => set({ adapters })
869
- })
870
- }) : null,
871
- gateways.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
872
- label: "Gateway",
873
- children: /* @__PURE__ */ jsx(FacetSelect, {
874
- label: "Gateway",
875
- value: config.gateways,
876
- options: gateways.map((g) => ({
877
- value: g.id,
878
- label: g.name
879
- })),
880
- onChange: (gateways) => set({ gateways })
881
- })
882
- }) : null,
883
- projects.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
884
- label: "Project",
885
- children: /* @__PURE__ */ jsx(FacetSelect, {
886
- label: "Project",
887
- value: config.projects ?? [],
888
- options: projects.map((p) => ({
889
- value: p.key,
890
- label: p.label
891
- })),
892
- onChange: (next) => set({ projects: next })
893
- })
894
- }) : null,
895
- /* @__PURE__ */ jsx(FilterRow, {
896
- label: "Group",
897
- children: /* @__PURE__ */ jsx(OneOfSelect, {
898
- label: "Group",
899
- value: config.groupBy,
900
- options: [
901
- {
902
- value: "none",
903
- label: "No grouping"
904
- },
905
- {
906
- value: "state",
907
- label: "By state"
908
- },
909
- {
910
- value: "adapter",
911
- label: "By engine"
912
- },
913
- ...projects.length > 1 ? [{
914
- value: "project",
915
- label: "By project"
916
- }] : [],
917
- ...gateways.length > 1 ? [{
918
- value: "gateway",
919
- label: "By gateway"
920
- }] : []
921
- ],
922
- onChange: (groupBy) => set({ groupBy })
923
- })
924
- }),
925
- /* @__PURE__ */ jsx(FilterRow, {
926
- label: "Sub-agents",
927
- children: /* @__PURE__ */ jsx(OneOfSelect, {
928
- label: "Sub-agents",
929
- value: config.subagents,
930
- options: [
931
- {
932
- value: "active",
933
- label: "Hide completed"
934
- },
935
- {
936
- value: "all",
937
- label: "Show all"
938
- },
939
- {
940
- value: "none",
941
- label: "Hide all"
942
- }
943
- ],
944
- onChange: (subagents) => set({ subagents })
945
- })
946
- }),
947
- /* @__PURE__ */ jsx(FilterRow, {
948
- label: "Sort",
949
- children: /* @__PURE__ */ jsx(OneOfSelect, {
950
- label: "Sort",
951
- value: config.sortBy,
952
- options: [
953
- {
954
- value: "recent",
955
- label: "Recent"
956
- },
957
- {
958
- value: "name",
959
- label: "Name"
960
- },
961
- {
962
- value: "state",
963
- label: "State"
964
- },
965
- ...projects.length > 1 ? [{
966
- value: "project",
967
- label: "Project"
968
- }] : [],
969
- ...gateways.length > 1 ? [{
970
- value: "gateway",
971
- label: "Gateway"
972
- }] : []
973
- ],
974
- onChange: (sortBy) => set({ sortBy })
975
- })
976
- })
977
- ]
978
- }),
979
- subset ? /* @__PURE__ */ jsxs("div", {
1248
+ showSearch ? /* @__PURE__ */ jsx(SessionSearch, {
1249
+ value: config.search,
1250
+ onChange: (search) => set({ search }),
1251
+ autoFocus: autoFocusSearch,
1252
+ className: "px-2"
1253
+ }) : null,
1254
+ showControls ? /* @__PURE__ */ jsx(SessionFilters, {
1255
+ config,
1256
+ onConfigChange,
1257
+ rows,
1258
+ scope,
1259
+ className: "px-2"
1260
+ }) : null,
1261
+ subset && showSubset ? /* @__PURE__ */ jsxs("div", {
980
1262
  className: "flex items-center gap-2 px-3 text-label text-fg-4",
981
1263
  children: [/* @__PURE__ */ jsxs("span", { children: [
982
1264
  subset.shown,
@@ -999,6 +1281,12 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
999
1281
  description: "No session matches the current search and filters.",
1000
1282
  action: "Clear filters",
1001
1283
  onAction: () => onConfigChange(clearFilters(config))
1284
+ }) : scope && scopeActive(config, scope) ? /* @__PURE__ */ jsx(Empty, {
1285
+ icon: /* @__PURE__ */ jsx(FolderOpen, {}),
1286
+ title: "Nothing in this folder",
1287
+ description: `No session is running in ${scope.label}.`,
1288
+ action: "Show all folders",
1289
+ onAction: () => set({ scoped: false })
1002
1290
  }) : /* @__PURE__ */ jsx(Empty, {
1003
1291
  icon: /* @__PURE__ */ jsx(Layers, {}),
1004
1292
  title: "Nothing here",
@@ -1026,19 +1314,24 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
1026
1314
  ]
1027
1315
  }) : null, group.rows.map((row) => /* @__PURE__ */ jsx(SessionRowItem, {
1028
1316
  row,
1029
- active: row.info.id === activeId,
1317
+ active: isActive(row),
1030
1318
  activeSubagentId,
1031
1319
  activeShellId,
1320
+ actions: rowActions?.(row),
1032
1321
  now,
1033
- showGateway: gateways.length > 1 && config.groupBy !== "gateway",
1322
+ showGateway: (gatewayCount ?? rowGateways) > 1 && config.groupBy !== "gateway",
1034
1323
  showProject: config.groupBy !== "project",
1035
1324
  subagents: config.subagents,
1325
+ shells: config.shells,
1326
+ tasks: config.tasks,
1036
1327
  projectIcons,
1037
1328
  onSelect,
1038
1329
  onDelete,
1039
1330
  onRename,
1040
1331
  onClearContext,
1041
1332
  onSelectSubagent,
1333
+ onSelectTask,
1334
+ onStopTask,
1042
1335
  onSelectShell,
1043
1336
  onKillShell,
1044
1337
  onShellAgentWrite
@@ -1052,28 +1345,32 @@ function iconSrcOf(row, icons) {
1052
1345
  const icon = row?.info.project?.icon;
1053
1346
  return icon?.type === "image" ? icons?.[icon.hash] : void 0;
1054
1347
  }
1055
- function SessionRowItem({ row, active, activeSubagentId, activeShellId, now, showGateway, showProject = true, subagents, projectIcons, onSelect, onDelete, onRename, onClearContext, onSelectSubagent, onSelectShell, onKillShell, onShellAgentWrite }) {
1348
+ function SessionRowItem({ row, active, actions, activeSubagentId, activeShellId, now, showGateway, showProject = true, subagents, shells, tasks, projectIcons, onSelect, onDelete, onRename, onClearContext, onSelectSubagent, onSelectTask, onStopTask, onSelectShell, onKillShell, onShellAgentWrite }) {
1056
1349
  const { info } = row;
1057
1350
  const [editing, setEditing] = useState(false);
1058
1351
  return /* @__PURE__ */ jsx(SessionItem, {
1059
1352
  row,
1060
1353
  active: active === true,
1061
- activeStepKey: activeShellId ?? activeSubagentId,
1354
+ activeStepKey: active ? activeShellId ?? activeSubagentId : void 0,
1062
1355
  now,
1063
1356
  showGateway,
1064
1357
  showProject,
1065
1358
  subagents,
1359
+ shells,
1360
+ tasks,
1066
1361
  projectIcons,
1067
- onSelect: () => onSelect?.(row),
1362
+ onSelect: (modifiers) => onSelect?.(row, modifiers),
1068
1363
  onSelectSubagent: onSelectSubagent ? (id) => onSelectSubagent(row, id) : void 0,
1364
+ onSelectTask: onSelectTask ? (task) => onSelectTask(row, task) : void 0,
1365
+ onStopTask: onStopTask ? (id) => onStopTask(row, id) : void 0,
1069
1366
  onSelectShell: onSelectShell ? (id) => onSelectShell(row, id) : void 0,
1070
1367
  onKillShell: onKillShell ? (id) => onKillShell(row, id) : void 0,
1071
1368
  onShellAgentWrite: onShellAgentWrite ? (id, enabled) => onShellAgentWrite(row, id, enabled) : void 0,
1072
1369
  onRename: onRename ? (title) => onRename(row, title) : void 0,
1073
- renameOn: "external",
1074
- editing,
1075
- onEditingChange: setEditing,
1076
- actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [
1370
+ renameOn: actions === void 0 ? "external" : "doubleClick",
1371
+ editing: actions === void 0 ? editing : void 0,
1372
+ onEditingChange: actions === void 0 ? setEditing : void 0,
1373
+ actions: actions ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
1077
1374
  onRename && !editing ? /* @__PURE__ */ jsx(RowAction, {
1078
1375
  label: "Rename session",
1079
1376
  onClick: () => setEditing(true),
@@ -1107,55 +1404,33 @@ function RowAction({ label, title, onClick, children }) {
1107
1404
  children
1108
1405
  });
1109
1406
  }
1110
- function FilterRow({ label, children }) {
1111
- return /* @__PURE__ */ jsxs("div", {
1112
- className: "flex items-center gap-2",
1113
- children: [/* @__PURE__ */ jsx("span", {
1114
- "aria-hidden": true,
1115
- className: "w-14 shrink-0 truncate text-label text-fg-3",
1116
- children: label
1117
- }), /* @__PURE__ */ jsx("div", {
1118
- className: "min-w-0 flex-1",
1119
- children
1120
- })]
1121
- });
1122
- }
1123
- function FacetSelect({ label, value, options, onChange }) {
1407
+ function SessionSearch({ value, onChange, autoFocus, className, inputClassName }) {
1124
1408
  return /* @__PURE__ */ jsxs("div", {
1125
- className: "flex items-center gap-1",
1126
- children: [/* @__PURE__ */ jsxs(Select, {
1127
- multiple: true,
1128
- value,
1129
- onValueChange: (v) => onChange(v),
1130
- children: [/* @__PURE__ */ jsx(SelectTrigger, {
1131
- "aria-label": label,
1132
- className: "min-w-0 flex-1",
1133
- children: /* @__PURE__ */ jsx(SelectValue, { children: value.length === 0 ? "All" : value.length === 1 ? options.find((o) => o.value === value[0])?.label ?? "All" : `${value.length} selected` })
1134
- }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
1135
- value: option.value,
1136
- children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
1137
- }, option.value)) })]
1138
- }), value.length > 0 ? /* @__PURE__ */ jsx(Button, {
1139
- variant: "ghost",
1140
- size: "icon-sm",
1141
- "aria-label": `Clear ${label}`,
1142
- onClick: () => onChange([]),
1143
- children: /* @__PURE__ */ jsx(X, { className: "size-3 text-fg-4" })
1144
- }) : null]
1145
- });
1146
- }
1147
- function OneOfSelect({ label, value, options, onChange }) {
1148
- return /* @__PURE__ */ jsxs(Select, {
1149
- value,
1150
- onValueChange: (v) => onChange(v),
1151
- children: [/* @__PURE__ */ jsx(SelectTrigger, {
1152
- "aria-label": label,
1153
- className: "w-full min-w-0",
1154
- children: /* @__PURE__ */ jsx(SelectValue, { children: options.find((o) => o.value === value)?.label ?? label })
1155
- }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
1156
- value: option.value,
1157
- children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
1158
- }, option.value)) })]
1409
+ className: cn("relative", className),
1410
+ children: [
1411
+ /* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute top-1/2 left-4.5 size-3.5 -translate-y-1/2 text-fg-4" }),
1412
+ /* @__PURE__ */ jsx(Input, {
1413
+ value,
1414
+ onChange: (e) => onChange(e.target.value),
1415
+ onKeyDown: (e) => {
1416
+ if (e.key === "Escape" && value) {
1417
+ e.stopPropagation();
1418
+ onChange("");
1419
+ }
1420
+ },
1421
+ placeholder: "Search sessions",
1422
+ "aria-label": "Search sessions",
1423
+ autoFocus,
1424
+ className: cn("pr-7 pl-8", inputClassName)
1425
+ }),
1426
+ value ? /* @__PURE__ */ jsx("button", {
1427
+ type: "button",
1428
+ "aria-label": "Clear search",
1429
+ onClick: () => onChange(""),
1430
+ className: "absolute top-1/2 right-3.5 -translate-y-1/2 rounded p-0.5 text-fg-4 hover:text-fg-1",
1431
+ children: /* @__PURE__ */ jsx(X, { className: "size-3" })
1432
+ }) : null
1433
+ ]
1159
1434
  });
1160
1435
  }
1161
1436
  //#endregion
@@ -1234,6 +1509,6 @@ function SubagentToggle({ value, onChange, className }) {
1234
1509
  })] });
1235
1510
  }
1236
1511
  //#endregion
1237
- export { AgentWriteIcon, AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, Band, Blank, Button, Card, CardContent, CardHeader, CardTitle, CodeBlock, Composer, ContextDialog, ContextRing, Conversation, ConversationContent, ConversationScrollButton, CopyAction, CopyButton, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, Empty, EmptyKey, EngineIcon, FileCard, FileLinkProvider, HostFilesDialog, ImageViewer, ImageViewerProvider, Ink, Input, Loader, McpDialog, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, ModelSelect, PERMISSION_MODES, PermissionModeSelect, PermissionPrompt, ProgressRing, ProjectIcon, PromptArea, PromptTokenText, QUESTION_BEHAVIORS, QuestionPrompt, Reasoning, Response, Row, SHELL_AGENT_WRITE_NOTE, SHELL_GLYPH, SHELL_KILL_GLYPH, STATUS_META, SUBAGENT_DISPLAY_META, SUBAGENT_DISPLAY_ORDER, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionBrowser, SessionEmptyState, SessionInfoDialog, SessionItem, SessionList, SessionListItem, SessionNamesProvider, SessionPanel, SessionStatusIcon, ShellActionsProvider, ShellStrip, SkillNamesProvider, SkillsDialog, Spinner, Splitter, StatusBar, StepRow, SubagentDisplayIcon, SubagentStrip, SubagentToggle, TaskList, TasksDialog, TerminalDiff, TerminalItemView, TerminalMarkdown, TerminalPermissionPrompt, TerminalQuestionPrompt, TerminalStatusLine, TerminalSurface, TerminalTranscript, Textarea, Tip, Toaster, ToolCallCard, ToolTitleProvider, TooltipContent, TooltipProvider, Transcript, TranscriptVariantProvider, UsageDialog, UsageMeters, ViewableImage, WithActions, badgeVariants, buttonVariants, cn, commandTrigger, copyText, engineMark, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, launchTrigger, matchClientCommand, matchPath, mentionTrigger, mergeComposerRows, parseFileLink, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, previewPatch, rankComposerRows, rankPeerSessions, rateLimitWindowSeconds, resolveAgainstCwd, rowShapeClass, segmentsToPlainText, sessionSteps, shellAgentWriteLabel, shellGrantable, shellInfoFailed, shellInfoLabel, shellInfoStatusText, shellTitle, skillPrompt, toast, toolIcon, toolInputPreview, useAffordances, useFileLinks, useMinuteClock, useOpenImage, usePathLinks, usePromptAreaState, useShellActions, useShellFrame, useToolTitle, useTranscriptVariant, vendorMarkClass, vendorTextClass };
1512
+ export { AgentWriteIcon, AlertDialog, AlertDialogClose, AlertDialogContent, AlertDialogDescription, AlertDialogTitle, AlertDialogTrigger, Badge, Band, Blank, Button, Card, CardContent, CardHeader, CardTitle, CodeBlock, Composer, ContextDialog, ContextPanel, ContextRing, Conversation, ConversationContent, ConversationScrollButton, CopyAction, CopyButton, Dialog, DialogBody, DialogClose, DialogContent, DialogHeader, DialogRow, DialogTrigger, Empty, EmptyKey, EngineIcon, FileCard, FileLinkProvider, HostFilesDialog, ImageViewer, ImageViewerProvider, Ink, Input, Loader, McpDialog, McpPanel, McpPanelActions, Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Message, MessageContent, ModelSelect, OptionSelect, PERMISSION_MODES, PermissionModeSelect, PermissionPrompt, Popover, PopoverContent, PopoverTrigger, ProgressRing, ProjectIcon, PromptArea, PromptTokenText, QUESTION_BEHAVIORS, QuestionPrompt, Reasoning, Response, Row, SHELL_AGENT_WRITE_NOTE, SHELL_GLYPH, SHELL_KILL_GLYPH, STATUS_META, STEP_DISPLAY_OPTIONS, SUBAGENT_DISPLAY_META, SUBAGENT_DISPLAY_ORDER, Select, SelectContent, SelectItem, SelectItemText, SelectTrigger, SelectValue, SessionBrowser, SessionEmptyState, SessionFilters, SessionFiltersButton, SessionInfoDialog, SessionInfoPanel, SessionItem, SessionList, SessionListItem, SessionNamesProvider, SessionPanel, SessionSearch, SessionStatusIcon, ShellActionsProvider, ShellStrip, SkillNamesProvider, SkillsDialog, Spinner, Splitter, StatusBar, StepDisplayControl, StepRow, SubagentDisplayIcon, SubagentStrip, SubagentToggle, TaskList, TasksDialog, TerminalDiff, TerminalItemView, TerminalMarkdown, TerminalPermissionPrompt, TerminalQuestionPrompt, TerminalStatusLine, TerminalSurface, TerminalTranscript, Textarea, Tip, Toaster, ToolCallCard, ToolTitleProvider, TooltipContent, TooltipProvider, Transcript, TranscriptVariantProvider, UsageDialog, UsageMeters, ViewableImage, WithActions, badgeVariants, buttonVariants, cn, commandTrigger, copyText, engineMark, formatAgoPrecise, formatBytes, formatCost, formatCountdown, formatDuration, formatRateLimitWindow, formatRateLimitWindowLong, formatRelativeTime, formatTokens, friendlyModel, getChipsByTrigger, hashtagTrigger, isMutatingTool, isSegmentsEmpty, launchTrigger, matchClientCommand, matchPath, mentionTrigger, mergeComposerRows, parseFileLink, parseUserQuestions, permissionModeChoices, permissionModeMeta, plainTextToSegments, previewPatch, rankComposerRows, rankPeerSessions, rateLimitWindowSeconds, resolveAgainstCwd, rowShapeClass, segmentsToPlainText, sessionSteps, shellAgentWriteLabel, shellGrantable, shellInfoFailed, shellInfoLabel, shellInfoStatusText, shellTitle, skillPrompt, toast, toolIcon, toolInputPreview, useAffordances, useFileLinks, useMcpPanel, useMinuteClock, useOpenImage, usePathLinks, usePromptAreaState, useShellActions, useShellFrame, useToolTitle, useTranscriptVariant, vendorMarkClass, vendorTextClass };
1238
1513
 
1239
1514
  //# sourceMappingURL=index.mjs.map