@arbidocs/blocks 0.5.38 → 0.5.40

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 (147) hide show
  1. package/README.md +10 -0
  2. package/dist/{ConnectedCallDock-V7DPSE6X.cjs → ConnectedCallDock-NGHSDLJS.cjs} +4 -4
  3. package/dist/{ConnectedCallDock-V7DPSE6X.cjs.map → ConnectedCallDock-NGHSDLJS.cjs.map} +1 -1
  4. package/dist/{ConnectedCallDock-CT3D6LLI.js → ConnectedCallDock-YJSO52N4.js} +4 -4
  5. package/dist/{ConnectedCallDock-CT3D6LLI.js.map → ConnectedCallDock-YJSO52N4.js.map} +1 -1
  6. package/dist/{ConnectedCallRoom-TNOCSTX2.cjs → ConnectedCallRoom-4XGFFYHE.cjs} +4 -4
  7. package/dist/{ConnectedCallRoom-TNOCSTX2.cjs.map → ConnectedCallRoom-4XGFFYHE.cjs.map} +1 -1
  8. package/dist/{ConnectedCallRoom-A27AM7IQ.js → ConnectedCallRoom-T6NS2MY4.js} +4 -4
  9. package/dist/{ConnectedCallRoom-A27AM7IQ.js.map → ConnectedCallRoom-T6NS2MY4.js.map} +1 -1
  10. package/dist/{ConnectedNativeDocxComparison-RWKFPJPJ.js → ConnectedNativeDocxComparison-52KQKJGY.js} +7 -7
  11. package/dist/{ConnectedNativeDocxComparison-RWKFPJPJ.js.map → ConnectedNativeDocxComparison-52KQKJGY.js.map} +1 -1
  12. package/dist/{ConnectedNativeDocxComparison-H2OZMWHT.cjs → ConnectedNativeDocxComparison-UVLZGS2V.cjs} +8 -8
  13. package/dist/{ConnectedNativeDocxComparison-H2OZMWHT.cjs.map → ConnectedNativeDocxComparison-UVLZGS2V.cjs.map} +1 -1
  14. package/dist/{ConnectedNativeDocxEditor-43BI5LN6.js → ConnectedNativeDocxEditor-BRBL3MOV.js} +6 -6
  15. package/dist/{ConnectedNativeDocxEditor-43BI5LN6.js.map → ConnectedNativeDocxEditor-BRBL3MOV.js.map} +1 -1
  16. package/dist/{ConnectedNativeDocxEditor-6DQEM6SD.cjs → ConnectedNativeDocxEditor-KHR5I7W6.cjs} +8 -8
  17. package/dist/{ConnectedNativeDocxEditor-6DQEM6SD.cjs.map → ConnectedNativeDocxEditor-KHR5I7W6.cjs.map} +1 -1
  18. package/dist/{ConnectedStreamedWordArtifact-3VKYIG6C.cjs → ConnectedStreamedWordArtifact-DSVFI7BX.cjs} +8 -8
  19. package/dist/ConnectedStreamedWordArtifact-DSVFI7BX.cjs.map +1 -0
  20. package/dist/{ConnectedStreamedWordArtifact-TEB332E3.js → ConnectedStreamedWordArtifact-EQUE6WT5.js} +7 -7
  21. package/dist/ConnectedStreamedWordArtifact-EQUE6WT5.js.map +1 -0
  22. package/dist/{WorkspaceTableView-KG546U7M.cjs → WorkspaceTableView-2CGEO5KK.cjs} +6 -6
  23. package/dist/{WorkspaceTableView-KG546U7M.cjs.map → WorkspaceTableView-2CGEO5KK.cjs.map} +1 -1
  24. package/dist/{WorkspaceTableView-OSFIWJ5C.js → WorkspaceTableView-3ARFQYNO.js} +4 -4
  25. package/dist/{WorkspaceTableView-OSFIWJ5C.js.map → WorkspaceTableView-3ARFQYNO.js.map} +1 -1
  26. package/dist/agents/index.cjs +376 -376
  27. package/dist/agents/index.js +2 -2
  28. package/dist/calls/index.cjs +35 -35
  29. package/dist/calls/index.js +7 -7
  30. package/dist/chat/index.cjs +89 -89
  31. package/dist/chat/index.js +2 -2
  32. package/dist/{chunk-BRYRZOS3.cjs → chunk-3YZ3RUSB.cjs} +4 -4
  33. package/dist/{chunk-BRYRZOS3.cjs.map → chunk-3YZ3RUSB.cjs.map} +1 -1
  34. package/dist/{chunk-VPWCARVO.js → chunk-4DDPMLGU.js} +4 -4
  35. package/dist/{chunk-VPWCARVO.js.map → chunk-4DDPMLGU.js.map} +1 -1
  36. package/dist/{chunk-24H5WTGM.js → chunk-4U4NXFV5.js} +4 -4
  37. package/dist/{chunk-24H5WTGM.js.map → chunk-4U4NXFV5.js.map} +1 -1
  38. package/dist/{chunk-6EQSP77K.cjs → chunk-5ZHAHJ4H.cjs} +5 -5
  39. package/dist/{chunk-6EQSP77K.cjs.map → chunk-5ZHAHJ4H.cjs.map} +1 -1
  40. package/dist/{chunk-BIWPXSGS.cjs → chunk-6AJJJ5HR.cjs} +7 -7
  41. package/dist/{chunk-BIWPXSGS.cjs.map → chunk-6AJJJ5HR.cjs.map} +1 -1
  42. package/dist/{chunk-2YCCCXYV.js → chunk-7LN3ISPG.js} +3 -3
  43. package/dist/{chunk-2YCCCXYV.js.map → chunk-7LN3ISPG.js.map} +1 -1
  44. package/dist/{chunk-5NTSJV5H.cjs → chunk-BY2EW2QU.cjs} +16 -91
  45. package/dist/chunk-BY2EW2QU.cjs.map +1 -0
  46. package/dist/{chunk-FHB4G77H.js → chunk-CEO7YI7I.js} +3 -3
  47. package/dist/{chunk-FHB4G77H.js.map → chunk-CEO7YI7I.js.map} +1 -1
  48. package/dist/{chunk-LTO4JYU3.cjs → chunk-DWWRLKEZ.cjs} +188 -2
  49. package/dist/chunk-DWWRLKEZ.cjs.map +1 -0
  50. package/dist/chunk-E3IEZMRK.cjs +507 -0
  51. package/dist/chunk-E3IEZMRK.cjs.map +1 -0
  52. package/dist/{chunk-MLHOG7YH.js → chunk-EFDZRAW6.js} +3 -3
  53. package/dist/{chunk-MLHOG7YH.js.map → chunk-EFDZRAW6.js.map} +1 -1
  54. package/dist/chunk-FOIDBAZB.js +497 -0
  55. package/dist/chunk-FOIDBAZB.js.map +1 -0
  56. package/dist/{chunk-MB3S2ETI.cjs → chunk-G2BKHCI2.cjs} +2 -2
  57. package/dist/chunk-G2BKHCI2.cjs.map +1 -0
  58. package/dist/{chunk-EFSL4O3B.cjs → chunk-GT5FCYV5.cjs} +7 -7
  59. package/dist/{chunk-EFSL4O3B.cjs.map → chunk-GT5FCYV5.cjs.map} +1 -1
  60. package/dist/{chunk-QWKT4DO6.cjs → chunk-GX5MKJ3F.cjs} +433 -2
  61. package/dist/chunk-GX5MKJ3F.cjs.map +1 -0
  62. package/dist/{chunk-C3YIVBTU.cjs → chunk-HDEOORSV.cjs} +9 -9
  63. package/dist/{chunk-C3YIVBTU.cjs.map → chunk-HDEOORSV.cjs.map} +1 -1
  64. package/dist/{chunk-T4P237N6.js → chunk-ILBBV2ZY.js} +2 -2
  65. package/dist/chunk-ILBBV2ZY.js.map +1 -0
  66. package/dist/{chunk-XFSEPGF7.cjs → chunk-K53QRFPJ.cjs} +4 -4
  67. package/dist/{chunk-XFSEPGF7.cjs.map → chunk-K53QRFPJ.cjs.map} +1 -1
  68. package/dist/{chunk-NOKTUWTN.cjs → chunk-K7S5BMAB.cjs} +7 -7
  69. package/dist/{chunk-NOKTUWTN.cjs.map → chunk-K7S5BMAB.cjs.map} +1 -1
  70. package/dist/{chunk-FY4C7HU5.cjs → chunk-O3MRE2HL.cjs} +2233 -8
  71. package/dist/chunk-O3MRE2HL.cjs.map +1 -0
  72. package/dist/{chunk-N3HVTMQK.js → chunk-OPZBIGW4.js} +3 -3
  73. package/dist/{chunk-N3HVTMQK.js.map → chunk-OPZBIGW4.js.map} +1 -1
  74. package/dist/{chunk-JVXHVFUA.cjs → chunk-P6HVJP6Z.cjs} +4 -4
  75. package/dist/{chunk-JVXHVFUA.cjs.map → chunk-P6HVJP6Z.cjs.map} +1 -1
  76. package/dist/{chunk-PXYP3DM5.js → chunk-PD4AKBYZ.js} +432 -6
  77. package/dist/chunk-PD4AKBYZ.js.map +1 -0
  78. package/dist/{chunk-VKY4SQMH.js → chunk-REHG7VRQ.js} +5 -5
  79. package/dist/{chunk-VKY4SQMH.js.map → chunk-REHG7VRQ.js.map} +1 -1
  80. package/dist/{chunk-M4MZPH2S.js → chunk-SEZEEHLU.js} +190 -6
  81. package/dist/chunk-SEZEEHLU.js.map +1 -0
  82. package/dist/{chunk-5JEM3BWT.js → chunk-SYP2A4GQ.js} +4 -4
  83. package/dist/{chunk-5JEM3BWT.js.map → chunk-SYP2A4GQ.js.map} +1 -1
  84. package/dist/{chunk-QFYRXQTD.js → chunk-TTPXMCJL.js} +6 -80
  85. package/dist/chunk-TTPXMCJL.js.map +1 -0
  86. package/dist/{chunk-VMLEISRZ.cjs → chunk-UZVXVTTB.cjs} +17 -17
  87. package/dist/{chunk-VMLEISRZ.cjs.map → chunk-UZVXVTTB.cjs.map} +1 -1
  88. package/dist/{chunk-YDY4GIC2.cjs → chunk-V7JDMKNQ.cjs} +4 -4
  89. package/dist/{chunk-YDY4GIC2.cjs.map → chunk-V7JDMKNQ.cjs.map} +1 -1
  90. package/dist/{chunk-YPR4FSDJ.js → chunk-VA3YYR7R.js} +8 -192
  91. package/dist/chunk-VA3YYR7R.js.map +1 -0
  92. package/dist/{chunk-NUV5F6MM.js → chunk-WAIHNFUH.js} +3 -3
  93. package/dist/{chunk-NUV5F6MM.js.map → chunk-WAIHNFUH.js.map} +1 -1
  94. package/dist/{chunk-H5BFOVVL.cjs → chunk-WRERJFEV.cjs} +2 -188
  95. package/dist/chunk-WRERJFEV.cjs.map +1 -0
  96. package/dist/{chunk-4DKI37QQ.js → chunk-YAGSGBVM.js} +2213 -13
  97. package/dist/chunk-YAGSGBVM.js.map +1 -0
  98. package/dist/{chunk-K6W2GWCN.js → chunk-ZAYUJFPI.js} +3 -3
  99. package/dist/{chunk-K6W2GWCN.js.map → chunk-ZAYUJFPI.js.map} +1 -1
  100. package/dist/connect/docx.cjs +10 -10
  101. package/dist/connect/docx.js +6 -6
  102. package/dist/connect/index.cjs +1237 -591
  103. package/dist/connect/index.cjs.map +1 -1
  104. package/dist/connect/index.d.ts +3 -0
  105. package/dist/connect/index.js +665 -23
  106. package/dist/connect/index.js.map +1 -1
  107. package/dist/connect/viewer.cjs +27 -27
  108. package/dist/connect/viewer.js +10 -10
  109. package/dist/connection/panels/ConnectedPanelHost.d.ts +48 -0
  110. package/dist/connection/panels/useSessionPanelMode.d.ts +18 -0
  111. package/dist/connection/threads-page/ConnectedThreadsPage.d.ts +14 -0
  112. package/dist/connection/threads-page/ThreadSearch.d.ts +24 -0
  113. package/dist/connection/workflows/index.d.ts +1 -0
  114. package/dist/connection/workflows/useWorkflowsPageState.d.ts +134 -0
  115. package/dist/index.cjs +610 -594
  116. package/dist/index.js +9 -9
  117. package/dist/provider/host.d.ts +3 -0
  118. package/dist/shell/PanelPortal.d.ts +30 -0
  119. package/dist/shell/index.cjs +78 -61
  120. package/dist/shell/index.d.ts +3 -0
  121. package/dist/shell/index.js +3 -2
  122. package/dist/shell/panel-host.d.ts +8 -0
  123. package/dist/shell/panel-windows.d.ts +33 -0
  124. package/dist/studio/index.cjs +5 -5
  125. package/dist/studio/index.js +3 -3
  126. package/dist/workflow-canvas/index.cjs +21 -21
  127. package/dist/workflow-canvas/index.js +5 -5
  128. package/node_modules/@arbidocs/coedit/package.json +1 -1
  129. package/package.json +5 -5
  130. package/dist/ConnectedStreamedWordArtifact-3VKYIG6C.cjs.map +0 -1
  131. package/dist/ConnectedStreamedWordArtifact-TEB332E3.js.map +0 -1
  132. package/dist/chunk-4DKI37QQ.js.map +0 -1
  133. package/dist/chunk-5NTSJV5H.cjs.map +0 -1
  134. package/dist/chunk-EZSYYENN.js +0 -2700
  135. package/dist/chunk-EZSYYENN.js.map +0 -1
  136. package/dist/chunk-FY4C7HU5.cjs.map +0 -1
  137. package/dist/chunk-H5BFOVVL.cjs.map +0 -1
  138. package/dist/chunk-LTO4JYU3.cjs.map +0 -1
  139. package/dist/chunk-M4MZPH2S.js.map +0 -1
  140. package/dist/chunk-MB3S2ETI.cjs.map +0 -1
  141. package/dist/chunk-PUX4M22Q.cjs +0 -2735
  142. package/dist/chunk-PUX4M22Q.cjs.map +0 -1
  143. package/dist/chunk-PXYP3DM5.js.map +0 -1
  144. package/dist/chunk-QFYRXQTD.js.map +0 -1
  145. package/dist/chunk-QWKT4DO6.cjs.map +0 -1
  146. package/dist/chunk-T4P237N6.js.map +0 -1
  147. package/dist/chunk-YPR4FSDJ.js.map +0 -1
@@ -1,22 +1,28 @@
1
1
  "use client";
2
2
  import { MultiSelect } from './chunk-CQCC7LE7.js';
3
- import { SchemaForm, workflowRunStatusLabel } from './chunk-7CHI36EP.js';
3
+ import { SchemaForm, PersonPill, workflowRunStatusLabel } from './chunk-7CHI36EP.js';
4
4
  import { ScopePicker, FoldSection, AddFilesFirst } from './chunk-2C3I27VI.js';
5
- import { UploadDropzone } from './chunk-M4S75AEJ.js';
5
+ import { TriStateFilterMenu } from './chunk-G4GLDQLY.js';
6
+ import { UploadDropzone, CellHoverIcon } from './chunk-M4S75AEJ.js';
7
+ import { ToneBadge } from './chunk-5LXQPP2K.js';
8
+ import { SelectionBar, SelectionBarAction } from './chunk-NUNKSZKU.js';
6
9
  import { useControllableState } from './chunk-RLWIUUQ5.js';
10
+ import { FilterInput } from './chunk-YU2KUMGE.js';
7
11
  import { ActionLink } from './chunk-73DANGPH.js';
8
12
  import { GridView } from './chunk-7F5Z4K5W.js';
9
13
  import { TabHeader } from './chunk-ABEKUV6L.js';
14
+ import { EmptyState } from './chunk-P6GHJSLR.js';
10
15
  import { DEFAULT_STEP_RECORD_LABELS, DEFAULT_STEP_DOCUMENT_LABELS, DEFAULT_STEP_KIND_LABELS, workflowSteps, canAssign, nextAction, validateStep, assigneeName, runFieldsOf, failedUpstream, stepPhase, sendBackTargets, formatDate, shownValue, stepKindOf, stepLevels, waitingDocuments, stepDependencies, reviewInstructions, splitDocRef, isPersonStep, stepFields, useMentionAutocomplete, eventWaitingDocuments, waitingForDocumentsText, StepChip, StepDocumentButton, isRunFinished, stepDocuments, STEP_KIND_ICONS, StepDocumentCards, StepRecord, composeStepPrompt, useElementSize, runFields, StepBadgeMark } from './chunk-THNTNAYI.js';
11
16
  import { workflowsForHost, isWorkflowScope, fieldToFrontmatter, workflowFromFrontmatter, defaultInputs, validateInputs, mergeSkillWorkflows, composeWorkflowPrompt } from './chunk-TZGBRLPK.js';
17
+ import { useIsPhone } from './chunk-SLSBJRWW.js';
12
18
  import { MentionMenu } from './chunk-GAGYAHYO.js';
13
19
  import { useBlocksEnvironment, openDialog, closeDialog, useDialogProps } from './chunk-QZUZPC4J.js';
14
20
  import { ModalHeader } from './chunk-TX2ZICS7.js';
15
21
  import { testIdOr, prefixedTestId } from './chunk-7F6CBP3Z.js';
