@workerdeck/ui 2.15.0 → 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 (75) hide show
  1. package/README.md +6 -5
  2. package/build/{SessionPanel-BVKqPs_3.d.mts → SessionPanel-BNNc8grK.d.mts} +18 -16
  3. package/build/index.d.mts +194 -49
  4. package/build/index.mjs +562 -260
  5. package/build/index.mjs.map +1 -1
  6. package/build/scoped.css +170 -21
  7. package/build/{use-path-links-BgWXmfAS.mjs → use-path-links-C6Fh5zdx.mjs} +3312 -2758
  8. package/build/use-path-links-C6Fh5zdx.mjs.map +1 -0
  9. package/build/workspace.d.mts +3 -3
  10. package/build/workspace.mjs +3 -3
  11. package/build/workspace.mjs.map +1 -1
  12. package/package.json +4 -4
  13. package/src/components/agent/ApprovalPrompts.tsx +87 -0
  14. package/src/components/agent/Composer.tsx +25 -47
  15. package/src/components/agent/ContextDialog.tsx +75 -67
  16. package/src/components/agent/FrameStrip.tsx +74 -0
  17. package/src/components/agent/HostFilesDialog.tsx +3 -2
  18. package/src/components/agent/McpDialog.tsx +112 -78
  19. package/src/components/agent/PermissionPrompt.tsx +22 -17
  20. package/src/components/agent/QuestionPrompt.tsx +6 -41
  21. package/src/components/agent/Response.tsx +8 -1
  22. package/src/components/agent/Scrubber.tsx +6 -75
  23. package/src/components/agent/SessionBrowser.tsx +131 -214
  24. package/src/components/agent/SessionFilters.tsx +266 -0
  25. package/src/components/agent/SessionInfoDialog.tsx +47 -63
  26. package/src/components/agent/SessionItem.tsx +29 -6
  27. package/src/components/agent/SessionPanel.tsx +249 -498
  28. package/src/components/agent/SessionSteps.tsx +98 -14
  29. package/src/components/agent/SessionWorkspace.tsx +3 -3
  30. package/src/components/agent/ShellStrip.tsx +43 -36
  31. package/src/components/agent/ShellTerminal.tsx +1 -1
  32. package/src/components/agent/SubagentStrip.tsx +13 -30
  33. package/src/components/agent/ToolCallCard.tsx +18 -41
  34. package/src/components/agent/Transcript.tsx +111 -93
  35. package/src/components/agent/TranscriptItemView.tsx +80 -67
  36. package/src/components/agent/TranscriptRows.tsx +4 -2
  37. package/src/components/agent/composer-commands.ts +80 -1
  38. package/src/components/agent/image-viewer.tsx +326 -0
  39. package/src/components/agent/markdown-image.tsx +139 -0
  40. package/src/components/agent/scrubber-marks.ts +33 -11
  41. package/src/components/agent/scrubber-peek.tsx +122 -0
  42. package/src/components/agent/session-panel-providers.tsx +41 -0
  43. package/src/components/agent/shell-actions.tsx +38 -1
  44. package/src/components/agent/tool-result-image.tsx +40 -0
  45. package/src/components/agent/transcript-variant.tsx +3 -21
  46. package/src/components/agent/use-catch-up.ts +20 -0
  47. package/src/components/agent/use-frame.ts +88 -0
  48. package/src/components/agent/use-host-image.ts +81 -0
  49. package/src/components/agent/use-shell-frame.ts +12 -70
  50. package/src/components/agent/use-subagent-frame.ts +19 -75
  51. package/src/components/prompt-area/prompt-area-engine.ts +21 -20
  52. package/src/components/prompt-area/prompt-area-list-ops.ts +12 -15
  53. package/src/components/prompt-area/use-prompt-area-keydown.ts +4 -2
  54. package/src/components/terminal/PermissionPrompt.tsx +31 -28
  55. package/src/components/terminal/QuestionPrompt.tsx +10 -46
  56. package/src/components/terminal/TerminalTranscript.tsx +23 -89
  57. package/src/components/terminal/affordances.tsx +100 -74
  58. package/src/components/terminal/height.ts +48 -32
  59. package/src/components/terminal/image-box.ts +31 -0
  60. package/src/components/terminal/items.tsx +70 -30
  61. package/src/components/terminal/markdown.tsx +4 -1
  62. package/src/components/terminal/scrubber.tsx +25 -272
  63. package/src/components/terminal/shell-row.ts +17 -3
  64. package/src/components/ui/Popover.tsx +29 -0
  65. package/src/components/ui/Select.tsx +25 -0
  66. package/src/index.ts +65 -12
  67. package/src/lib/file-link.ts +3 -16
  68. package/src/lib/permission-prompt.ts +57 -0
  69. package/src/lib/question-answers.ts +65 -0
  70. package/src/lib/shell-request.ts +115 -0
  71. package/src/lib/tool-icon.ts +13 -1
  72. package/src/styles/terminal.css +129 -22
  73. package/src/styles/theme.css +4 -0
  74. package/build/use-path-links-BgWXmfAS.mjs.map +0 -1
  75. package/src/components/prompt-area/use-markdown-mode.ts +0 -103
