@invergent/agent-chat-react 2.0.1 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { cn } from './chunk-QSC4UIVT.js';
2
- import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, lazy, useContext, Suspense, Children } from 'react';
3
- import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, ChevronRightIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, Loader2Icon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, CopyIcon, TerminalIcon, SparklesIcon, ClockIcon, PlusIcon, CloudIcon, HardDriveIcon, PaperclipIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, SearchIcon, GitBranchIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, EyeIcon, GlobeIcon, ListTodoIcon, ArrowUpIcon, XCircleIcon, CheckCircle2Icon, Code, CircleCheckIcon, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
2
+ import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, lazy, useContext, Fragment as Fragment$1, Suspense, Children } from 'react';
3
+ import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, ChevronRightIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, Loader2Icon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, CopyIcon, TerminalIcon, SparklesIcon, ClockIcon, PlusIcon, CloudIcon, HardDriveIcon, PaperclipIcon, GlobeIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, SearchIcon, GitBranchIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, EyeIcon, ListTodoIcon, ArrowUpIcon, XCircleIcon, CheckCircle2Icon, Code, CircleCheckIcon, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
4
4
  import { cva } from 'class-variance-authority';
5
- import { Collapsible as Collapsible$1, Slot, Tooltip as Tooltip$1, Separator as Separator$1, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Popover as Popover$1, Progress as Progress$1, Tabs as Tabs$1 } from 'radix-ui';
5
+ import { Collapsible as Collapsible$1, Slot, Tooltip as Tooltip$1, Progress as Progress$1, Tabs as Tabs$1, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Popover as Popover$1 } from 'radix-ui';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
7
  import { StickToBottom, useStickToBottomContext } from 'use-stick-to-bottom';
8
8
  import { cjk } from '@streamdown/cjk';
@@ -597,26 +597,6 @@ var ConversationScrollButton = ({
597
597
  }
598
598
  );
599
599
  };
600
- function Separator({
601
- className,
602
- orientation = "horizontal",
603
- decorative = true,
604
- ...props
605
- }) {
606
- return /* @__PURE__ */ jsx(
607
- Separator$1.Root,
608
- {
609
- "data-slot": "separator",
610
- decorative,
611
- orientation,
612
- className: cn(
613
- "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
614
- className
615
- ),
616
- ...props
617
- }
618
- );
619
- }
620
600
  var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsx(
621
601
  "div",
622
602
  {
@@ -5698,7 +5678,13 @@ function ChatComposerInner({
5698
5678
  disabled = false,
5699
5679
  disabledReason,
5700
5680
  tokenUsage,
5701
- onComposerError
5681
+ onComposerError,
5682
+ showBrowser = false,
5683
+ onToggleBrowser,
5684
+ showWorkspace = false,
5685
+ onToggleWorkspace,
5686
+ canShowBrowser = false,
5687
+ canShowWorkspace = false
5702
5688
  }) {
5703
5689
  const { adapter } = useAgentChatAdapterContext();
5704
5690
  const { textInput, attachments } = usePromptInputController();
@@ -6005,6 +5991,28 @@ function ChatComposerInner({
6005
5991
  }
6006
5992
  )
6007
5993
  ] }),
5994
+ canShowBrowser && onToggleBrowser && /* @__PURE__ */ jsx(
5995
+ PromptInputButton,
5996
+ {
5997
+ "aria-label": showBrowser ? "Hide browser pane" : "Show browser pane",
5998
+ "aria-pressed": showBrowser,
5999
+ onClick: onToggleBrowser,
6000
+ tooltip: showBrowser ? "Hide browser pane" : "Show browser pane",
6001
+ className: showBrowser ? "bg-accent text-foreground" : void 0,
6002
+ children: /* @__PURE__ */ jsx(GlobeIcon, { className: "size-4" })
6003
+ }
6004
+ ),
6005
+ canShowWorkspace && onToggleWorkspace && /* @__PURE__ */ jsx(
6006
+ PromptInputButton,
6007
+ {
6008
+ "aria-label": showWorkspace ? "Hide workspace pane" : "Show workspace pane",
6009
+ "aria-pressed": showWorkspace,
6010
+ onClick: onToggleWorkspace,
6011
+ tooltip: showWorkspace ? "Hide workspace pane" : "Show workspace pane",
6012
+ className: showWorkspace ? "bg-accent text-foreground" : void 0,
6013
+ children: /* @__PURE__ */ jsx(FolderIcon, { className: "size-4" })
6014
+ }
6015
+ ),
6008
6016
  tokenUsage && tokenUsage.contextWindow > 0 && /* @__PURE__ */ jsxs(
6009
6017
  Context,
6010
6018
  {
@@ -7223,7 +7231,13 @@ function ChatThread({
7223
7231
  tokenUsage,
7224
7232
  retryIndicator,
7225
7233
  onRetry,
7226
- onComposerError
7234
+ onComposerError,
7235
+ showBrowser = false,
7236
+ onToggleBrowser,
7237
+ showWorkspace = false,
7238
+ onToggleWorkspace,
7239
+ canShowBrowser = false,
7240
+ canShowWorkspace = false
7227
7241
  }) {
7228
7242
  const groups = useMemo(() => groupMessages(messages), [messages]);
7229
7243
  const artifactFallbacks = useMemo(() => {
@@ -7340,7 +7354,13 @@ function ChatThread({
7340
7354
  disabled,
7341
7355
  disabledReason,
7342
7356
  tokenUsage,
7343
- onComposerError
7357
+ onComposerError,
7358
+ showBrowser,
7359
+ onToggleBrowser,
7360
+ showWorkspace,
7361
+ onToggleWorkspace,
7362
+ canShowBrowser,
7363
+ canShowWorkspace
7344
7364
  }
7345
7365
  )
7346
7366
  ] })
@@ -9274,6 +9294,16 @@ function useAgentChatRuntime({
9274
9294
  }));
9275
9295
  }
9276
9296
  }).catch(() => void 0);