16
- import { cn, Label, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Textarea, Input, Switch, Button, Collapsible, CollapsibleTrigger, CollapsibleContent, Tooltip, TooltipTrigger, TooltipContent, EntityPill, Card, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Badge, Slider, DialogClose, VisibilityToggle, Popover, PopoverTrigger, PopoverContent, Command, CommandInput, CommandList, CommandEmpty, CommandItem, UserEntity, ARBI_MARK_SRC, ProviderIcon, formatFriendlyDate, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, PopoverClose } from '@arbidocs/react/ui';
22
+ import { cn, Label, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Textarea, Input, Switch, Button, Collapsible, CollapsibleTrigger, CollapsibleContent, Tooltip, TooltipTrigger, TooltipContent, EntityPill, Card, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Badge, Slider, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, VisibilityToggle, ThreadVisibilityIcon, DialogClose, Popover, PopoverTrigger, PopoverContent, Command, CommandInput, CommandList, CommandEmpty, CommandItem, Checkbox, UserEntity, ARBI_MARK_SRC, ProviderIcon, formatFriendlyDate, DropdownMenuSeparator, PopoverClose } from '@arbidocs/react/ui';
17
23
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
18
24
  import { memo, forwardRef, useState, useMemo, useRef, useEffect, useCallback, useSyncExternalStore, useLayoutEffect } from 'react';
19
- import { ChevronDown, ChevronRight, Plus, Trash2, Globe, Terminal, Telescope, ListChecks, FileText, ImageIcon, Brain, Wand2, Glasses, Zap, Sparkles, Reply, Wrench, MessageSquare, Target, Cog, ClipboardList, CornerDownRight, Crown, Milestone, Bookmark, MessageCircleQuestion, Languages, ImagePlus, FilePlus, Bot, Link, Image, List, Search, UserRound, CornerUpLeft, ShieldCheck, Check, Hourglass, Clock, PenLine, X, ExternalLink, Mail, Table2, CheckCircle2, ArrowLeft, Loader2, ArrowRight, RotateCw, GitBranch, AlertTriangle, Library, NotebookPen, GanttChartSquare, Copy, Play, Pencil, Lock, Download, CalendarClock, ArrowUpRight, SendHorizontal, MessagesSquare, Eye, History, ChevronUp, Pause, Activity, MoreVertical, TriangleAlert, CheckSquare, Square, SquareArrowOutUpRight, LayoutGrid, CornerLeftUp, KeyRound, AlertCircle, CheckCheck, CircleDashed, CircleCheck, Hand, BellRing, Flag, RotateCcw, Disc, Phone, UserRoundCog, MessageSquareReply, ChevronLeft } from 'lucide-react';
25
+ import { ChevronDown, ChevronRight, Plus, Trash2, Globe, Terminal, Telescope, ListChecks, FileText, ImageIcon, Brain, Wand2, Glasses, Zap, Sparkles, Reply, Wrench, MessageSquare, Target, Cog, ClipboardList, CornerDownRight, Crown, Milestone, Bookmark, MessageCircleQuestion, Languages, ImagePlus, FilePlus, Bot, Link, Image, List, Search, UserRound, CornerUpLeft, ShieldCheck, Check, Hourglass, Clock, PenLine, X, ExternalLink, Mail, Table2, CheckCircle2, ArrowLeft, Loader2, ArrowRight, RotateCw, GitBranch, AlertTriangle, Library, NotebookPen, GanttChartSquare, Copy, Play, Pencil, Lock, Download, FileX, SkipForward, AlertCircle, KeyRound, Workflow, ChevronsUpDown, ChevronsDownUp, ListTodo, CheckCheck, MoreHorizontal, CalendarClock, ArrowUpRight, SendHorizontal, MessagesSquare, Eye, History, ChevronUp, Pause, Activity, MoreVertical, TriangleAlert, CheckSquare, Square, SquareArrowOutUpRight, LayoutGrid, CornerLeftUp, CircleDashed, RotateCcw, ListPlus, CircleCheck, Hand, BellRing, Flag, Disc, Phone, UserRoundCog, MessageSquareReply, ChevronLeft } from 'lucide-react';
20
26
  import { unzip, strFromU8 } from 'fflate';
21
27
  import { isSharedSkill, getStepTool, getAgentStepLabel, getCurrentStep } from '@arbidocs/sdk/browser';
22
28
  import { toMessageMentions, extractMentions } from '@arbidocs/react/shell';
@@ -4620,6 +4626,215 @@ function TaskPlan({
4620
4626
  );
4621
4627
  }
4622
4628
 
4629
+ // src/agents/tasks/elapsed.ts
4630
+ function formatElapsed2(startTime, endTime) {
4631
+ const elapsedMs = (endTime || Date.now()) - startTime;
4632
+ if (elapsedMs < 1e3) return `${Math.round(elapsedMs)}ms`;
4633
+ if (elapsedMs < 6e4) return `${Math.round(elapsedMs / 1e3)}s`;
4634
+ if (elapsedMs < 36e5) {
4635
+ const minutes2 = Math.floor(elapsedMs / 6e4);
4636
+ const seconds = Math.round(elapsedMs % 6e4 / 1e3);
4637
+ return seconds > 0 ? `${minutes2}m ${seconds}s` : `${minutes2}m`;
4638
+ }
4639
+ const hours = Math.floor(elapsedMs / 36e5);
4640
+ const minutes = Math.round(elapsedMs % 36e5 / 6e4);
4641
+ return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
4642
+ }
4643
+ var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["parsing", "encrypting", "indexing", "analysing"]);
4644
+ var RUNNING_STATUSES = /* @__PURE__ */ new Set(["queued", ...ACTIVE_STATUSES]);
4645
+ var TONES = {
4646
+ completed: { text: "text-green-text", bar: "bg-green-text/90", Icon: Check },
4647
+ failed: { text: "text-red-text", bar: "bg-red-text/90", Icon: X },
4648
+ parsing: { text: "text-blue-text", bar: "bg-blue-text/90", Icon: Loader2 },
4649
+ encrypting: { text: "text-blue-text", bar: "bg-blue-text/90", Icon: Loader2 },
4650
+ indexing: { text: "text-blue-text", bar: "bg-blue-text/90", Icon: Loader2 },
4651
+ analysing: { text: "text-blue-text", bar: "bg-blue-text/90", Icon: Loader2 },
4652
+ queued: { text: "text-yellow-text", bar: "bg-yellow-text/90", Icon: Loader2 },
4653
+ skipped: { text: "text-gray-text", bar: "bg-gray-text/90", Icon: SkipForward },
4654
+ empty: { text: "text-yellow-text", bar: "bg-yellow-text/90", Icon: FileX },
4655
+ "low-content": { text: "text-yellow-text", bar: "bg-yellow-text/90", Icon: AlertTriangle }
4656
+ };
4657
+ var DEFAULT_TONE = { text: "text-gray-text", bar: "bg-blue-text/90", Icon: Loader2 };
4658
+ var DEFAULT_UPLOAD_TASK_ITEM_LABELS = {
4659
+ delete: "Delete",
4660
+ deleteTitle: "Delete file",
4661
+ progress: (fileName) => `${fileName} progress`,
4662
+ status: (status, percent) => `${status.charAt(0).toUpperCase() + status.slice(1)} - ${percent}%`
4663
+ };
4664
+ function UploadTaskItem({
4665
+ taskId,
4666
+ fileName,
4667
+ status,
4668
+ progress,
4669
+ startTime,
4670
+ endTime,
4671
+ fileIcon,
4672
+ onDelete,
4673
+ testIds,
4674
+ labels,
4675
+ className
4676
+ }) {
4677
+ const l = { ...DEFAULT_UPLOAD_TASK_ITEM_LABELS, ...labels };
4678
+ const [elapsed, setElapsed] = useState("");
4679
+ useEffect(() => {
4680
+ if (!startTime) {
4681
+ setElapsed("");
4682
+ return;
4683
+ }
4684
+ if (RUNNING_STATUSES.has(status)) {
4685
+ const tick = () => setElapsed(formatElapsed2(startTime));
4686
+ tick();
4687
+ const interval = setInterval(tick, 1e3);
4688
+ return () => clearInterval(interval);
4689
+ }
4690
+ setElapsed(formatElapsed2(startTime, endTime));
4691
+ }, [startTime, endTime, status]);
4692
+ const percent = progress > 1 ? progress : progress * 100;
4693
+ const tone = TONES[status] ?? DEFAULT_TONE;
4694
+ const StatusIcon2 = tone.Icon;
4695
+ return /* @__PURE__ */ jsxs(
4696
+ "div",
4697
+ {
4698
+ className: cn(
4699
+ "mb-2 w-full max-w-full overflow-hidden rounded-md bg-muted p-2 box-border",
4700
+ className
4701
+ ),
4702
+ "data-testid": testIdOr(testIds?.item?.(taskId), { testId: `task-item-${taskId}` }),
4703
+ "data-slot": "upload-task-item",
4704
+ children: [
4705
+ /* @__PURE__ */ jsxs("div", { className: "mb-1 flex w-full max-w-full items-center gap-2 overflow-hidden", children: [
4706
+ /* @__PURE__ */ jsx("div", { className: cn("shrink-0", tone.text), children: /* @__PURE__ */ jsx(StatusIcon2, { className: cn("size-4", ACTIVE_STATUSES.has(status) && "animate-spin") }) }),
4707
+ fileIcon && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: fileIcon }),
4708
+ /* @__PURE__ */ jsx(
4709
+ "div",
4710
+ {
4711
+ className: "min-w-0 flex-1 truncate text-sm font-medium",
4712
+ title: fileName,
4713
+ "data-testid": testIdOr(testIds?.fileName?.(taskId), { testId: `task-filename-${taskId}` }),
4714
+ children: fileName
4715
+ }
4716
+ )
4717
+ ] }),
4718
+ /* @__PURE__ */ jsx(
4719
+ "div",
4720
+ {
4721
+ className: "mb-1 h-2 w-full max-w-full overflow-hidden rounded-md bg-background",
4722
+ "data-testid": testIdOr(testIds?.progressBar?.(taskId), {
4723
+ testId: `task-progress-bar-${taskId}`
4724
+ }),
4725
+ role: "progressbar",
4726
+ "aria-valuemin": 0,
4727
+ "aria-valuemax": 100,
4728
+ "aria-valuenow": Math.round(percent),
4729
+ "aria-label": l.progress(fileName),
4730
+ children: /* @__PURE__ */ jsx(
4731
+ "div",
4732
+ {
4733
+ className: cn("h-2 rounded-md transition-all duration-300 ease-in-out", tone.bar),
4734
+ style: { width: `${percent}%` }
4735
+ }
4736
+ )
4737
+ }
4738
+ ),
4739
+ /* @__PURE__ */ jsxs("div", { className: "flex w-full max-w-full items-center justify-between overflow-hidden text-sm", children: [
4740
+ /* @__PURE__ */ jsxs(
4741
+ "span",
4742
+ {
4743
+ className: "truncate text-gray-text",
4744
+ "data-testid": testIdOr(testIds?.status?.(taskId), { testId: `task-status-${taskId}` }),
4745
+ children: [
4746
+ l.status(status, Math.round(percent)),
4747
+ elapsed && /* @__PURE__ */ jsxs("span", { className: "ml-2 text-muted-foreground", children: [
4748
+ "(",
4749
+ elapsed,
4750
+ ")"
4751
+ ] })
4752
+ ]
4753
+ }
4754
+ ),
4755
+ status === "failed" && onDelete && /* @__PURE__ */ jsx(
4756
+ "button",
4757
+ {
4758
+ type: "button",
4759
+ onClick: () => onDelete(taskId),
4760
+ className: "shrink-0 text-sm text-red-text hover:text-red-text/80 pointer-coarse:min-h-11 pointer-coarse:px-3",
4761
+ title: l.deleteTitle,
4762
+ "data-testid": testIdOr(testIds?.delete?.(taskId), { testId: `delete-task-${taskId}` }),
4763
+ children: l.delete
4764
+ }
4765
+ )
4766
+ ] })
4767
+ ]
4768
+ }
4769
+ );
4770
+ }
4771
+ var DEFAULT_UPLOAD_TASK_LIST_LABELS = {
4772
+ title: "Active Tasks",
4773
+ empty: "No documents in this category"
4774
+ };
4775
+ function UploadTaskList({
4776
+ tasks,
4777
+ filter,
4778
+ title,
4779
+ onDelete,
4780
+ renderFileIcon,
4781
+ showEmptyState = true,
4782
+ testIds,
4783
+ labels,
4784
+ itemLabels,
4785
+ className
4786
+ }) {
4787
+ const l = { ...DEFAULT_UPLOAD_TASK_LIST_LABELS, ...labels };
4788
+ const heading = title ?? l.title;
4789
+ const safeTasks = typeof tasks === "object" && tasks !== null ? tasks : {};
4790
+ let entries = Object.entries(safeTasks);
4791
+ if (filter) entries = entries.filter(([id, task]) => filter(id, task));
4792
+ if (entries.length === 0) {
4793
+ return showEmptyState ? /* @__PURE__ */ jsx(
4794
+ "div",
4795
+ {
4796
+ className: "text-sm italic text-muted-foreground",
4797
+ "data-testid": testIdOr(testIds?.empty, { testId: "task-list-empty-state" }),
4798
+ children: l.empty
4799
+ }
4800
+ ) : null;
4801
+ }
4802
+ return /* @__PURE__ */ jsxs(
4803
+ "div",
4804
+ {
4805
+ "data-testid": testIdOr(testIds?.root, { testId: "task-status-list" }),
4806
+ "data-slot": "upload-task-list",
4807
+ className: cn("box-border w-full max-w-full", className),
4808
+ children: [
4809
+ heading && /* @__PURE__ */ jsx(
4810
+ "h3",
4811
+ {
4812
+ className: "mb-2 truncate text-sm font-semibold",
4813
+ "data-testid": testIdOr(testIds?.title, { testId: "task-list-title" }),
4814
+ children: heading
4815
+ }
4816
+ ),
4817
+ /* @__PURE__ */ jsx("div", { className: "box-border w-full max-w-full overflow-hidden", children: entries.map(([taskId, task]) => /* @__PURE__ */ jsx(
4818
+ UploadTaskItem,
4819
+ {
4820
+ taskId,
4821
+ fileName: task.fileName,
4822
+ status: task.status,
4823
+ progress: task.progress,
4824
+ startTime: task.startTime,
4825
+ endTime: task.endTime,
4826
+ fileIcon: renderFileIcon?.(task.fileName),
4827
+ onDelete,
4828
+ labels: itemLabels,
4829
+ className: "box-border max-w-full"
4830
+ },
4831
+ taskId
4832
+ )) })
4833
+ ]
4834
+ }
4835
+ );
4836
+ }
4837
+
4623
4838
  // src/agents/tasks/rrule.ts
4624
4839
  var WEEKDAYS = ["MO", "TU", "WE", "TH", "FR", "SA", "SU"];