package/build/index.mjs CHANGED
@@ -1,11 +1,12 @@
1
- import { $ as useToolTitle, $t as DialogContent, At as rankComposerRows, B as SkillsDialog, Bt as segmentsToPlainText, C as SessionInfoDialog, Ct as toolIcon, D as QuestionPrompt, Dt as useTranscriptVariant, E as QUESTION_BEHAVIORS, Et as useTranscriptDensity, F as PERMISSION_MODES, Ft as launchTrigger, G as TaskList, Gt as CopyButton, H as HostFilesDialog, Ht as Splitter, I as PermissionModeSelect, It as mentionTrigger, J as Composer, Jt as TooltipContent, K as ContextDialog, Kt as copyText, L as permissionModeChoices, Lt as usePromptAreaState, M as SubagentStrip, Mt as skillPrompt, N as PermissionPrompt, Nt as commandTrigger, O as parseUserQuestions, Ot as matchClientCommand, P as Response, Pt as hashtagTrigger, Q as ToolTitleProvider, Qt as DialogClose, R as permissionModeMeta, Rt as PromptArea, S as STATUS_META, St as isMutatingTool, T as TerminalPermissionPrompt, Tt as TranscriptVariantProvider, Ut as CodeBlock, V as McpDialog, Vt as ProgressRing, W as TasksDialog, Wt as Spinner, X as ShellActionsProvider, Xt as Dialog, Y as TerminalSurface, Yt as TooltipProvider, Z as useShellActions, Zt as DialogBody, _ as Loader, _n as Badge, _t as shellInfoStatusText, a as UsageDialog, an as MenuItem, at as previewPatch, b as ConversationScrollButton, bn as buttonVariants, bt as SessionNamesProvider, c as Transcript, cn as Select, ct as Ink, d as Message, dn as SelectItemText, dt as WithActions, en as DialogHeader, et as TerminalMarkdown, f as MessageContent, fn as SelectTrigger, ft as useAffordances, g as SessionEmptyState, gn as Input, gt as shellInfoLabel, h as TerminalTranscript, hn as Textarea, ht as shellInfoFailed, i as SessionPanel, in as MenuContent, it as TerminalDiff, j as ShellStrip, jt as rankPeerSessions, k as useShellFrame, kt as mergeComposerRows, l as ToolCallCard, ln as SelectContent, lt as Row, m as TerminalItemView, mn as PortalScope, mt as SHELL_KILL_GLYPH, n as usePathLinks, nn as DialogTrigger, nt as useFileLinks, o as UsageMeters, on as MenuSeparator, ot as Band, p as FileCard, pn as SelectValue, pt as SHELL_GLYPH, q as contextNote, qt as Tip, r as matchPath, rn as Menu, rt as parseFileLink, s as useMinuteClock, sn as MenuTrigger, st as Blank, t as resolveAgainstCwd, tn as DialogRow, tt as FileLinkProvider, u as Reasoning, un as SelectItem, ut as CopyAction, v as Conversation, vn as badgeVariants, vt as shellTitle, w as TerminalQuestionPrompt, wt as TranscriptDensityProvider, x as StatusBar, xn as cn, xt as SkillNamesProvider, y as ConversationContent, yn as Button, yt as PromptTokenText, z as ModelSelect, zt as plainTextToSegments } from "./use-path-links-BgWXmfAS.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,10 +917,33 @@ 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;
528
- return [...agents, ...promotedShells(info, shells.now).map((shell) => shellStep(shell, shells))];
920
+ const taskSteps = tasks === void 0 ? [] : displayedTasks(info, tasks.show).map((task) => taskStep(task, tasks));
921
+ if (shells === void 0) return [...agents, ...taskSteps];
922
+ const grants = info.shellAgentWrite !== void 0;
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
+ };
529
945
  }