9297
+ void adapter.getBrowserState(sessionId).then((browserState) => {
9298
+ if (sessionIdRef.current !== sessionId) return;
9299
+ setState((prev) => ({
9300
+ ...prev,
9301
+ browser: browserState ? {
9302
+ status: browserState.status,
9303
+ controlOwner: browserState.controlOwner ?? null
9304
+ } : null
9305
+ }));
9306
+ }).catch(() => void 0);
9277
9307
  return () => {
9278
9308
  clearReconnectTimer();
9279
9309
  closeStream();
@@ -9518,6 +9548,8 @@ function AgentChat({
9518
9548
  }) {
9519
9549
  const [workspacePath, setWorkspacePath] = useState(null);
9520
9550
  const [mobileView, setMobileView] = useState("chat");
9551
+ const [showBrowser, setShowBrowser] = useState(true);
9552
+ const [showWorkspace, setShowWorkspace] = useState(true);
9521
9553
  const runtime = useAgentChatRuntime({
9522
9554
  adapter,
9523
9555
  agentId,
@@ -9528,7 +9560,12 @@ function AgentChat({
9528
9560
  const effectiveDisabled = disabled || isReadOnlySession;
9529
9561
  const disabledReason = isReadOnlySession ? "Scheduled run is read-only" : void 0;
9530
9562
  const browserState = runtime.state.browser;
9531
- const hasBrowserPanel = browserState !== null && sessionId;
9563
+ const browserAvailable = browserState !== null && browserState.status !== "closed" && !!sessionId;
9564
+ const browserVisible = browserAvailable && showBrowser;
9565
+ const workspaceAvailable = !!sessionId;
9566
+ const workspaceVisible = workspaceAvailable && showWorkspace;
9567
+ const rightStackVisible = browserVisible || workspaceVisible;
9568
+ const bothPanesVisible = browserVisible && workspaceVisible;
9532
9569
  useEffect(() => {
9533
9570
  onMessagesChange?.(runtime.messages);
9534
9571
  }, [onMessagesChange, runtime.messages]);
@@ -9536,11 +9573,18 @@ function AgentChat({
9536
9573
  (path) => {
9537
9574
  setWorkspacePath(path);
9538
9575
  setMobileView("workspace");
9576
+ setShowWorkspace(true);
9539
9577
  onFileSelect?.(path);
9540
9578
  },
9541
9579
  [onFileSelect]
9542
9580
  );
9543
- const showMobileToggle = Boolean(sessionId);
9581
+ const handleToggleBrowser = useCallback(() => {
9582
+ setShowBrowser((prev) => !prev);
9583
+ }, []);
9584
+ const handleToggleWorkspace = useCallback(() => {
9585
+ setShowWorkspace((prev) => !prev);
9586
+ }, []);
9587
+ const showMobileToggle = rightStackVisible;
9544
9588
  return /* @__PURE__ */ jsx(
9545
9589
  AgentChatAdapterProvider,
9546
9590
  {
@@ -9558,8 +9602,11 @@ function AgentChat({
9558
9602
  // Phone: flex column, tab toggle on top, then either chat or
9559
9603
  // right stack visible based on `data-mobile-view`.
9560
9604
  "flex min-h-0 flex-1 flex-col overflow-hidden bg-background text-sm text-foreground",
9561
- // md+: restore desktop two-pane layout.
9562
- hasBrowserPanel ? "md:relative md:flex-row" : "md:flex-row"
9605
+ // md+: restore desktop two-pane layout when the right stack
9606
+ // is visible. With both panes, absolute positioning lets the
9607
+ // browser/workspace split occupy a fixed width. Without the
9608
+ // right stack, the chat takes the full width.
9609
+ browserVisible ? "md:relative md:flex-row" : "md:flex-row"
9563
9610
  ),
9564
9611
  style: { direction: "ltr", ...RIGHT_STACK_STYLE },
9565
9612
  children: [
@@ -9600,8 +9647,13 @@ function AgentChat({
9600
9647
  // Phone: full width column, hidden when workspace tab active.
9601
9648
  "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden",
9602
9649
  showMobileToggle && "data-[mobile-view=workspace]:hidden md:flex!",
9603
- // md+: restore desktop positioning.
9604
- hasBrowserPanel ? "md:absolute md:inset-y-0 md:left-0 md:right-(--right-stack-w,440px) md:flex" : "md:relative md:flex-1"
9650
+ // md+: positioning depends on whether the browser/workspace
9651
+ // right stack is laid out. When the browser pane is shown
9652
+ // we pin a fixed-width column on the right and absolutely
9653
+ // position the chat panel beside it. Otherwise the chat
9654
+ // panel just flexes alongside the workspace (or fills the
9655
+ // space when nothing else is visible).
9656
+ browserVisible ? "md:absolute md:inset-y-0 md:left-0 md:right-(--right-stack-w,440px) md:flex" : "md:relative md:flex-1"
9605
9657
  ),
9606
9658
  children: /* @__PURE__ */ jsx(
9607
9659
  ChatThread,
@@ -9618,12 +9670,18 @@ function AgentChat({
9618
9670
  disabledReason,
9619
9671
  tokenUsage: runtime.tokenUsage,
9620
9672
  retryIndicator: runtime.retryIndicator,
9621
- onComposerError
9673
+ onComposerError,
9674
+ showBrowser,
9675
+ onToggleBrowser: handleToggleBrowser,
9676
+ showWorkspace,
9677
+ onToggleWorkspace: handleToggleWorkspace,
9678
+ canShowBrowser: browserAvailable,
9679
+ canShowWorkspace: workspaceAvailable
9622
9680
  }
9623
9681
  )
9624
9682
  }
9625
9683
  ),
9626
- /* @__PURE__ */ jsxs(
9684
+ rightStackVisible && /* @__PURE__ */ jsxs(
9627
9685
  "div",
9628
9686
  {
9629
9687
  "data-testid": "right-stack",
@@ -9632,17 +9690,23 @@ function AgentChat({
9632
9690
  // Phone: full width column, hidden when chat tab active.
9633
9691
  "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden",
9634
9692
  showMobileToggle && "data-[mobile-view=chat]:hidden md:flex!",
9635
- // md+: restore desktop positioning. With browser panel the
9636
- // right stack is absolutely positioned at the configured
9637
- // width; without it the stack flows in the row.
9638
- hasBrowserPanel ? "md:absolute md:inset-y-0 md:right-0 md:w-(--right-stack-w,440px) md:flex-none" : "md:relative md:shrink-0 md:flex-none md:w-(--right-stack-w,440px)"
9693
+ // md+: positioning differs depending on what is inside.
9694
+ // - browser visible (with or without workspace): absolute
9695
+ // right column at the configured width.
9696
+ // - workspace only: relative shrink-0 column letting
9697
+ // WorkspacePanel manage its own width via the resize
9698
+ // handle.
9699
+ browserVisible ? "md:absolute md:inset-y-0 md:right-0 md:w-(--right-stack-w,440px) md:flex-none" : "md:relative md:shrink-0 md:flex-none md:w-auto"
9639
9700
  ),
9640
9701
  children: [
9641
- hasBrowserPanel && /* @__PURE__ */ jsx(
9702
+ browserVisible && /* @__PURE__ */ jsx(
9642
9703
  "div",
9643
9704
  {
9644
9705
  "data-testid": "browser-panel",
9645
- className: "h-1/2 min-h-0 w-full overflow-hidden border-b border-line",
9706
+ className: cn(
9707
+ "min-h-0 w-full overflow-hidden",
9708
+ bothPanesVisible ? "h-1/2 border-b border-line" : "h-full"
9709
+ ),
9646
9710
  children: /* @__PURE__ */ jsx(
9647
9711
  BrowserPane,
9648
9712
  {
@@ -9653,11 +9717,11 @@ function AgentChat({
9653
9717
  )
9654
9718
  }
9655
9719
  ),
9656
- /* @__PURE__ */ jsx(
9720
+ workspaceVisible && /* @__PURE__ */ jsx(
9657
9721
  "div",
9658
9722
  {
9659
9723
  "data-testid": "workspace-panel-frame",
9660
- className: hasBrowserPanel ? "h-1/2 min-h-0 w-full overflow-hidden" : "min-h-0 h-full",
9724
+ className: bothPanesVisible ? "h-1/2 min-h-0 w-full overflow-hidden" : "min-h-0 h-full",
9661
9725
  children: /* @__PURE__ */ jsx(
9662
9726
  WorkspacePanel,
9663
9727
  {
@@ -9667,7 +9731,7 @@ function AgentChat({
9667
9731
  onSelectedPathChange: setWorkspacePath,
9668
9732
  refreshSignal: runtime.workspaceRefreshKey,
9669
9733
  disabled: effectiveDisabled,
9670
- fillParent: Boolean(hasBrowserPanel)
9734
+ fillParent: bothPanesVisible
9671
9735
  }
9672
9736
  )
9673
9737
  }
@@ -10377,42 +10441,6 @@ function Card({
10377
10441
  }
10378
10442
  );
10379
10443
  }
10380
- function CardHeader({ className, ...props }) {
10381
- return /* @__PURE__ */ jsx(
10382
- "div",
10383
- {
10384
- "data-slot": "card-header",
10385
- className: cn(
10386
- "group/card-header @container/card-header grid auto-rows-min items-start gap-1.5 rounded-none px-8 group-data-[size=sm]/card:px-5 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-8 group-data-[size=sm]/card:[.border-b]:pb-5",
10387
- className
10388
- ),
10389
- ...props
10390
- }
10391
- );
10392
- }
10393
- function CardTitle({ className, ...props }) {
10394
- return /* @__PURE__ */ jsx(
10395
- "div",
10396
- {
10397
- "data-slot": "card-title",
10398
- className: cn(
10399
- "font-heading text-lg font-semibold tracking-wider uppercase",
10400
- className
10401
- ),
10402
- ...props
10403
- }
10404
- );
10405
- }
10406
- function CardDescription({ className, ...props }) {
10407
- return /* @__PURE__ */ jsx(
10408
- "div",
10409
- {
10410
- "data-slot": "card-description",
10411
- className: cn("text-sm leading-relaxed text-muted-foreground", className),
10412
- ...props
10413
- }
10414
- );
10415
- }
10416
10444
  function CardContent({ className, ...props }) {
10417
10445
  return /* @__PURE__ */ jsx(
10418
10446
  "div",
@@ -10480,6 +10508,97 @@ var MISSION_WORKER_KIND_TOOLTIP = {
10480
10508
  worker: "Async one-shot session spawned by spawn_worker. Durable session, no retry/DAG.",
10481
10509
  delegation: "Sync fork-join child spawned by delegate_task. Coordinator's wake blocked until it finished."
10482
10510
  };
10511
+ function CountBadge({ n }) {
10512
+ if (n === 0) return null;
10513
+ return /* @__PURE__ */ jsx("span", { className: "ml-1 rounded bg-muted px-1 py-px text-[9px] text-muted-foreground/70", children: n });
10514
+ }
10515
+ function firstLine3(text, max = 140) {
10516
+ const trimmed = text.replace(/\s+/g, " ").trim();
10517
+ if (trimmed.length <= max) return trimmed;
10518
+ return `${trimmed.slice(0, max).trimEnd()}\u2026`;
10519
+ }
10520
+ var ACTIVITY_KIND_TONE = {
10521
+ "mission.defined": "bg-primary/10 text-primary border-primary/30",
10522
+ "mission.paused": "bg-amber-500/10 text-amber-600 border-amber-500/30",
10523
+ "mission.cancelled": "bg-destructive/10 text-destructive border-destructive/30",
10524
+ "task.spawned": "bg-foreground/5 text-foreground/80 border-foreground/20",
10525
+ "task.completed": "bg-emerald-500/10 text-emerald-600 border-emerald-500/30",
10526
+ "task.failed": "bg-destructive/10 text-destructive border-destructive/30",
10527
+ "task.cancelled": "bg-muted text-muted-foreground border-border",
10528
+ "worker.latest": "bg-foreground/5 text-foreground/70 border-foreground/15",
10529
+ "evaluator.verdict": "bg-primary/10 text-primary border-primary/30"
10530
+ };
10531
+ function buildMissionActivity(mission, tasks, workers) {
10532
+ const entries = [];
10533
+ entries.push({
10534
+ at: mission.createdAt,
10535
+ kind: "mission.defined",
10536
+ label: "Mission defined",
10537
+ detail: mission.description
10538
+ });
10539
+ if (mission.status === "paused" && mission.pausedReason) {
10540
+ entries.push({
10541
+ at: mission.updatedAt,
10542
+ kind: "mission.paused",
10543
+ label: "Paused",
10544
+ detail: mission.pausedReason
10545
+ });
10546
+ }
10547
+ if (mission.status === "cancelled" && mission.cancelledReason) {
10548
+ entries.push({
10549
+ at: mission.updatedAt,
10550
+ kind: "mission.cancelled",
10551
+ label: "Cancelled",
10552
+ detail: mission.cancelledReason
10553
+ });
10554
+ }
10555
+ for (const task of tasks) {
10556
+ if (task.createdAt) {
10557
+ entries.push({
10558
+ at: task.createdAt,
10559
+ kind: "task.spawned",
10560
+ label: `Spawn \xB7 ${task.agentDefName ?? "task"}`,
10561
+ detail: firstLine3(task.goal, 200)
10562
+ });
10563
+ }
10564
+ if (task.completedAt) {
10565
+ const kind = task.status === "done" ? "task.completed" : task.status === "failed" ? "task.failed" : task.status === "cancelled" ? "task.cancelled" : "task.completed";
10566
+ entries.push({
10567
+ at: task.completedAt,
10568
+ kind,
10569
+ label: `${task.status} \xB7 ${task.agentDefName ?? "task"}`,
10570
+ detail: task.result ? firstLine3(task.result, 200) : void 0
10571
+ });
10572
+ }
10573
+ }
10574
+ for (const worker of workers) {
10575
+ if (worker.latestEventAt && worker.latestEventKind) {
10576
+ entries.push({
10577
+ at: worker.latestEventAt,
10578
+ kind: "worker.latest",
10579
+ label: `${worker.kind} \xB7 ${worker.latestEventKind}`,
10580
+ detail: deriveMissionWorkerActivityLabel(worker)
10581
+ });
10582
+ }
10583
+ }
10584
+ if (mission.lastEvaluationAt && mission.lastEvaluationResult) {
10585
+ entries.push({
10586
+ at: mission.lastEvaluationAt,
10587
+ kind: "evaluator.verdict",
10588
+ label: `Verdict \xB7 ${mission.lastEvaluationResult}`,
10589
+ detail: mission.lastEvaluationFeedback ?? void 0
10590
+ });
10591
+ }
10592
+ entries.sort((a, b) => b.at.localeCompare(a.at));
10593
+ return entries;
10594
+ }
10595
+ function formatTimestamp(iso) {
10596
+ try {
10597
+ return new Date(iso).toLocaleTimeString();
10598
+ } catch {
10599
+ return iso;
10600
+ }
10601
+ }
10483
10602
  var INITIAL_STATE = {
10484
10603
  mission: null,
10485
10604
  tasks: [],
@@ -10632,210 +10751,153 @@ function MissionDashboard({
10632
10751
  setBusy(false);
10633
10752
  }
10634
10753
  };
10635
- const statusVariant = mission.status === "satisfied" ? "default" : mission.status === "failed" || mission.status === "cancelled" ? "destructive" : "secondary";
10636
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-4 sm:gap-6 sm:p-6", children: [
10637
- /* @__PURE__ */ jsxs(Card, { children: [
10638
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-stretch gap-4 sm:flex-row sm:items-start sm:justify-between", children: [
10639
- /* @__PURE__ */ jsxs("div", { className: "space-y-1 min-w-0 flex-1", children: [
10640
- /* @__PURE__ */ jsx(CardTitle, { className: "wrap-break-word -uppercase text-sm", children: mission.description }),
10641
- /* @__PURE__ */ jsxs(CardDescription, { className: "wrap-break-word text-foreground/70", children: [
10642
- "Rubric: ",
10643
- mission.rubric
10644
- ] }),
10645
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 pt-2 text-xs text-foreground/70", children: [
10646
- /* @__PURE__ */ jsx(Badge, { variant: statusVariant, className: "font-mono text-foreground", children: mission.status }),
10647
- /* @__PURE__ */ jsxs("span", { className: "font-mono text-primary", children: [
10648
- "Iteration ",
10649
- mission.iteration,
10650
- "/",
10651
- mission.maxIterations
10652
- ] }),
10653
- mission.lastEvaluationResult ? /* @__PURE__ */ jsxs("span", { children: [
10654
- "Last verdict:",
10655
- " ",
10656
- /* @__PURE__ */ jsx("span", { className: "font-mono text-primary", children: mission.lastEvaluationResult })
10657
- ] }) : null
10658
- ] })
10659
- ] }),
10660
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2 shrink-0", children: ACTIVE_MISSION_STATUSES.has(mission.status) ? /* @__PURE__ */ jsxs(Fragment, { children: [
10661
- mission.status === "active" ? /* @__PURE__ */ jsxs(
10662
- Button,
10663
- {
10664
- size: "sm",
10665
- variant: "outline",
10666
- onClick: doPause,
10667
- disabled: busy,
10668
- children: [
10669
- /* @__PURE__ */ jsx(Pause, { className: "size-4" }),
10670
- " Pause"
10671
- ]
10672
- }
10673
- ) : /* @__PURE__ */ jsxs(
10674
- Button,
10754
+ const statusTone = mission.status === "satisfied" ? "border-emerald-500/40 bg-emerald-500/10 text-emerald-700 dark:text-emerald-400" : mission.status === "failed" || mission.status === "cancelled" ? "border-destructive/40 bg-destructive/10 text-destructive" : mission.status === "paused" ? "border-amber-500/40 bg-amber-500/10 text-amber-700 dark:text-amber-400" : "border-primary/40 bg-primary/10 text-primary";
10755
+ const activity = buildMissionActivity(mission, state.tasks, state.workers);
10756
+ const isActive = ACTIVE_MISSION_STATUSES.has(mission.status);
10757
+ const iterationPct = mission.maxIterations > 0 ? Math.min(100, mission.iteration / mission.maxIterations * 100) : 0;
10758
+ return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-1 flex-col overflow-hidden bg-muted/30", children: [
10759
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 px-5 pt-5 sm:px-6 sm:pt-6", children: /* @__PURE__ */ jsx(Card, { className: "border-border/60 bg-card shadow-sm", children: /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4 p-5 sm:p-6", children: [
10760
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [
10761
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
10762
+ /* @__PURE__ */ jsx(
10763
+ "span",
10675
10764
  {
10676
- size: "sm",
10677
- variant: "outline",
10678
- onClick: doResume,
10679
- disabled: busy,
10680
- children: [
10681
- /* @__PURE__ */ jsx(Play, { className: "size-4" }),
10682
- " Resume"
10683
- ]
10765
+ className: `rounded-md border px-2 py-0.5 font-mono text-[10px] font-semibold uppercase tracking-wider ${statusTone}`,
10766
+ children: mission.status
10684
10767
  }
10685
10768
  ),
10686
- /* @__PURE__ */ jsxs(
10769
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1.5", children: [
10770
+ /* @__PURE__ */ jsx("span", { className: "font-display text-2xl font-bold tracking-tight tabular-nums text-foreground", children: mission.iteration }),
10771
+ /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground/70", children: [
10772
+ "/ ",
10773
+ mission.maxIterations
10774
+ ] }),
10775
+ /* @__PURE__ */ jsx("span", { className: "ml-1 text-[10px] uppercase tracking-wider text-muted-foreground/60", children: "iterations" })
10776
+ ] }),
10777
+ mission.lastEvaluationResult ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-muted-foreground/70", children: [
10778
+ /* @__PURE__ */ jsx("span", { className: "opacity-70", children: "last verdict" }),
10779
+ /* @__PURE__ */ jsx("span", { className: "rounded border border-primary/30 bg-primary/10 px-1.5 py-0.5 font-mono text-[10px] uppercase tracking-wider text-primary", children: mission.lastEvaluationResult })
10780
+ ] }) : null
10781
+ ] }),
10782
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-2", children: [
10783
+ isActive ? /* @__PURE__ */ jsxs(Fragment, { children: [
10784
+ mission.status === "active" ? /* @__PURE__ */ jsxs(
10785
+ Button,
10786
+ {
10787
+ size: "sm",
10788
+ variant: "outline",
10789
+ onClick: doPause,
10790
+ disabled: busy,
10791
+ children: [
10792
+ /* @__PURE__ */ jsx(Pause, { className: "size-4" }),
10793
+ " Pause"
10794
+ ]
10795
+ }
10796
+ ) : /* @__PURE__ */ jsxs(
10797
+ Button,
10798
+ {
10799
+ size: "sm",
10800
+ variant: "outline",
10801
+ onClick: doResume,
10802
+ disabled: busy,
10803
+ children: [
10804
+ /* @__PURE__ */ jsx(Play, { className: "size-4" }),
10805
+ " Resume"
10806
+ ]
10807
+ }
10808
+ ),
10809
+ /* @__PURE__ */ jsxs(
10810
+ Button,
10811
+ {
10812
+ size: "sm",
10813
+ variant: "destructive",
10814
+ onClick: () => {
10815
+ setCancelCascade(false);
10816
+ setCancelOpen(true);
10817
+ },
10818
+ disabled: busy,
10819
+ children: [
10820
+ /* @__PURE__ */ jsx(Ban, { className: "size-4" }),
10821
+ " Cancel"
10822
+ ]
10823
+ }
10824
+ )
10825
+ ] }) : onNavigateBack ? /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", onClick: onNavigateBack, children: "Back" }) : null,
10826
+ /* @__PURE__ */ jsx(
10687
10827
  Button,
10688
10828
  {
10829
+ variant: "ghost",
10689
10830
  size: "sm",
10690
- variant: "destructive",
10691
- onClick: () => {
10692
- setCancelCascade(false);
10693
- setCancelOpen(true);
10694
- },
10831
+ onClick: () => void refresh(),
10695
10832
  disabled: busy,
10696
- children: [
10697
- /* @__PURE__ */ jsx(Ban, { className: "size-4" }),
10698
- " Cancel"
10699
- ]
10833
+ "aria-label": "Refresh",
10834
+ title: "Refresh",
10835
+ children: /* @__PURE__ */ jsx(RefreshCw, { className: "size-4" })
10700
10836
  }
10701
10837
  )
10702
- ] }) : onNavigateBack ? /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", onClick: onNavigateBack, children: "Back" }) : null })
10703
- ] }) }),
10704
- mission.lastEvaluationFeedback ? /* @__PURE__ */ jsxs(CardContent, { className: "space-y-2", children: [
10705
- /* @__PURE__ */ jsx("div", { className: "text-xs font-semibold uppercase tracking-widest text-foreground/70", children: "Evaluator feedback" }),
10706
- /* @__PURE__ */ jsx("p", { className: "text-sm whitespace-pre-wrap wrap-break-word", children: mission.lastEvaluationFeedback }),
10707
- mission.lastEvaluationExplanation ? /* @__PURE__ */ jsx("p", { className: "text-xs text-foreground/70 whitespace-pre-wrap wrap-break-word", children: mission.lastEvaluationExplanation }) : null
10708
- ] }) : null
10709
- ] }),
10710
- /* @__PURE__ */ jsxs(Card, { children: [
10711
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { children: [
10712
- "Tasks (",
10713
- state.tasks.length,
10714
- ")"
10715
- ] }) }),
10716
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
10717
- ["in_flight", "blocked", "done", "failed_or_cancelled"].map((bucket) => {
10718
- const rows = taskBuckets[bucket];
10719
- if (rows.length === 0) return null;
10720
- const heading = {
10721
- in_flight: "In flight",
10722
- blocked: "Blocked",
10723
- done: "Done",
10724
- failed_or_cancelled: "Failed / cancelled"
10725
- }[bucket];
10726
- return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
10727
- /* @__PURE__ */ jsxs("div", { className: "text-xs font-semibold uppercase tracking-widest text-foreground/70", children: [
10728
- heading,
10729
- " (",
10730
- rows.length,
10731
- ")"
10732
- ] }),
10733
- /* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: rows.map((task) => /* @__PURE__ */ jsx(
10734
- "li",
10735
- {
10736
- className: "flex items-start justify-between gap-3 rounded border border-border/40 px-3 py-2 text-sm",
10737
- children: /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
10738
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10739
- task.agentDefName ? /* @__PURE__ */ jsx("span", { className: "text-xs text-foreground/70", children: task.agentDefName }) : null,
10740
- task.attemptCount > 1 ? /* @__PURE__ */ jsxs("span", { className: "text-xs text-foreground/70", children: [
10741
- "attempt ",
10742
- task.attemptCount,
10743
- "/",
10744
- task.maxAttempts
10745
- ] }) : null
10746
- ] }),
10747
- /* @__PURE__ */ jsx("div", { className: "text-sm wrap-break-word", children: task.goal }),
10748
- task.parentIds.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "text-xs text-foreground/70", children: [
10749
- "after:",
10750
- " ",
10751
- task.parentIds.map((p) => p.slice(0, 8)).join(", ")
10752
- ] }) : null,
10753
- task.result ? /* @__PURE__ */ jsx("pre", { className: "text-xs whitespace-pre-wrap bg-muted/30 rounded px-2 py-1 max-h-32 overflow-auto", children: task.result }) : null,
10754
- task.resultMetadata ? /* @__PURE__ */ jsx("pre", { className: "text-xs whitespace-pre-wrap bg-muted/30 rounded px-2 py-1 max-h-32 overflow-auto", children: JSON.stringify(task.resultMetadata, null, 2) }) : null
10755
- ] })
10756
- },
10757
- task.id
10758
- )) })
10759
- ] }, bucket);
10760
- }),
10761
- state.tasks.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-sm text-foreground/70", children: "No tasks spawned yet." }) : null
10762
- ] })
10763
- ] }),
10764
- /* @__PURE__ */ jsxs(Card, { children: [
10765
- /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { children: [
10766
- "Live workers (",
10767
- state.workers.length,
10768
- ")"
10769
- ] }) }),
10770
- /* @__PURE__ */ jsx(CardContent, { children: state.workers.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-sm text-foreground/70", children: "No workers attached to this mission right now." }) : /* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: state.workers.map((w) => {
10771
- const onTranscriptClick = (e) => {
10772
- if (onOpenTranscript) {
10773
- e.preventDefault();
10774
- onOpenTranscript(w.workerSessionId);
10775
- }
10776
- };
10777
- return /* @__PURE__ */ jsxs(
10778
- "li",
10779
- {
10780
- className: "flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between rounded border border-border/40 px-3 py-2 text-sm",
10781
- children: [
10782
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
10783
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
10784
- /* @__PURE__ */ jsx(
10785
- Badge,
10786
- {
10787
- variant: "outline",
10788
- className: MISSION_WORKER_KIND_BADGE_CLASS[w.kind],
10789
- title: MISSION_WORKER_KIND_TOOLTIP[w.kind],
10790
- children: w.kind
10791
- }
10792
- ),
10793
- /* @__PURE__ */ jsx(Badge, { className: "text-foreground/70", children: w.kind === "task" ? w.taskStatus ?? "\u2014" : w.sessionStatus }),
10794
- w.agentDefName ? /* @__PURE__ */ jsx("span", { className: "text-xs text-foreground/70", children: w.agentDefName }) : null
10795
- ] }),
10796
- /* @__PURE__ */ jsx("div", { className: "text-sm wrap-break-word", children: deriveMissionWorkerActivityLabel(w) }),
10797
- w.latestEventAt ? /* @__PURE__ */ jsx("div", { className: "text-xs text-foreground/70", children: new Date(w.latestEventAt).toLocaleTimeString() }) : null
10798
- ] }),
10799
- /* @__PURE__ */ jsx(
10800
- "a",
10801
- {
10802
- href: w.transcriptUrl,
10803
- target: "_blank",
10804
- rel: "noreferrer",
10805
- onClick: onTranscriptClick,
10806
- className: "text-xs text-primary hover:underline self-start",
10807
- children: "View session"
10808
- }
10809
- )
10810
- ]
10811
- },
10812
- w.workerSessionId
10813
- );
10814
- }) }) })
10815
- ] }),
10816
- /* @__PURE__ */ jsx(Separator, {}),
10817
- /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-xs text-foreground/70", children: [
10818
- /* @__PURE__ */ jsxs("span", { children: [
10819
- "Auto-refresh every ",
10820
- pollIntervalMs / 1e3,
10821
- "s while mission is active."
10838
+ ] })
10822
10839
  ] }),