4625
4840
  var WEEKDAY_LABELS = {
@@ -4902,6 +5117,322 @@ function goalProgress(task) {
4902
5117
  if (!gs || gs.criteria_total == null) return null;
4903
5118
  return { met: gs.criteria_met ?? 0, total: gs.criteria_total, done: gs.done === true };
4904
5119
  }
5120
+ var DEFAULT_TASK_OUTPUTS_CELL_LABELS = {
5121
+ none: "\u2014",
5122
+ open: (count) => `${count} ${count === 1 ? "output" : "outputs"}`,
5123
+ more: (count) => `+${count}`
5124
+ };
5125
+ function TaskOutputsCell({ id, outputs, onOpen, testId, labels }) {
5126
+ const l = { ...DEFAULT_TASK_OUTPUTS_CELL_LABELS, ...labels };
5127
+ const base = testIdOr(testId, { testId: `task-outputs-${id}` });
5128
+ if (!outputs || outputs.length === 0) {
5129
+ return /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", "data-testid": base, "data-state": "none", children: l.none });
5130
+ }
5131
+ const [first] = outputs;
5132
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
5133
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
5134
+ Button,
5135
+ {
5136
+ variant: "ghost",
5137
+ size: "sm",
5138
+ className: "h-7 max-w-full gap-1.5 px-2 text-xs",
5139
+ "aria-label": l.open(outputs.length),
5140
+ "data-testid": base,
5141
+ "data-count": outputs.length,
5142
+ children: [
5143
+ /* @__PURE__ */ jsx(FileText, { className: "size-3.5 shrink-0", "aria-hidden": true }),
5144
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: first.name }),
5145
+ outputs.length > 1 && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: l.more(outputs.length - 1) })
5146
+ ]
5147
+ }
5148
+ ) }),
5149
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", children: outputs.map((o) => /* @__PURE__ */ jsxs(
5150
+ DropdownMenuItem,
5151
+ {
5152
+ onSelect: () => onOpen(o.id),
5153
+ "data-testid": `task-output-${id}-${o.id}`,
5154
+ children: [
5155
+ /* @__PURE__ */ jsx(FileText, { className: "mr-2 size-4", "aria-hidden": true }),
5156
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: o.name })
5157
+ ]
5158
+ },
5159
+ o.id
5160
+ )) })
5161
+ ] });
5162
+ }
5163
+ function TaskMoveDialog({
5164
+ open,
5165
+ onOpenChange,
5166
+ options,
5167
+ currentParentId,
5168
+ onPick,
5169
+ labels,
5170
+ testId
5171
+ }) {
5172
+ const [query, setQuery] = useState("");
5173
+ const id = testIdOr(testId, { testId: "task-move" });
5174
+ const q = query.trim().toLowerCase();
5175
+ const shown = q ? options.filter((o) => o.label.toLowerCase().includes(q)) : options;
5176
+ const pick = (parentId) => {
5177
+ onPick(parentId);
5178
+ onOpenChange(false);
5179
+ };
5180
+ return /* @__PURE__ */ jsx(
5181
+ Dialog,
5182
+ {
5183
+ open,
5184
+ onOpenChange: (next) => {
5185
+ if (!next) setQuery("");
5186
+ onOpenChange(next);
5187
+ },
5188
+ children: /* @__PURE__ */ jsxs(DialogContent, { presentation: "sheet", className: "max-h-[80dvh] sm:max-w-md", "data-testid": id, children: [
5189
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
5190
+ /* @__PURE__ */ jsx(DialogTitle, { children: labels.title }),
5191
+ /* @__PURE__ */ jsx(DialogDescription, { className: "sr-only", children: labels.title })
5192
+ ] }),
5193
+ /* @__PURE__ */ jsx(
5194
+ Input,
5195
+ {
5196
+ value: query,
5197
+ placeholder: labels.search,
5198
+ "aria-label": labels.search,
5199
+ onChange: (e) => setQuery(e.target.value),
5200
+ "data-testid": `${id}-search`
5201
+ }
5202
+ ),
5203
+ /* @__PURE__ */ jsxs(
5204
+ "ul",
5205
+ {
5206
+ className: "flex max-h-[50dvh] flex-col gap-1 overflow-y-auto",
5207
+ "data-testid": `${id}-list`,
5208
+ children: [
5209
+ !q && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
5210
+ Button,
5211
+ {
5212
+ variant: "ghost",
5213
+ className: "h-9 w-full justify-start gap-2 pointer-coarse:h-11",
5214
+ disabled: !currentParentId,
5215
+ onClick: () => pick(null),
5216
+ "data-testid": `${id}-none`,
5217
+ children: labels.none
5218
+ }
5219
+ ) }),
5220
+ shown.map((o) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
5221
+ Button,
5222
+ {
5223
+ variant: "ghost",
5224
+ className: "h-9 w-full justify-start gap-2 pointer-coarse:h-11",
5225
+ disabled: o.id === currentParentId,
5226
+ onClick: () => pick(o.id),
5227
+ "data-testid": `${id}-option-${o.id}`,
5228
+ children: [
5229
+ /* @__PURE__ */ jsx(CornerDownRight, { className: "size-3.5 shrink-0", "aria-hidden": true }),
5230
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: o.label })
5231
+ ]
5232
+ }
5233
+ ) }, o.id)),
5234
+ shown.length === 0 && /* @__PURE__ */ jsx("li", { className: "px-2 py-4 text-center text-sm text-muted-foreground", children: labels.empty })
5235
+ ]
5236
+ }
5237
+ ),
5238
+ /* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: labels.cancel }) })
5239
+ ] })
5240
+ }
5241
+ );
5242
+ }
5243
+ var DEFAULT_TASK_STATUS_PILL_LABELS = {
5244
+ waitingForAccess: "Waiting for access",
5245
+ lastRunFailed: "Last run failed",
5246
+ failed: "Failed"
5247
+ };
5248
+ var ICON = "size-3";
5249
+ function StatusIcon({ status }) {
5250
+ switch (status) {
5251
+ case "generating":
5252
+ return /* @__PURE__ */ jsx(Loader2, { className: `${ICON} animate-spin`, "aria-hidden": true });
5253
+ case "done":
5254
+ return /* @__PURE__ */ jsx(Check, { className: ICON, "aria-hidden": true });
5255
+ case "chat":
5256
+ return /* @__PURE__ */ jsx(MessageSquare, { className: ICON, "aria-hidden": true });
5257
+ default:
5258
+ return /* @__PURE__ */ jsx(CircleDashed, { className: ICON, "aria-hidden": true });
5259
+ }
5260
+ }
5261
+ function useNow(active) {
5262
+ const [now, setNow] = useState(() => Date.now());
5263
+ useEffect(() => {
5264
+ if (!active) return;
5265
+ const timer = setInterval(() => setNow(Date.now()), 1e3);
5266
+ return () => clearInterval(timer);
5267
+ }, [active]);
5268
+ return now;
5269
+ }
5270
+ function TaskStatusPill({
5271
+ id,
5272
+ status,
5273
+ runStartedAt,
5274
+ lastError,
5275
+ awaitingAccess = false,
5276
+ testId,
5277
+ labels,
5278
+ hint
5279
+ }) {
5280
+ const l = { ...DEFAULT_TASK_STATUS_PILL_LABELS, ...labels };
5281
+ const key = asTaskStatus(status);
5282
+ const generating = key === "generating";
5283
+ const now = useNow(generating && Boolean(runStartedAt));
5284
+ const started = runStartedAt ? Date.parse(runStartedAt) : NaN;
5285
+ let text2 = STATUS_LABELS[key];
5286
+ let tone = STATUS_TONE[key];
5287
+ if (awaitingAccess) {
5288
+ text2 = l.waitingForAccess;
5289
+ tone = "danger";
5290
+ }
5291
+ const elapsed = generating && !Number.isNaN(started) ? formatElapsed2(started, now) : null;
5292
+ return /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5", "data-slot": "task-status", title: hint, children: [
5293
+ /* @__PURE__ */ jsxs(
5294
+ ToneBadge,
5295
+ {
5296
+ tone,
5297
+ icon: /* @__PURE__ */ jsx(StatusIcon, { status: key }),
5298
+ "data-status": key,
5299
+ "data-testid": testIdOr(testId, { testId: `task-status-${id}` }),
5300
+ children: [
5301
+ text2,
5302
+ elapsed && /* @__PURE__ */ jsxs("span", { className: "tabular-nums opacity-70", children: [
5303
+ "\xB7 ",
5304
+ elapsed
5305
+ ] })
5306
+ ]
5307
+ }
5308
+ ),
5309
+ lastError && !generating && /* @__PURE__ */ jsxs(
5310
+ "span",
5311
+ {
5312
+ role: "img",
5313
+ "aria-label": l.lastRunFailed,
5314
+ title: `${l.lastRunFailed}: ${lastError}`,
5315
+ className: "inline-flex shrink-0 items-center gap-1 text-xs font-medium text-red-text",
5316
+ "data-testid": `task-error-${id}`,
5317
+ children: [
5318
+ /* @__PURE__ */ jsx(AlertCircle, { className: "size-3.5", "aria-hidden": true }),
5319
+ l.failed
5320
+ ]
5321
+ }
5322
+ )
5323
+ ] });
5324
+ }
5325
+
5326
+ // src/agents/tasks/taskColumns.tsx
5327
+ var ACTIONS_WIDTH = 160;
5328
+ var NARROW_ACTIONS_WIDTH = 56;
5329
+ var TASK_COLUMN_ORDER = [
5330
+ "name",
5331
+ "owner",
5332
+ "due",
5333
+ "status",
5334
+ "outputs",
5335
+ "shared",
5336
+ "actions"
5337
+ ];
5338
+ var keepOrder = () => 0;
5339
+ function cell(render) {
5340
+ return (params) => params.data ? render(params.data) : null;
5341
+ }
5342
+ function createTaskColumns(o) {
5343
+ const l = o.labels;
5344
+ const sortable = {
5345
+ sortable: true,
5346
+ comparator: keepOrder,
5347
+ sortingOrder: ["asc", "desc", null]
5348
+ };
5349
+ const base = {
5350
+ sortable: false,
5351
+ suppressMovable: true,
5352
+ // Keyboard focus lands on the name cell only (arrow keys expand and collapse sub-tasks there).
5353
+ suppressNavigable: true,
5354
+ cellStyle: { display: "flex", alignItems: "center" }
5355
+ };
5356
+ const name = {
5357
+ ...base,
5358
+ colId: "name",
5359
+ ...sortable,
5360
+ suppressNavigable: false,
5361
+ headerName: l.colTask,
5362
+ flex: 3,
5363
+ minWidth: 200,
5364
+ cellRenderer: cell(o.renderName)
5365
+ };
5366
+ const shared = {
5367
+ ...base,
5368
+ colId: "shared",
5369
+ headerName: l.colShared,
5370
+ headerTooltip: l.shared,
5371
+ width: 90,
5372
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "center" },
5373
+ valueGetter: (p) => p.data?.task.is_shared ?? false,
5374
+ cellRenderer: cell(o.renderShared)
5375
+ };
5376
+ const actions = () => ({
5377
+ ...base,
5378
+ colId: "actions",
5379
+ headerName: "",
5380
+ // Always in view, even if the rest has to scroll.
5381
+ pinned: "right",
5382
+ lockPinned: true,
5383
+ width: o.narrow ? NARROW_ACTIONS_WIDTH : ACTIONS_WIDTH,
5384
+ minWidth: NARROW_ACTIONS_WIDTH,
5385
+ cellStyle: { display: "flex", alignItems: "center", justifyContent: "flex-end" },
5386
+ cellRenderer: cell(o.renderActions)
5387
+ });
5388
+ return [
5389
+ name,
5390
+ {
5391
+ ...base,
5392
+ colId: "owner",
5393
+ ...sortable,
5394
+ headerName: l.colOwner,
5395
+ headerTooltip: l.ownerHint,
5396
+ flex: 1.4,
5397
+ minWidth: 150,
5398
+ valueGetter: (p) => p.data ? o.getOwnerName(p.data) : "",
5399
+ cellRenderer: cell(o.renderOwner)
5400
+ },
5401
+ {
5402
+ ...base,
5403
+ colId: "due",
5404
+ ...sortable,
5405
+ headerName: l.colDue,
5406
+ flex: 1,
5407
+ minWidth: 140,
5408
+ valueGetter: (p) => p.data?.task.due_at ?? "",
5409
+ cellRenderer: cell(o.renderDue)
5410
+ },
5411
+ {
5412
+ ...base,
5413
+ colId: "status",
5414
+ ...sortable,
5415
+ headerName: l.colStatus,
5416
+ // Wide enough for "Generating" and "Waiting for access" in full, with the elapsed time.
5417
+ flex: 1.3,
5418
+ minWidth: 170,
5419
+ valueGetter: (p) => p.data?.task.status ?? "",
5420
+ cellRenderer: cell(o.renderStatus)
5421
+ },
5422
+ ...o.showOutputs ? [
5423
+ {
5424
+ ...base,
5425
+ colId: "outputs",
5426
+ headerName: l.colOutputs,
5427
+ flex: 1.2,
5428
+ minWidth: 130,
5429
+ cellRenderer: cell(o.renderOutputs)
5430
+ }
5431
+ ] : [],
5432
+ shared,
5433
+ actions()
5434
+ ];
5435
+ }
4905
5436
 
4906
5437
  // src/agents/tasks/taskRows.ts
4907
5438
  var MAX_TASK_DEPTH = 5;
@@ -5033,12 +5564,1219 @@ function buildTaskRows(tasks, filter, collapsed, compare, options = {}) {
5033
5564
  node.children.forEach((child, i) => walk(child, id, node.children.length, i + 1));
5034
5565
  }
5035
5566
  };