530
- function shellStep(shell, options) {
946
+ function shellStep(shell, options, grants) {
531
947
  const status = shellInfoStatusText(shell);
532
948
  const running = shell.status === "running";
533
949
  return {
@@ -536,10 +952,16 @@ function shellStep(shell, options) {
536
952
  label: shellInfoLabel(shell),
537
953
  noun: "shell",
538
954
  state: shellInfoFailed(shell) ? "failed" : running ? "running" : "done",
539
- detail: running ? void 0 : status,
955
+ detail: running ? shell.agentWrite === true ? SHELL_AGENT_WRITE_NOTE : void 0 : status,
540
956
  title: `${shellTitle(shell)} · ${status}`,
541
957
  onSelect: () => options.onSelect(shell.id),
542
- onKill: running && options.onKill ? () => options.onKill?.(shell.id) : void 0
958
+ onKill: running && options.onKill ? () => options.onKill?.(shell.id) : void 0,
959
+ killLabel: "Kill this shell",
960
+ agentWrite: grants && options.onAgentWrite && shellGrantable(shell) ? {
961
+ granted: shell.agentWrite === true,
962
+ label: shellAgentWriteLabel(shell),
963
+ toggle: () => options.onAgentWrite?.(shell.id, shell.agentWrite !== true)
964
+ } : void 0
543
965
  };
544
966
  }
545
967
  function stepState(status) {
@@ -550,41 +972,59 @@ function stepState(status) {
550
972
  }
551
973
  }
552
974
  function StepRow({ step, active = false, onSelect }) {
553
- 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";
554
976
  return /* @__PURE__ */ jsxs("div", {
555
977
  className: cn("flex w-full items-center rounded-[4px] pr-1.5", active ? "bg-row-selected" : "hover:bg-row-active", body),
556
- children: [/* @__PURE__ */ jsxs("button", {
557
- type: "button",
558
- title: step.title,
559
- "aria-current": active || void 0,
560
- onClick: (e) => {
561
- e.stopPropagation();
562
- onSelect();
563
- },
564
- className: "flex min-w-0 flex-1 items-center gap-1.5 py-1 pr-1 pl-3.5 text-left text-micro outline-none",
565
- children: [
566
- /* @__PURE__ */ jsx(StepIcon, { step }),
567
- /* @__PURE__ */ jsx("span", {
568
- className: "min-w-0 flex-1 truncate",
569
- children: step.label
570
- }),
571
- step.detail ? /* @__PURE__ */ jsx("span", {
572
- className: "shrink-0 tabular-nums text-fg-4",
573
- children: step.detail
574
- }) : null,
575
- /* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5 shrink-0 text-fg-4" })
576
- ]
577
- }), step.onKill ? /* @__PURE__ */ jsx("button", {
578
- type: "button",
579
- "aria-label": `Kill ${step.label}`,
580
- title: "Kill this shell",
581
- onClick: (e) => {
582
- e.stopPropagation();
583
- step.onKill?.();
584
- },
585
- className: "shrink-0 px-1 text-micro leading-none text-fg-4 outline-none hover:text-danger",
586
- children: "✕"
587
- }) : null]
978
+ children: [
979
+ /* @__PURE__ */ jsxs("button", {
980
+ type: "button",
981
+ title: step.title,
982
+ "aria-current": active || void 0,
983
+ onClick: (e) => {
984
+ e.stopPropagation();
985
+ onSelect();
986
+ },
987
+ className: "flex min-w-0 flex-1 items-center gap-1.5 py-1 pr-1 pl-3.5 text-left text-micro outline-none",
988
+ children: [
989
+ /* @__PURE__ */ jsx(StepIcon, { step }),
990
+ /* @__PURE__ */ jsx("span", {
991
+ className: "min-w-0 flex-1 truncate",
992
+ children: step.label
993
+ }),
994
+ step.detail ? /* @__PURE__ */ jsx("span", {
995
+ className: "shrink-0 tabular-nums text-fg-4",
996
+ children: step.detail
997
+ }) : null,
998
+ step.kind === "agent" ? /* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5 shrink-0 text-fg-4" }) : null
999
+ ]
1000
+ }),
1001
+ step.agentWrite ? /* @__PURE__ */ jsx("button", {
1002
+ type: "button",
1003
+ "aria-label": step.agentWrite.label,
1004
+ "aria-pressed": step.agentWrite.granted,
1005
+ title: step.agentWrite.label,
1006
+ onClick: (e) => {
1007
+ e.stopPropagation();
1008
+ step.agentWrite?.toggle();
1009
+ },
1010
+ className: cn("shrink-0 px-1 text-micro leading-none outline-none", step.agentWrite.granted ? "text-warning" : "text-fg-4 hover:text-fg-1"),
1011
+ children: /* @__PURE__ */ jsx(AgentWriteIcon, {
1012
+ granted: step.agentWrite.granted,
1013
+ className: "size-3.5"
1014
+ })
1015
+ }) : null,
1016
+ step.onKill ? /* @__PURE__ */ jsx("button", {
1017
+ type: "button",
1018
+ "aria-label": `${step.kind === "task" ? "Stop" : "Kill"} ${step.label}`,
1019
+ title: step.killLabel,
1020
+ onClick: (e) => {
1021
+ e.stopPropagation();
1022
+ step.onKill?.();
1023
+ },
1024
+ className: "shrink-0 px-1 text-micro leading-none text-fg-4 outline-none hover:text-danger",
1025
+ children: "✕"
1026
+ }) : null
1027
+ ]
588
1028
  });
589
1029
  }
590
1030
  function StepIcon({ step }) {
@@ -595,6 +1035,7 @@ function StepIcon({ step }) {
595
1035
  switch (step.state) {
596
1036
  case "running": return /* @__PURE__ */ jsx(Spinner, { className: "size-[11px] shrink-0" });
597
1037
  case "failed": return /* @__PURE__ */ jsx(CircleAlert, { className: "size-[11px] shrink-0" });
1038
+ case "pending": return /* @__PURE__ */ jsx(Circle, { className: "size-[11px] shrink-0" });
598
1039
  default: return /* @__PURE__ */ jsx(Check, { className: "size-[11px] shrink-0" });
599
1040
  }
600
1041
  }
@@ -605,7 +1046,7 @@ const NO_MODIFIERS = {
605
1046
  ctrl: false,
606
1047
  alt: false
607
1048
  };
608
- function SessionItem({ row, active = false, activeStepKey, showGateway, showProject = true, projectIcons, subagents = "active", onSelect, onSelectSubagent, onSelectShell, onKillShell, 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 }) {
609
1050
  const { info } = row;
610
1051
  const [ownEditing, setOwnEditing] = useState(false);
611
1052
  const isEditing = editing ?? ownEditing;
@@ -642,8 +1083,15 @@ function SessionItem({ row, active = false, activeStepKey, showGateway, showProj
642
1083
  for (const extra of extras) parts.push(/* @__PURE__ */ jsx("span", { children: extra }, extra));
643
1084
  const steps = sessionSteps(info, (toolUseId) => onSelectSubagent ? onSelectSubagent(toolUseId) : onSelect?.(NO_MODIFIERS), subagents, {
644
1085
  now: now ?? Date.now(),
1086
+ show: shells,
645
1087
  onSelect: (shellId) => onSelectShell ? onSelectShell(shellId) : onSelect?.(NO_MODIFIERS),
646
- onKill: onKillShell
1088
+ onKill: onKillShell,
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
647
1095
  });
648
1096
  const holdsOpenStep = steps.some((s) => s.key === activeStepKey);
649
1097
  return /* @__PURE__ */ jsxs("div", {
@@ -780,7 +1228,7 @@ function NameEditor({ initial, onCommit, onCancel }) {
780
1228
  function rowShapeClass(active) {
781
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");
782
1230
  }
783
- function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeSubagentId, activeShellId, now, onSelect, onDelete, onRename, onClearContext, onSelectSubagent, onSelectShell, onKillShell, 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 }) {
784
1232
  const visible = useMemo(() => filterRows(rows, config, scope), [
785
1233
  rows,
786
1234
  config,
@@ -788,16 +1236,7 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
788
1236
  ]);
789
1237
  const groups = useMemo(() => groupRows(visible, config), [visible, config]);
790
1238
  const subset = subsetSummary(config, scope, visible.length, rows.length);
791
- const adapters = useMemo(() => adaptersOf(rows), [rows]);
792
- const projects = useMemo(() => projectsOf(rows), [rows]);
793
- const gateways = useMemo(() => {
794
- const seen = /* @__PURE__ */ new Map();
795
- for (const row of rows) seen.set(row.hostId, row.hostName);
796
- return [...seen].map(([id, name]) => ({
797
- id,
798
- name
799
- }));
800
- }, [rows]);
1239
+ const rowGateways = useMemo(() => new Set(rows.map((row) => row.hostId)).size, [rows]);
801
1240
  const set = (patch) => onConfigChange({
802
1241
  ...config,
803
1242
  ...patch
@@ -806,152 +1245,20 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
806
1245
  "data-slot": "session-browser",
807
1246
  className: cn("flex flex-col gap-3", className),
808
1247
  children: [
809
- /* @__PURE__ */ jsxs("div", {
810
- className: cn("flex flex-col gap-1.5 px-2", !showControls && "hidden"),
811
- children: [
812
- /* @__PURE__ */ jsxs("div", {
813
- className: "relative",
814
- 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, {
815
- value: config.search,
816
- onChange: (e) => set({ search: e.target.value }),
817
- placeholder: "Search sessions",
818
- "aria-label": "Search sessions",
819
- className: "pl-8"
820
- })]
821
- }),
822
- /* @__PURE__ */ jsx(FilterRow, {
823
- label: "State",
824
- children: /* @__PURE__ */ jsx(FacetSelect, {
825
- label: "State",
826
- value: config.states,
827
- options: STATE_ORDER.map((s) => ({
828
- value: s,
829
- label: STATE_LABELS[s]
830
- })),
831
- onChange: (states) => set({ states })
832
- })
833
- }),
834
- adapters.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
835
- label: "Engine",
836
- children: /* @__PURE__ */ jsx(FacetSelect, {
837
- label: "Engine",
838
- value: config.adapters,
839
- options: adapters.map((a) => ({
840
- value: a,
841
- label: a
842
- })),
843
- onChange: (adapters) => set({ adapters })
844
- })
845
- }) : null,
846
- gateways.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
847
- label: "Gateway",
848
- children: /* @__PURE__ */ jsx(FacetSelect, {
849
- label: "Gateway",
850
- value: config.gateways,
851
- options: gateways.map((g) => ({
852
- value: g.id,
853
- label: g.name
854
- })),
855
- onChange: (gateways) => set({ gateways })
856
- })
857
- }) : null,
858
- projects.length > 1 ? /* @__PURE__ */ jsx(FilterRow, {
859
- label: "Project",
860
- children: /* @__PURE__ */ jsx(FacetSelect, {
861
- label: "Project",
862
- value: config.projects ?? [],
863
- options: projects.map((p) => ({
864
- value: p.key,
865
- label: p.label
866
- })),
867
- onChange: (next) => set({ projects: next })
868
- })
869
- }) : null,
870
- /* @__PURE__ */ jsx(FilterRow, {
871
- label: "Group",
872
- children: /* @__PURE__ */ jsx(OneOfSelect, {
873
- label: "Group",
874
- value: config.groupBy,
875
- options: [
876
- {
877
- value: "none",
878
- label: "No grouping"
879
- },
880
- {
881
- value: "state",
882
- label: "By state"
883
- },
884
- {
885
- value: "adapter",
886
- label: "By engine"
887
- },
888
- ...projects.length > 1 ? [{
889
- value: "project",
890
- label: "By project"
891
- }] : [],
892
- ...gateways.length > 1 ? [{
893
- value: "gateway",
894
- label: "By gateway"
895
- }] : []
896
- ],
897
- onChange: (groupBy) => set({ groupBy })
898
- })
899
- }),
900
- /* @__PURE__ */ jsx(FilterRow, {
901
- label: "Sub-agents",
902
- children: /* @__PURE__ */ jsx(OneOfSelect, {
903
- label: "Sub-agents",
904
- value: config.subagents,
905
- options: [
906
- {
907
- value: "active",
908
- label: "Hide completed"
909
- },
910
- {
911
- value: "all",
912
- label: "Show all"
913
- },
914
- {
915
- value: "none",
916
- label: "Hide all"
917
- }
918
- ],
919
- onChange: (subagents) => set({ subagents })
920
- })
921
- }),
922
- /* @__PURE__ */ jsx(FilterRow, {
923
- label: "Sort",
924
- children: /* @__PURE__ */ jsx(OneOfSelect, {
925
- label: "Sort",
926
- value: config.sortBy,
927
- options: [
928
- {
929
- value: "recent",
930
- label: "Recent"
931
- },
932
- {
933
- value: "name",
934
- label: "Name"
935
- },
936
- {
937
- value: "state",
938
- label: "State"
939
- },
940
- ...projects.length > 1 ? [{
941
- value: "project",
942
- label: "Project"
943
- }] : [],
944
- ...gateways.length > 1 ? [{
945
- value: "gateway",
946
- label: "Gateway"
947
- }] : []
948
- ],
949
- onChange: (sortBy) => set({ sortBy })
950
- })
951
- })
952
- ]
953
- }),
954
- 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", {
955
1262
  className: "flex items-center gap-2 px-3 text-label text-fg-4",
956
1263
  children: [/* @__PURE__ */ jsxs("span", { children: [
957
1264
  subset.shown,
@@ -974,6 +1281,12 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
974
1281
  description: "No session matches the current search and filters.",
975
1282
  action: "Clear filters",
976
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 })
977
1290
  }) : /* @__PURE__ */ jsx(Empty, {
978
1291
  icon: /* @__PURE__ */ jsx(Layers, {}),
979
1292
  title: "Nothing here",
@@ -1001,21 +1314,27 @@ function SessionBrowser({ rows, config, onConfigChange, scope, activeId, activeS
1001
1314
  ]
1002
1315
  }) : null, group.rows.map((row) => /* @__PURE__ */ jsx(SessionRowItem, {
1003
1316
  row,
1004
- active: row.info.id === activeId,
1317
+ active: isActive(row),
1005
1318
  activeSubagentId,
1006
1319
  activeShellId,
1320
+ actions: rowActions?.(row),
1007
1321
  now,
1008
- showGateway: gateways.length > 1 && config.groupBy !== "gateway",
1322
+ showGateway: (gatewayCount ?? rowGateways) > 1 && config.groupBy !== "gateway",
1009
1323
  showProject: config.groupBy !== "project",
1010
1324
  subagents: config.subagents,
1325
+ shells: config.shells,
1326
+ tasks: config.tasks,
1011
1327
  projectIcons,
1012
1328
  onSelect,
1013
1329
  onDelete,
1014
1330
  onRename,
1015
1331
  onClearContext,
1016
1332
  onSelectSubagent,
1333
+ onSelectTask,
1334
+ onStopTask,
1017
1335
  onSelectShell,
1018
- onKillShell
1336
+ onKillShell,
1337
+ onShellAgentWrite
1019
1338
  }, `${row.hostId}:${row.info.id}`))]
1020
1339
  }, group.key))
1021
1340
  })
@@ -1026,27 +1345,32 @@ function iconSrcOf(row, icons) {
1026
1345
  const icon = row?.info.project?.icon;
1027
1346
  return icon?.type === "image" ? icons?.[icon.hash] : void 0;
1028
1347
  }
1029
- function SessionRowItem({ row, active, activeSubagentId, activeShellId, now, showGateway, showProject = true, subagents, projectIcons, onSelect, onDelete, onRename, onClearContext, onSelectSubagent, onSelectShell, onKillShell }) {
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 }) {
1030
1349
  const { info } = row;
1031
1350
  const [editing, setEditing] = useState(false);
1032
1351
  return /* @__PURE__ */ jsx(SessionItem, {
1033
1352
  row,
1034
1353
  active: active === true,
1035
- activeStepKey: activeShellId ?? activeSubagentId,
1354
+ activeStepKey: active ? activeShellId ?? activeSubagentId : void 0,
1036
1355
  now,
1037
1356
  showGateway,
1038
1357
  showProject,
1039
1358
  subagents,
1359
+ shells,
1360
+ tasks,
1040
1361
  projectIcons,
1041
- onSelect: () => onSelect?.(row),
1362
+ onSelect: (modifiers) => onSelect?.(row, modifiers),
1042
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,
1043
1366
  onSelectShell: onSelectShell ? (id) => onSelectShell(row, id) : void 0,
1044
1367
  onKillShell: onKillShell ? (id) => onKillShell(row, id) : void 0,
1368
+ onShellAgentWrite: onShellAgentWrite ? (id, enabled) => onShellAgentWrite(row, id, enabled) : void 0,
1045
1369
  onRename: onRename ? (title) => onRename(row, title) : void 0,
1046
- renameOn: "external",
1047
- editing,
1048
- onEditingChange: setEditing,
1049
- 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: [
1050
1374
  onRename && !editing ? /* @__PURE__ */ jsx(RowAction, {
1051
1375
  label: "Rename session",
1052
1376
  onClick: () => setEditing(true),
@@ -1080,55 +1404,33 @@ function RowAction({ label, title, onClick, children }) {
1080
1404
  children
1081
1405
  });
1082
1406
  }
1083
- function FilterRow({ label, children }) {
1084
- return /* @__PURE__ */ jsxs("div", {
1085
- className: "flex items-center gap-2",
1086
- children: [/* @__PURE__ */ jsx("span", {
1087
- "aria-hidden": true,
1088
- className: "w-14 shrink-0 truncate text-label text-fg-3",
1089
- children: label
1090
- }), /* @__PURE__ */ jsx("div", {
1091
- className: "min-w-0 flex-1",
1092
- children
1093
- })]
1094
- });
1095
- }
1096
- function FacetSelect({ label, value, options, onChange }) {
1407
+ function SessionSearch({ value, onChange, autoFocus, className, inputClassName }) {
1097
1408
  return /* @__PURE__ */ jsxs("div", {
1098
- className: "flex items-center gap-1",
1099
- children: [/* @__PURE__ */ jsxs(Select, {
1100
- multiple: true,
1101
- value,
1102
- onValueChange: (v) => onChange(v),
1103
- children: [/* @__PURE__ */ jsx(SelectTrigger, {
1104
- "aria-label": label,
1105
- className: "min-w-0 flex-1",
1106
- children: /* @__PURE__ */ jsx(SelectValue, { children: value.length === 0 ? "All" : value.length === 1 ? options.find((o) => o.value === value[0])?.label ?? "All" : `${value.length} selected` })
1107
- }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
1108
- value: option.value,
1109
- children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
1110
- }, option.value)) })]
1111
- }), value.length > 0 ? /* @__PURE__ */ jsx(Button, {
1112
- variant: "ghost",
1113
- size: "icon-sm",
1114
- "aria-label": `Clear ${label}`,
1115
- onClick: () => onChange([]),
1116
- children: /* @__PURE__ */ jsx(X, { className: "size-3 text-fg-4" })
1117
- }) : null]
1118
- });
1119
- }
1120
- function OneOfSelect({ label, value, options, onChange }) {
1121
- return /* @__PURE__ */ jsxs(Select, {
1122
- value,
1123
- onValueChange: (v) => onChange(v),
1124
- children: [/* @__PURE__ */ jsx(SelectTrigger, {
1125
- "aria-label": label,
1126
- className: "w-full min-w-0",
1127
- children: /* @__PURE__ */ jsx(SelectValue, { children: options.find((o) => o.value === value)?.label ?? label })
1128
- }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
1129
- value: option.value,
1130
- children: /* @__PURE__ */ jsx(SelectItemText, { children: option.label })
1131
- }, 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
+ ]
1132
1434
  });
1133
1435
  }
1134
1436
  //#endregion
@@ -1207,6 +1509,6 @@ function SubagentToggle({ value, onChange, className }) {
1207
1509
  })] });
1208
1510
  }
1209
1511
  //#endregion
1210
- export { 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, 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_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, TranscriptDensityProvider, TranscriptVariantProvider, UsageDialog, UsageMeters, 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, shellInfoFailed, shellInfoLabel, shellInfoStatusText, shellTitle, skillPrompt, toast, toolIcon, toolInputPreview, useAffordances, useFileLinks, useMinuteClock, usePathLinks, usePromptAreaState, useShellActions, useShellFrame, useToolTitle, useTranscriptDensity, 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 };
1211
1513
 
1212
1514
  //# sourceMappingURL=index.mjs.map