10823
- /* @__PURE__ */ jsxs(
10824
- Button,
10840
+ /* @__PURE__ */ jsx(
10841
+ Progress,
10825
10842
  {
10826
- variant: "ghost",
10827
- size: "sm",
10828
- onClick: () => {
10829
- void refresh();
10830
- },
10831
- disabled: busy,
10832
- children: [
10833
- /* @__PURE__ */ jsx(RefreshCw, { className: "size-4" }),
10834
- " Refresh"
10835
- ]
10843
+ value: iterationPct,
10844
+ className: `h-1 ${isActive ? "" : "opacity-40"}`
10836
10845
  }
10837
- )
10838
- ] }),
10846
+ ),
10847
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
10848
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("h1", { className: "line-clamp-4 cursor-default font-display text-lg font-semibold leading-snug text-foreground wrap-break-word", children: mission.description }) }),
10849
+ mission.description.length > 240 ? /* @__PURE__ */ jsx(TooltipContent, { className: "max-w-lg", side: "bottom", children: /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-xs", children: mission.description }) }) : null
10850
+ ] }) }),
10851
+ /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border/60 bg-muted/40 px-3 py-2", children: [
10852
+ /* @__PURE__ */ jsx("div", { className: "mb-0.5 font-mono text-[9px] uppercase tracking-widest text-muted-foreground/70", children: "Rubric" }),
10853
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
10854
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("p", { className: "line-clamp-3 cursor-default text-sm leading-relaxed text-foreground/90 wrap-break-word", children: mission.rubric }) }),
10855
+ mission.rubric.length > 200 ? /* @__PURE__ */ jsx(TooltipContent, { className: "max-w-lg", side: "bottom", children: /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-xs", children: mission.rubric }) }) : null
10856
+ ] })
10857
+ ] })
10858
+ ] }) }) }),
10859
+ /* @__PURE__ */ jsxs(
10860
+ Tabs,
10861
+ {
10862
+ defaultValue: "activity",
10863
+ className: "mt-5 flex flex-1 flex-col overflow-hidden sm:mt-6",
10864
+ children: [
10865
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-border bg-background px-5 sm:px-6", children: /* @__PURE__ */ jsxs(TabsList, { variant: "line", children: [
10866
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "activity", children: [
10867
+ "Activity",
10868
+ /* @__PURE__ */ jsx(CountBadge, { n: activity.length })
10869
+ ] }),
10870
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "tasks", children: [
10871
+ "Tasks",
10872
+ /* @__PURE__ */ jsx(CountBadge, { n: state.tasks.length })
10873
+ ] }),
10874
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "workers", children: [
10875
+ "Workers",
10876
+ /* @__PURE__ */ jsx(CountBadge, { n: state.workers.length })
10877
+ ] }),
10878
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "metadata", children: "Metadata" })
10879
+ ] }) }),
10880
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto bg-background px-5 py-4 sm:px-6", children: [
10881
+ /* @__PURE__ */ jsx(TabsContent, { value: "activity", className: "mt-0", children: /* @__PURE__ */ jsx(ActivityTimeline, { entries: activity }) }),
10882
+ /* @__PURE__ */ jsx(TabsContent, { value: "tasks", className: "mt-0", children: /* @__PURE__ */ jsx(
10883
+ TasksList,
10884
+ {
10885
+ taskBuckets,
10886
+ totalTasks: state.tasks.length
10887
+ }
10888
+ ) }),
10889
+ /* @__PURE__ */ jsx(TabsContent, { value: "workers", className: "mt-0", children: /* @__PURE__ */ jsx(
10890
+ WorkersList,
10891
+ {
10892
+ workers: state.workers,
10893
+ onOpenTranscript
10894
+ }
10895
+ ) }),
10896
+ /* @__PURE__ */ jsx(TabsContent, { value: "metadata", className: "mt-0", children: /* @__PURE__ */ jsx(MetadataPane, { mission }) })
10897
+ ] })
10898
+ ]
10899
+ }
10900
+ ),
10839
10901
  /* @__PURE__ */ jsx(
10840
10902
  Dialog,
10841
10903
  {
@@ -10893,6 +10955,234 @@ function MissionDashboard({
10893
10955
  ] })
10894
10956
  }