5036
- const ordered = [...STATUS_ORDER, "sorted"].flatMap((s) => sections.get(s) ?? []);
5037
- ordered.forEach((node, i) => walk(node, null, ordered.length, i + 1));
5038
- if (cache2) {
5039
- for (const id of [...cache2.keys()]) if (!used.has(id)) cache2.delete(id);
5040
- }
5041
- return rows;
5567
+ const ordered = [...STATUS_ORDER, "sorted"].flatMap((s) => sections.get(s) ?? []);
5568
+ ordered.forEach((node, i) => walk(node, null, ordered.length, i + 1));
5569
+ if (cache2) {
5570
+ for (const id of [...cache2.keys()]) if (!used.has(id)) cache2.delete(id);
5571
+ }
5572
+ return rows;
5573
+ }
5574
+
5575
+ // src/agents/tasks/taskTableLabels.ts
5576
+ var DEFAULT_TASK_LIST_LABELS = {
5577
+ filterAll: "All",
5578
+ emptyTitle: "No tasks yet",
5579
+ emptyMessage: "Use New to add one: just type what you need, or add a due date. Automations that create tasks live on the Workflows page. You always decide when a task is done.",
5580
+ noMatches: "No tasks match.",
5581
+ due: (when) => when,
5582
+ overdue: (when) => `${when} \xB7 overdue`,
5583
+ agent: "Agent",
5584
+ colTask: "Task",
5585
+ colOwner: "Owner",
5586
+ ownerHint: "Who created the task. They are notified when its run finishes.",
5587
+ colOutputs: "Outputs",
5588
+ preparedBy: (agent) => `Prepared by ${agent}`,
5589
+ colDue: "Due",
5590
+ colStatus: "Status",
5591
+ me: "Me",
5592
+ someone: "Someone",
5593
+ noDue: "\u2014",
5594
+ colShared: "Shared",
5595
+ shared: "Shared with the workspace",
5596
+ sharedOwnerOnly: "Only the creator can change who can see this",
5597
+ deleteOwnerOnly: "Only the creator or workspace owner can delete this",
5598
+ goalMet: (met, total) => `${met}/${total} met`,
5599
+ subtasksDone: (done, total) => `${done}/${total} sub-tasks done`,
5600
+ expandSubtasks: "Show sub-tasks",
5601
+ collapseSubtasks: "Hide sub-tasks",
5602
+ selectAll: "Select all tasks",
5603
+ selectTask: (name) => `Select ${name}`,
5604
+ markDone: "Mark done",
5605
+ reopen: "Reopen",
5606
+ markDoneMany: "Mark done",
5607
+ markDoneManyHint: "Marks the selected tasks done.",
5608
+ deleteMany: "Delete",
5609
+ moveTo: "Move to\u2026",
5610
+ untitled: "Untitled task",
5611
+ fromWorkflow: (name) => `From \u201C${name}\u201D`,
5612
+ searchLabel: "Search tasks",
5613
+ searchPlaceholder: "Search tasks\u2026",
5614
+ expandAll: "Expand all",
5615
+ collapseAll: "Collapse all",
5616
+ moveToTitle: (name) => `Move \u201C${name}\u201D to\u2026`,
5617
+ moveToNone: "No parent (top level)",
5618
+ moveToSearch: "Search tasks\u2026",
5619
+ moveToEmpty: "No task to move it under.",
5620
+ moveToCancel: "Cancel",
5621
+ subtasksSelected: (count) => `${count} ${count === 1 ? "sub-task" : "sub-tasks"} included`,
5622
+ addSubtask: "Add sub-task",
5623
+ edit: "Edit",
5624
+ rename: "Rename",
5625
+ delete: "Delete",
5626
+ grantAccess: "Allow access and continue",
5627
+ allowAccess: "Allow access",
5628
+ moreActions: "More actions",
5629
+ activity: "Activity",
5630
+ statusHint: (status, ago) => `${status} \xB7 ${ago}`,
5631
+ status: {}
5632
+ };
5633
+ function TaskRowMenu({
5634
+ task,
5635
+ status,
5636
+ busy,
5637
+ isOwner,
5638
+ canAdmin,
5639
+ canEdit,
5640
+ labels,
5641
+ canMarkDone = canEdit,
5642
+ canReopen = canEdit,
5643
+ selected = false,
5644
+ onToggleSelected,
5645
+ onMarkDone,
5646
+ onReopen,
5647
+ onAddSubtask,
5648
+ onEdit,
5649
+ onDelete,
5650
+ onMoveTo,
5651
+ onOpenActivity,
5652
+ onToggleShared,
5653
+ onGrantAccess
5654
+ }) {
5655
+ const [open, setOpen] = useState(false);
5656
+ const id = task.external_id;
5657
+ const isChat = status === "chat";
5658
+ const done = status === "done";
5659
+ return /* @__PURE__ */ jsxs(DropdownMenu, { open, onOpenChange: setOpen, children: [
5660
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
5661
+ Button,
5662
+ {
5663
+ variant: "ghost",
5664
+ size: "icon",
5665
+ className: "size-8 pointer-coarse:size-11",
5666
+ "aria-label": labels.moreActions,
5667
+ "data-testid": `task-menu-${id}`,
5668
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4", "aria-hidden": true })
5669
+ }
5670
+ ) }),
5671
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
5672
+ onToggleSelected && /* @__PURE__ */ jsx(DropdownMenuItem, { onSelect: onToggleSelected, "data-testid": `task-select-${id}`, children: selected ? "Deselect task" : "Select task" }),
5673
+ isOwner && onGrantAccess && task.pending_auth_request_id && /* @__PURE__ */ jsxs(
5674
+ DropdownMenuItem,
5675
+ {
5676
+ onSelect: onGrantAccess,
5677
+ "data-testid": `task-grant-${id}`,
5678
+ className: "text-destructive",
5679
+ children: [
5680
+ /* @__PURE__ */ jsx(KeyRound, { className: "mr-2 size-4", "aria-hidden": true }),
5681
+ labels.grantAccess
5682
+ ]
5683
+ }
5684
+ ),
5685
+ isChat || !canEdit ? null : done ? canReopen && /* @__PURE__ */ jsxs(
5686
+ DropdownMenuItem,
5687
+ {
5688
+ disabled: busy,
5689
+ onSelect: onReopen,
5690
+ "data-testid": `task-reopen-${id}`,
5691
+ children: [
5692
+ /* @__PURE__ */ jsx(RotateCcw, { className: "mr-2 size-4", "aria-hidden": true }),
5693
+ labels.reopen
5694
+ ]
5695
+ }
5696
+ ) : canMarkDone && /* @__PURE__ */ jsxs(
5697
+ DropdownMenuItem,
5698
+ {
5699
+ disabled: busy,
5700
+ onSelect: onMarkDone,
5701
+ "data-testid": `task-mark-done-${id}`,
5702
+ children: [
5703
+ /* @__PURE__ */ jsx(CheckCheck, { className: "mr-2 size-4", "aria-hidden": true }),
5704
+ labels.markDone
5705
+ ]
5706
+ }
5707
+ ),
5708
+ !isChat && onOpenActivity && /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: onOpenActivity, "data-testid": `task-activity-${id}`, children: [
5709
+ /* @__PURE__ */ jsx(History, { className: "mr-2 size-4", "aria-hidden": true }),
5710
+ labels.activity
5711
+ ] }),
5712
+ isOwner && onToggleShared && /* @__PURE__ */ jsx(DropdownMenuItem, { disabled: busy, onSelect: onToggleShared, children: task.is_shared ? "Make private" : "Share with workspace" }),
5713
+ canEdit && onAddSubtask && /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: onAddSubtask, "data-testid": `task-add-subtask-${id}`, children: [
5714
+ /* @__PURE__ */ jsx(ListPlus, { className: "mr-2 size-4", "aria-hidden": true }),
5715
+ labels.addSubtask
5716
+ ] }),
5717
+ canEdit && onMoveTo && /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: onMoveTo, "data-testid": `task-move-${id}`, children: [
5718
+ /* @__PURE__ */ jsx(CornerDownRight, { className: "mr-2 size-4", "aria-hidden": true }),
5719
+ labels.moveTo
5720
+ ] }),
5721
+ canEdit && /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: onEdit, "data-testid": `task-edit-${id}`, children: [
5722
+ /* @__PURE__ */ jsx(Pencil, { className: "mr-2 size-4", "aria-hidden": true }),
5723
+ isChat ? labels.rename : labels.edit
5724
+ ] }),
5725
+ canEdit && onDelete && /* @__PURE__ */ jsxs(Fragment, { children: [
5726
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
5727
+ /* @__PURE__ */ jsxs(
5728
+ DropdownMenuItem,
5729
+ {
5730
+ disabled: busy || !canAdmin,
5731
+ onSelect: onDelete,
5732
+ title: canAdmin ? void 0 : labels.deleteOwnerOnly,
5733
+ className: "text-destructive focus:text-destructive",
5734
+ "data-testid": `task-delete-${id}`,
5735
+ children: [
5736
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-2 size-4", "aria-hidden": true }),
5737
+ labels.delete
5738
+ ]
5739
+ }
5740
+ )
5741
+ ] })
5742
+ ] })
5743
+ ] });
5744
+ }
5745
+
5746
+ // src/agents/tasks/gridWidth.ts
5747
+ function applyColumnWidthRules(api, gridWidth, rules) {
5748
+ for (const rule of rules) {
5749
+ if (api.getColumn(rule.colId)) api.setColumnsVisible([rule.colId], gridWidth >= rule.minWidth);
5750
+ }
5751
+ }
5752
+ var ROW_HEIGHT = 56;
5753
+ var NARROW_ROW_HEIGHT = 76;
5754
+ var MAX_INDENT_DEPTH = 4;
5755
+ var ANIMATE_ROWS_UP_TO = 500;
5756
+ var NARROW_GRID = 640;
5757
+ var WIDTH_RULES = [
5758
+ { colId: "shared", minWidth: 1050 },
5759
+ { colId: "due", minWidth: 850 },
5760
+ { colId: "outputs", minWidth: 930 },
5761
+ { colId: "owner", minWidth: 730 },
5762
+ { colId: "status", minWidth: NARROW_GRID }
5763
+ ];
5764
+ function statusHint(task, ctx) {
5765
+ const { props: p, l } = ctx;
5766
+ if (!p.formatRelative || !task.updated_at) return void 0;
5767
+ const key = asTaskStatus(task.status);
5768
+ const pill = { ...DEFAULT_TASK_STATUS_PILL_LABELS, ...p.statusPillLabels };
5769
+ const label = task.pending_auth_request_id ? pill.waitingForAccess : STATUS_LABELS[key];
5770
+ return l.statusHint(label, p.formatRelative(task.updated_at));
5771
+ }
5772
+ function TaskTable(props) {
5773
+ const { tasks: allTasks, isLoading, busyId, header, testId } = props;
5774
+ const l = {
5775
+ ...DEFAULT_TASK_LIST_LABELS,
5776
+ ...props.labels,
5777
+ status: { ...STATUS_LABELS, ...props.labels?.status }
5778
+ };
5779
+ const [filter, setFilter] = useState("all");
5780
+ const [query, setQuery] = useState("");
5781
+ const [collapsed, setCollapsed] = useState(/* @__PURE__ */ new Set());
5782
+ const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
5783
+ const [sort, setSort] = useState(null);
5784
+ const [moving, setMoving] = useState(null);
5785
+ const tasks = allTasks;
5786
+ const apiRef = useRef(null);
5787
+ const [narrow, setNarrow] = useState(false);
5788
+ const rowCache = useRef(/* @__PURE__ */ new Map());
5789
+ const tree = useMemo(() => indexTasks(tasks), [tasks]);
5790
+ const peopleNames = useMemo(
5791
+ () => new Map((props.people ?? []).map((p) => [p.id, p.label])),
5792
+ [props.people]
5793
+ );
5794
+ const nameOf = (task) => task.title?.trim() || task.workflow_ext_id && props.workflowNames?.[task.workflow_ext_id] || l.untitled;
5795
+ const owner = (task) => {
5796
+ const id = ownerExtId(task);
5797
+ const mine = task.is_owner !== false;
5798
+ return {
5799
+ id,
5800
+ label: mine ? l.me : (id && peopleNames.get(id)) ?? l.someone,
5801
+ isMe: mine
5802
+ };
5803
+ };
5804
+ const starter = (task) => {
5805
+ const id = task.created_by_ext_id ?? task.owner_ext_id;
5806
+ const mine = task.is_owner !== false;
5807
+ return {
5808
+ id,
5809
+ label: mine ? l.me : (id && peopleNames.get(id)) ?? l.someone,
5810
+ isMe: mine
5811
+ };
5812
+ };
5813
+ const renderPerson = props.renderPerson ?? ((person) => /* @__PURE__ */ jsx(PersonPill, { person }));
5814
+ const q = (query.trim() || (props.filterText ?? "").trim()).toLowerCase();
5815
+ const counts = useMemo(() => {
5816
+ const map = new Map(STATUS_ORDER.map((s) => [s, 0]));
5817
+ let all = 0;
5818
+ for (const task of tasks) {
5819
+ const text2 = `${nameOf(task)} ${task.description ?? ""}`.toLowerCase();
5820
+ if (q && !text2.includes(q)) continue;
5821
+ all += 1;
5822
+ const s = asTaskStatus(task.status);
5823
+ map.set(s, (map.get(s) ?? 0) + 1);
5824
+ }
5825
+ map.set("all", all);
5826
+ return map;
5827
+ }, [tasks, q, props.workflowNames, l.untitled]);
5828
+ const compare = useMemo(() => {
5829
+ if (!sort) return void 0;
5830
+ const keys = /* @__PURE__ */ new Map();
5831
+ const compute = (t) => {
5832
+ switch (sort.colId) {
5833
+ case "name":
5834
+ return nameOf(t).toLowerCase();
5835
+ case "owner":
5836
+ return owner(t).label.toLowerCase();
5837
+ case "updated":
5838
+ return t.updated_at ? Date.parse(t.updated_at) : 0;
5839
+ case "messages":
5840
+ return t.message_count ?? 0;
5841
+ case "due":
5842
+ return t.due_at ? Date.parse(t.due_at) : Number.POSITIVE_INFINITY;
5843
+ default:
5844
+ return STATUS_ORDER.indexOf(asTaskStatus(t.status));
5845
+ }
5846
+ };
5847
+ const key = (t) => {
5848
+ let k = keys.get(t);
5849
+ if (k === void 0) {
5850
+ k = compute(t);
5851
+ keys.set(t, k);
5852
+ }
5853
+ return k;
5854
+ };
5855
+ const sign = sort.dir === "asc" ? 1 : -1;
5856
+ return (a, b) => {
5857
+ const [x, y] = [key(a), key(b)];
5858
+ if (typeof x === "number" && typeof y === "number") return (x - y) * sign;
5859
+ return String(x).localeCompare(String(y)) * sign;
5860
+ };
5861
+ }, [
5862
+ sort,
5863
+ peopleNames,
5864
+ props.agentNames,
5865
+ props.workflowNames,
5866
+ l.me,
5867
+ l.agent,
5868
+ l.someone,
5869
+ l.untitled
5870
+ ]);
5871
+ const rows = useMemo(
5872
+ () => buildTaskRows(tasks, filter, collapsed, compare, {
5873
+ query: query.trim() || props.filterText,
5874
+ titleOf: nameOf,
5875
+ cache: rowCache.current
5876
+ }),
5877
+ // nameOf reads the labels and workflow names the table was given.
5878
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5879
+ [tasks, filter, collapsed, compare, query, props.filterText, props.workflowNames, l.untitled]
5880
+ );
5881
+ const selectedRows = useMemo(
5882
+ () => rows.filter((r) => selectedIds.has(r.external_id)),
5883
+ [rows, selectedIds]
5884
+ );
5885
+ const selectedTasks = useMemo(
5886
+ () => tasks.filter((t) => selectedIds.has(t.external_id)),
5887
+ [tasks, selectedIds]
5888
+ );
5889
+ const subtasksIncluded = useMemo(
5890
+ () => selectedTasks.filter((t) => {
5891
+ const parent = tree.parentOf.get(t.external_id);
5892
+ return parent !== void 0 && selectedIds.has(parent);
5893
+ }).length,
5894
+ [selectedTasks, selectedIds, tree]
5895
+ );
5896
+ const markable = selectedTasks.filter(
5897
+ (t) => t.status != null && (t.is_owner !== false || props.canEditShared) && isPlainTodo(t) && asTaskStatus(t.status) !== "done"
5898
+ );
5899
+ const deletable = selectedTasks.filter((t) => t.is_owner !== false || props.isWorkspaceOwner);
5900
+ const rowsRef = useRef(rows);
5901
+ rowsRef.current = rows;
5902
+ const handleSelectionChange = (picked) => {
5903
+ const visible = new Set(rowsRef.current.map((r) => r.external_id));
5904
+ const pickedIds = new Set(picked.map((r) => r.external_id));
5905
+ setSelectedIds((prev) => {
5906
+ const added = [...pickedIds].filter((id) => !prev.has(id));
5907
+ const removed = [...prev].filter((id) => visible.has(id) && !pickedIds.has(id));
5908
+ if (added.length === 0 && removed.length === 0) return prev;
5909
+ const next = new Set(prev);
5910
+ for (const id of added) {
5911
+ next.add(id);
5912
+ for (const d of descendantIds(tree, id)) next.add(d);
5913
+ }
5914
+ for (const id of removed) {
5915
+ next.delete(id);
5916
+ for (const d of descendantIds(tree, id)) next.delete(d);
5917
+ for (let at = tree.parentOf.get(id); at; at = tree.parentOf.get(at)) next.delete(at);
5918
+ }
5919
+ return next;
5920
+ });
5921
+ };
5922
+ const setExpanded = (id, expanded) => setCollapsed((prev) => {
5923
+ if (prev.has(id) === !expanded) return prev;
5924
+ const next = new Set(prev);
5925
+ if (expanded) next.delete(id);
5926
+ else next.add(id);
5927
+ return next;
5928
+ });
5929
+ const expandAll = () => setCollapsed(/* @__PURE__ */ new Set());
5930
+ const collapseAll = () => setCollapsed(new Set(tree.kids.keys()));
5931
+ const latest = useRef({ props, l, owner, starter, renderPerson, nameOf, setExpanded, narrow });
5932
+ latest.current = { props, l, owner, starter, renderPerson, nameOf, setExpanded, narrow };
5933
+ const showOutputs = Object.values(props.outputsByTask ?? {}).some((o) => o.length > 0);
5934
+ const columnDefs = useMemo(
5935
+ () => createTaskColumns({
5936
+ narrow,
5937
+ labels: l,
5938
+ getOwnerName: (row) => latest.current.owner(row.task).label,
5939
+ renderName: (row) => {
5940
+ const { l: lb, props: p, nameOf: name } = latest.current;
5941
+ const { task, depth, childStats, expanded } = row;
5942
+ const id = task.external_id;
5943
+ const status = asTaskStatus(task.status);
5944
+ const goal = goalProgress(task);
5945
+ const workflowName = task.workflow_ext_id ? p.workflowNames?.[task.workflow_ext_id] : null;
5946
+ return /* @__PURE__ */ jsxs(
5947
+ "div",
5948
+ {
5949
+ className: "flex min-w-0 flex-1 items-center gap-1.5",
5950
+ style: depth > 0 ? { paddingLeft: `${Math.min(depth, MAX_INDENT_DEPTH) * 1.5}rem` } : void 0,
5951
+ "data-depth": depth,
5952
+ "aria-level": depth + 1,
5953
+ "aria-setsize": row.setSize,
5954
+ "aria-posinset": row.posInSet,
5955
+ "data-context": row.context || void 0,
5956
+ children: [
5957
+ childStats ? /* @__PURE__ */ jsx(
5958
+ "button",
5959
+ {
5960
+ type: "button",
5961
+ onClick: () => latest.current.setExpanded(id, !expanded),
5962
+ "aria-expanded": expanded,
5963
+ "aria-label": expanded ? lb.collapseSubtasks : lb.expandSubtasks,
5964
+ className: "flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
5965
+ "data-testid": `task-expand-${id}`,
5966
+ children: expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-4", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-4", "aria-hidden": true })
5967
+ }
5968
+ ) : depth > 0 ? /* @__PURE__ */ jsx("span", { className: "size-5 shrink-0", "aria-hidden": true }) : null,
5969
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 leading-tight", children: [
5970
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
5971
+ /* @__PURE__ */ jsx(
5972
+ "button",
5973
+ {
5974
+ type: "button",
5975
+ onClick: () => latest.current.props.onOpenThread(id, task),
5976
+ title: task.agent_ext_id ? lb.preparedBy(p.agentNames?.[task.agent_ext_id] || lb.agent) : void 0,
5977
+ className: cn(
5978
+ // The title has priority: it keeps at least 12 characters before it ellipsises.
5979
+ "min-w-[12ch] truncate text-left text-sm font-medium hover:underline focus-visible:underline focus-visible:outline-none",
5980
+ status === "done" && "text-muted-foreground line-through"
5981
+ ),
5982
+ "data-testid": `task-name-${id}`,
5983
+ children: name(task)
5984
+ }
5985
+ ),
5986
+ goal && /* @__PURE__ */ jsxs(
5987
+ ToneBadge,
5988
+ {
5989
+ tone: goal.done ? "success" : "neutral",
5990
+ "data-testid": `task-goal-progress-${id}`,
5991
+ children: [
5992
+ goal.done ? "\u2713 " : "",
5993
+ lb.goalMet(goal.met, goal.total)
5994
+ ]
5995
+ }
5996
+ )
5997
+ ] }),
5998
+ latest.current.narrow && /* @__PURE__ */ jsx("div", { className: "pt-0.5", children: /* @__PURE__ */ jsx(
5999
+ TaskStatusPill,
6000
+ {
6001
+ id,
6002
+ status,
6003
+ runStartedAt: task.run_started_at,
6004
+ lastError: task.last_error,
6005
+ awaitingAccess: Boolean(task.pending_auth_request_id),
6006
+ labels: p.statusPillLabels
6007
+ }
6008
+ ) }),
6009
+ (task.description || workflowName || childStats) && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2 text-xs text-muted-foreground", children: [
6010
+ task.description ? /* @__PURE__ */ jsx("p", { className: "min-w-0 truncate", children: task.description }) : workflowName ? /* @__PURE__ */ jsxs(
6011
+ "span",
6012
+ {
6013
+ className: "inline-flex min-w-0 items-center gap-1.5",
6014
+ "data-testid": `task-workflow-${id}`,
6015
+ children: [
6016
+ /* @__PURE__ */ jsx(Workflow, { className: "size-3.5 shrink-0", "aria-hidden": true }),
6017
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: lb.fromWorkflow(workflowName) })
6018
+ ]
6019
+ }
6020
+ ) : null,
6021
+ childStats && /* @__PURE__ */ jsx(
6022
+ "span",
6023
+ {
6024
+ className: "shrink-0 tabular-nums",
6025
+ "data-testid": `task-subtask-progress-${id}`,
6026
+ children: lb.subtasksDone(childStats.done, childStats.total)
6027
+ }
6028
+ )
6029
+ ] })
6030
+ ] })
6031
+ ]
6032
+ }
6033
+ );
6034
+ },
6035
+ // Who has the next step: the person pill, with the "Me" treatment. A plain chat is its starter's.
6036
+ renderOwner: (row) => /* @__PURE__ */ jsx("span", { "data-testid": `task-owner-${row.external_id}`, className: "flex min-w-0", children: latest.current.renderPerson(
6037
+ row.task.status ? latest.current.owner(row.task) : latest.current.starter(row.task)
6038
+ ) }),
6039
+ renderDue: (row) => {
6040
+ const { l: lb, props: p } = latest.current;
6041
+ const { task } = row;
6042
+ const dueMs = task.due_at ? Date.parse(task.due_at) : NaN;
6043
+ const overdue = asTaskStatus(task.status) !== "done" && !Number.isNaN(dueMs) && dueMs < Date.now();
6044
+ return /* @__PURE__ */ jsx(
6045
+ "span",
6046
+ {
6047
+ className: cn(
6048
+ "truncate text-sm",
6049
+ overdue ? "font-medium text-red-text" : "text-muted-foreground"
6050
+ ),
6051
+ "data-testid": `task-due-${task.external_id}`,
6052
+ "data-overdue": overdue,
6053
+ children: task.due_at ? overdue ? lb.overdue(p.formatDate(task.due_at)) : lb.due(p.formatDate(task.due_at)) : lb.noDue
6054
+ }
6055
+ );
6056
+ },
6057
+ renderShared: (row) => {
6058
+ const { l: lb, props: p } = latest.current;
6059
+ const { task } = row;
6060
+ if (!p.onToggleShared) return null;
6061
+ return /* @__PURE__ */ jsx(
6062
+ VisibilityToggle,
6063
+ {
6064
+ items: { shared: task.is_shared ?? false },
6065
+ onToggle: (shouldShare) => latest.current.props.onToggleShared?.(task, shouldShare),
6066
+ disabled: task.is_owner === false,
6067
+ disabledTooltip: lb.sharedOwnerOnly,
6068
+ showLabel: false,
6069
+ "data-testid": `task-shared-${task.external_id}`
6070
+ }
6071
+ );
6072
+ },
6073
+ showOutputs,
6074
+ renderOutputs: (row) => /* @__PURE__ */ jsx(
6075
+ TaskOutputsCell,
6076
+ {
6077
+ id: row.external_id,
6078
+ outputs: latest.current.props.outputsByTask?.[row.external_id],
6079
+ onOpen: (docId) => latest.current.props.onOpenOutput?.(docId, row.task),
6080
+ labels: latest.current.props.outputsLabels
6081
+ }
6082
+ ),
6083
+ renderStatus: (row) => /* @__PURE__ */ jsx(
6084
+ TaskStatusPill,
6085
+ {
6086
+ id: row.external_id,
6087
+ status: asTaskStatus(row.task.status),
6088
+ runStartedAt: row.task.run_started_at,
6089
+ lastError: row.task.last_error,
6090
+ awaitingAccess: Boolean(row.task.pending_auth_request_id),
6091
+ labels: latest.current.props.statusPillLabels,
6092
+ hint: statusHint(row.task, latest.current)
6093
+ }
6094
+ ),
6095
+ renderActions: (row) => {
6096
+ const { l: lb, props: p } = latest.current;
6097
+ const { task } = row;
6098
+ const id = task.external_id;
6099
+ const status = asTaskStatus(task.status);
6100
+ const busy = p.busyId === id;
6101
+ const isOwner = task.is_owner !== false;
6102
+ const canEdit = isOwner || Boolean(p.canEditShared);
6103
+ const canAdmin = isOwner || Boolean(p.isWorkspaceOwner);
6104
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
6105
+ !latest.current.narrow && isOwner && task.pending_auth_request_id && p.onGrantAccess && /* @__PURE__ */ jsxs(
6106
+ Button,
6107
+ {
6108
+ size: "sm",
6109
+ className: "h-8 gap-1.5 pointer-coarse:h-11",
6110
+ onClick: () => p.onGrantAccess?.(task),
6111
+ "data-testid": `task-allow-access-${id}`,
6112
+ children: [
6113
+ /* @__PURE__ */ jsx(KeyRound, { className: "size-3.5", "aria-hidden": true }),
6114
+ lb.allowAccess
6115
+ ]
6116
+ }
6117
+ ),
6118
+ /* @__PURE__ */ jsx(
6119
+ TaskRowMenu,
6120
+ {
6121
+ task,
6122
+ status,
6123
+ busy,
6124
+ isOwner,
6125
+ canAdmin,
6126
+ canEdit,
6127
+ labels: lb,
6128
+ onMarkDone: () => p.onMarkDone(task),
6129
+ onReopen: () => p.onReopen(task),
6130
+ onAddSubtask: p.onAddSubtask ? () => p.onAddSubtask?.(task) : void 0,
6131
+ onMoveTo: p.onMove ? () => setMoving(task) : void 0,
6132
+ onEdit: () => p.onEdit(task),
6133
+ onDelete: () => p.onDelete(task),
6134
+ onOpenActivity: p.onOpenActivity ? () => p.onOpenActivity?.(task) : void 0,
6135
+ onGrantAccess: p.onGrantAccess ? () => p.onGrantAccess?.(task) : void 0
6136
+ }
6137
+ )
6138
+ ] });
6139
+ }
6140
+ }),
6141
+ // Stable on purpose: only the header texts rebuild the columns (see `latest`).
6142
+ // eslint-disable-next-line react-hooks/exhaustive-deps
6143
+ [
6144
+ l.colTask,
6145
+ l.colOwner,
6146
+ l.colDue,
6147
+ l.colStatus,
6148
+ l.colShared,
6149
+ l.colOutputs,
6150
+ l.shared,
6151
+ showOutputs,
6152
+ narrow
6153
+ ]
6154
+ );
6155
+ useEffect(() => {
6156
+ apiRef.current?.refreshCells({ force: true });
6157
+ }, [
6158
+ busyId,
6159
+ props.people,
6160
+ props.agentNames,
6161
+ props.workflowNames,
6162
+ props.outputsByTask,
6163
+ props.renderPerson,
6164
+ props.labels,
6165
+ props.canEditShared,
6166
+ props.isWorkspaceOwner,
6167
+ narrow
6168
+ ]);
6169
+ const animate = rows.length <= ANIMATE_ROWS_UP_TO;
6170
+ const gridOptions = useMemo(
6171
+ () => ({
6172
+ suppressClickEdit: true,
6173
+ // Keyboard focus lives on the name column only (the others are not navigable): ArrowRight
6174
+ // opens a task's sub-tasks and ArrowLeft closes them, or steps up to the parent.
6175
+ suppressCellFocus: false,
6176
+ suppressColumnVirtualisation: true,
6177
+ animateRows: animate,
6178
+ getRowClass: (p) => p.data?.context ? "opacity-60" : void 0,
6179
+ // The grid shows and reports the sort; the table orders each level (see buildTaskRows).
6180
+ onSortChanged: (event) => {
6181
+ const sorted = event.api.getColumnState().find((c) => c.sort);
6182
+ setSort(
6183
+ sorted?.colId ? { colId: sorted.colId, dir: sorted.sort ?? "asc" } : null
6184
+ );
6185
+ },
6186
+ onGridSizeChanged: (event) => {
6187
+ applyColumnWidthRules(event.api, event.clientWidth, WIDTH_RULES);
6188
+ setNarrow(event.clientWidth < NARROW_GRID);
6189
+ },
6190
+ onCellKeyDown: (event) => {
6191
+ const row = event.data;
6192
+ const key = event.event?.key;
6193
+ if (!row || event.column.getColId() !== "name") return;
6194
+ if (key === "ArrowRight" && row.childStats && !row.expanded) {
6195
+ event.event?.preventDefault();
6196
+ latest.current.setExpanded(row.external_id, true);
6197
+ } else if (key === "ArrowLeft") {
6198
+ if (row.childStats && row.expanded) {
6199
+ event.event?.preventDefault();
6200
+ latest.current.setExpanded(row.external_id, false);
6201
+ } else if (row.parentId) {
6202
+ event.event?.preventDefault();
6203
+ const parent = event.api.getRowNode(row.parentId);
6204
+ if (parent?.rowIndex != null) {
6205
+ event.api.ensureIndexVisible(parent.rowIndex);
6206
+ event.api.setFocusedCell(parent.rowIndex, "name");
6207
+ }
6208
+ }
6209
+ }
6210
+ }
6211
+ }),
6212
+ [animate]
6213
+ );
6214
+ const clearSelection = () => setSelectedIds(/* @__PURE__ */ new Set());
6215
+ const filterKeys = ["all", ...STATUS_ORDER].filter(
6216
+ (key) => key !== "chat" || (counts.get(key) ?? 0) > 0
6217
+ );
6218
+ const hasChildren = tree.kids.size > 0;
6219
+ return /* @__PURE__ */ jsxs(
6220
+ "div",
6221
+ {
6222
+ className: "flex min-h-0 flex-1 flex-col gap-3",
6223
+ "data-testid": testIdOr(testId, { testId: "task-list" }),
6224
+ children: [
6225
+ header,
6226
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
6227
+ /* @__PURE__ */ jsx("div", { role: "tablist", "aria-label": "Filter tasks", className: "flex flex-wrap gap-1.5", children: filterKeys.map((key) => {
6228
+ const count = counts.get(key) ?? 0;
6229
+ const isSelected = filter === key;
6230
+ return /* @__PURE__ */ jsxs(
6231
+ "button",
6232
+ {
6233
+ type: "button",
6234
+ role: "tab",
6235
+ "aria-selected": isSelected,
6236
+ onClick: () => setFilter(key),
6237
+ className: cn(
6238
+ "inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:min-h-11",
6239
+ isSelected ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:bg-accent"
6240
+ ),
6241
+ "data-testid": `task-filter-${key}`,
6242
+ children: [
6243
+ key === "all" ? l.filterAll : l.status[key],
6244
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums opacity-70", children: count })
6245
+ ]
6246
+ },
6247
+ key
6248
+ );
6249
+ }) }),
6250
+ /* @__PURE__ */ jsx(
6251
+ Input,
6252
+ {
6253
+ type: "search",
6254
+ value: query,
6255
+ onChange: (e) => setQuery(e.target.value),
6256
+ placeholder: l.searchPlaceholder,
6257
+ "aria-label": l.searchLabel,
6258
+ className: "h-8 max-w-56 text-xs pointer-coarse:h-11",
6259
+ "data-testid": "task-search"
6260
+ }
6261
+ ),
6262
+ hasChildren && /* @__PURE__ */ jsxs("div", { className: "ml-auto flex gap-1", children: [
6263
+ /* @__PURE__ */ jsxs(
6264
+ Button,
6265
+ {
6266
+ type: "button",
6267
+ variant: "ghost",
6268
+ size: "sm",
6269
+ className: "h-8 gap-1.5 text-xs pointer-coarse:h-11",
6270
+ onClick: expandAll,
6271
+ "data-testid": "task-expand-all",
6272
+ children: [
6273
+ /* @__PURE__ */ jsx(ChevronsUpDown, { className: "size-3.5", "aria-hidden": true }),
6274
+ l.expandAll
6275
+ ]
6276
+ }
6277
+ ),
6278
+ /* @__PURE__ */ jsxs(
6279
+ Button,
6280
+ {
6281
+ type: "button",
6282
+ variant: "ghost",
6283
+ size: "sm",
6284
+ className: "h-8 gap-1.5 text-xs pointer-coarse:h-11",
6285
+ onClick: collapseAll,
6286
+ "data-testid": "task-collapse-all",
6287
+ children: [
6288
+ /* @__PURE__ */ jsx(ChevronsDownUp, { className: "size-3.5", "aria-hidden": true }),
6289
+ l.collapseAll
6290
+ ]
6291
+ }
6292
+ )
6293
+ ] })
6294
+ ] }),
6295
+ tasks.length === 0 && !isLoading ? /* @__PURE__ */ jsx(
6296
+ EmptyState,
6297
+ {
6298
+ icon: ListTodo,
6299
+ title: l.emptyTitle,
6300
+ description: l.emptyMessage,
6301
+ testId: "task-list-empty"
6302
+ }
6303
+ ) : /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(
6304
+ GridView,
6305
+ {
6306
+ testId: "task-grid",
6307
+ gridId: props.gridId ?? "tasks-grid-v4",
6308
+ items: rows,
6309
+ columnDefs,
6310
+ getItemId: (row) => row.external_id,
6311
+ getRowTestId: (row) => `task-row-${row.external_id}`,
6312
+ isLoading,
6313
+ showEmpty: rows.length === 0,
6314
+ emptyState: { title: l.noMatches },
6315
+ rowHeight: narrow ? NARROW_ROW_HEIGHT : ROW_HEIGHT,
6316
+ height: "100%",
6317
+ onGridReady: ({ api }) => {
6318
+ apiRef.current = api;
6319
+ },
6320
+ selection: {
6321
+ mode: "multiple",
6322
+ controlled: true,
6323
+ selected: selectedRows,
6324
+ onSelectionChange: handleSelectionChange
6325
+ },
6326
+ gridOptions
6327
+ }
6328
+ ) }),
6329
+ /* @__PURE__ */ jsx(
6330
+ SelectionBar,
6331
+ {
6332
+ count: selectedTasks.length,
6333
+ onClear: clearSelection,
6334
+ status: selectedTasks.length > 0 && subtasksIncluded > 0 ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", "data-testid": "task-selection-subtasks", children: l.subtasksSelected(subtasksIncluded) }) : void 0,
6335
+ children: (isCompact) => /* @__PURE__ */ jsxs(Fragment, { children: [
6336
+ props.selectionActions?.(selectedTasks, isCompact, clearSelection),
6337
+ props.onMarkDoneMany && /* @__PURE__ */ jsx(
6338
+ SelectionBarAction,
6339
+ {
6340
+ icon: CheckCheck,
6341
+ label: l.markDoneMany,
6342
+ onClick: () => {
6343
+ props.onMarkDoneMany?.(markable);
6344
+ clearSelection();
6345
+ },
6346
+ disabled: markable.length === 0,
6347
+ isCompact,
6348
+ tooltip: l.markDoneManyHint,
6349
+ testId: "task-bulk-done"
6350
+ }
6351
+ ),
6352
+ props.onDeleteMany && /* @__PURE__ */ jsx(
6353
+ SelectionBarAction,
6354
+ {
6355
+ icon: Trash2,
6356
+ label: l.deleteMany,
6357
+ onClick: () => {
6358
+ props.onDeleteMany?.(deletable);
6359
+ clearSelection();
6360
+ },
6361
+ disabled: deletable.length === 0,
6362
+ isCompact,
6363
+ className: "border-red-border text-red-text hover:bg-red-bg hover:text-red-text",
6364
+ testId: "task-bulk-delete"
6365
+ }
6366
+ )
6367
+ ] })
6368
+ }
6369
+ ),
6370
+ moving && props.onMove && /* @__PURE__ */ jsx(
6371
+ TaskMoveDialog,
6372
+ {
6373
+ open: true,
6374
+ onOpenChange: (open) => !open && setMoving(null),
6375
+ options: moveTargets(tasks, moving).map((t) => ({ id: t.external_id, label: nameOf(t) })),
6376
+ currentParentId: moving.parent_conversation_ext_id,
6377
+ onPick: (parentId) => props.onMove?.(moving, parentId),
6378
+ labels: {
6379
+ title: l.moveToTitle(nameOf(moving)),
6380
+ none: l.moveToNone,
6381
+ search: l.moveToSearch,
6382
+ empty: l.moveToEmpty,
6383
+ cancel: l.moveToCancel
6384
+ }
6385
+ }
6386
+ )
6387
+ ]
6388
+ }
6389
+ );
6390
+ }
6391
+ function TaskInbox(p) {
6392
+ const [filterOpen, setFilterOpen] = useState(false);
6393
+ const [statusFilters, setStatusFilters] = useState(
6394
+ () => /* @__PURE__ */ new Map([["done", "exclude"]])
6395
+ );
6396
+ const [localQuery, setLocalQuery] = useState("");
6397
+ const [searchFields, setSearchFields] = useState(["text", "labels"]);
6398
+ const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
6399
+ const [collapsed, setCollapsed] = useState(/* @__PURE__ */ new Set());
6400
+ const [moving, setMoving] = useState(null);
6401
+ const l = { ...DEFAULT_TASK_LIST_LABELS, ...p.labels };
6402
+ const nameOf = (t) => t.title?.trim() || t.workflow_ext_id && p.workflowNames?.[t.workflow_ext_id] || l.untitled;
6403
+ const all = p.tasks.filter((t) => t.status != null);
6404
+ const filterText = p.filterText ?? localQuery;
6405
+ const q = filterText.trim().toLowerCase();
6406
+ const included = [...statusFilters].filter(([, state]) => state === "include").map(([id]) => id);
6407
+ const statusMatches = (t) => statusFilters.get(asTaskStatus(t.status)) !== "exclude" && (!included.length || included.includes(asTaskStatus(t.status)));
6408
+ const rows = all.filter(
6409
+ (t) => statusMatches(t) && (!q || [
6410
+ searchFields.includes("text") ? `${nameOf(t)} ${t.description ?? ""}` : "",
6411
+ searchFields.includes("labels") && t.workflow_ext_id ? p.workflowNames?.[t.workflow_ext_id] ?? "" : ""
6412
+ ].join(" ").toLowerCase().includes(q))
6413
+ );
6414
+ const hasActiveFilters = !!q || [...statusFilters.values()].some((state) => state != null);
6415
+ const selectedTasks = all.filter((t) => selected.has(t.external_id));
6416
+ const canEdit = (t) => t.is_owner !== false || Boolean(p.canEditShared);
6417
+ const markable = (t) => t.status !== "done" && t.status !== "generating" && canEdit(t) && !t.in_progress;
6418
+ const markableTasks = selectedTasks.filter(markable);
6419
+ const deletableTasks = selectedTasks.filter((t) => t.is_owner !== false || p.isWorkspaceOwner);
6420
+ const clearSelection = () => setSelected(/* @__PURE__ */ new Set());
6421
+ const toggle = (set, id) => set((old) => {
6422
+ const next = new Set(old);
6423
+ if (next.has(id)) next.delete(id);
6424
+ else next.add(id);
6425
+ return next;
6426
+ });
6427
+ p.renderPerson ?? ((value) => /* @__PURE__ */ jsx(PersonPill, { person: value }));
6428
+ const taskById = new Map(all.map((t) => [t.external_id, t]));
6429
+ const visible = new Set(rows.map((t) => t.external_id));
6430
+ for (const task of rows) {
6431
+ let id = task.parent_conversation_ext_id;
6432
+ const seen = /* @__PURE__ */ new Set();
6433
+ while (id && taskById.has(id) && !seen.has(id)) {
6434
+ seen.add(id);
6435
+ visible.add(id);
6436
+ id = taskById.get(id)?.parent_conversation_ext_id;
6437
+ }
6438
+ }
6439
+ const listed = all.filter((t) => visible.has(t.external_id));
6440
+ const roots = listed.filter(
6441
+ (t) => !t.parent_conversation_ext_id || !visible.has(t.parent_conversation_ext_id)
6442
+ );
6443
+ const workflows = (p.workflows ?? []).filter((w) => {
6444
+ const runs = roots.filter((t) => t.workflow_ext_id === w.external_id);
6445
+ return runs.length > 0 || !included.length && (!q || w.name.toLowerCase().includes(q));
6446
+ });
6447
+ const workflowIds = new Set(workflows.map((w) => w.external_id));
6448
+ const order = (a, b) => {
6449
+ const weight = (t) => t.pending_auth_request_id || t.last_error ? 0 : t.status === "todo" ? 1 : t.status === "generating" ? 2 : 3;
6450
+ return weight(a) - weight(b) || (b.updated_at ?? "").localeCompare(a.updated_at ?? "");
6451
+ };
6452
+ const renderTask = (task, depth = 0) => {
6453
+ const id = task.external_id;
6454
+ const status = asTaskStatus(task.status);
6455
+ const busy = p.busyId === id;
6456
+ const children = listed.filter((t) => t.parent_conversation_ext_id === id).sort(order);
6457
+ const outputs = p.outputsByTask?.[id] ?? [];
6458
+ return /* @__PURE__ */ jsxs("li", { "data-testid": `task-inbox-row-${id}`, children: [
6459
+ /* @__PURE__ */ jsxs(
6460
+ "div",
6461
+ {
6462
+ className: cn(
6463
+ "relative flex cursor-pointer items-start gap-2 border-b py-3 hover:bg-muted/40",
6464
+ selected.has(id) && "bg-muted/60"
6465
+ ),
6466
+ onClick: (event) => {
6467
+ if (!event.target.closest(
6468
+ 'button, a, input, select, textarea, [role="menuitem"], [role="checkbox"], [role="combobox"]'
6469
+ )) {
6470
+ p.onOpenThread(id, task);
6471
+ }
6472
+ },
6473
+ style: { paddingLeft: `${Math.min(depth, 5) * 20}px` },
6474
+ children: [
6475
+ children.length > 0 && /* @__PURE__ */ jsx(
6476
+ Button,
6477
+ {
6478
+ variant: "ghost",
6479
+ size: "icon",
6480
+ className: "size-7 shrink-0",
6481
+ "aria-label": `${collapsed.has(id) ? "Expand" : "Collapse"} ${nameOf(task)}`,
6482
+ onClick: () => toggle(setCollapsed, id),
6483
+ children: collapsed.has(id) ? /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
6484
+ }
6485
+ ),
6486
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
6487
+ /* @__PURE__ */ jsx(
6488
+ "button",
6489
+ {
6490
+ className: cn(
6491
+ "block w-full text-left text-sm font-medium hover:underline",
6492
+ status === "done" && "text-muted-foreground"
6493
+ ),
6494
+ "data-testid": `task-open-${id}`,
6495
+ onClick: () => p.onOpenThread(id, task),
6496
+ children: nameOf(task)
6497
+ }
6498
+ ),
6499
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
6500
+ status !== "todo" && /* @__PURE__ */ jsx(
6501
+ TaskStatusPill,
6502
+ {
6503
+ id,
6504
+ status: task.status,
6505
+ runStartedAt: task.run_started_at,
6506
+ lastError: task.last_error,
6507
+ awaitingAccess: Boolean(task.pending_auth_request_id)
6508
+ }
6509
+ ),
6510
+ task.due_at && /* @__PURE__ */ jsxs("span", { children: [
6511
+ "Due ",
6512
+ p.formatDate(task.due_at)
6513
+ ] }),
6514
+ children.length > 0 && /* @__PURE__ */ jsxs("span", { children: [
6515
+ all.filter((t) => t.parent_conversation_ext_id === id && t.status === "done").length,
6516
+ "/",
6517
+ all.filter((t) => t.parent_conversation_ext_id === id).length,
6518
+ " steps complete"
6519
+ ] })
6520
+ ] }),
6521
+ outputs.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-wrap gap-2", "aria-label": "Outputs", children: outputs.map((output) => /* @__PURE__ */ jsxs(
6522
+ Button,
6523
+ {
6524
+ variant: "link",
6525
+ size: "sm",
6526
+ className: "h-auto max-w-full gap-1 px-0 py-1 text-xs",
6527
+ disabled: !p.onOpenOutput,
6528
+ onClick: () => p.onOpenOutput?.(output.id, task),
6529
+ "data-testid": `task-output-${id}-${output.id}`,
6530
+ children: [
6531
+ /* @__PURE__ */ jsx(FileText, { className: "size-3.5 shrink-0" }),
6532
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: output.name })
6533
+ ]
6534
+ },
6535
+ output.id
6536
+ )) })
6537
+ ] }),
6538
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
6539
+ task.pending_auth_request_id && task.is_owner !== false && p.onGrantAccess && /* @__PURE__ */ jsx(
6540
+ Button,
6541
+ {
6542
+ size: "sm",
6543
+ variant: "outline",
6544
+ disabled: busy,
6545
+ onClick: () => p.onGrantAccess?.(task),
6546
+ children: "Allow access"
6547
+ }
6548
+ ),
6549
+ /* @__PURE__ */ jsx(
6550
+ TaskRowMenu,
6551
+ {
6552
+ task,
6553
+ status,
6554
+ busy,
6555
+ isOwner: task.is_owner !== false,
6556
+ canAdmin: task.is_owner !== false || Boolean(p.isWorkspaceOwner),
6557
+ canEdit: canEdit(task),
6558
+ canMarkDone: markable(task),
6559
+ canReopen: canEdit(task),
6560
+ selected: selected.has(id),
6561
+ onToggleSelected: p.selectionActions || p.onMarkDoneMany || p.onDeleteMany ? () => toggle(setSelected, id) : void 0,
6562
+ labels: l,
6563
+ onMarkDone: () => p.onMarkDone(task),
6564
+ onNotify: p.onNotify ? () => p.onNotify?.(task) : void 0,
6565
+ onReopen: () => p.onReopen(task),
6566
+ onEdit: () => p.onEdit(task),
6567
+ onAddSubtask: p.onAddSubtask ? () => p.onAddSubtask?.(task) : void 0,
6568
+ onMoveTo: p.onMove ? () => setMoving(task) : void 0,
6569
+ onOpenActivity: p.onOpenActivity ? () => p.onOpenActivity?.(task) : void 0,
6570
+ onToggleShared: p.onToggleShared ? () => p.onToggleShared?.(task, !task.is_shared) : void 0
6571
+ }
6572
+ )
6573
+ ] })
6574
+ ]
6575
+ }
6576
+ ),
6577
+ children.length > 0 && !collapsed.has(id) && /* @__PURE__ */ jsx("ul", { children: children.map((child) => renderTask(child, depth + 1)) })
6578
+ ] }, id);
6579
+ };
6580
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col", "data-testid": p.testId ?? "task-inbox", children: [
6581
+ /* @__PURE__ */ jsx(
6582
+ TabHeader,
6583
+ {
6584
+ testId: "tasks-tab-header",
6585
+ tabs: [
6586
+ {
6587
+ id: "tasks",
6588
+ label: "",
6589
+ count: rows.length,
6590
+ countPlacement: "leading",
6591
+ countIcon: /* @__PURE__ */ jsx(ListTodo, { className: "size-3.5" }),
6592
+ hasActiveFilters,
6593
+ testId: "tasks-tab",
6594
+ presentation: "count"
6595
+ }
6596
+ ],
6597
+ activeTabId: "tasks",
6598
+ onTabChange: () => {
6599
+ },
6600
+ firstTabContent: /* @__PURE__ */ jsx(
6601
+ FilterInput,
6602
+ {
6603
+ value: filterText,
6604
+ onChange: p.onFilterTextChange ?? setLocalQuery,
6605
+ fields: searchFields,
6606
+ onFieldsChange: setSearchFields,
6607
+ labels: { fieldNames: { text: "Task", labels: "Workflow" } },
6608
+ className: "w-44 max-w-[40vw]",
6609
+ testIds: {
6610
+ root: "tasks-filter",
6611
+ input: "tasks-filter-input",
6612
+ fieldsButton: "tasks-filter-fields"
6613
+ },
6614
+ filter: /* @__PURE__ */ jsx(
6615
+ TriStateFilterMenu,
6616
+ {
6617
+ testId: "tasks-status-filter",
6618
+ open: filterOpen,
6619
+ onOpenChange: setFilterOpen,
6620
+ filterStates: statusFilters,
6621
+ onFiltersChange: setStatusFilters,
6622
+ options: [
6623
+ {
6624
+ id: "todo",
6625
+ label: "To do",
6626
+ count: all.filter((t) => t.status === "todo").length
6627
+ },
6628
+ {
6629
+ id: "generating",
6630
+ label: "Generating",
6631
+ count: all.filter((t) => t.status === "generating").length
6632
+ },
6633
+ {
6634
+ id: "done",
6635
+ label: "Completed",
6636
+ count: all.filter((t) => t.status === "done").length
6637
+ }
6638
+ ],
6639
+ groups: [{ label: "Status", options: ["todo", "generating", "done"] }],
6640
+ triggerClassName: "flex h-5 items-center gap-0.5 rounded px-1 text-muted-foreground hover:text-foreground pointer-coarse:h-11! pointer-coarse:min-w-11 pointer-coarse:justify-center",
6641
+ renderChevron: true,
6642
+ disableHoverOpen: true
6643
+ }
6644
+ )
6645
+ }
6646
+ ),
6647
+ rightContent: p.onCreate ? /* @__PURE__ */ jsxs(DropdownMenu, { children: [
6648
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { "data-testid": "new-task-button", children: [
6649
+ /* @__PURE__ */ jsx(Plus, { className: "mr-1 size-4" }),
6650
+ "New",
6651
+ /* @__PURE__ */ jsx(ChevronDown, { className: "ml-1 size-3" })
6652
+ ] }) }),
6653
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
6654
+ /* @__PURE__ */ jsx(DropdownMenuItem, { onSelect: p.onCreate, children: "Task" }),
6655
+ p.onCreateWorkflow && /* @__PURE__ */ jsx(DropdownMenuItem, { onSelect: p.onCreateWorkflow, children: "Saved workflow" })
6656
+ ] })
6657
+ ] }) : p.header
6658
+ }
6659
+ ),
6660
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", "aria-busy": p.isLoading, children: p.isLoading ? /* @__PURE__ */ jsx("p", { className: "py-12 text-center text-sm text-muted-foreground", children: "Loading work\u2026" }) : !listed.length && !workflows.length ? /* @__PURE__ */ jsx(
6661
+ EmptyState,
6662
+ {
6663
+ title: q ? "No matches" : all.length ? "You\u2019re all caught up" : "No work here yet",
6664
+ description: "Create a task from a prompt or a saved workflow. Keep its drafts and outputs together."
6665
+ }
6666
+ ) : /* @__PURE__ */ jsxs("ul", { children: [
6667
+ workflows.map((w) => {
6668
+ const runs = roots.filter((t) => t.workflow_ext_id === w.external_id).sort(order);
6669
+ const editable = w.is_owner !== false || p.canEditShared;
6670
+ return /* @__PURE__ */ jsxs("li", { "data-testid": `task-workflow-${w.external_id}`, children: [
6671
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 border-b py-3", children: [
6672
+ runs.length > 0 ? /* @__PURE__ */ jsx(
6673
+ Button,
6674
+ {
6675
+ variant: "ghost",
6676
+ size: "icon",
6677
+ className: "size-7",
6678
+ "aria-label": `${collapsed.has(w.external_id) ? "Expand" : "Collapse"} ${w.name}`,
6679
+ onClick: () => toggle(setCollapsed, w.external_id),
6680
+ children: collapsed.has(w.external_id) ? /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
6681
+ }
6682
+ ) : /* @__PURE__ */ jsx(Workflow, { className: "mx-1 mt-1 size-4 shrink-0 text-muted-foreground" }),
6683
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
6684
+ /* @__PURE__ */ jsx(
6685
+ "button",
6686
+ {
6687
+ className: "block text-left text-sm font-medium hover:underline",
6688
+ disabled: !editable,
6689
+ onClick: () => p.onEditWorkflow?.(w.external_id),
6690
+ children: w.name
6691
+ }
6692
+ ),
6693
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: [
6694
+ "Saved workflow \xB7 ",
6695
+ w.summary ?? "Run when needed",
6696
+ !w.active ? " \xB7 Paused" : "",
6697
+ runs.length ? ` \xB7 ${runs.length} ${runs.length === 1 ? "task" : "tasks"}` : ""
6698
+ ] }),
6699
+ w.last_error && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-destructive", children: w.last_error })
6700
+ ] }),
6701
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
6702
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
6703
+ Button,
6704
+ {
6705
+ variant: "ghost",
6706
+ size: "icon",
6707
+ className: "size-8",
6708
+ "aria-label": `Actions for ${w.name}`,
6709
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" })
6710
+ }
6711
+ ) }),
6712
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
6713
+ p.onWorkflowHistory && /* @__PURE__ */ jsx(DropdownMenuItem, { onSelect: () => p.onWorkflowHistory?.(w.external_id), children: "Run history" }),
6714
+ editable && p.onToggleWorkflow && /* @__PURE__ */ jsx(
6715
+ DropdownMenuItem,
6716
+ {
6717
+ onSelect: () => p.onToggleWorkflow?.(w.external_id, !w.active),
6718
+ children: w.active ? "Pause" : "Resume"
6719
+ }
6720
+ ),
6721
+ (w.is_owner !== false || p.isWorkspaceOwner) && p.onDeleteWorkflow && /* @__PURE__ */ jsx(DropdownMenuItem, { onSelect: () => p.onDeleteWorkflow?.(w.external_id), children: "Delete workflow" })
6722
+ ] })
6723
+ ] })
6724
+ ] }),
6725
+ !collapsed.has(w.external_id) && runs.length > 0 && /* @__PURE__ */ jsx("ul", { children: runs.map((t) => renderTask(t, 1)) })
6726
+ ] }, w.external_id);
6727
+ }),
6728
+ roots.filter((t) => !t.workflow_ext_id || !workflowIds.has(t.workflow_ext_id)).sort(order).map((t) => renderTask(t))
6729
+ ] }) }),
6730
+ /* @__PURE__ */ jsx(SelectionBar, { count: selectedTasks.length, onClear: clearSelection, children: (isCompact) => /* @__PURE__ */ jsxs(Fragment, { children: [
6731
+ p.selectionActions?.(selectedTasks, isCompact, clearSelection),
6732
+ p.onMarkDoneMany && /* @__PURE__ */ jsx(
6733
+ SelectionBarAction,
6734
+ {
6735
+ icon: CheckCheck,
6736
+ label: l.markDoneMany,
6737
+ isCompact,
6738
+ disabled: !markableTasks.length,
6739
+ onClick: () => {
6740
+ p.onMarkDoneMany?.(markableTasks);
6741
+ clearSelection();
6742
+ },
6743
+ testId: "task-bulk-done"
6744
+ }
6745
+ ),
6746
+ p.onDeleteMany && /* @__PURE__ */ jsx(
6747
+ SelectionBarAction,
6748
+ {
6749
+ icon: Trash2,
6750
+ label: l.deleteMany,
6751
+ isCompact,
6752
+ disabled: !deletableTasks.length,
6753
+ onClick: () => {
6754
+ p.onDeleteMany?.(deletableTasks);
6755
+ clearSelection();
6756
+ },
6757
+ className: "text-red-text hover:bg-red-bg hover:text-red-text",
6758
+ testId: "task-bulk-delete"
6759
+ }
6760
+ )
6761
+ ] }) }),
6762
+ moving && p.onMove && /* @__PURE__ */ jsx(
6763
+ TaskMoveDialog,
6764
+ {
6765
+ open: true,
6766
+ onOpenChange: (open) => !open && setMoving(null),
6767
+ options: moveTargets(all, moving).map((t) => ({ id: t.external_id, label: nameOf(t) })),
6768
+ currentParentId: moving.parent_conversation_ext_id,
6769
+ onPick: (id) => p.onMove?.(moving, id),
6770
+ labels: {
6771
+ title: l.moveToTitle(nameOf(moving)),
6772
+ none: l.moveToNone,
6773
+ search: l.moveToSearch,
6774
+ empty: l.moveToEmpty,
6775
+ cancel: l.moveToCancel
6776
+ }
6777
+ }
6778
+ )
6779
+ ] });
5042
6780
  }
5043
6781
  var DEFAULT_THREAD_STATE_LABELS = {
5044
6782
  generating: "Generating",
@@ -5096,6 +6834,220 @@ function ThreadStatusLine({
5096
6834
  }
5097
6835
  );
5098
6836
  }
6837
+ function filterConversationRows(conversations, query, labelText, doneFilter = "exclude", visibilityFilters, meetingFilter = null) {
6838
+ const q = query.trim().toLowerCase();
6839
+ return [...conversations].sort(
6840
+ (a, b) => (Date.parse(b.last_message_updated_at || b.updated_at || b.created_at || "") || 0) - (Date.parse(a.last_message_updated_at || a.updated_at || a.created_at || "") || 0)
6841
+ ).filter(
6842
+ (row) => doneFilter === "exclude" ? row.status !== "done" : doneFilter === "include" ? row.status === "done" : true
6843
+ ).filter((row) => {
6844
+ const state = row.is_shared ? visibilityFilters?.workspace : visibilityFilters?.me;
6845
+ const hasIncluded = visibilityFilters?.me === "include" || visibilityFilters?.workspace === "include";
6846
+ return state !== "exclude" && (!hasIncluded || state === "include");
6847
+ }).filter(
6848
+ (row) => meetingFilter === "include" ? !!row.meeting_call_ext_id : meetingFilter === "exclude" ? !row.meeting_call_ext_id : true
6849
+ ).filter((row) => !q || `${row.title ?? ""} ${labelText?.(row) ?? ""}`.toLowerCase().includes(q));
6850
+ }
6851
+ function ConversationListView(p) {
6852
+ const liveProps = useRef(p);
6853
+ liveProps.current = p;
6854
+ const [query, setQuery] = useState("");
6855
+ const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
6856
+ const q = `${query} ${p.filterText ?? ""}`.trim().toLowerCase();
6857
+ const isPhone = useIsPhone();
6858
+ const rows = useMemo(
6859
+ () => filterConversationRows(
6860
+ p.conversations,
6861
+ q,
6862
+ p.labelText,
6863
+ p.doneFilter,
6864
+ p.visibilityFilters,
6865
+ p.meetingFilter
6866
+ ),
6867
+ [p.conversations, q, p.labelText, p.doneFilter, p.visibilityFilters, p.meetingFilter]
6868
+ );
6869
+ const selectedRows = p.conversations.filter((c) => selected.has(c.external_id));
6870
+ const hasLabels = p.conversations.some((c) => !!p.labelText?.(c));
6871
+ const columns = useMemo(
6872
+ () => [
6873
+ {
6874
+ colId: "name",
6875
+ headerName: "Thread",
6876
+ flex: 2,
6877
+ minWidth: 200,
6878
+ valueGetter: ({ data }) => data?.title?.trim() || "Untitled thread",
6879
+ cellRenderer: ({ data }) => data && /* @__PURE__ */ jsxs("div", { className: "group flex h-full min-w-0 items-center gap-2", children: [
6880
+ /* @__PURE__ */ jsx("div", { className: "min-w-0", children: liveProps.current.renderThread ? liveProps.current.renderThread(data) : /* @__PURE__ */ jsx(
6881
+ EntityChip,
6882
+ {
6883
+ icon: /* @__PURE__ */ jsx(ThreadVisibilityIcon, { shared: data.is_shared ?? false, className: "size-4" }),
6884
+ label: data.title?.trim() || "Untitled thread",
6885
+ pillTooltip: "Open conversation",
6886
+ labelMaxWidth: "max-w-full",
6887
+ onClick: () => liveProps.current.onOpen(data),
6888
+ testId: `thread-open-${data.external_id}`
6889
+ }
6890
+ ) }),
6891
+ (data.message_count ?? 0) > 0 && /* @__PURE__ */ jsxs(
6892
+ "span",
6893
+ {
6894
+ className: "inline-flex h-5 shrink-0 items-center gap-0.5 self-center rounded-full bg-muted px-1.5 text-[10px] font-medium leading-none tabular-nums text-muted-foreground",
6895
+ title: `${data.message_count} ${data.message_count === 1 ? "message" : "messages"}`,
6896
+ "data-testid": `thread-messages-${data.external_id}`,
6897
+ children: [
6898
+ /* @__PURE__ */ jsx(MessageSquare, { className: "size-3", "aria-hidden": true }),
6899
+ data.message_count
6900
+ ]
6901
+ }
6902
+ ),
6903
+ (data.is_owner !== false || liveProps.current.canEditShared) && /* @__PURE__ */ jsx(
6904
+ "button",
6905
+ {
6906
+ type: "button",
6907
+ "aria-label": `Rename ${data.title?.trim() || "Untitled thread"}`,
6908
+ onClick: () => liveProps.current.onRename(data),
6909
+ "data-testid": `thread-rename-${data.external_id}`,
6910
+ className: "shrink-0 pointer-coarse:flex pointer-coarse:size-11 pointer-coarse:items-center pointer-coarse:justify-center",
6911
+ children: /* @__PURE__ */ jsx(CellHoverIcon, {})
6912
+ }
6913
+ )
6914
+ ] })
6915
+ },
6916
+ // Labels only when a thread has some (an empty column only takes the names' room), and never
6917
+ // on a phone, where the status is what a row must say.
6918
+ ...liveProps.current.renderLabels && hasLabels && !isPhone ? [
6919
+ {
6920
+ colId: "labels",
6921
+ headerName: "Labels",
6922
+ flex: 0.5,
6923
+ minWidth: 100,
6924
+ valueGetter: ({ data }) => data ? liveProps.current.labelText?.(data) ?? "" : "",
6925
+ cellRenderer: ({ data }) => data && liveProps.current.renderLabels?.(data)
6926
+ }
6927
+ ] : [],
6928
+ {
6929
+ colId: "status",
6930
+ headerName: "Status",
6931
+ width: isPhone ? 170 : 240,
6932
+ valueGetter: ({ data }) => data?.status,
6933
+ cellRenderer: ({ data }) => data && (liveProps.current.renderStatus ? liveProps.current.renderStatus(data) : /* @__PURE__ */ jsx(
6934
+ ThreadStatusLine,
6935
+ {
6936
+ state: data.status === "done" ? "done" : data.status === "todo" ? "todo" : "ready"
6937
+ }
6938
+ ))
6939
+ },
6940
+ // Who spoke last (their face) and when: the two read together, at the row's end.
6941
+ ...liveProps.current.renderBy || liveProps.current.renderOwner ? [
6942
+ {
6943
+ colId: liveProps.current.renderBy ? "by" : "owner",
6944
+ headerName: liveProps.current.renderBy ? "By" : "Owner",
6945
+ width: 64,
6946
+ hide: isPhone,
6947
+ sortable: false,
6948
+ resizable: false,
6949
+ cellRenderer: ({ data }) => data && (liveProps.current.renderBy || liveProps.current.renderOwner)?.(data)
6950
+ }
6951
+ ] : [],
6952
+ {
6953
+ colId: "activity",
6954
+ initialSort: "desc",
6955
+ headerName: "Updated",
6956
+ width: 128,
6957
+ hide: isPhone,
6958
+ valueGetter: ({ data }) => data?.last_message_updated_at || data?.updated_at || data?.created_at || "",
6959
+ valueFormatter: ({ value }) => value ? liveProps.current.formatDate(value) : "\u2014",
6960
+ cellClass: "flex items-center text-xs text-muted-foreground/80"
6961
+ }
6962
+ ],
6963
+ [
6964
+ Boolean(p.renderThread),
6965
+ Boolean(p.renderLabels),
6966
+ Boolean(p.renderOwner),
6967
+ Boolean(p.renderBy),
6968
+ Boolean(p.renderStatus),
6969
+ isPhone,
6970
+ hasLabels
6971
+ ]
6972
+ );
6973
+ const centred = useMemo(
6974
+ () => columns.map((c) => ({ cellClass: "flex items-center", ...c })),
6975
+ [columns]
6976
+ );
6977
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col", "data-testid": "conversation-list-view", children: [
6978
+ p.showHeader !== false && /* @__PURE__ */ jsx(
6979
+ TabHeader,
6980
+ {
6981
+ testId: "threads-tab-header",
6982
+ tabs: [
6983
+ {
6984
+ id: "threads",
6985
+ label: "",
6986
+ count: rows.length,
6987
+ countIcon: /* @__PURE__ */ jsx(MessageSquare, { className: "size-3.5" }),
6988
+ countPlacement: "leading",
6989
+ presentation: "count",
6990
+ hasActiveFilters: !!q
6991
+ }
6992
+ ],
6993
+ activeTabId: "threads",
6994
+ onTabChange: () => {
6995
+ },
6996
+ firstTabContent: /* @__PURE__ */ jsx(
6997
+ FilterInput,
6998
+ {
6999
+ value: query,
7000
+ hideFieldPicker: true,
7001
+ ariaLabel: "Search threads",
7002
+ onChange: setQuery,
7003
+ fields: ["text"],
7004
+ onFieldsChange: () => {
7005
+ },
7006
+ labels: {
7007
+ placeholder: "Find a thread\u2026",
7008
+ fieldNames: { text: "Thread" }
7009
+ },
7010
+ className: "w-44 max-w-[40vw]"
7011
+ }
7012
+ ),
7013
+ rightContent: p.header
7014
+ }
7015
+ ),
7016
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(
7017
+ GridView,
7018
+ {
7019
+ testId: "threads-grid",
7020
+ items: rows,
7021
+ columnDefs: centred,
7022
+ getItemId: (row) => row.external_id,
7023
+ getRowTestId: (row) => `thread-row-${row.external_id}`,
7024
+ onRowClick: p.onOpen,
7025
+ height: "100%",
7026
+ isLoading: p.isLoading,
7027
+ loadingMessage: "Loading threads\u2026",
7028
+ emptyState: {
7029
+ title: q ? "No threads match" : "No conversations yet",
7030
+ message: p.footer ? "Type below to ask ARBI, bring in people, or both." : "Use New Task to ask ARBI, bring in people, or both."
7031
+ },
7032
+ selection: p.selectionActions ? {
7033
+ mode: "multiple",
7034
+ controlled: true,
7035
+ selected: selectedRows,
7036
+ onSelectionChange: (items) => setSelected(new Set(items.map((item) => item.external_id)))
7037
+ } : void 0,
7038
+ gridOptions: {
7039
+ suppressClickEdit: true,
7040
+ onCellKeyDown: (event) => {
7041
+ if (event.event?.key === "Enter" && "column" in event && event.column.getColId() === "name" && event.data)
7042
+ p.onOpen(event.data);
7043
+ }
7044
+ }
7045
+ }
7046
+ ) }),
7047
+ p.footer,
7048
+ p.selectionActions && /* @__PURE__ */ jsx(SelectionBar, { count: selectedRows.length, onClear: () => setSelected(/* @__PURE__ */ new Set()), children: (compact2) => p.selectionActions?.(selectedRows, compact2, () => setSelected(/* @__PURE__ */ new Set())) })
7049
+ ] });
7050
+ }
5099
7051
  var NO_PEOPLE = [];