10895
10957
  )
10958
+ ] }) });
10959
+ }
10960
+ function ActivityTimeline({ entries }) {
10961
+ if (entries.length === 0) {
10962
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No mission activity yet." });
10963
+ }
10964
+ return /* @__PURE__ */ jsx("ol", { className: "space-y-1", children: entries.map((e, i) => /* @__PURE__ */ jsxs(
10965
+ "li",
10966
+ {
10967
+ className: "flex items-start gap-3 rounded px-2 py-1.5 text-sm hover:bg-muted/30",
10968
+ children: [
10969
+ /* @__PURE__ */ jsx("span", { className: "w-20 shrink-0 font-mono text-[10px] text-muted-foreground/60", children: formatTimestamp(e.at) }),
10970
+ /* @__PURE__ */ jsx(
10971
+ "span",
10972
+ {
10973
+ className: `shrink-0 rounded border px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wide ${ACTIVITY_KIND_TONE[e.kind]}`,
10974
+ children: e.label
10975
+ }
10976
+ ),
10977
+ e.detail ? /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-foreground/80", children: e.detail }) : null
10978
+ ]
10979
+ },
10980
+ `${e.kind}-${e.at}-${i}`
10981
+ )) });
10982
+ }
10983
+ function TaskRow({ task }) {
10984
+ const [open, setOpen] = useState(false);
10985
+ const goalPreview = firstLine3(task.goal, 160);
10986
+ const hasMore = task.goal.length > 160 || Boolean(task.result) || Boolean(task.resultMetadata);
10987
+ const statusTone = task.status === "done" ? "border-emerald-500/30 bg-emerald-500/10 text-emerald-600" : task.status === "failed" ? "border-destructive/30 bg-destructive/10 text-destructive" : task.status === "cancelled" ? "border-border bg-muted text-muted-foreground" : task.status === "running" ? "border-primary/30 bg-primary/10 text-primary" : "border-foreground/20 bg-foreground/5 text-foreground/70";
10988
+ return /* @__PURE__ */ jsx(Collapsible, { open, onOpenChange: setOpen, asChild: true, children: /* @__PURE__ */ jsxs("li", { className: "rounded border border-border/40 text-sm", children: [
10989
+ /* @__PURE__ */ jsx(
10990
+ CollapsibleTrigger,
10991
+ {
10992
+ asChild: true,
10993
+ disabled: !hasMore,
10994
+ children: /* @__PURE__ */ jsxs(
10995
+ "button",
10996
+ {
10997
+ type: "button",
10998
+ className: "flex w-full items-start gap-3 px-3 py-2 text-left hover:bg-muted/30 disabled:hover:bg-transparent",
10999
+ children: [
11000
+ /* @__PURE__ */ jsx(
11001
+ ChevronRight,
11002
+ {
11003
+ className: `mt-0.5 size-3.5 shrink-0 text-muted-foreground/60 transition-transform ${open ? "rotate-90" : ""} ${hasMore ? "" : "opacity-0"}`
11004
+ }
11005
+ ),
11006
+ /* @__PURE__ */ jsx(
11007
+ "span",
11008
+ {
11009
+ className: `shrink-0 rounded border px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wide ${statusTone}`,
11010
+ children: task.status
11011
+ }
11012
+ ),
11013
+ task.agentDefName ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground/70", children: task.agentDefName }) : null,
11014
+ task.attemptCount > 1 ? /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: [
11015
+ "(",
11016
+ task.attemptCount,
11017
+ "/",
11018
+ task.maxAttempts,
11019
+ ")"
11020
+ ] }) : null,
11021
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-foreground/80", children: goalPreview })
11022
+ ]
11023
+ }
11024
+ )
11025
+ }
11026
+ ),
11027
+ /* @__PURE__ */ jsxs(CollapsibleContent, { className: "border-t border-border/40 px-3 py-2 text-xs", children: [
11028
+ /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
11029
+ /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Goal" }),
11030
+ /* @__PURE__ */ jsx("pre", { className: "max-h-64 overflow-auto whitespace-pre-wrap rounded bg-muted/30 px-2 py-1.5 text-[11px] text-foreground/90", children: task.goal })
11031
+ ] }),
11032
+ task.parentIds.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mb-2 text-[10px] text-muted-foreground/70", children: [
11033
+ "after: ",
11034
+ task.parentIds.map((p) => p.slice(0, 8)).join(", ")
11035
+ ] }) : null,
11036
+ task.result ? /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
11037
+ /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Result" }),
11038
+ /* @__PURE__ */ jsx("pre", { className: "max-h-64 overflow-auto whitespace-pre-wrap rounded bg-muted/30 px-2 py-1.5 text-[11px] text-foreground/90", children: task.result })
11039
+ ] }) : null,
11040
+ task.resultMetadata ? /* @__PURE__ */ jsxs("div", { children: [
11041
+ /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Result metadata" }),
11042
+ /* @__PURE__ */ jsx("pre", { className: "max-h-64 overflow-auto whitespace-pre-wrap rounded bg-muted/30 px-2 py-1.5 text-[11px] text-foreground/90", children: JSON.stringify(task.resultMetadata, null, 2) })
11043
+ ] }) : null
11044
+ ] })
11045
+ ] }) });
11046
+ }
11047
+ function TasksList({
11048
+ taskBuckets,
11049
+ totalTasks
11050
+ }) {
11051
+ if (totalTasks === 0) {
11052
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No tasks spawned yet." });
11053
+ }
11054
+ const headings = {
11055
+ in_flight: "In flight",
11056
+ blocked: "Blocked",
11057
+ done: "Done",
11058
+ failed_or_cancelled: "Failed / cancelled"
11059
+ };
11060
+ return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: Object.keys(headings).map((bucket) => {
11061
+ const rows = taskBuckets[bucket];
11062
+ if (rows.length === 0) return null;
11063
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
11064
+ /* @__PURE__ */ jsxs("div", { className: "font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: [
11065
+ headings[bucket],
11066
+ " (",
11067
+ rows.length,
11068
+ ")"
11069
+ ] }),
11070
+ /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: rows.map((task) => /* @__PURE__ */ jsx(TaskRow, { task }, task.id)) })
11071
+ ] }, bucket);
11072
+ }) });
11073
+ }
11074
+ function WorkersList({
11075
+ workers,
11076
+ onOpenTranscript
11077
+ }) {
11078
+ if (workers.length === 0) {
11079
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No workers attached to this mission right now." });
11080
+ }
11081
+ return /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: workers.map((w) => {
11082
+ const onTranscriptClick = (e) => {
11083
+ if (onOpenTranscript) {
11084
+ e.preventDefault();
11085
+ onOpenTranscript(w.workerSessionId);
11086
+ }
11087
+ };
11088
+ return /* @__PURE__ */ jsxs(
11089
+ "li",
11090
+ {
11091
+ className: "flex flex-col gap-2 rounded border border-border/40 px-3 py-2 text-sm sm:flex-row sm:items-start sm:justify-between",
11092
+ children: [
11093
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
11094
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
11095
+ /* @__PURE__ */ jsx(
11096
+ Badge,
11097
+ {
11098
+ variant: "outline",
11099
+ className: MISSION_WORKER_KIND_BADGE_CLASS[w.kind],
11100
+ title: MISSION_WORKER_KIND_TOOLTIP[w.kind],
11101
+ children: w.kind
11102
+ }
11103
+ ),
11104
+ /* @__PURE__ */ jsx(Badge, { className: "text-foreground/70", children: w.kind === "task" ? w.taskStatus ?? "\u2014" : w.sessionStatus }),
11105
+ w.agentDefName ? /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/70", children: w.agentDefName }) : null,
11106
+ w.latestEventAt ? /* @__PURE__ */ jsx("span", { className: "ml-auto font-mono text-[10px] text-muted-foreground/60", children: formatTimestamp(w.latestEventAt) }) : null
11107
+ ] }),
11108
+ /* @__PURE__ */ jsx("div", { className: "truncate text-sm text-foreground/80", children: deriveMissionWorkerActivityLabel(w) })
11109
+ ] }),
11110
+ /* @__PURE__ */ jsx(
11111
+ "a",
11112
+ {
11113
+ href: w.transcriptUrl,
11114
+ target: "_blank",
11115
+ rel: "noreferrer",
11116
+ onClick: onTranscriptClick,
11117
+ className: "self-start text-xs text-primary hover:underline",
11118
+ children: "View session"
11119
+ }
11120
+ )
11121
+ ]
11122
+ },
11123
+ w.workerSessionId
11124
+ );
11125
+ }) });
11126
+ }
11127
+ function MetadataPane({ mission }) {
11128
+ const rows = [];
11129
+ rows.push({
11130
+ label: "Mission ID",
11131
+ value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.id })
11132
+ });
11133
+ rows.push({
11134
+ label: "Session ID",
11135
+ value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.sessionId })
11136
+ });
11137
+ rows.push({
11138
+ label: "Agent ID",
11139
+ value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.agentId })
11140
+ });
11141
+ rows.push({ label: "Status", value: mission.status });
11142
+ rows.push({
11143
+ label: "Iteration",
11144
+ value: `${mission.iteration} / ${mission.maxIterations}`
11145
+ });
11146
+ rows.push({
11147
+ label: "Owner",
11148
+ value: mission.userId ? /* @__PURE__ */ jsxs(Fragment, { children: [
11149
+ "user ",
11150
+ /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.userId })
11151
+ ] }) : mission.serviceAccountId ? /* @__PURE__ */ jsxs(Fragment, { children: [
11152
+ "service account ",
11153
+ /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.serviceAccountId })
11154
+ ] }) : "\u2014"
11155
+ });
11156
+ rows.push({
11157
+ label: "Created",
11158
+ value: /* @__PURE__ */ jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.createdAt).toLocaleString() })
11159
+ });
11160
+ rows.push({
11161
+ label: "Updated",
11162
+ value: /* @__PURE__ */ jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.updatedAt).toLocaleString() })
11163
+ });
11164
+ if (mission.pausedReason) {
11165
+ rows.push({ label: "Paused reason", value: mission.pausedReason });
11166
+ }
11167
+ if (mission.cancelledReason) {
11168
+ rows.push({ label: "Cancelled reason", value: mission.cancelledReason });
11169
+ }
11170
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
11171
+ mission.lastEvaluationResult ? /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
11172
+ /* @__PURE__ */ jsxs("div", { className: "font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: [
11173
+ "Last verdict \u2014 ",
11174
+ mission.lastEvaluationResult
11175
+ ] }),
11176
+ mission.lastEvaluationFeedback ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-sm text-foreground/90", children: mission.lastEvaluationFeedback }) : null,
11177
+ mission.lastEvaluationExplanation ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-xs text-muted-foreground/70", children: mission.lastEvaluationExplanation }) : null
11178
+ ] }) : null,
11179
+ /* @__PURE__ */ jsxs("section", { children: [
11180
+ /* @__PURE__ */ jsx("div", { className: "mb-2 font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: "Identifiers" }),
11181
+ /* @__PURE__ */ jsx("dl", { className: "grid grid-cols-[max-content_1fr] gap-x-4 gap-y-1 text-xs", children: rows.map((r) => /* @__PURE__ */ jsxs(Fragment$1, { children: [
11182
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground/70", children: r.label }),
11183
+ /* @__PURE__ */ jsx("dd", { className: "break-all text-foreground/90", children: r.value })
11184
+ ] }, r.label)) })
11185
+ ] })
10896
11186
  ] });
10897
11187
  }
10898
11188
  var DEFAULT_POLL_INTERVAL_MS2 = 3e4;