5100
7052
  function TaskStartDialog({
5101
7053
  open,
@@ -7179,6 +9131,56 @@ function compactThreadActivity(events, stepTitleOf) {
7179
9131
  }
7180
9132
  return result;
7181
9133
  }
9134
+ var DEFAULT_TASK_THREAD_CHIP_LABELS = {
9135
+ open: "Open thread",
9136
+ watch: "Watch live",
9137
+ none: "No thread yet"
9138
+ };
9139
+ function TaskThreadChip({
9140
+ id,
9141
+ conversationId,
9142
+ generating = false,
9143
+ onOpen,
9144
+ testId,
9145
+ labels
9146
+ }) {
9147
+ const l = { ...DEFAULT_TASK_THREAD_CHIP_LABELS, ...labels };
9148
+ if (!conversationId) {
9149
+ return /* @__PURE__ */ jsxs(
9150
+ "span",
9151
+ {
9152
+ className: "inline-flex items-center gap-1 text-xs text-muted-foreground",
9153
+ "data-testid": testIdOr(testId, { testId: `task-thread-${id}` }),
9154
+ "data-state": "none",
9155
+ children: [
9156
+ /* @__PURE__ */ jsx(MessageSquare, { className: "size-3.5 opacity-50", "aria-hidden": true }),
9157
+ l.none
9158
+ ]
9159
+ }
9160
+ );
9161
+ }
9162
+ return /* @__PURE__ */ jsxs(
9163
+ Button,
9164
+ {
9165
+ variant: "ghost",
9166
+ size: "sm",
9167
+ className: cn(
9168
+ "h-7 gap-1.5 px-2 text-xs pointer-coarse:h-11",
9169
+ generating && "text-ai-ink hover:text-ai-ink"
9170
+ ),
9171
+ onClick: () => onOpen(conversationId),
9172
+ "data-testid": testIdOr(testId, { testId: `task-thread-${id}` }),
9173
+ "data-state": generating ? "live" : "idle",
9174
+ children: [
9175
+ /* @__PURE__ */ jsxs("span", { className: "relative flex size-3.5 items-center justify-center", children: [
9176
+ generating && /* @__PURE__ */ jsx("span", { className: "absolute inline-flex size-full animate-ping rounded-full bg-ai-soft" }),
9177
+ /* @__PURE__ */ jsx(MessageSquare, { className: "relative size-3.5", "aria-hidden": true })
9178
+ ] }),
9179
+ generating ? l.watch : l.open
9180
+ ]
9181
+ }
9182
+ );
9183
+ }
7182
9184
  var DEFAULT_TASK_RUNS_DIALOG_LABELS = {
7183
9185
  title: (taskName) => `Run history \u2014 ${taskName}`,
7184
9186
  description: "Every time this task ran. Open a run to read or watch it in its conversation.",
@@ -7313,6 +9315,78 @@ function TaskRunsDialog({
7313
9315
  }
7314
9316
  ) });
7315
9317
  }
9318
+ var DEFAULT_TASKS_CHROME_LABELS = {
9319
+ tasksTab: "Tasks",
9320
+ newTask: "New task"
9321
+ };
9322
+ function TasksToolbar({ count, onNewTask, testIds, labels }) {
9323
+ const l = { ...DEFAULT_TASKS_CHROME_LABELS, ...labels };
9324
+ const tabs = [
9325
+ {
9326
+ id: "tasks",
9327
+ label: l.tasksTab,
9328
+ icon: /* @__PURE__ */ jsx(ListTodo, { className: "size-4" }),
9329
+ count,
9330
+ testId: testIdOr(testIds?.tab, { testId: "tasks-tab" })
9331
+ }
9332
+ ];
9333
+ return /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 bg-background", "data-slot": "tasks-toolbar", children: /* @__PURE__ */ jsx(
9334
+ TabHeader,
9335
+ {
9336
+ tabs,
9337
+ activeTabId: "tasks",
9338
+ onTabChange: () => {
9339
+ },
9340
+ rightContent: /* @__PURE__ */ jsxs(
9341
+ Button,
9342
+ {
9343
+ onClick: onNewTask,
9344
+ "data-testid": testIdOr(testIds?.newTask, { testId: "task-new" }),
9345
+ children: [
9346
+ /* @__PURE__ */ jsx(Plus, { size: 16, className: "mr-1.5" }),
9347
+ l.newTask
9348
+ ]
9349
+ }
9350
+ )
9351
+ }
9352
+ ) });
9353
+ }
9354
+ var DEFAULT_WORKFLOWS_CHROME_LABELS = {
9355
+ workflowsTab: "Workflows",
9356
+ newWorkflow: "New workflow"
9357
+ };
9358
+ function WorkflowsToolbar({ count, onNewWorkflow, testIds, labels }) {
9359
+ const l = { ...DEFAULT_WORKFLOWS_CHROME_LABELS, ...labels };
9360
+ const tabs = [
9361
+ {
9362
+ id: "workflows",
9363
+ label: l.workflowsTab,
9364
+ icon: /* @__PURE__ */ jsx(Workflow, { className: "size-4" }),
9365
+ count,
9366
+ testId: testIdOr(testIds?.tab, { testId: "workflows-tab" })
9367
+ }
9368
+ ];
9369
+ return /* @__PURE__ */ jsx("div", { className: "sticky top-0 z-10 bg-background", "data-slot": "workflows-toolbar", children: /* @__PURE__ */ jsx(
9370
+ TabHeader,
9371
+ {
9372
+ tabs,
9373
+ activeTabId: "workflows",
9374
+ onTabChange: () => {
9375
+ },
9376
+ rightContent: /* @__PURE__ */ jsxs(
9377
+ Button,
9378
+ {
9379
+ onClick: onNewWorkflow,
9380
+ "data-testid": testIdOr(testIds?.newWorkflow, { testId: "workflow-new" }),
9381
+ children: [
9382
+ /* @__PURE__ */ jsx(Plus, { size: 16, className: "mr-1.5" }),
9383
+ l.newWorkflow
9384
+ ]
9385
+ }
9386
+ )
9387
+ }
9388
+ ) });
9389
+ }
7316
9390
 
7317
9391
  // src/agents/tasks/taskComposerTypes.ts
7318
9392
  var DEFAULT_TASK_COMPOSER_LABELS = {
@@ -8500,6 +10574,132 @@ function WorkTaskComposer({
8500
10574
  function TaskComposer(props) {
8501
10575
  return props.kind === "workflow" ? /* @__PURE__ */ jsx(WorkflowComposer, { ...props }) : /* @__PURE__ */ jsx(WorkTaskComposer, { ...props });
8502
10576
  }
10577
+ function ThreadNotifyDialog({
10578
+ open,
10579
+ onOpenChange,
10580
+ people,
10581
+ isShared,
10582
+ onNotify
10583
+ }) {
10584
+ const [selected, setSelected] = useState([]);
10585
+ const [query, setQuery] = useState("");
10586
+ const [busy, setBusy] = useState(false);
10587
+ const [error, setError] = useState(null);
10588
+ useEffect(() => {
10589
+ if (open) {
10590
+ setSelected([]);
10591
+ setQuery("");
10592
+ setError(null);
10593
+ }
10594
+ }, [open]);
10595
+ return /* @__PURE__ */ jsx(
10596
+ Dialog,
10597
+ {
10598
+ open,
10599
+ onOpenChange: (value) => {
10600
+ if (!busy) onOpenChange(value);
10601
+ },
10602
+ children: /* @__PURE__ */ jsxs(DialogContent, { className: "max-w-sm", "data-testid": "thread-notify-dialog", children: [
10603
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Notify" }),
10604
+ /* @__PURE__ */ jsx(DialogDescription, { children: isShared ? "Ask someone to follow up in this thread." : "Notifying someone shares this thread with your workspace." }),
10605
+ /* @__PURE__ */ jsx(
10606
+ Input,
10607
+ {
10608
+ "aria-label": "Find people",
10609
+ placeholder: "Find someone\u2026",
10610
+ value: query,
10611
+ onChange: (event) => setQuery(event.target.value)
10612
+ }
10613
+ ),
10614
+ /* @__PURE__ */ jsxs("div", { className: "max-h-64 overflow-y-auto space-y-1", children: [
10615
+ people.filter((person) => person.label.toLowerCase().includes(query.toLowerCase())).map((person) => /* @__PURE__ */ jsxs(
10616
+ "label",
10617
+ {
10618
+ className: "flex cursor-pointer items-center gap-2 rounded px-2 py-2 hover:bg-muted",
10619
+ children: [
10620
+ /* @__PURE__ */ jsx(
10621
+ Checkbox,
10622
+ {
10623
+ disabled: busy,
10624
+ checked: selected.includes(person.id),
10625
+ onCheckedChange: (checked) => setSelected(
10626
+ (old) => checked ? [...old, person.id] : old.filter((id) => id !== person.id)
10627
+ )
10628
+ }
10629
+ ),
10630
+ person.label
10631
+ ]
10632
+ },
10633
+ person.id
10634
+ )),
10635
+ !people.length && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No other workspace members yet." })
10636
+ ] }),
10637
+ error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm text-destructive", children: error }),
10638
+ /* @__PURE__ */ jsx(
10639
+ Button,
10640
+ {
10641
+ disabled: busy || !selected.length,
10642
+ "data-testid": "thread-notify-submit",
10643
+ onClick: async () => {
10644
+ setBusy(true);
10645
+ setError(null);
10646
+ try {
10647
+ await onNotify(selected);
10648
+ onOpenChange(false);
10649
+ } catch (failure) {
10650
+ setError(failure instanceof Error ? failure.message : "Could not notify people");
10651
+ } finally {
10652
+ setBusy(false);
10653
+ }
10654
+ },
10655
+ children: busy ? "Notifying\u2026" : "Notify"
10656
+ }
10657
+ )
10658
+ ] })
10659
+ }
10660
+ );
10661
+ }
10662
+ function ConversationTurnSpeaker({
10663
+ role,
10664
+ actor,
10665
+ currentUserId,
10666
+ colorClass,
10667
+ platformName = "ARBI",
10668
+ platformLogoSrc = ARBI_MARK_SRC,
10669
+ variant = "pill"
10670
+ }) {
10671
+ if (!role) return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" });
10672
+ if (role === "assistant" && !actor)
10673
+ return /* @__PURE__ */ jsx(
10674
+ UserEntity,
10675
+ {
10676
+ size: "sm",
10677
+ variant,
10678
+ interactive: false,
10679
+ picture: platformLogoSrc,
10680
+ avatarImageClassName: "object-contain p-0.5",
10681
+ initials: platformName.charAt(0),
10682
+ displayName: platformName
10683
+ }
10684
+ );
10685
+ if (!actor) return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Unknown participant" });
10686
+ const isMe = actor.external_id === currentUserId;
10687
+ const displayName = isMe ? "You" : [actor.given_name, actor.family_name].filter(Boolean).join(" ");
10688
+ return /* @__PURE__ */ jsx(
10689
+ UserEntity,
10690
+ {
10691
+ size: "sm",
10692
+ variant,
10693
+ interactive: false,
10694
+ isMe,
10695
+ isAgent: actor.external_id.startsWith("agt-"),
10696
+ displayName,
10697
+ initials: `${actor.given_name.charAt(0)}${actor.family_name?.charAt(0) ?? ""}`.toUpperCase(),
10698
+ picture: actor.picture,
10699
+ colorClass
10700
+ }
10701
+ );
10702
+ }
8503
10703
  var STEP_ICON_MAP = {
8504
10704
  goal: Target,
8505
10705
  interjection: CornerDownRight,
@@ -10431,6 +12631,6 @@ function AgentCreateView({
10431
12631
  ] });
10432
12632
  }
10433
12633
 
10434
- export { ANNOTATE, ANNOTATE_ID, AUTOMATION_EVENTS, ActionStepBody, AgentAvatarField, AgentBar, AgentBarIconButton, AgentBarMenu, AgentBarNotes, AgentBarProbeAnswer, AgentBarQueuedNote, AgentBarStatus, AgentConnectInstructions, AgentCreateView, AgentCreatedView, AgentCreator, AgentEditView, AgentMainView, AgentTypeSelector, ApprovalEvidence, AssigneeLine, AssistantEntity, BUILTIN_SKILLS, CHRONOLOGY, CHRONOLOGY_ID, CUSTOM_TASK, CUSTOM_TASK_ID, CapabilityGrid, CapabilityTile, ConfigField, ConfigForm, ConsentActions, ConsentBulletList, ConsentCard, ConsentFootnote, ConsentHeader, ConsentMessage, ConsentNotice, ConsentPage, ConsentPermissionList, ConsentSection, ConsentStrong, ConsentText, CopyableUrl, DASHBOARD_OPERATIONS, DASHBOARD_PINNED, DEEP_RESEARCH, DEEP_RESEARCH_ID, DEFAULT_AGENT_AVATAR_FIELD_LABELS, DEFAULT_AGENT_BAR_LABELS, DEFAULT_AGENT_CAPABILITIES, DEFAULT_AGENT_CREATOR_LABELS, DEFAULT_AGENT_STEPS_LABELS, DEFAULT_AGENT_TEMPLATES, DEFAULT_AGENT_TYPES, DEFAULT_AGENT_TYPE_SELECTOR_LABELS, DEFAULT_AUTHORIZE_AGENT_LABELS, DEFAULT_CONFIG_FIELD_LABELS, DEFAULT_CONFIG_FORM_LABELS, DEFAULT_CONSENT_ACTIONS_LABELS, DEFAULT_COPYABLE_URL_LABELS, DEFAULT_NEW_THREAD_DIALOG_LABELS, DEFAULT_PILL_SELECT_LABELS, DEFAULT_RECURRENCE, DEFAULT_RECURRENCE_BUILDER_LABELS, DEFAULT_SKILL_EDIT_FORM_LABELS, DEFAULT_SKILL_GENERATE_FORM_LABELS, DEFAULT_SKILL_GLOBAL_BADGE_LABELS, DEFAULT_SKILL_VIEW_TOGGLE_LABELS, DEFAULT_STEP_BAR_LABELS, DEFAULT_SUBAGENT_ROSTER_LABELS, DEFAULT_TASK_ACTIVITY_LABELS, DEFAULT_TASK_COMPOSER_LABELS, DEFAULT_TASK_PLAN_LABELS, DEFAULT_TASK_RUNS_DIALOG_LABELS, DEFAULT_THREAD_LAUNCHER_LABELS, DEFAULT_THREAD_STATE_LABELS, DEFAULT_TUPLE_ARRAY_FIELD_LABELS, DEFAULT_WORKFLOW_RUNNER_LABELS, DEFAULT_WORKFLOW_RUN_STATUS_LABELS, DEFAULT_WORKFLOW_STEP_PARTS_LABELS, DEFAULT_WORKFLOW_THREAD_STRIP_LABELS, DERIVED_NAME_WORDS, EMPTY_NEW_THREAD, EntityChip, GENERATE_IMAGE, GENERATE_IMAGE_ID, GoalCriteria, IMAGE_ASPECT_AUTO, IMAGE_ASPECT_RATIOS, MAX_TASK_DEPTH, MODEL_NAME_ICONS, MODEL_TIER_ICON_MAP, MODEL_TIER_LABELS, NewThreadDialog, PillSelect, REMIND_TASK, REMIND_TASK_ID, RecurrenceBuilder, SKILL_FIELD_TYPE_LABELS, SKILL_MAIN_FILENAME, SKILL_SOURCE_LABELS, SKILL_TYPES, SKILL_TYPE_LABELS, STATUS_LABELS, STATUS_ORDER, STATUS_TONE, STEP_ICON_MAP, SUMMARISE, SUMMARISE_ID, SendBackControl, SkillActionButton, SkillDetail, SkillDetailSection, SkillEditForm, SkillFilterChips, SkillGenerateForm, SkillGlobalBadge, SkillLibraryDetail, SkillTile, SkillTypeBadge, SkillViewToggle, StepDetail, StepNarration, StepOutcome, StepParams, StepRow, StepSummary, StepTrace, StepTraceSummary, SubAgentLane, SubStepGroup, SubagentRoster, TAG_ICONS, TIMELINE, TIMELINE_ID, TIMELINE_PROMPT, TOOL_ICON_MAP, TRANSLATE, TRANSLATE_ID, TRANSLATE_LANGUAGES, TRIGGER_LABELS, TaskActivityDialog, TaskActivityTimeline, TaskComposer, TaskEmptyState, TaskFlow, TaskPlan, TaskRunsDialog, TaskStartDialog, ThreadActivity, ThreadLauncher, ThreadStatusLine, TupleArrayField, WEB_WORKFLOWS, WEEKDAYS, WORD_ASK, WORD_ASK_ID, WORD_CONTINUE, WORD_CONTINUE_ID, WORD_SUMMARISE, WORD_SUMMARISE_ID, WORD_SUPPORT, WORD_SUPPORT_ID, WORD_WORKFLOWS, WORKFLOW_REGISTRY, WorkflowRunStatus, WorkflowRunner, WorkflowStepAction, WorkflowStepBar, WorkflowThreadStartedBy, WorkflowThreadStrip, activateOnKey, activeStepId, agentConfigSectionToValues, agentCreatorToConfigSection, asTaskStatus, authModeFor, buildLibrarySkills, buildRRule, buildTaskRows, buildZipSkillImport, closeWorkflowLaunch, compactThreadActivity, composePersona, composerToTaskQuery, composerToWorkRequest, composerToWorkflowRequest, composerToWorkflowUpdate, createsWork, defaultScopeRenderer, defaultTaskComposerValues, deriveAgentName, deriveAnnotationName, deriveWorkflowName, descendantIds, describeRRule, describeTrigger, filterLibrarySkills, firstWords, fromPlanAssignee, fromPlanDocumentRef, fromPlanSteps, getAgentStepIcon, getAgentStepPresentation, getCurrentAgentStepPresentation, getModelIcon, goalProgress, groupThreadActivity, hasTaskFields, humanizeSection, importMarkdownSkill, importSkillFile, importSkillFromUrl, indexTasks, inferType, inputDocumentIds, isAgenticWorkflow, isIncompleteSignal, isMainSkillFile, isOutOfBounds, isPlainTodo, isSupersededStop, isValidAgentName, isoToLocalInput, latestMessageTime, layoutFromPlanSteps, linkedRunsFromActivity, localInputToIso, moveTargets, newThreadToRequest, nextCriterionId, notifiedLabel, openWorkflowLaunch, ownerExtId, parseRRule, parseSkillFrontmatter, prettifyKey, readSkillArchive, recordWorkflowUse, renderWorkflowIcon, resetWorkflowUsage, resolveScopeInputs, serializeSkill, skillSlug, sortByRecentUse, stepAccent, stepWindow, stripPersonaPreamble, summarizeAgent, summarizeCapabilities, taskActivityHeadline, taskComposerToCreateRequest, taskComposerToUpdateRequest, taskNeedsAccess, taskToComposerValues, toPlanAssignee, toPlanDocumentRef, toPlanSteps, unnotifiedMentions, useWorkflowLaunchRequest, useWorkflowUsage, useWorkflowView, workflowFromSkillMarkdown, workflowTaskFields, workflowToComposerValues, workflowToSkillMarkdown, workflowWhen };
10435
- //# sourceMappingURL=chunk-4DKI37QQ.js.map
10436
- //# sourceMappingURL=chunk-4DKI37QQ.js.map
12634
+ export { ANNOTATE, ANNOTATE_ID, AUTOMATION_EVENTS, ActionStepBody, AgentAvatarField, AgentBar, AgentBarIconButton, AgentBarMenu, AgentBarNotes, AgentBarProbeAnswer, AgentBarQueuedNote, AgentBarStatus, AgentConnectInstructions, AgentCreateView, AgentCreatedView, AgentCreator, AgentEditView, AgentMainView, AgentTypeSelector, ApprovalEvidence, AssigneeLine, AssistantEntity, BUILTIN_SKILLS, CHRONOLOGY, CHRONOLOGY_ID, CUSTOM_TASK, CUSTOM_TASK_ID, CapabilityGrid, CapabilityTile, ConfigField, ConfigForm, ConsentActions, ConsentBulletList, ConsentCard, ConsentFootnote, ConsentHeader, ConsentMessage, ConsentNotice, ConsentPage, ConsentPermissionList, ConsentSection, ConsentStrong, ConsentText, ConversationListView, ConversationTurnSpeaker, CopyableUrl, DASHBOARD_OPERATIONS, DASHBOARD_PINNED, DEEP_RESEARCH, DEEP_RESEARCH_ID, DEFAULT_AGENT_AVATAR_FIELD_LABELS, DEFAULT_AGENT_BAR_LABELS, DEFAULT_AGENT_CAPABILITIES, DEFAULT_AGENT_CREATOR_LABELS, DEFAULT_AGENT_STEPS_LABELS, DEFAULT_AGENT_TEMPLATES, DEFAULT_AGENT_TYPES, DEFAULT_AGENT_TYPE_SELECTOR_LABELS, DEFAULT_AUTHORIZE_AGENT_LABELS, DEFAULT_CONFIG_FIELD_LABELS, DEFAULT_CONFIG_FORM_LABELS, DEFAULT_CONSENT_ACTIONS_LABELS, DEFAULT_COPYABLE_URL_LABELS, DEFAULT_NEW_THREAD_DIALOG_LABELS, DEFAULT_PILL_SELECT_LABELS, DEFAULT_RECURRENCE, DEFAULT_RECURRENCE_BUILDER_LABELS, DEFAULT_SKILL_EDIT_FORM_LABELS, DEFAULT_SKILL_GENERATE_FORM_LABELS, DEFAULT_SKILL_GLOBAL_BADGE_LABELS, DEFAULT_SKILL_VIEW_TOGGLE_LABELS, DEFAULT_STEP_BAR_LABELS, DEFAULT_SUBAGENT_ROSTER_LABELS, DEFAULT_TASKS_CHROME_LABELS, DEFAULT_TASK_ACTIVITY_LABELS, DEFAULT_TASK_COMPOSER_LABELS, DEFAULT_TASK_LIST_LABELS, DEFAULT_TASK_OUTPUTS_CELL_LABELS, DEFAULT_TASK_PLAN_LABELS, DEFAULT_TASK_RUNS_DIALOG_LABELS, DEFAULT_TASK_STATUS_PILL_LABELS, DEFAULT_TASK_THREAD_CHIP_LABELS, DEFAULT_THREAD_LAUNCHER_LABELS, DEFAULT_THREAD_STATE_LABELS, DEFAULT_TUPLE_ARRAY_FIELD_LABELS, DEFAULT_UPLOAD_TASK_ITEM_LABELS, DEFAULT_UPLOAD_TASK_LIST_LABELS, DEFAULT_WORKFLOWS_CHROME_LABELS, DEFAULT_WORKFLOW_RUNNER_LABELS, DEFAULT_WORKFLOW_RUN_STATUS_LABELS, DEFAULT_WORKFLOW_STEP_PARTS_LABELS, DEFAULT_WORKFLOW_THREAD_STRIP_LABELS, DERIVED_NAME_WORDS, EMPTY_NEW_THREAD, EntityChip, GENERATE_IMAGE, GENERATE_IMAGE_ID, GoalCriteria, IMAGE_ASPECT_AUTO, IMAGE_ASPECT_RATIOS, MAX_TASK_DEPTH, MODEL_NAME_ICONS, MODEL_TIER_ICON_MAP, MODEL_TIER_LABELS, NewThreadDialog, PillSelect, REMIND_TASK, REMIND_TASK_ID, RecurrenceBuilder, SKILL_FIELD_TYPE_LABELS, SKILL_MAIN_FILENAME, SKILL_SOURCE_LABELS, SKILL_TYPES, SKILL_TYPE_LABELS, STATUS_LABELS, STATUS_ORDER, STATUS_TONE, STEP_ICON_MAP, SUMMARISE, SUMMARISE_ID, SendBackControl, SkillActionButton, SkillDetail, SkillDetailSection, SkillEditForm, SkillFilterChips, SkillGenerateForm, SkillGlobalBadge, SkillLibraryDetail, SkillTile, SkillTypeBadge, SkillViewToggle, StepDetail, StepNarration, StepOutcome, StepParams, StepRow, StepSummary, StepTrace, StepTraceSummary, SubAgentLane, SubStepGroup, SubagentRoster, TAG_ICONS, TASK_COLUMN_ORDER, TIMELINE, TIMELINE_ID, TIMELINE_PROMPT, TOOL_ICON_MAP, TRANSLATE, TRANSLATE_ID, TRANSLATE_LANGUAGES, TRIGGER_LABELS, TaskActivityDialog, TaskActivityTimeline, TaskComposer, TaskEmptyState, TaskFlow, TaskInbox, TaskMoveDialog, TaskOutputsCell, TaskPlan, TaskRunsDialog, TaskStartDialog, TaskStatusPill, TaskTable, TaskThreadChip, TasksToolbar, ThreadActivity, ThreadLauncher, ThreadNotifyDialog, ThreadStatusLine, TupleArrayField, UploadTaskItem, UploadTaskList, WEB_WORKFLOWS, WEEKDAYS, WORD_ASK, WORD_ASK_ID, WORD_CONTINUE, WORD_CONTINUE_ID, WORD_SUMMARISE, WORD_SUMMARISE_ID, WORD_SUPPORT, WORD_SUPPORT_ID, WORD_WORKFLOWS, WORKFLOW_REGISTRY, WorkflowRunStatus, WorkflowRunner, WorkflowStepAction, WorkflowStepBar, WorkflowThreadStartedBy, WorkflowThreadStrip, WorkflowsToolbar, activateOnKey, activeStepId, agentConfigSectionToValues, agentCreatorToConfigSection, asTaskStatus, authModeFor, buildLibrarySkills, buildRRule, buildTaskRows, buildZipSkillImport, closeWorkflowLaunch, compactThreadActivity, composePersona, composerToTaskQuery, composerToWorkRequest, composerToWorkflowRequest, composerToWorkflowUpdate, createTaskColumns, createsWork, defaultScopeRenderer, defaultTaskComposerValues, deriveAgentName, deriveAnnotationName, deriveWorkflowName, descendantIds, describeRRule, describeTrigger, filterConversationRows, filterLibrarySkills, firstWords, formatElapsed2 as formatElapsed, fromPlanAssignee, fromPlanDocumentRef, fromPlanSteps, getAgentStepIcon, getAgentStepPresentation, getCurrentAgentStepPresentation, getModelIcon, goalProgress, groupThreadActivity, hasTaskFields, humanizeSection, importMarkdownSkill, importSkillFile, importSkillFromUrl, indexTasks, inferType, inputDocumentIds, isAgenticWorkflow, isIncompleteSignal, isMainSkillFile, isOutOfBounds, isPlainTodo, isSupersededStop, isValidAgentName, isoToLocalInput, latestMessageTime, layoutFromPlanSteps, linkedRunsFromActivity, localInputToIso, moveTargets, newThreadToRequest, nextCriterionId, notifiedLabel, openWorkflowLaunch, ownerExtId, parseRRule, parseSkillFrontmatter, prettifyKey, readSkillArchive, recordWorkflowUse, renderWorkflowIcon, resetWorkflowUsage, resolveScopeInputs, serializeSkill, skillSlug, sortByRecentUse, stepAccent, stepWindow, stripPersonaPreamble, summarizeAgent, summarizeCapabilities, taskActivityHeadline, taskComposerToCreateRequest, taskComposerToUpdateRequest, taskNeedsAccess, taskToComposerValues, toPlanAssignee, toPlanDocumentRef, toPlanSteps, unnotifiedMentions, useWorkflowLaunchRequest, useWorkflowUsage, useWorkflowView, workflowFromSkillMarkdown, workflowTaskFields, workflowToComposerValues, workflowToSkillMarkdown, workflowWhen };
12635
+ //# sourceMappingURL=chunk-YAGSGBVM.js.map
12636
+ //# sourceMappingURL=chunk-YAGSGBVM.js.map