@invergent/agent-chat-react 2.5.8 → 2.5.9

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,6 +1,6 @@
1
1
  import { cn } from './chunk-QSC4UIVT.js';
2
2
  import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, useLayoutEffect, lazy, useContext, Fragment as Fragment$1, Children, Suspense } from 'react';
3
- import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, PlugZapIcon, ChevronRightIcon, ArrowLeftIcon, Loader2Icon, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, TerminalIcon, SparklesIcon, ClockIcon, PlusIcon, CloudIcon, HardDriveIcon, PaperclipIcon, GlobeIcon, FolderIcon, CopyIcon, FileIcon, ChevronLeftIcon, MinusIcon, SearchIcon, ArrowUpIcon, CircleCheckIcon, ThumbsUpIcon, ThumbsDownIcon, BookOpenIcon, GitBranchIcon, ActivityIcon, EyeIcon, ListTodoIcon, ListIcon, PenLineIcon, ArrowRight, FileEditIcon, WrenchIcon, FileCodeIcon, CodeIcon, FileArchiveIcon, FileVideoIcon, FileAudioIcon, FileImageIcon, FileChartLineIcon, FileSpreadsheetIcon, XCircleIcon, CheckCircle2Icon, Code, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
3
+ import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, PlugZapIcon, ChevronRightIcon, ArrowLeftIcon, Loader2Icon, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, Clock, ArrowRight, TerminalIcon, SparklesIcon, ClockIcon, PlusIcon, CloudIcon, HardDriveIcon, PaperclipIcon, GlobeIcon, FolderIcon, CopyIcon, FileIcon, ChevronLeftIcon, MinusIcon, SearchIcon, CircleDot, XCircle, CheckCircle2, ArrowUpIcon, CircleCheckIcon, ThumbsUpIcon, ThumbsDownIcon, BookOpenIcon, GitBranchIcon, ActivityIcon, EyeIcon, ListTodoIcon, BotIcon, ListIcon, PenLineIcon, FileEditIcon, WrenchIcon, FileCodeIcon, CodeIcon, FileArchiveIcon, FileVideoIcon, FileAudioIcon, FileImageIcon, FileChartLineIcon, FileSpreadsheetIcon, XCircleIcon, CheckCircle2Icon, Code, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
4
4
  import { cva } from 'class-variance-authority';
5
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';
@@ -13,7 +13,7 @@ import { Streamdown } from 'streamdown';
13
13
  import { useControllableState } from '@radix-ui/react-use-controllable-state';
14
14
  import { createHighlighter } from 'shiki';
15
15
  import { diffLines, diffWordsWithSpace } from 'diff';
16
- import Ansi from 'ansi-to-react';
16
+ import AnsiImport from 'ansi-to-react';
17
17
  import { Command as Command$1 } from 'cmdk';
18
18
  import { nanoid } from 'nanoid';
19
19
  import { getUsage } from 'tokenlens';
@@ -826,6 +826,11 @@ var MessageResponse = memo(
826
826
  {
827
827
  className: cn(
828
828
  "size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
829
+ // Streamdown emits ``list-inside`` lists and preflight strips
830
+ // the UA list padding, so bullet markers hug the container
831
+ // edge and wrapped lines slide under them. Hanging-indent
832
+ // lists instead, everywhere markdown renders.
833
+ "[&_ol]:list-outside [&_ol]:pl-5 [&_ul]:list-outside [&_ul]:pl-5",
829
834
  className
830
835
  ),
831
836
  plugins: streamdownPlugins,
@@ -1010,7 +1015,14 @@ var ReasoningContent = memo(
1010
1015
  className
1011
1016
  ),
1012
1017
  ...props,
1013
- children: /* @__PURE__ */ jsx(Streamdown, { plugins: streamdownPlugins2, children })
1018
+ children: /* @__PURE__ */ jsx(
1019
+ Streamdown,
1020
+ {
1021
+ className: "[&_ol]:list-outside [&_ol]:pl-5 [&_ul]:list-outside [&_ul]:pl-5",
1022
+ plugins: streamdownPlugins2,
1023
+ children
1024
+ }
1025
+ )
1014
1026
  }
1015
1027
  )
1016
1028
  );
@@ -3074,7 +3086,7 @@ var TerminalContent = ({
3074
3086
  ref: containerRef,
3075
3087
  ...props,
3076
3088
  children: children ?? /* @__PURE__ */ jsxs("pre", { className: "whitespace-pre-wrap break-words", children: [
3077
- /* @__PURE__ */ jsx(Ansi, { children: output }),
3089
+ /* @__PURE__ */ jsx(AnsiImport, { children: output }),
3078
3090
  isStreaming && /* @__PURE__ */ jsx("span", { className: "ml-0.5 inline-block h-4 w-2 animate-pulse bg-foreground" })
3079
3091
  ] })
3080
3092
  }
@@ -4318,6 +4330,107 @@ function ResearchOutlineBlock({ tc }) {
4318
4330
  outline ? /* @__PURE__ */ jsx("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap font-mono text-[11px] leading-snug", children: outline }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "updated" })
4319
4331
  ] });
4320
4332
  }
4333
+ var Ansi2 = AnsiImport.default ?? AnsiImport;
4334
+ function parseCodeRun(result, args) {
4335
+ const fallback = {
4336
+ agent: "",
4337
+ provider: "",
4338
+ prompt: "",
4339
+ output: "",
4340
+ finalMessage: "",
4341
+ error: null,
4342
+ inputTokens: 0,
4343
+ outputTokens: 0
4344
+ };
4345
+ if (result) {
4346
+ try {
4347
+ const parsed = JSON.parse(result);
4348
+ return { ...fallback, ...parsed, error: parsed.error ?? null };
4349
+ } catch {
4350
+ }
4351
+ }
4352
+ try {
4353
+ const parsedArgs = JSON.parse(args);
4354
+ return { ...fallback, ...parsedArgs, error: null };
4355
+ } catch {
4356
+ return fallback;
4357
+ }
4358
+ }
4359
+ function agentLabel(state) {
4360
+ if (state.agent) return state.agent;
4361
+ if (state.provider === "anthropic") return "claude";
4362
+ if (state.provider === "openai") return "codex";
4363
+ return "coding agent";
4364
+ }
4365
+ function CodeRunToolBlock({
4366
+ tc,
4367
+ defaultOpen = false
4368
+ }) {
4369
+ const [isOpen, setIsOpen] = useState(defaultOpen);
4370
+ const isRunning = tc.status === "running";
4371
+ const state = parseCodeRun(tc.result, tc.args);
4372
+ const label = agentLabel(state);
4373
+ const hasError = tc.status === "error" || Boolean(state.error);
4374
+ return /* @__PURE__ */ jsxs(
4375
+ Collapsible,
4376
+ {
4377
+ open: isOpen,
4378
+ onOpenChange: setIsOpen,
4379
+ className: "not-prose w-full",
4380
+ children: [
4381
+ /* @__PURE__ */ jsxs(CollapsibleTrigger, { className: "group/trigger flex w-fit items-center gap-2 text-sm transition-colors", children: [
4382
+ /* @__PURE__ */ jsx("span", { className: "text-left", children: isRunning ? /* @__PURE__ */ jsx(Shimmer, { as: "span", duration: 1, children: `Running ${label}...` }) : hasError ? /* @__PURE__ */ jsx("span", { className: "font-semibold text-destructive", children: `${label} failed` }) : /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: `Ran ${label}` }) }),
4383
+ /* @__PURE__ */ jsx(
4384
+ ChevronDownIcon,
4385
+ {
4386
+ className: cn(
4387
+ "size-4 shrink-0 transition-transform",
4388
+ isOpen ? "rotate-180" : "rotate-0"
4389
+ )
4390
+ }
4391
+ )
4392
+ ] }),
4393
+ /* @__PURE__ */ jsx(
4394
+ CollapsibleContent,
4395
+ {
4396
+ className: cn(
4397
+ "mt-2 overflow-hidden",
4398
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in"
4399
+ ),
4400
+ children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-border overflow-hidden", children: [
4401
+ state.prompt && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 bg-background text-muted-foreground px-3 py-2 font-mono text-sm leading-relaxed", children: [
4402
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 select-none text-emerald-600", children: "IN" }),
4403
+ /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word text-foreground/90 flex-1", children: state.prompt })
4404
+ ] }),
4405
+ /* @__PURE__ */ jsxs(
4406
+ "div",
4407
+ {
4408
+ className: cn(
4409
+ "px-3 py-2 bg-background font-mono text-sm leading-relaxed max-h-96 overflow-auto",
4410
+ state.prompt && "border-t border-border"
4411
+ ),
4412
+ children: [
4413
+ (state.output || !isRunning) && /* @__PURE__ */ jsxs("div", { className: "flex gap-2 text-foreground/90", children: [
4414
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 select-none text-sky-600", children: "OUT" }),
4415
+ /* @__PURE__ */ jsxs("pre", { className: "whitespace-pre-wrap wrap-break-word flex-1", children: [
4416
+ state.output ? /* @__PURE__ */ jsx(Ansi2, { children: state.output }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/60", children: "(no output)" }),
4417
+ isRunning && /* @__PURE__ */ jsx("span", { className: "ml-0.5 inline-block h-3.5 w-1.5 animate-pulse bg-foreground" })
4418
+ ] })
4419
+ ] }),
4420
+ isRunning && !state.output && /* @__PURE__ */ jsx("span", { className: "ml-0.5 inline-block h-3.5 w-1.5 animate-pulse bg-foreground" })
4421
+ ]
4422
+ }
4423
+ ),
4424
+ !isRunning && hasError && state.error && /* @__PURE__ */ jsx("div", { className: "border-t border-border bg-destructive/5 px-3 py-2 text-sm text-destructive", children: /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word", children: state.error }) }),
4425
+ !isRunning && !hasError && state.finalMessage && /* @__PURE__ */ jsx("div", { className: "border-t border-border bg-background px-3 py-2 text-sm text-foreground/90", children: /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap wrap-break-word", children: state.finalMessage }) }),
4426
+ !isRunning && (state.inputTokens > 0 || state.outputTokens > 0) && /* @__PURE__ */ jsx("div", { className: "border-t border-border bg-background px-3 py-1.5 text-xs text-muted-foreground", children: `${state.inputTokens.toLocaleString()} in \xB7 ${state.outputTokens.toLocaleString()} out tokens` })
4427
+ ] })
4428
+ }
4429
+ )
4430
+ ]
4431
+ }
4432
+ );
4433
+ }
4321
4434
  function ToolCallBlock({
4322
4435
  tc,
4323
4436
  resolvedArtifactName,
@@ -4374,6 +4487,8 @@ function ToolCallBlock({
4374
4487
  return /* @__PURE__ */ jsx(ResearchOutlineBlock, { tc });
4375
4488
  case "research_memory":
4376
4489
  return /* @__PURE__ */ jsx(ResearchMemoryBlock, { tc });
4490
+ case "code_run":
4491
+ return /* @__PURE__ */ jsx(CodeRunToolBlock, { tc });
4377
4492
  case "spawn_worker":
4378
4493
  case "send_worker_message":
4379
4494
  case "stop_worker":
@@ -5942,6 +6057,7 @@ function ChatComposerInner({
5942
6057
  canShowBrowser = false,
5943
6058
  canShowWorkspace = false,
5944
6059
  deepResearchEnabled = false,
6060
+ codeAgentsEnabled = false,
5945
6061
  viewMode = "simple",
5946
6062
  onViewModeChange
5947
6063
  }) {
@@ -5996,9 +6112,18 @@ function ChatComposerInner({
5996
6112
  description: "Delegate a topic to the deep-research workflow"
5997
6113
  });
5998
6114
  }
6115
+ if (codeAgentsEnabled) {
6116
+ base.push(
6117
+ { value: "/code claude ", label: "/code claude", description: "Run Claude Code on the workspace (your plan)" },
6118
+ { value: "/code codex ", label: "/code codex", description: "Run Codex on the workspace (your plan)" },
6119
+ { value: "/code status", label: "/code status", description: "Show connected coding agents" },
6120
+ { value: "/code login claude", label: "/code login claude", description: "Connect your Claude plan" },
6121
+ { value: "/code login codex", label: "/code login codex", description: "Connect your ChatGPT plan" }
6122
+ );
6123
+ }
5999
6124
  return base;
6000
6125
  },
6001
- [deepResearchEnabled]
6126
+ [deepResearchEnabled, codeAgentsEnabled]
6002
6127
  );
6003
6128
  const scheduledExamples = useMemo(
6004
6129
  () => [
@@ -7208,6 +7333,53 @@ function ArtifactSvg({ spec }) {
7208
7333
  spec.caption && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: spec.caption })
7209
7334
  ] });
7210
7335
  }
7336
+ function useMediaSrc(sessionId, path) {
7337
+ const { adapter } = useAgentChatAdapterContext();
7338
+ return useMemo(
7339
+ () => adapter.getWorkspaceDownloadUrl({ sessionId, path }),
7340
+ [adapter, sessionId, path]
7341
+ );
7342
+ }
7343
+ function MediaCaption({ caption }) {
7344
+ if (!caption) return null;
7345
+ return /* @__PURE__ */ jsx("figcaption", { className: "border-t border-border px-3 py-2 text-xs leading-snug text-muted-foreground", children: caption });
7346
+ }
7347
+ function ArtifactImage({ sessionId, spec, fill = false }) {
7348
+ const src = useMediaSrc(sessionId, spec.path);
7349
+ return /* @__PURE__ */ jsxs("figure", { className: "m-0", children: [
7350
+ /* @__PURE__ */ jsx(
7351
+ "img",
7352
+ {
7353
+ src,
7354
+ alt: spec.caption ?? spec.path,
7355
+ loading: "lazy",
7356
+ className: cn(
7357
+ "block w-full bg-muted/30 object-contain",
7358
+ fill ? "max-h-full" : "max-h-[480px]"
7359
+ )
7360
+ }
7361
+ ),
7362
+ /* @__PURE__ */ jsx(MediaCaption, { caption: spec.caption })
7363
+ ] });
7364
+ }
7365
+ function ArtifactVideo({ sessionId, spec, fill = false }) {
7366
+ const src = useMediaSrc(sessionId, spec.path);
7367
+ return /* @__PURE__ */ jsxs("figure", { className: "m-0", children: [
7368
+ /* @__PURE__ */ jsx(
7369
+ "video",
7370
+ {
7371
+ src,
7372
+ controls: true,
7373
+ preload: "metadata",
7374
+ className: cn(
7375
+ "block w-full bg-black object-contain",
7376
+ fill ? "max-h-full" : "max-h-[480px]"
7377
+ )
7378
+ }
7379
+ ),
7380
+ /* @__PURE__ */ jsx(MediaCaption, { caption: spec.caption })
7381
+ ] });
7382
+ }
7211
7383
 
7212
7384
  // src/components/chat/artifacts/artifact-export.ts
7213
7385
  function exportArtifact(payload) {
@@ -7242,6 +7414,17 @@ function exportArtifact(payload) {
7242
7414
  mime: "image/svg+xml",
7243
7415
  extension: "svg"
7244
7416
  };
7417
+ // Media artifacts are file references — the bytes live in the
7418
+ // workspace. Copy yields the path; the download action in
7419
+ // ArtifactBlock bypasses this serialisation and uses the
7420
+ // authenticated workspace download URL directly.
7421
+ case "image":
7422
+ case "video":
7423
+ return {
7424
+ text: payload.spec.path,
7425
+ mime: "text/plain",
7426
+ extension: "txt"
7427
+ };
7245
7428
  }
7246
7429
  }
7247
7430
  function tableToCsv(columns, rows) {
@@ -7294,7 +7477,9 @@ var KIND_LABEL = {
7294
7477
  table: "Table",
7295
7478
  chart: "Chart",
7296
7479
  html: "HTML preview",
7297
- svg: "SVG"
7480
+ svg: "SVG",
7481
+ image: "Generated image",
7482
+ video: "Generated video"
7298
7483
  };
7299
7484
  var COPY_FEEDBACK_MS = 1500;
7300
7485
  function ArtifactBlock({
@@ -7335,6 +7520,18 @@ function ArtifactBlock({
7335
7520
  };
7336
7521
  const handleDownload = () => {
7337
7522
  if (!payload) return;
7523
+ if (payload.kind === "image" || payload.kind === "video") {
7524
+ const a = document.createElement("a");
7525
+ a.href = adapter.getWorkspaceDownloadUrl({
7526
+ sessionId,
7527
+ path: payload.spec.path
7528
+ });
7529
+ a.download = "";
7530
+ document.body.appendChild(a);
7531
+ a.click();
7532
+ document.body.removeChild(a);
7533
+ return;
7534
+ }
7338
7535
  const { text, mime, extension } = exportArtifact(payload);
7339
7536
  downloadText(`${safeFilename(name)}.${extension}`, text, mime);
7340
7537
  };
@@ -7380,20 +7577,21 @@ function ArtifactBlock({
7380
7577
  )
7381
7578
  ] })
7382
7579
  ] }),
7383
- /* @__PURE__ */ jsx(ArtifactContent, { className: "p-0 overflow-visible", children: /* @__PURE__ */ jsx(ArtifactBody, { error, payload }) })
7580
+ /* @__PURE__ */ jsx(ArtifactContent, { className: "p-0 overflow-visible", children: /* @__PURE__ */ jsx(ArtifactBody, { error, payload, sessionId }) })
7384
7581
  ] }),
7385
7582
  /* @__PURE__ */ jsx(Dialog, { open: expanded, onOpenChange: setExpanded, children: /* @__PURE__ */ jsxs(DialogContent, { className: "flex h-[95vh] w-[95vw] max-w-[95vw] flex-col gap-4 overflow-hidden p-6 sm:max-w-[95vw]", children: [
7386
7583
  /* @__PURE__ */ jsxs(DialogHeader, { children: [
7387
7584
  /* @__PURE__ */ jsx(DialogTitle, { className: "truncate pr-10", children: name }),
7388
7585
  /* @__PURE__ */ jsx(DialogDescription, { children: description })
7389
7586
  ] }),
7390
- /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-auto", children: /* @__PURE__ */ jsx(ArtifactBody, { error, payload, fill: true }) })
7587
+ /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-auto", children: /* @__PURE__ */ jsx(ArtifactBody, { error, payload, sessionId, fill: true }) })
7391
7588
  ] }) })
7392
7589
  ] });
7393
7590
  }
7394
7591
  function ArtifactBody({
7395
7592
  error,
7396
7593
  payload,
7594
+ sessionId,
7397
7595
  fill = false
7398
7596
  }) {
7399
7597
  if (error) {
@@ -7419,6 +7617,10 @@ function ArtifactBody({
7419
7617
  return /* @__PURE__ */ jsx(ArtifactHtml, { spec: payload.spec, fill });
7420
7618
  case "svg":
7421
7619
  return /* @__PURE__ */ jsx(ArtifactSvg, { spec: payload.spec });
7620
+ case "image":
7621
+ return /* @__PURE__ */ jsx(ArtifactImage, { sessionId, spec: payload.spec, fill });
7622
+ case "video":
7623
+ return /* @__PURE__ */ jsx(ArtifactVideo, { sessionId, spec: payload.spec, fill });
7422
7624
  }
7423
7625
  }
7424
7626
  var ErrorMessage = memo(function ErrorMessage2({
@@ -8517,13 +8719,17 @@ function cancelledToolLabel(toolName) {
8517
8719
  ask_user_question: "Ask User Question",
8518
8720
  process: "Process",
8519
8721
  create_artifact: "Create artifact",
8722
+ run_coding_agent: "Coding agent",
8723
+ code_run: "Coding agent",
8520
8724
  // ``Research memory`` reads as a noun ("memory of research") and
8521
8725
  // makes the shimmer awkward ("Running Research memory…"). The
8522
8726
  // one-liner renderer shows just ``Research`` as the label, so
8523
8727
  // mirror that here so the live shimmer matches the row that
8524
8728
  // replaces it on completion.
8525
8729
  research_memory: "Research",
8526
- research_outline: "Research"
8730
+ research_outline: "Research",
8731
+ generate_image: "image generation",
8732
+ generate_video: "video generation"
8527
8733
  };
8528
8734
  if (map[toolName]) return map[toolName];
8529
8735
  if (toolName.startsWith("mcp__")) return formatMcpToolLabel(toolName);
@@ -8811,6 +9017,11 @@ function extractToolDetail(tc) {
8811
9017
  case "consult_expert":
8812
9018
  case "delegate_task":
8813
9019
  return stringArg("name") ?? stringArg("task") ?? stringArg("title");
9020
+ case "run_coding_agent":
9021
+ case "code_run": {
9022
+ const prompt = stringArg("prompt");
9023
+ return prompt ? truncate3(prompt, 60) : null;
9024
+ }
8814
9025
  case "memory":
8815
9026
  return stringArg("action") ?? stringArg("key");
8816
9027
  case "research_memory": {
@@ -8934,7 +9145,9 @@ var _TOOL_ROW_ICON = {
8934
9145
  memory: PenLineIcon,
8935
9146
  todo: ListIcon,
8936
9147
  research_memory: BookOpenIcon,
8937
- research_outline: ListIcon
9148
+ research_outline: ListIcon,
9149
+ run_coding_agent: BotIcon,
9150
+ code_run: BotIcon
8938
9151
  };
8939
9152
  function _toolRowIcon(toolName) {
8940
9153
  return _TOOL_ROW_ICON[toolName] ?? WrenchIcon;
@@ -8980,6 +9193,13 @@ function _toolRowLabel(tc) {
8980
9193
  return detail ? `Memory ${detail}` : "Updated memory";
8981
9194
  case "todo":
8982
9195
  return detail ? `Todo ${detail}` : "Updated todo list";
9196
+ case "run_coding_agent":
9197
+ case "code_run": {
9198
+ const a = parseArgs(tc.args);
9199
+ const agent = a?.agent ?? (a?.provider === "openai" ? "codex" : a?.provider === "anthropic" ? "claude" : void 0);
9200
+ const name = agent === "codex" ? "Codex" : agent === "claude" ? "Claude Code" : "coding agent";
9201
+ return detail ? `${name}: ${detail}` : `Ran ${name}`;
9202
+ }
8983
9203
  case "research_memory": {
8984
9204
  const args = parseArgs(tc.args);
8985
9205
  const action = args?.action;
@@ -9063,6 +9283,9 @@ function IterationExpanded({
9063
9283
  if (tc.toolName === "todo") {
9064
9284
  return /* @__PURE__ */ jsx("div", { className: "pr-1", children: /* @__PURE__ */ jsx(TodoToolBlock, { tc }) }, tc.id);
9065
9285
  }
9286
+ if (tc.toolName === "code_run") {
9287
+ return /* @__PURE__ */ jsx("div", { className: "pr-1", children: /* @__PURE__ */ jsx(CodeRunToolBlock, { tc, defaultOpen: true }) }, tc.id);
9288
+ }
9066
9289
  return /* @__PURE__ */ jsx(SimpleDetailRow, { icon: _toolRowIcon(tc.toolName), children: /* @__PURE__ */ jsx("span", { children: _toolRowLabel(tc) }) }, tc.id);
9067
9290
  }),
9068
9291
  showDone && /* @__PURE__ */ jsx(SimpleDetailRow, { icon: CircleCheckIcon, children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: "Done" }) })
@@ -9389,6 +9612,7 @@ function ChatThread({
9389
9612
  viewMode = "simple",
9390
9613
  onViewModeChange,
9391
9614
  deepResearchEnabled = false,
9615
+ codeAgentsEnabled = false,
9392
9616
  researchSources = [],
9393
9617
  hideTurnSummary = false,
9394
9618
  agentId,
@@ -9453,7 +9677,8 @@ function ChatThread({
9453
9677
  canShowWorkspace,
9454
9678
  viewMode,
9455
9679
  onViewModeChange,
9456
- deepResearchEnabled
9680
+ deepResearchEnabled,
9681
+ codeAgentsEnabled
9457
9682
  }
9458
9683
  ),
9459
9684
  onOpenIntegrations && /* @__PURE__ */ jsx(
@@ -10273,6 +10498,9 @@ var AGENT_CHAT_LISTENED_EVENTS = [
10273
10498
  "expert.failure",
10274
10499
  "expert.endorse",
10275
10500
  "expert.override",
10501
+ "code.run_started",
10502
+ "code.run_progress",
10503
+ "code.run_result",
10276
10504
  "user.feedback",
10277
10505
  "artifact.created",
10278
10506
  "artifact.updated",
@@ -10452,6 +10680,21 @@ function applyAgentChatEvent(state, event) {
10452
10680
  nextState,
10453
10681
  applyExpertFeedback(nextState.messages, event.type, event.data)
10454
10682
  );
10683
+ case "code.run_started":
10684
+ return applyCodeRunStarted(nextState, event);
10685
+ case "code.run_progress":
10686
+ return withMessages(
10687
+ nextState,
10688
+ applyCodeRunProgress(nextState.messages, event.data)
10689
+ );
10690
+ case "code.run_result":
10691
+ return {
10692
+ ...withMessages(
10693
+ nextState,
10694
+ applyCodeRunResult(nextState.messages, event.data)
10695
+ ),
10696
+ isRunning: false
10697
+ };
10455
10698
  case "user.feedback":
10456
10699
  return withMessages(
10457
10700
  nextState,
@@ -11002,6 +11245,141 @@ function applyExpertDelegation(state, event) {
11002
11245
  isRunning: true
11003
11246
  };
11004
11247
  }
11248
+ var CODE_RUN_TOOL = "code_run";
11249
+ function codeRunFrameId(runId) {
11250
+ return `code-run-${runId}`;
11251
+ }
11252
+ function parseCodeRunState(raw) {
11253
+ if (raw) {
11254
+ try {
11255
+ const parsed = JSON.parse(raw);
11256
+ return {
11257
+ agent: parsed.agent ?? "",
11258
+ provider: parsed.provider ?? "",
11259
+ prompt: parsed.prompt ?? "",
11260
+ output: parsed.output ?? "",
11261
+ finalMessage: parsed.finalMessage ?? "",
11262
+ error: parsed.error ?? null,
11263
+ inputTokens: parsed.inputTokens ?? 0,
11264
+ outputTokens: parsed.outputTokens ?? 0
11265
+ };
11266
+ } catch {
11267
+ }
11268
+ }
11269
+ return {
11270
+ agent: "",
11271
+ provider: "",
11272
+ prompt: "",
11273
+ output: "",
11274
+ finalMessage: "",
11275
+ error: null,
11276
+ inputTokens: 0,
11277
+ outputTokens: 0
11278
+ };
11279
+ }
11280
+ function findCodeRunFrame(messages, runId) {
11281
+ const toolId = codeRunFrameId(runId);
11282
+ for (let i = messages.length - 1; i >= 0; i--) {
11283
+ const tc = messages[i]?.toolCalls?.find((c) => c.id === toolId);
11284
+ if (tc) return { msgIdx: i, toolId };
11285
+ }
11286
+ return null;
11287
+ }
11288
+ function applyCodeRunStarted(state, event) {
11289
+ const runId = stringValue2(event.data.run_id);
11290
+ if (!runId) return state;
11291
+ if (findCodeRunFrame(state.messages, runId)) {
11292
+ return { ...state, terminal: false, isRunning: true };
11293
+ }
11294
+ const agent = stringValue2(event.data.agent);
11295
+ const provider = stringValue2(event.data.provider);
11296
+ const prompt = stringValue2(event.data.prompt);
11297
+ const messages = [...state.messages];
11298
+ const assistantIdx = findLastAssistantIndex(messages);
11299
+ let assistant = assistantIdx >= 0 ? messages[assistantIdx] : null;
11300
+ const userAfterAssistant = assistantIdx >= 0 && hasUserAfterIndex(messages, assistantIdx);
11301
+ if (!assistant || assistant.status === "complete" || userAfterAssistant) {
11302
+ assistant = {
11303
+ id: `evt-${event.eventId}-code-run`,
11304
+ role: "assistant",
11305
+ content: "",
11306
+ createdAt: /* @__PURE__ */ new Date(),
11307
+ status: "streaming"
11308
+ };
11309
+ messages.push(assistant);
11310
+ } else {
11311
+ assistant = { ...assistant };
11312
+ messages[assistantIdx] = assistant;
11313
+ }
11314
+ const frameState = {
11315
+ agent,
11316
+ provider,
11317
+ prompt,
11318
+ output: "",
11319
+ finalMessage: "",
11320
+ error: null,
11321
+ inputTokens: 0,
11322
+ outputTokens: 0
11323
+ };
11324
+ const toolCall = {
11325
+ id: codeRunFrameId(runId),
11326
+ toolName: CODE_RUN_TOOL,
11327
+ args: JSON.stringify({ agent, provider, prompt }),
11328
+ status: "running",
11329
+ result: JSON.stringify(frameState)
11330
+ };
11331
+ assistant.toolCalls = [...assistant.toolCalls ?? [], toolCall];
11332
+ return { ...state, messages, terminal: false, isRunning: true };
11333
+ }
11334
+ function applyCodeRunProgress(messages, data) {
11335
+ const runId = stringValue2(data.run_id);
11336
+ if (!runId) return messages;
11337
+ const match = findCodeRunFrame(messages, runId);
11338
+ if (!match) return messages;
11339
+ const chunk = stringValue2(data.chunk);
11340
+ if (!chunk) return messages;
11341
+ const next = [...messages];
11342
+ const msg = next[match.msgIdx];
11343
+ next[match.msgIdx] = {
11344
+ ...msg,
11345
+ toolCalls: msg.toolCalls?.map((tc) => {
11346
+ if (tc.id !== match.toolId) return tc;
11347
+ const frame = parseCodeRunState(tc.result);
11348
+ frame.output += chunk;
11349
+ return { ...tc, result: JSON.stringify(frame) };
11350
+ })
11351
+ };
11352
+ return next;
11353
+ }
11354
+ function applyCodeRunResult(messages, data) {
11355
+ const runId = stringValue2(data.run_id);
11356
+ if (!runId) return messages;
11357
+ const match = findCodeRunFrame(messages, runId);
11358
+ if (!match) return messages;
11359
+ const error = optionalStringValue(data.error) ?? null;
11360
+ const finalMessage = stringValue2(data.final_message);
11361
+ const inputTokens = numberValue(data.input_tokens);
11362
+ const outputTokens = numberValue(data.output_tokens);
11363
+ const next = [...messages];
11364
+ const msg = next[match.msgIdx];
11365
+ next[match.msgIdx] = {
11366
+ ...msg,
11367
+ toolCalls: msg.toolCalls?.map((tc) => {
11368
+ if (tc.id !== match.toolId) return tc;
11369
+ const frame = parseCodeRunState(tc.result);
11370
+ frame.finalMessage = finalMessage;
11371
+ frame.error = error;
11372
+ frame.inputTokens = inputTokens;
11373
+ frame.outputTokens = outputTokens;
11374
+ return {
11375
+ ...tc,
11376
+ status: error ? "error" : "complete",
11377
+ result: JSON.stringify(frame)
11378
+ };
11379
+ })
11380
+ };
11381
+ return next;
11382
+ }
11005
11383
  function applyExpertFailure(messages, eventId, data) {
11006
11384
  const match = findLatestConsultExpertCall(messages);
11007
11385
  if (!match) return messages;
@@ -11675,6 +12053,7 @@ function AgentChat({
11675
12053
  disabled,
11676
12054
  onComposerError,
11677
12055
  deepResearchEnabled = false,
12056
+ codeAgentsEnabled = false,
11678
12057
  onOpenIntegrations
11679
12058
  }) {
11680
12059
  const [workspacePath, setWorkspacePath] = useState(null);
@@ -11824,6 +12203,7 @@ function AgentChat({
11824
12203
  viewMode: runtime.viewMode,
11825
12204
  onViewModeChange: runtime.setViewMode,
11826
12205
  deepResearchEnabled,
12206
+ codeAgentsEnabled,
11827
12207
  researchSources: runtime.researchSources,
11828
12208
  hideTurnSummary,
11829
12209
  agentId,
@@ -12110,76 +12490,299 @@ function ToolkitRow({
12110
12490
  ] })
12111
12491
  ] });
12112
12492
  }
12113
- var DEFAULT_LIMIT = 50;
12114
- function requireInboxAdapter(adapter) {
12115
- if (!adapter.listInbox || !adapter.getInboxItem || !adapter.markInboxItemRead || !adapter.acknowledgeInboxItem || !adapter.respondGovernanceInboxItem || !adapter.openInboxStream) {
12116
- throw new Error("Inbox is not supported by this adapter.");
12493
+ var PROVIDERS = [
12494
+ {
12495
+ key: "claude",
12496
+ provider: "anthropic",
12497
+ name: "Claude Code",
12498
+ oauthInstructions: "Run `claude setup-token` locally, then paste the `sk-ant-oat...` token it prints to connect your Claude subscription.",
12499
+ apiKeyInstructions: "Paste an Anthropic API key (`sk-ant-...`) to bill usage to your API account instead of a subscription.",
12500
+ oauthPlaceholder: "sk-ant-oat...",
12501
+ apiKeyPlaceholder: "sk-ant-...",
12502
+ validateOauth: (value) => value.startsWith("sk-ant-oat") ? null : "That doesn't look like a setup token \u2014 it should start with `sk-ant-oat`."
12503
+ },
12504
+ {
12505
+ key: "codex",
12506
+ provider: "openai",
12507
+ name: "Codex",
12508
+ oauthInstructions: "Run `codex login` locally, then paste the contents of `~/.codex/auth.json` to connect your ChatGPT plan.",
12509
+ apiKeyInstructions: "Paste an OpenAI API key (`sk-...`) to bill usage to your API account instead of a ChatGPT plan.",
12510
+ oauthPlaceholder: '{"OPENAI_API_KEY": ..., "tokens": { ... }}',
12511
+ apiKeyPlaceholder: "sk-...",
12512
+ validateOauth: (value) => {
12513
+ try {
12514
+ JSON.parse(value);
12515
+ return null;
12516
+ } catch {
12517
+ return "That doesn't look like valid JSON \u2014 paste the whole `~/.codex/auth.json` file.";
12518
+ }
12519
+ }
12117
12520
  }
12118
- return adapter;
12119
- }
12120
- var KIND_LABEL2 = {
12121
- input_required: "Input needed",
12122
- action_required: "Action needed",
12123
- task_complete: "Task complete",
12124
- governance_gate: "Approval",
12125
- progress_checkin: "Progress"
12126
- };
12127
- function kindLabel(kind) {
12128
- return KIND_LABEL2[kind] ?? kind.replace(/[_-]+/g, " ");
12129
- }
12130
- function statusLabel(status) {
12131
- return status.split(/[_-]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
12132
- }
12133
- function formatRelative(value) {
12134
- const date = new Date(value);
12135
- if (Number.isNaN(date.getTime())) return "";
12136
- return formatDistanceToNow(date, { addSuffix: true });
12137
- }
12138
- function kindIcon(kind) {
12139
- if (kind === "input_required") return MessageSquareIcon;
12140
- if (kind === "action_required") return ExternalLinkIcon;
12141
- if (kind === "task_complete") return ClipboardCheckIcon;
12142
- if (kind === "governance_gate") return ShieldAlertIcon;
12143
- if (kind === "progress_checkin") return TimerIcon;
12144
- return CircleDotIcon;
12145
- }
12146
- function sortItems(items) {
12147
- return [...items].sort((a, b) => {
12148
- if (a.createdAt !== b.createdAt) return a.createdAt > b.createdAt ? -1 : 1;
12149
- return b.id - a.id;
12150
- });
12151
- }
12152
- function QuestionInput({
12153
- prompt,
12154
- choices,
12155
- disabled,
12156
- value,
12157
- onChange
12158
- }) {
12159
- if (choices && choices.length > 0) {
12160
- return /* @__PURE__ */ jsxs(
12161
- "select",
12521
+ ];
12522
+ function CodingAgentsPanel({ agentId, adapter, onBack }) {
12523
+ const supported = !!adapter.listCodingAgentConnections && !!adapter.submitCodingAgentCredential && !!adapter.disconnectCodingAgentProvider;
12524
+ const [connections, setConnections] = useState([]);
12525
+ const refresh = useCallback(async () => {
12526
+ if (!adapter.listCodingAgentConnections) return;
12527
+ const res = await adapter.listCodingAgentConnections({ agentId });
12528
+ setConnections(res.connections);
12529
+ }, [adapter, agentId]);
12530
+ useEffect(() => {
12531
+ if (!supported) return;
12532
+ void refresh();
12533
+ }, [supported, refresh]);
12534
+ const byProvider = useMemo(() => {
12535
+ const map = /* @__PURE__ */ new Map();
12536
+ for (const c of connections) map.set(c.provider, c);
12537
+ return map;
12538
+ }, [connections]);
12539
+ if (!supported) return null;
12540
+ return /* @__PURE__ */ jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-6 p-6", children: [
12541
+ onBack && /* @__PURE__ */ jsxs(
12542
+ "button",
12162
12543
  {
12163
- "aria-label": prompt,
12164
- className: "h-9 w-full border border-line bg-background px-2 text-sm text-foreground outline-none focus:border-primary disabled:opacity-50",
12165
- disabled,
12166
- value,
12167
- onChange: (event) => onChange(event.target.value),
12544
+ type: "button",
12545
+ onClick: onBack,
12546
+ className: "flex w-fit items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground",
12168
12547
  children: [
12169
- /* @__PURE__ */ jsx("option", { value: "", children: "Select" }),
12170
- choices.map((choice) => /* @__PURE__ */ jsx("option", { value: choice.label, children: choice.label }, choice.label))
12548
+ /* @__PURE__ */ jsx(ArrowLeftIcon, { className: "h-4 w-4" }),
12549
+ "Back"
12171
12550
  ]
12172
12551
  }
12173
- );
12174
- }
12175
- return /* @__PURE__ */ jsx(
12176
- "input",
12177
- {
12178
- "aria-label": prompt,
12179
- className: "h-9 w-full border border-line bg-background px-2 text-sm text-foreground outline-none focus:border-primary disabled:opacity-50",
12180
- disabled,
12181
- value,
12182
- onChange: (event) => onChange(event.target.value)
12552
+ ),
12553
+ /* @__PURE__ */ jsxs("div", { children: [
12554
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-foreground", children: "Coding agents" }),
12555
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Connect your Claude or ChatGPT plan so the agent can run `/code` on your behalf without separate API billing." })
12556
+ ] }),
12557
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: PROVIDERS.map((meta) => /* @__PURE__ */ jsx(
12558
+ ProviderCard,
12559
+ {
12560
+ meta,
12561
+ connection: byProvider.get(meta.provider) ?? null,
12562
+ adapter,
12563
+ agentId,
12564
+ onChanged: refresh
12565
+ },
12566
+ meta.key
12567
+ )) })
12568
+ ] });
12569
+ }
12570
+ function ProviderCard({
12571
+ meta,
12572
+ connection,
12573
+ adapter,
12574
+ agentId,
12575
+ onChanged
12576
+ }) {
12577
+ const [mode, setMode] = useState("oauth");
12578
+ const [value, setValue] = useState("");
12579
+ const [busy, setBusy] = useState(false);
12580
+ const [error, setError] = useState(null);
12581
+ const connected = connection?.connected ?? false;
12582
+ const instructions = mode === "oauth" ? meta.oauthInstructions : meta.apiKeyInstructions;
12583
+ const placeholder = mode === "oauth" ? meta.oauthPlaceholder : meta.apiKeyPlaceholder;
12584
+ const submit = async () => {
12585
+ if (!adapter.submitCodingAgentCredential) return;
12586
+ const trimmed = value.trim();
12587
+ setError(null);
12588
+ if (!trimmed) {
12589
+ setError("Paste a value first.");
12590
+ return;
12591
+ }
12592
+ if (mode === "oauth") {
12593
+ const hint = meta.validateOauth(trimmed);
12594
+ if (hint) {
12595
+ setError(hint);
12596
+ return;
12597
+ }
12598
+ }
12599
+ setBusy(true);
12600
+ try {
12601
+ await adapter.submitCodingAgentCredential({
12602
+ agentId,
12603
+ provider: meta.provider,
12604
+ mode,
12605
+ value: trimmed
12606
+ });
12607
+ setValue("");
12608
+ await onChanged();
12609
+ } catch (e) {
12610
+ setError(e instanceof Error ? e.message : "Failed to save the credential");
12611
+ } finally {
12612
+ setBusy(false);
12613
+ }
12614
+ };
12615
+ const disconnect = async () => {
12616
+ if (!adapter.disconnectCodingAgentProvider) return;
12617
+ setBusy(true);
12618
+ setError(null);
12619
+ try {
12620
+ await adapter.disconnectCodingAgentProvider({ agentId, provider: meta.provider });
12621
+ await onChanged();
12622
+ } catch (e) {
12623
+ setError(e instanceof Error ? e.message : "Failed to disconnect");
12624
+ } finally {
12625
+ setBusy(false);
12626
+ }
12627
+ };
12628
+ return /* @__PURE__ */ jsxs("section", { className: "flex flex-col gap-3 rounded-lg border border-border p-4", children: [
12629
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
12630
+ /* @__PURE__ */ jsx("h2", { className: "text-base font-semibold text-foreground", children: meta.name }),
12631
+ /* @__PURE__ */ jsx(
12632
+ "span",
12633
+ {
12634
+ className: `inline-flex items-center rounded px-1.5 py-0.5 text-xs font-semibold ${connected ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground"}`,
12635
+ children: connected ? `Connected${connection?.auth_mode === "api_key" ? " (API key)" : ""}` : "Not connected"
12636
+ }
12637
+ )
12638
+ ] }),
12639
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-1 text-xs", children: [
12640
+ /* @__PURE__ */ jsx(
12641
+ "button",
12642
+ {
12643
+ type: "button",
12644
+ onClick: () => {
12645
+ setMode("oauth");
12646
+ setError(null);
12647
+ },
12648
+ className: `rounded-md border px-2 py-1 ${mode === "oauth" ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:bg-accent"}`,
12649
+ children: "Subscription"
12650
+ }
12651
+ ),
12652
+ /* @__PURE__ */ jsx(
12653
+ "button",
12654
+ {
12655
+ type: "button",
12656
+ onClick: () => {
12657
+ setMode("api_key");
12658
+ setError(null);
12659
+ },
12660
+ className: `rounded-md border px-2 py-1 ${mode === "api_key" ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground hover:bg-accent"}`,
12661
+ children: "API key"
12662
+ }
12663
+ )
12664
+ ] }),
12665
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: instructions }),
12666
+ /* @__PURE__ */ jsx(
12667
+ "textarea",
12668
+ {
12669
+ value,
12670
+ onChange: (e) => setValue(e.target.value),
12671
+ placeholder,
12672
+ spellCheck: false,
12673
+ autoComplete: "off",
12674
+ rows: mode === "oauth" && meta.provider === "openai" ? 4 : 2,
12675
+ "aria-label": `${meta.name} credential`,
12676
+ className: "w-full resize-y rounded-md border border-border bg-background px-3 py-2 font-mono text-xs [-webkit-text-security:disc]"
12677
+ }
12678
+ ),
12679
+ error && /* @__PURE__ */ jsx("div", { role: "alert", className: "text-xs text-red-500", children: error }),
12680
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
12681
+ /* @__PURE__ */ jsxs(
12682
+ "button",
12683
+ {
12684
+ type: "button",
12685
+ disabled: busy,
12686
+ onClick: submit,
12687
+ className: "inline-flex items-center justify-center gap-1.5 rounded-md border border-border px-3 py-1.5 text-xs text-foreground hover:bg-accent disabled:opacity-60",
12688
+ children: [
12689
+ busy && /* @__PURE__ */ jsx(Loader2Icon, { className: "h-3.5 w-3.5 animate-spin" }),
12690
+ connected ? "Update" : "Connect"
12691
+ ]
12692
+ }
12693
+ ),
12694
+ connected && /* @__PURE__ */ jsx(
12695
+ "button",
12696
+ {
12697
+ type: "button",
12698
+ disabled: busy,
12699
+ onClick: disconnect,
12700
+ className: "inline-flex items-center justify-center rounded-md border border-border px-3 py-1.5 text-xs text-muted-foreground hover:bg-accent disabled:opacity-60",
12701
+ children: "Disconnect"
12702
+ }
12703
+ )
12704
+ ] })
12705
+ ] });
12706
+ }
12707
+ var DEFAULT_LIMIT = 50;
12708
+ function requireInboxAdapter(adapter) {
12709
+ if (!adapter.listInbox || !adapter.getInboxItem || !adapter.markInboxItemRead || !adapter.acknowledgeInboxItem || !adapter.respondGovernanceInboxItem || !adapter.openInboxStream) {
12710
+ throw new Error("Inbox is not supported by this adapter.");
12711
+ }
12712
+ return adapter;
12713
+ }
12714
+ var KIND_LABEL2 = {
12715
+ input_required: "Input needed",
12716
+ action_required: "Action needed",
12717
+ task_complete: "Task complete",
12718
+ governance_gate: "Approval",
12719
+ progress_checkin: "Progress"
12720
+ };
12721
+ function kindLabel(kind) {
12722
+ return KIND_LABEL2[kind] ?? kind.replace(/[_-]+/g, " ");
12723
+ }
12724
+ function statusLabel(status) {
12725
+ return status.split(/[_-]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
12726
+ }
12727
+ function formatRelative(value) {
12728
+ const date = new Date(value);
12729
+ if (Number.isNaN(date.getTime())) return "";
12730
+ return formatDistanceToNow(date, { addSuffix: true });
12731
+ }
12732
+ function kindIcon(kind) {
12733
+ if (kind === "input_required") return MessageSquareIcon;
12734
+ if (kind === "action_required") return ExternalLinkIcon;
12735
+ if (kind === "task_complete") return ClipboardCheckIcon;
12736
+ if (kind === "governance_gate") return ShieldAlertIcon;
12737
+ if (kind === "progress_checkin") return TimerIcon;
12738
+ return CircleDotIcon;
12739
+ }
12740
+ function sortItems(items) {
12741
+ return [...items].sort((a, b) => {
12742
+ if (a.createdAt !== b.createdAt) return a.createdAt > b.createdAt ? -1 : 1;
12743
+ return b.id - a.id;
12744
+ });
12745
+ }
12746
+ function InboxBody({ body, muted }) {
12747
+ return /* @__PURE__ */ jsx(
12748
+ MessageResponse,
12749
+ {
12750
+ className: cn("text-sm", muted && "text-muted-foreground"),
12751
+ children: body
12752
+ }
12753
+ );
12754
+ }
12755
+ function QuestionInput({
12756
+ prompt,
12757
+ choices,
12758
+ disabled,
12759
+ value,
12760
+ onChange
12761
+ }) {
12762
+ if (choices && choices.length > 0) {
12763
+ return /* @__PURE__ */ jsxs(
12764
+ "select",
12765
+ {
12766
+ "aria-label": prompt,
12767
+ className: "h-9 w-full border border-line bg-background px-2 text-sm text-foreground outline-none focus:border-primary disabled:opacity-50",
12768
+ disabled,
12769
+ value,
12770
+ onChange: (event) => onChange(event.target.value),
12771
+ children: [
12772
+ /* @__PURE__ */ jsx("option", { value: "", children: "Select" }),
12773
+ choices.map((choice) => /* @__PURE__ */ jsx("option", { value: choice.label, children: choice.label }, choice.label))
12774
+ ]
12775
+ }
12776
+ );
12777
+ }
12778
+ return /* @__PURE__ */ jsx(
12779
+ "input",
12780
+ {
12781
+ "aria-label": prompt,
12782
+ className: "h-9 w-full border border-line bg-background px-2 text-sm text-foreground outline-none focus:border-primary disabled:opacity-50",
12783
+ disabled,
12784
+ value,
12785
+ onChange: (event) => onChange(event.target.value)
12183
12786
  }
12184
12787
  );
12185
12788
  }
@@ -12272,7 +12875,7 @@ function InputRequiredDetail({
12272
12875
  }
12273
12876
  }
12274
12877
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
12275
- item.body && /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-sm text-muted-foreground", children: item.body }),
12878
+ item.body && /* @__PURE__ */ jsx(InboxBody, { body: item.body, muted: true }),
12276
12879
  questions.map((question) => /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
12277
12880
  /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: question.prompt }),
12278
12881
  /* @__PURE__ */ jsx(
@@ -12325,7 +12928,7 @@ function AckDetail({
12325
12928
  const duration = typeof item.payload.duration_seconds === "number" ? item.payload.duration_seconds : null;
12326
12929
  return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
12327
12930
  outcome && /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: outcome }),
12328
- item.body && /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-sm", children: item.body }),
12931
+ item.body && /* @__PURE__ */ jsx(InboxBody, { body: item.body }),
12329
12932
  typeof item.payload.error === "string" && /* @__PURE__ */ jsx("pre", { className: "overflow-x-auto bg-destructive/10 p-3 text-xs text-destructive", children: item.payload.error }),
12330
12933
  duration !== null && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
12331
12934
  "Duration: ",
@@ -12439,7 +13042,7 @@ function ActionRequiredDetail({
12439
13042
  }
12440
13043
  }
12441
13044
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
12442
- item.body && /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-sm", children: item.body }),
13045
+ item.body && /* @__PURE__ */ jsx(InboxBody, { body: item.body }),
12443
13046
  context && context !== item.body && /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-sm text-muted-foreground", children: context }),
12444
13047
  actionType && /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: actionType }),
12445
13048
  /* @__PURE__ */ jsx(
@@ -12488,7 +13091,7 @@ function ProgressDetail({
12488
13091
  }
12489
13092
  }
12490
13093
  return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
12491
- item.body && /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-sm", children: item.body }),
13094
+ item.body && /* @__PURE__ */ jsx(InboxBody, { body: item.body }),
12492
13095
  rows.length > 0 && /* @__PURE__ */ jsx("dl", { className: "space-y-1 text-xs text-muted-foreground", children: rows.map(([label, value]) => /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
12493
13096
  /* @__PURE__ */ jsx("dt", { className: "w-20 shrink-0", children: String(label) }),
12494
13097
  /* @__PURE__ */ jsx("dd", { className: "min-w-0", children: String(value) })
@@ -12806,6 +13409,45 @@ function Card({
12806
13409
  }
12807
13410
  );
12808
13411
  }
13412
+ function CardHeader({ className, ...props }) {
13413
+ return /* @__PURE__ */ jsx(
13414
+ "div",
13415
+ {
13416
+ "data-slot": "card-header",
13417
+ className: cn(
13418
+ "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",
13419
+ className
13420
+ ),
13421
+ ...props
13422
+ }
13423
+ );
13424
+ }
13425
+ function CardTitle({ className, ...props }) {
13426
+ return /* @__PURE__ */ jsx(
13427
+ "div",
13428
+ {
13429
+ "data-slot": "card-title",
13430
+ className: cn(
13431
+ "font-heading text-lg font-semibold tracking-wider uppercase",
13432
+ className
13433
+ ),
13434
+ ...props
13435
+ }
13436
+ );
13437
+ }
13438
+ function CardAction({ className, ...props }) {
13439
+ return /* @__PURE__ */ jsx(
13440
+ "div",
13441
+ {
13442
+ "data-slot": "card-action",
13443
+ className: cn(
13444
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
13445
+ className
13446
+ ),
13447
+ ...props
13448
+ }
13449
+ );
13450
+ }
12809
13451
  function CardContent({ className, ...props }) {
12810
13452
  return /* @__PURE__ */ jsx(
12811
13453
  "div",
@@ -12862,109 +13504,791 @@ function truncate4(s, max) {
12862
13504
  if (s.length <= max) return s;
12863
13505
  return `${s.slice(0, max - 1)}\u2026`;
12864
13506
  }
12865
- var DEFAULT_POLL_INTERVAL_MS = 5e3;
12866
- var MISSION_WORKER_KIND_BADGE_CLASS = {
12867
- task: "border-primary/40 bg-primary/10 text-primary uppercase tracking-wide text-[10px]",
12868
- worker: "border-foreground/30 bg-foreground/5 text-foreground/80 uppercase tracking-wide text-[10px]",
12869
- delegation: "border-foreground/20 bg-foreground/[0.03] text-foreground/60 uppercase tracking-wide text-[10px]"
12870
- };
12871
- var MISSION_WORKER_KIND_TOOLTIP = {
12872
- task: "Durable Task row created by spawn_task. Retried by the dispatcher; survives across coordinator wakes.",
12873
- worker: "Async one-shot session spawned by spawn_worker. Durable session, no retry/DAG.",
12874
- delegation: "Sync fork-join child spawned by delegate_task. Coordinator's wake blocked until it finished."
12875
- };
12876
- function CountBadge({ n }) {
12877
- if (n === 0) return null;
12878
- return /* @__PURE__ */ jsx("span", { className: "ml-1 rounded bg-muted px-1 py-px text-[9px] text-muted-foreground/70", children: n });
12879
- }
12880
- function firstLine3(text, max = 140) {
12881
- const trimmed = text.replace(/\s+/g, " ").trim();
12882
- if (trimmed.length <= max) return trimmed;
12883
- return `${trimmed.slice(0, max).trimEnd()}\u2026`;
12884
- }
12885
- var ACTIVITY_KIND_TONE = {
12886
- "mission.defined": "bg-primary/10 text-primary border-primary/30",
12887
- "mission.paused": "bg-amber-500/10 text-amber-600 border-amber-500/30",
12888
- "mission.cancelled": "bg-destructive/10 text-destructive border-destructive/30",
12889
- "task.spawned": "bg-foreground/5 text-foreground/80 border-foreground/20",
12890
- "task.completed": "bg-emerald-500/10 text-emerald-600 border-emerald-500/30",
12891
- "task.failed": "bg-destructive/10 text-destructive border-destructive/30",
12892
- "task.cancelled": "bg-muted text-muted-foreground border-border",
12893
- "worker.latest": "bg-foreground/5 text-foreground/70 border-foreground/15",
12894
- "evaluator.verdict": "bg-primary/10 text-primary border-primary/30"
12895
- };
12896
- function buildMissionActivity(mission, tasks, workers) {
12897
- const entries = [];
12898
- entries.push({
12899
- at: mission.createdAt,
12900
- kind: "mission.defined",
12901
- label: "Mission defined",
12902
- detail: mission.description
12903
- });
12904
- if (mission.status === "paused" && mission.pausedReason) {
12905
- entries.push({
12906
- at: mission.updatedAt,
12907
- kind: "mission.paused",
12908
- label: "Paused",
12909
- detail: mission.pausedReason
12910
- });
12911
- }
12912
- if (mission.status === "cancelled" && mission.cancelledReason) {
12913
- entries.push({
12914
- at: mission.updatedAt,
12915
- kind: "mission.cancelled",
12916
- label: "Cancelled",
12917
- detail: mission.cancelledReason
12918
- });
13507
+ var MISSION_EVENT_CATEGORIES = [
13508
+ "spawn",
13509
+ "output",
13510
+ "done",
13511
+ "verdict",
13512
+ "system"
13513
+ ];
13514
+ function missionEventCategory(type) {
13515
+ switch (type) {
13516
+ case "worker.spawned":
13517
+ return "spawn";
13518
+ case "iteration.summary":
13519
+ return "output";
13520
+ case "worker.complete":
13521
+ return "done";
13522
+ case "mission.evaluation.end":
13523
+ return "verdict";
13524
+ default:
13525
+ return "system";
12919
13526
  }
12920
- for (const task of tasks) {
12921
- if (task.createdAt) {
12922
- entries.push({
12923
- at: task.createdAt,
12924
- kind: "task.spawned",
12925
- label: `Spawn \xB7 ${task.agentDefName ?? "task"}`,
12926
- detail: firstLine3(task.goal, 200)
12927
- });
12928
- }
12929
- if (task.completedAt) {
12930
- const kind = task.status === "done" ? "task.completed" : task.status === "failed" ? "task.failed" : task.status === "cancelled" ? "task.cancelled" : "task.completed";
12931
- entries.push({
12932
- at: task.completedAt,
12933
- kind,
12934
- label: `${task.status} \xB7 ${task.agentDefName ?? "task"}`,
12935
- detail: task.result ? firstLine3(task.result, 200) : void 0
12936
- });
13527
+ }
13528
+ function dataString(data, key) {
13529
+ const v = data?.[key];
13530
+ return typeof v === "string" && v.trim().length > 0 ? v.trim() : null;
13531
+ }
13532
+ var CONTROL_MARKUP_RE = /<next_action\b[^>]*(?:\/>|>[\s\S]*?<\/next_action>)/gi;
13533
+ function stripMissionControlMarkup(text) {
13534
+ return text.replace(CONTROL_MARKUP_RE, "").trim();
13535
+ }
13536
+ function missionEventSummary(event) {
13537
+ return stripMissionControlMarkup(rawMissionEventSummary(event));
13538
+ }
13539
+ function rawMissionEventSummary(event) {
13540
+ const d = event.data ?? null;
13541
+ switch (event.type) {
13542
+ case "worker.spawned":
13543
+ return dataString(d, "goal") ?? "Task spawned";
13544
+ case "worker.complete":
13545
+ return dataString(d, "result") ?? "Worker complete";
13546
+ case "iteration.summary":
13547
+ return dataString(d, "summary") ?? "";
13548
+ case "mission.evaluation.end": {
13549
+ const result = dataString(d, "result");
13550
+ const feedback = dataString(d, "feedback") ?? dataString(d, "explanation");
13551
+ if (result && feedback) return `${result} \u2014 ${feedback}`;
13552
+ return result ?? feedback ?? "Evaluation finished";
13553
+ }
13554
+ case "task.blocked":
13555
+ return dataString(d, "reason") ?? "Task blocked";
13556
+ case "task.failed":
13557
+ return "Task failed";
13558
+ default: {
13559
+ const text = dataString(d, "summary") ?? dataString(d, "text") ?? dataString(d, "message") ?? dataString(d, "reason");
13560
+ if (text) return text;
13561
+ if (!d) return "";
13562
+ try {
13563
+ return truncate4(JSON.stringify(d), 160);
13564
+ } catch {
13565
+ return "";
13566
+ }
12937
13567
  }
12938
13568
  }
12939
- for (const worker of workers) {
12940
- if (worker.latestEventAt && worker.latestEventKind) {
12941
- entries.push({
12942
- at: worker.latestEventAt,
12943
- kind: "worker.latest",
12944
- label: `${worker.kind} \xB7 ${worker.latestEventKind}`,
12945
- detail: deriveMissionWorkerActivityLabel(worker)
12946
- });
13569
+ }
13570
+ function missionEventTaskId(event, sessions) {
13571
+ return dataString(event.data ?? null, "task_id") ?? sessions[event.sessionId]?.taskId ?? null;
13572
+ }
13573
+ function missionEventActorLabel(event, sessions) {
13574
+ const meta = sessions[event.sessionId];
13575
+ if (!meta) return event.sessionId.slice(0, 8);
13576
+ if (meta.kind === "coordinator") return "orchestrator";
13577
+ return meta.agentDefName ?? "worker";
13578
+ }
13579
+ function missionTaskBlocks(tasks) {
13580
+ const blocks = {};
13581
+ for (const t of tasks) {
13582
+ for (const parent of t.parentIds) {
13583
+ (blocks[parent] ?? (blocks[parent] = [])).push(t.id);
12947
13584
  }
12948
13585
  }
12949
- if (mission.lastEvaluationAt && mission.lastEvaluationResult) {
12950
- entries.push({
12951
- at: mission.lastEvaluationAt,
12952
- kind: "evaluator.verdict",
12953
- label: `Verdict \xB7 ${mission.lastEvaluationResult}`,
12954
- detail: mission.lastEvaluationFeedback ?? void 0
12955
- });
12956
- }
12957
- entries.sort((a, b) => b.at.localeCompare(a.at));
12958
- return entries;
13586
+ return blocks;
12959
13587
  }
12960
- function formatTimestamp(iso) {
12961
- try {
12962
- return new Date(iso).toLocaleTimeString();
12963
- } catch {
12964
- return iso;
13588
+ function missionTaskTitle(goal, max = 80) {
13589
+ const line = goal.split("\n").find((l) => l.trim().length > 0)?.trim() ?? goal.trim();
13590
+ return truncate4(line.replace(/\s+/g, " "), max);
13591
+ }
13592
+ var RAIL_GROUP_DEFS = [
13593
+ { key: "running", label: "Running", match: (s) => s === "running" },
13594
+ { key: "blocked", label: "Blocked", match: (s) => s === "blocked" },
13595
+ {
13596
+ key: "queued",
13597
+ label: "Queued",
13598
+ match: (s) => s === "ready" || s === "todo"
13599
+ },
13600
+ { key: "done", label: "Done", match: (s) => s === "done" },
13601
+ {
13602
+ key: "failed",
13603
+ label: "Failed / cancelled",
13604
+ match: (s) => s === "failed" || s === "cancelled"
12965
13605
  }
13606
+ ];
13607
+ function missionTaskRailGroups(tasks) {
13608
+ const grouped = /* @__PURE__ */ new Set();
13609
+ const groups = RAIL_GROUP_DEFS.map((def) => ({
13610
+ key: def.key,
13611
+ label: def.label,
13612
+ tasks: tasks.filter((t) => {
13613
+ const hit = def.match(t.status);
13614
+ if (hit) grouped.add(t.id);
13615
+ return hit;
13616
+ })
13617
+ }));
13618
+ const stray = tasks.filter((t) => !grouped.has(t.id));
13619
+ if (stray.length > 0) {
13620
+ const queued = groups.find((g) => g.key === "queued");
13621
+ if (queued) queued.tasks.push(...stray);
13622
+ }
13623
+ return groups.filter((g) => g.tasks.length > 0);
12966
13624
  }
12967
- var INITIAL_STATE = {
13625
+ var TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set(["done", "failed", "cancelled"]);
13626
+ function defaultSelectedMissionTaskId(tasks) {
13627
+ if (tasks.length === 0) return null;
13628
+ const ordered = missionTaskRailGroups(tasks).flatMap((g) => g.tasks);
13629
+ const firstLive = ordered.find(
13630
+ (t) => !TERMINAL_TASK_STATUSES.has(t.status)
13631
+ );
13632
+ return (firstLive ?? ordered[0] ?? tasks[0]).id;
13633
+ }
13634
+ function mergeMissionEvents(existing, incoming) {
13635
+ if (incoming.length === 0) return existing;
13636
+ const byId = /* @__PURE__ */ new Map();
13637
+ for (const e of existing) byId.set(e.id, e);
13638
+ for (const e of incoming) byId.set(e.id, e);
13639
+ return [...byId.values()].sort((a, b) => a.id - b.id);
13640
+ }
13641
+ function missionTaskStatusDotClass(status) {
13642
+ switch (status) {
13643
+ case "running":
13644
+ return "bg-primary";
13645
+ case "blocked":
13646
+ return "bg-amber-500";
13647
+ case "done":
13648
+ return "bg-emerald-500";
13649
+ case "failed":
13650
+ return "bg-destructive";
13651
+ case "cancelled":
13652
+ return "bg-muted-foreground";
13653
+ default:
13654
+ return "bg-foreground/30";
13655
+ }
13656
+ }
13657
+ function missionWorkerTaskCounts(worker, tasks) {
13658
+ if (worker.kind !== "task") return null;
13659
+ const mine = tasks.filter((t) => t.agentDefName === worker.agentDefName);
13660
+ return {
13661
+ completed: mine.filter((t) => t.status === "done").length,
13662
+ inFlight: mine.filter(
13663
+ (t) => t.status === "running" || t.status === "blocked"
13664
+ ).length
13665
+ };
13666
+ }
13667
+ function formatMissionTimestamp(iso) {
13668
+ if (!iso) return "";
13669
+ const parsed = new Date(iso);
13670
+ if (Number.isNaN(parsed.getTime())) return iso;
13671
+ return parsed.toLocaleTimeString();
13672
+ }
13673
+ var CATEGORY_BADGE_CLASS = {
13674
+ spawn: "border-primary/30 bg-primary/10 text-primary",
13675
+ output: "border-foreground/20 bg-foreground/5 text-foreground/80",
13676
+ done: "border-emerald-500/30 bg-emerald-500/10 text-emerald-600",
13677
+ verdict: "border-amber-500/30 bg-amber-500/10 text-amber-600",
13678
+ system: "border-border bg-muted text-muted-foreground"
13679
+ };
13680
+ function MissionActivityTab({ feed }) {
13681
+ const [filter, setFilter] = useState("all");
13682
+ const rows = useMemo(() => {
13683
+ const newestFirst = [...feed.events].reverse();
13684
+ if (filter === "all") return newestFirst;
13685
+ return newestFirst.filter((e) => missionEventCategory(e.type) === filter);
13686
+ }, [feed.events, filter]);
13687
+ if (feed.events.length === 0) {
13688
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No mission activity yet." });
13689
+ }
13690
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
13691
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-1.5", children: ["all", ...MISSION_EVENT_CATEGORIES].map((cat) => /* @__PURE__ */ jsx(
13692
+ "button",
13693
+ {
13694
+ type: "button",
13695
+ onClick: () => setFilter(cat),
13696
+ className: `rounded-full border px-2.5 py-0.5 font-mono text-[10px] uppercase tracking-wide transition-colors ${filter === cat ? "border-foreground bg-foreground text-background" : "border-border/60 bg-background text-muted-foreground hover:bg-muted/40"}`,
13697
+ children: cat
13698
+ },
13699
+ cat
13700
+ )) }),
13701
+ /* @__PURE__ */ jsx("ol", { className: "space-y-1", children: rows.map((e) => /* @__PURE__ */ jsx(ActivityRow, { event: e, feed }, e.id)) })
13702
+ ] });
13703
+ }
13704
+ function ActivityRow({
13705
+ event,
13706
+ feed
13707
+ }) {
13708
+ const category = missionEventCategory(event.type);
13709
+ const taskId = missionEventTaskId(event, feed.sessions);
13710
+ return /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3 rounded px-2 py-1.5 text-sm hover:bg-muted/30", children: [
13711
+ /* @__PURE__ */ jsx("span", { className: "w-20 shrink-0 font-mono text-[10px] text-muted-foreground/60", children: formatMissionTimestamp(event.createdAt) }),
13712
+ /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
13713
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
13714
+ /* @__PURE__ */ jsx(
13715
+ "span",
13716
+ {
13717
+ className: `shrink-0 rounded border px-1.5 font-mono uppercase ${CATEGORY_BADGE_CLASS[category]}`,
13718
+ children: category
13719
+ }
13720
+ ),
13721
+ /* @__PURE__ */ jsx("p", { className: "shrink-0 text-xs text-foreground font-mono", children: missionEventActorLabel(event, feed.sessions) }),
13722
+ taskId ? /* @__PURE__ */ jsx("p", { className: "shrink-0 rounded bg-muted px-1.5 py-0.5 font-mono text-[9px] text-muted-foreground/70", children: taskId.slice(0, 8) }) : null
13723
+ ] }),
13724
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 truncate text-foreground/80", children: missionEventSummary(event) }) })
13725
+ ] })
13726
+ ] });
13727
+ }
13728
+ function verdictToneClass(result) {
13729
+ if (result === "satisfied") {
13730
+ return "border-emerald-500/30 bg-emerald-500/5 text-emerald-700 dark:text-emerald-400";
13731
+ }
13732
+ if (result === "failed" || result === "blocked") {
13733
+ return "border-destructive/30 bg-destructive/5 text-destructive";
13734
+ }
13735
+ return "border-amber-500/30 bg-amber-500/5 text-amber-700 dark:text-amber-400";
13736
+ }
13737
+ function MissionMetadataTab({ mission }) {
13738
+ const rows = [
13739
+ {
13740
+ label: "Mission ID",
13741
+ value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.id })
13742
+ },
13743
+ {
13744
+ label: "Session ID",
13745
+ value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.sessionId })
13746
+ },
13747
+ {
13748
+ label: "Agent ID",
13749
+ value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.agentId })
13750
+ },
13751
+ { label: "Status", value: mission.status },
13752
+ {
13753
+ label: "Iteration",
13754
+ value: `${mission.iteration} / ${mission.maxIterations}`
13755
+ },
13756
+ {
13757
+ label: "Owner",
13758
+ value: mission.userId ? /* @__PURE__ */ jsxs(Fragment, { children: [
13759
+ "user ",
13760
+ /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.userId })
13761
+ ] }) : mission.serviceAccountId ? /* @__PURE__ */ jsxs(Fragment, { children: [
13762
+ "service account",
13763
+ " ",
13764
+ /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.serviceAccountId })
13765
+ ] }) : "\u2014"
13766
+ },
13767
+ {
13768
+ label: "Created",
13769
+ value: /* @__PURE__ */ jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.createdAt).toLocaleString() })
13770
+ },
13771
+ {
13772
+ label: "Updated",
13773
+ value: /* @__PURE__ */ jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.updatedAt).toLocaleString() })
13774
+ }
13775
+ ];
13776
+ if (mission.pausedReason) {
13777
+ rows.push({ label: "Paused reason", value: mission.pausedReason });
13778
+ }
13779
+ if (mission.cancelledReason) {
13780
+ rows.push({ label: "Cancelled reason", value: mission.cancelledReason });
13781
+ }
13782
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
13783
+ mission.lastEvaluationResult ? /* @__PURE__ */ jsxs(
13784
+ "section",
13785
+ {
13786
+ className: `space-y-2 rounded-md border p-4 ${verdictToneClass(mission.lastEvaluationResult)}`,
13787
+ children: [
13788
+ /* @__PURE__ */ jsxs("div", { className: "font-mono text-[10px] uppercase tracking-widest", children: [
13789
+ "Last verdict \u2014 ",
13790
+ mission.lastEvaluationResult
13791
+ ] }),
13792
+ mission.lastEvaluationFeedback ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-sm font-medium text-foreground/90", children: mission.lastEvaluationFeedback }) : null,
13793
+ mission.lastEvaluationExplanation ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-xs text-muted-foreground/80", children: mission.lastEvaluationExplanation }) : null,
13794
+ mission.lastEvaluationAt ? /* @__PURE__ */ jsx("p", { className: "font-mono text-[10px] text-muted-foreground/60", children: new Date(mission.lastEvaluationAt).toLocaleString() }) : null
13795
+ ]
13796
+ }
13797
+ ) : null,
13798
+ /* @__PURE__ */ jsxs("section", { children: [
13799
+ /* @__PURE__ */ jsx("div", { className: "mb-2 font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: "Identifiers" }),
13800
+ /* @__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: [
13801
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground/70", children: r.label }),
13802
+ /* @__PURE__ */ jsx("dd", { className: "break-all text-foreground/90", children: r.value })
13803
+ ] }, r.label)) })
13804
+ ] })
13805
+ ] });
13806
+ }
13807
+ var TASK_STATUS_BADGE_CLASS = {
13808
+ running: "border-primary/30 bg-primary/10 text-primary",
13809
+ blocked: "border-amber-500/30 bg-amber-500/10 text-amber-600",
13810
+ done: "border-emerald-500/30 bg-emerald-500/10 text-emerald-600",
13811
+ failed: "border-destructive/30 bg-destructive/10 text-destructive",
13812
+ cancelled: "border-border bg-muted text-muted-foreground"
13813
+ };
13814
+ function statusBadgeClass(status) {
13815
+ return TASK_STATUS_BADGE_CLASS[status] ?? "border-foreground/20 bg-foreground/5 text-foreground/70";
13816
+ }
13817
+ function TaskChip({
13818
+ task,
13819
+ onSelect
13820
+ }) {
13821
+ return /* @__PURE__ */ jsxs(
13822
+ "button",
13823
+ {
13824
+ type: "button",
13825
+ "data-task-chip": true,
13826
+ onClick: () => onSelect(task.id),
13827
+ className: "inline-flex max-w-full items-center gap-1.5 rounded-full border border-border/60 bg-background px-2.5 py-1 text-xs hover:bg-muted/40",
13828
+ children: [
13829
+ /* @__PURE__ */ jsx(
13830
+ "span",
13831
+ {
13832
+ className: `size-1.5 shrink-0 rounded-full ${missionTaskStatusDotClass(task.status)}`
13833
+ }
13834
+ ),
13835
+ /* @__PURE__ */ jsx("span", { className: "truncate text-foreground/85", children: missionTaskTitle(task.goal, 40) }),
13836
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 font-mono text-[9px] text-muted-foreground/60", children: task.id.slice(0, 8) })
13837
+ ]
13838
+ }
13839
+ );
13840
+ }
13841
+ function TaskRailRow({
13842
+ task,
13843
+ selected,
13844
+ onSelect
13845
+ }) {
13846
+ const preview = stripMissionControlMarkup(
13847
+ task.status === "done" && task.result ? task.result : task.goal
13848
+ );
13849
+ return /* @__PURE__ */ jsxs(
13850
+ "button",
13851
+ {
13852
+ type: "button",
13853
+ onClick: () => onSelect(task.id),
13854
+ className: `w-full rounded-md border px-3 py-2 text-left text-sm transition-colors ${selected ? "border-primary/40 bg-primary/5" : "border-transparent hover:bg-muted/40"}`,
13855
+ children: [
13856
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
13857
+ /* @__PURE__ */ jsx(
13858
+ "span",
13859
+ {
13860
+ className: `size-2 shrink-0 rounded-full ${missionTaskStatusDotClass(task.status)}`
13861
+ }
13862
+ ),
13863
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate font-medium text-foreground/90", children: task.goal })
13864
+ ] }),
13865
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 flex flex-col gap-2 pl-4", children: [
13866
+ task.agentDefName ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs font-mono text-muted-foreground", children: task.agentDefName }) : null,
13867
+ /* @__PURE__ */ jsx("span", { className: "line-clamp-2 min-w-0 flex-1 text-xs text-muted-foreground/70", children: preview })
13868
+ ] })
13869
+ ]
13870
+ }
13871
+ );
13872
+ }
13873
+ function MissionTasksTab({
13874
+ tasks,
13875
+ feed,
13876
+ onOpenTranscript
13877
+ }) {
13878
+ const [selectedId, setSelectedId] = useState(null);
13879
+ const groups = useMemo(() => missionTaskRailGroups(tasks), [tasks]);
13880
+ const blocks = useMemo(() => missionTaskBlocks(tasks), [tasks]);
13881
+ const byId = useMemo(() => new Map(tasks.map((t) => [t.id, t])), [tasks]);
13882
+ const effectiveId = selectedId && byId.has(selectedId) ? selectedId : defaultSelectedMissionTaskId(tasks);
13883
+ const selected = effectiveId ? byId.get(effectiveId) ?? null : null;
13884
+ const taskEvents = useMemo(() => {
13885
+ if (!selected || !feed.supported) return [];
13886
+ return feed.events.filter(
13887
+ (e) => missionEventTaskId(e, feed.sessions) === selected.id
13888
+ );
13889
+ }, [selected, feed]);
13890
+ const liveOutput = useMemo(() => {
13891
+ if (!selected || selected.status !== "running") return null;
13892
+ const outputs = taskEvents.filter(
13893
+ (e) => missionEventCategory(e.type) === "output"
13894
+ );
13895
+ return outputs.length > 0 ? outputs[outputs.length - 1] : null;
13896
+ }, [selected, taskEvents]);
13897
+ if (tasks.length === 0) {
13898
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No tasks spawned yet." });
13899
+ }
13900
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-0 gap-4", children: [
13901
+ /* @__PURE__ */ jsx("div", { className: "w-72 shrink-0 space-y-4 overflow-y-auto pr-1", children: groups.map((group) => /* @__PURE__ */ jsxs("div", { children: [
13902
+ /* @__PURE__ */ jsxs("div", { className: "mb-1 px-1 font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: [
13903
+ group.label,
13904
+ " (",
13905
+ group.tasks.length,
13906
+ ")"
13907
+ ] }),
13908
+ /* @__PURE__ */ jsx("div", { className: "space-y-1", children: group.tasks.map((t) => /* @__PURE__ */ jsx(
13909
+ TaskRailRow,
13910
+ {
13911
+ task: t,
13912
+ selected: t.id === effectiveId,
13913
+ onSelect: setSelectedId
13914
+ },
13915
+ t.id
13916
+ )) })
13917
+ ] }, group.key)) }),
13918
+ /* @__PURE__ */ jsx(
13919
+ "div",
13920
+ {
13921
+ "data-testid": "task-detail",
13922
+ className: "min-w-0 flex-1 space-y-4 overflow-y-auto bg-card px-8 py-5",
13923
+ children: selected ? /* @__PURE__ */ jsx(
13924
+ TaskDetail,
13925
+ {
13926
+ task: selected,
13927
+ allTasks: byId,
13928
+ blockedTaskIds: blocks[selected.id] ?? [],
13929
+ taskEvents,
13930
+ liveOutput,
13931
+ eventsSupported: feed.supported,
13932
+ onSelect: setSelectedId,
13933
+ onOpenTranscript
13934
+ }
13935
+ ) : null
13936
+ }
13937
+ )
13938
+ ] });
13939
+ }
13940
+ function TaskDetail({
13941
+ task,
13942
+ allTasks,
13943
+ blockedTaskIds,
13944
+ taskEvents,
13945
+ liveOutput,
13946
+ eventsSupported,
13947
+ onSelect,
13948
+ onOpenTranscript
13949
+ }) {
13950
+ const parents = task.parentIds.map((id) => allTasks.get(id)).filter((t) => Boolean(t));
13951
+ const children = blockedTaskIds.map((id) => allTasks.get(id)).filter((t) => Boolean(t));
13952
+ const timeLabel = task.startedAt && task.completedAt ? `${formatMissionTimestamp(task.startedAt)} \u2192 ${formatMissionTimestamp(task.completedAt)}` : task.startedAt ? `started ${formatMissionTimestamp(task.startedAt)}` : "not started";
13953
+ const outcome = deriveTaskOutcome({ task, taskEvents, liveOutput, parents });
13954
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
13955
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
13956
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
13957
+ /* @__PURE__ */ jsx("h2", { className: "min-w-0 flex-1 truncate text-lg font-semibold text-foreground", children: missionTaskTitle(task.goal) }),
13958
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 font-mono text-[10px] text-muted-foreground/60", children: task.id.slice(0, 8) })
13959
+ ] }),
13960
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs", children: [
13961
+ /* @__PURE__ */ jsx(
13962
+ Badge,
13963
+ {
13964
+ variant: "destructive",
13965
+ className: `font-mono text-sm uppercase tracking-wide ${statusBadgeClass(task.status)}`,
13966
+ children: task.status
13967
+ }
13968
+ ),
13969
+ task.agentDefName ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: task.agentDefName }) : null,
13970
+ task.attemptCount > 1 ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
13971
+ "attempts ",
13972
+ task.attemptCount,
13973
+ "/",
13974
+ task.maxAttempts
13975
+ ] }) : null,
13976
+ /* @__PURE__ */ jsxs("span", { className: "ml-auto inline-flex items-center gap-1 text-muted-foreground", children: [
13977
+ /* @__PURE__ */ jsx(Clock, { className: "size-3" }),
13978
+ timeLabel
13979
+ ] })
13980
+ ] })
13981
+ ] }),
13982
+ /* @__PURE__ */ jsx(OutcomeCard, { outcome }),
13983
+ parents.length > 0 || children.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
13984
+ /* @__PURE__ */ jsx("div", { className: "font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: "Dependencies" }),
13985
+ parents.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
13986
+ /* @__PURE__ */ jsx("span", { className: "mr-1 text-[10px] uppercase text-muted-foreground/50", children: "Depends on" }),
13987
+ parents.map((p) => /* @__PURE__ */ jsx(TaskChip, { task: p, onSelect }, p.id))
13988
+ ] }) : null,
13989
+ children.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
13990
+ /* @__PURE__ */ jsx("span", { className: "mr-1 text-[10px] uppercase text-muted-foreground/50", children: "Blocks" }),
13991
+ children.map((c) => /* @__PURE__ */ jsx(TaskChip, { task: c, onSelect }, c.id))
13992
+ ] }) : null
13993
+ ] }) : null,
13994
+ /* @__PURE__ */ jsxs("div", { children: [
13995
+ /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: "Brief" }),
13996
+ /* @__PURE__ */ jsx(MessageResponse, { className: "text-sm leading-relaxed text-foreground/90", children: task.goal })
13997
+ ] }),
13998
+ task.resultMetadata ? /* @__PURE__ */ jsxs("details", { children: [
13999
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: "Result metadata" }),
14000
+ /* @__PURE__ */ jsx("pre", { className: "mt-1 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) })
14001
+ ] }) : null,
14002
+ eventsSupported && taskEvents.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
14003
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 font-mono font-semibold uppercase text-muted-foreground", children: [
14004
+ "History (",
14005
+ taskEvents.length,
14006
+ ")"
14007
+ ] }),
14008
+ /* @__PURE__ */ jsx("ol", { className: "space-y-3", children: taskEvents.map((e) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3 text-xs", children: [
14009
+ /* @__PURE__ */ jsx("span", { className: "w-16 shrink-0 font-mono text-[10px] text-muted-foreground/60", children: formatMissionTimestamp(e.createdAt) }),
14010
+ /* @__PURE__ */ jsxs("div", { className: "", children: [
14011
+ /* @__PURE__ */ jsx("p", { className: "shrink-0 font-mono uppercase text-muted-foreground", children: missionEventCategory(e.type) }),
14012
+ /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 text-foreground/80", children: missionEventSummary(e) })
14013
+ ] })
14014
+ ] }, e.id)) })
14015
+ ] }) : null,
14016
+ task.currentSessionId && onOpenTranscript ? /* @__PURE__ */ jsxs(
14017
+ Button,
14018
+ {
14019
+ "data-testid": "view-session",
14020
+ variant: "outline",
14021
+ size: "sm",
14022
+ onClick: () => onOpenTranscript(task.currentSessionId),
14023
+ children: [
14024
+ /* @__PURE__ */ jsx(ArrowRight, { className: "size-4" }),
14025
+ "View ",
14026
+ task.agentDefName ?? "worker",
14027
+ " session"
14028
+ ]
14029
+ }
14030
+ ) : null
14031
+ ] });
14032
+ }
14033
+ function deriveTaskOutcome({
14034
+ task,
14035
+ taskEvents,
14036
+ liveOutput,
14037
+ parents
14038
+ }) {
14039
+ const result = task.result ? stripMissionControlMarkup(task.result) : "";
14040
+ switch (task.status) {
14041
+ case "done":
14042
+ return {
14043
+ label: "Result",
14044
+ tone: "bg-emerald-500/5 ring-emerald-500/25",
14045
+ labelTone: "text-emerald-600",
14046
+ icon: /* @__PURE__ */ jsx(CheckCircle2, { className: "size-3" }),
14047
+ timestamp: task.completedAt,
14048
+ markdown: result || void 0,
14049
+ text: result ? void 0 : "Completed."
14050
+ };
14051
+ case "failed":
14052
+ return {
14053
+ label: "Failed",
14054
+ tone: "bg-destructive/5 ring-destructive/25",
14055
+ labelTone: "text-destructive",
14056
+ icon: /* @__PURE__ */ jsx(XCircle, { className: "size-3" }),
14057
+ timestamp: task.completedAt,
14058
+ markdown: result || void 0,
14059
+ text: result ? void 0 : `Failed after ${task.attemptCount}/${task.maxAttempts} attempts.`
14060
+ };
14061
+ case "cancelled":
14062
+ return {
14063
+ label: "Cancelled",
14064
+ tone: "bg-muted/40 ring-border",
14065
+ labelTone: "text-muted-foreground",
14066
+ icon: /* @__PURE__ */ jsx(Ban, { className: "size-3" }),
14067
+ timestamp: task.completedAt,
14068
+ text: "Task cancelled."
14069
+ };
14070
+ case "running":
14071
+ return {
14072
+ label: "Live output",
14073
+ tone: "bg-amber-500/5 ring-amber-500/25",
14074
+ labelTone: "text-amber-600",
14075
+ icon: /* @__PURE__ */ jsx(CircleDot, { className: "size-3 animate-pulse" }),
14076
+ timestamp: liveOutput?.createdAt ?? null,
14077
+ text: liveOutput ? missionEventSummary(liveOutput) : "Working \u2014 no output yet."
14078
+ };
14079
+ case "blocked": {
14080
+ const blockedEvent = [...taskEvents].reverse().find((e) => e.type === "task.blocked");
14081
+ return {
14082
+ label: "Waiting",
14083
+ tone: "bg-amber-500/5 ring-amber-500/20",
14084
+ labelTone: "text-amber-700 dark:text-amber-500",
14085
+ icon: /* @__PURE__ */ jsx(Clock, { className: "size-3" }),
14086
+ timestamp: blockedEvent?.createdAt ?? null,
14087
+ text: blockedEvent ? missionEventSummary(blockedEvent) : "Blocked \u2014 awaiting input."
14088
+ };
14089
+ }
14090
+ default: {
14091
+ const pending = parents.filter((p) => p.status !== "done");
14092
+ const text = pending.length > 0 ? `Waiting on ${pending.map((p) => missionTaskTitle(p.goal, 40)).join(" \xB7 ")} to complete.` : "Queued \u2014 waiting for a worker slot.";
14093
+ return {
14094
+ label: "Waiting",
14095
+ tone: "bg-muted/30 ring-border",
14096
+ labelTone: "text-muted-foreground",
14097
+ icon: /* @__PURE__ */ jsx(Clock, { className: "size-3" }),
14098
+ timestamp: null,
14099
+ text
14100
+ };
14101
+ }
14102
+ }
14103
+ }
14104
+ function OutcomeCard({ outcome }) {
14105
+ return /* @__PURE__ */ jsxs(
14106
+ Card,
14107
+ {
14108
+ "data-testid": "task-outcome",
14109
+ size: "sm",
14110
+ className: `mx-1 gap-3 rounded-lg py-4 shadow-none ${outcome.tone}`,
14111
+ children: [
14112
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
14113
+ /* @__PURE__ */ jsxs(
14114
+ CardTitle,
14115
+ {
14116
+ className: `flex items-center gap-1.5 font-mono text-[11px] font-semibold tracking-widest ${outcome.labelTone}`,
14117
+ children: [
14118
+ outcome.icon,
14119
+ outcome.label
14120
+ ]
14121
+ }
14122
+ ),
14123
+ outcome.timestamp ? /* @__PURE__ */ jsx(CardAction, { className: "font-mono text-[10px] text-muted-foreground/60", children: formatMissionTimestamp(outcome.timestamp) }) : null
14124
+ ] }),
14125
+ /* @__PURE__ */ jsx(CardContent, { children: outcome.markdown ? /* @__PURE__ */ jsx(MessageResponse, { className: "font-mono text-xs leading-relaxed text-foreground/90", children: outcome.markdown }) : /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap font-mono text-xs leading-relaxed text-foreground/90", children: outcome.text }) })
14126
+ ]
14127
+ }
14128
+ );
14129
+ }
14130
+ var MISSION_WORKER_KIND_BADGE_CLASS = {
14131
+ task: "border-primary/40 bg-primary/10 text-primary uppercase tracking-wide text-[10px]",
14132
+ worker: "border-foreground/30 bg-foreground/5 text-foreground/80 uppercase tracking-wide text-[10px]",
14133
+ delegation: "border-foreground/20 bg-foreground/[0.03] text-foreground/60 uppercase tracking-wide text-[10px]"
14134
+ };
14135
+ var MISSION_WORKER_KIND_TOOLTIP = {
14136
+ task: "Durable Task row created by spawn_task. Retried by the dispatcher; survives across coordinator wakes.",
14137
+ worker: "Async one-shot session spawned by spawn_worker. Durable session, no retry/DAG.",
14138
+ delegation: "Sync fork-join child spawned by delegate_task. Coordinator's wake blocked until it finished."
14139
+ };
14140
+ function MissionWorkersTab({
14141
+ workers,
14142
+ tasks,
14143
+ onOpenTranscript
14144
+ }) {
14145
+ if (workers.length === 0) {
14146
+ return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No workers attached to this mission right now." });
14147
+ }
14148
+ return /* @__PURE__ */ jsx("div", { className: "grid gap-3 sm:grid-cols-2", children: workers.map((w) => /* @__PURE__ */ jsx(
14149
+ WorkerCard,
14150
+ {
14151
+ worker: w,
14152
+ tasks,
14153
+ onOpenTranscript
14154
+ },
14155
+ w.workerSessionId
14156
+ )) });
14157
+ }
14158
+ function WorkerCard({
14159
+ worker,
14160
+ tasks,
14161
+ onOpenTranscript
14162
+ }) {
14163
+ const counts = missionWorkerTaskCounts(worker, tasks);
14164
+ const statusLabel2 = worker.kind === "task" ? worker.taskStatus ?? "\u2014" : worker.sessionStatus;
14165
+ const onTranscriptClick = (e) => {
14166
+ if (onOpenTranscript) {
14167
+ e.preventDefault();
14168
+ onOpenTranscript(worker.workerSessionId);
14169
+ }
14170
+ };
14171
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 rounded-md border border-border/60 bg-card p-4 shadow-sm", children: [
14172
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
14173
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
14174
+ /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-semibold text-foreground", children: worker.agentDefName ?? "worker" }),
14175
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
14176
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
14177
+ Badge,
14178
+ {
14179
+ variant: "outline",
14180
+ className: `mt-1 ${MISSION_WORKER_KIND_BADGE_CLASS[worker.kind]}`,
14181
+ children: worker.kind
14182
+ }
14183
+ ) }),
14184
+ /* @__PURE__ */ jsx(TooltipContent, { className: "max-w-xs", children: MISSION_WORKER_KIND_TOOLTIP[worker.kind] })
14185
+ ] })
14186
+ ] }),
14187
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 font-mono text-[10px] uppercase tracking-wider text-muted-foreground/70", children: statusLabel2 })
14188
+ ] }),
14189
+ counts ? /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-6", children: [
14190
+ /* @__PURE__ */ jsxs("div", { children: [
14191
+ /* @__PURE__ */ jsx("div", { className: "text-xl font-bold tabular-nums text-foreground", children: counts.completed }),
14192
+ /* @__PURE__ */ jsx("div", { className: "font-mono text-[9px] uppercase tracking-widest text-muted-foreground/60", children: "Completed" })
14193
+ ] }),
14194
+ /* @__PURE__ */ jsxs("div", { children: [
14195
+ /* @__PURE__ */ jsx(
14196
+ "div",
14197
+ {
14198
+ className: `text-xl font-bold tabular-nums ${counts.inFlight > 0 ? "text-amber-600" : "text-foreground"}`,
14199
+ children: counts.inFlight
14200
+ }
14201
+ ),
14202
+ /* @__PURE__ */ jsx("div", { className: "font-mono text-[9px] uppercase tracking-widest text-muted-foreground/60", children: "In flight" })
14203
+ ] })
14204
+ ] }) : null,
14205
+ /* @__PURE__ */ jsxs("div", { className: "mt-auto space-y-1 border-t border-border/40 pt-2", children: [
14206
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
14207
+ /* @__PURE__ */ jsx("span", { className: "truncate font-mono text-[10px] text-muted-foreground/70", children: worker.latestEventKind ?? "no events yet" }),
14208
+ worker.latestEventAt ? /* @__PURE__ */ jsx("span", { className: "shrink-0 font-mono text-[10px] text-muted-foreground/60", children: formatMissionTimestamp(worker.latestEventAt) }) : null
14209
+ ] }),
14210
+ /* @__PURE__ */ jsx("div", { className: "truncate text-xs text-foreground/80", children: deriveMissionWorkerActivityLabel(worker) }),
14211
+ /* @__PURE__ */ jsx(
14212
+ "a",
14213
+ {
14214
+ href: worker.transcriptUrl,
14215
+ target: "_blank",
14216
+ rel: "noreferrer",
14217
+ onClick: onTranscriptClick,
14218
+ className: "inline-block text-xs text-primary hover:underline",
14219
+ children: "View session"
14220
+ }
14221
+ )
14222
+ ] })
14223
+ ] });
14224
+ }
14225
+ var PAGE_LIMIT = 500;
14226
+ var MAX_PAGES_PER_PUMP = 20;
14227
+ function useMissionEvents(input) {
14228
+ const { adapter, missionId, missionStatus, isTerminal, pollIntervalMs } = input;
14229
+ const supported = typeof adapter.listMissionEvents === "function";
14230
+ const [events, setEvents] = useState([]);
14231
+ const [sessions, setSessions] = useState({});
14232
+ const lastIdRef = useRef(null);
14233
+ const pumpingRef = useRef(false);
14234
+ const mountedRef = useRef(true);
14235
+ useEffect(() => {
14236
+ mountedRef.current = true;
14237
+ return () => {
14238
+ mountedRef.current = false;
14239
+ };
14240
+ }, []);
14241
+ useEffect(() => {
14242
+ lastIdRef.current = null;
14243
+ setEvents([]);
14244
+ setSessions({});
14245
+ }, [missionId]);
14246
+ const pump = useCallback(async () => {
14247
+ const fn = adapter.listMissionEvents;
14248
+ if (typeof fn !== "function" || pumpingRef.current) return;
14249
+ pumpingRef.current = true;
14250
+ try {
14251
+ for (let page = 0; page < MAX_PAGES_PER_PUMP; page += 1) {
14252
+ const resp = await fn.call(adapter, {
14253
+ missionId,
14254
+ afterId: lastIdRef.current ?? void 0,
14255
+ limit: PAGE_LIMIT
14256
+ });
14257
+ if (!mountedRef.current) return;
14258
+ if (resp.events.length > 0) {
14259
+ lastIdRef.current = resp.events[resp.events.length - 1].id;
14260
+ setEvents((prev) => mergeMissionEvents(prev, resp.events));
14261
+ }
14262
+ if (Object.keys(resp.sessions).length > 0) {
14263
+ setSessions((prev) => ({ ...prev, ...resp.sessions }));
14264
+ }
14265
+ if (resp.events.length < PAGE_LIMIT) break;
14266
+ }
14267
+ } catch {
14268
+ } finally {
14269
+ pumpingRef.current = false;
14270
+ }
14271
+ }, [adapter, missionId]);
14272
+ useEffect(() => {
14273
+ void pump();
14274
+ }, [pump]);
14275
+ useEffect(() => {
14276
+ if (!supported || missionStatus === null || isTerminal) return;
14277
+ const id = window.setInterval(() => {
14278
+ void pump();
14279
+ }, pollIntervalMs);
14280
+ return () => {
14281
+ window.clearInterval(id);
14282
+ };
14283
+ }, [supported, missionStatus, isTerminal, pollIntervalMs, pump]);
14284
+ return { supported, events, sessions };
14285
+ }
14286
+ var DEFAULT_POLL_INTERVAL_MS = 5e3;
14287
+ function CountBadge({ n }) {
14288
+ if (n === 0) return null;
14289
+ return /* @__PURE__ */ jsx("span", { className: "ml-1 rounded bg-muted px-1 py-px text-[9px] text-muted-foreground/70", children: n });
14290
+ }
14291
+ var INITIAL_STATE = {
12968
14292
  mission: null,
12969
14293
  tasks: [],
12970
14294
  workers: [],
@@ -13045,10 +14369,13 @@ function MissionDashboard({
13045
14369
  window.clearInterval(id);
13046
14370
  };
13047
14371
  }, [refresh, state.mission, pollIntervalMs]);
13048
- const taskBuckets = useMemo(
13049
- () => groupMissionTasksByBucket(state.tasks),
13050
- [state.tasks]
13051
- );
14372
+ const feed = useMissionEvents({
14373
+ adapter,
14374
+ missionId,
14375
+ missionStatus: state.mission?.status ?? null,
14376
+ isTerminal: state.mission ? isTerminalMissionStatus(state.mission.status) : false,
14377
+ pollIntervalMs
14378
+ });
13052
14379
  const runningWorkerCount = useMemo(
13053
14380
  // "running" means the child is still consuming compute right now.
13054
14381
  // For task-backed children that's ``taskStatus === "running"``; for
@@ -13117,7 +14444,6 @@ function MissionDashboard({
13117
14444
  }
13118
14445
  };
13119
14446
  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";
13120
- const activity = buildMissionActivity(mission, state.tasks, state.workers);
13121
14447
  const isActive = ACTIVE_MISSION_STATUSES.has(mission.status);
13122
14448
  const iterationPct = mission.maxIterations > 0 ? Math.min(100, mission.iteration / mission.maxIterations * 100) : 0;
13123
14449
  return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-1 flex-col overflow-hidden bg-muted/30", children: [
@@ -13224,18 +14550,18 @@ function MissionDashboard({
13224
14550
  /* @__PURE__ */ jsxs(
13225
14551
  Tabs,
13226
14552
  {
13227
- defaultValue: "activity",
14553
+ defaultValue: "tasks",
13228
14554
  className: "mt-5 flex flex-1 flex-col overflow-hidden sm:mt-6",
13229
14555
  children: [
13230
14556
  /* @__PURE__ */ jsx("div", { className: "shrink-0 border-b border-border bg-background px-5 sm:px-6", children: /* @__PURE__ */ jsxs(TabsList, { variant: "line", children: [
13231
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "activity", children: [
13232
- "Activity",
13233
- /* @__PURE__ */ jsx(CountBadge, { n: activity.length })
13234
- ] }),
13235
14557
  /* @__PURE__ */ jsxs(TabsTrigger, { value: "tasks", children: [
13236
14558
  "Tasks",
13237
14559
  /* @__PURE__ */ jsx(CountBadge, { n: state.tasks.length })
13238
14560
  ] }),
14561
+ feed.supported ? /* @__PURE__ */ jsxs(TabsTrigger, { value: "activity", children: [
14562
+ "Activity",
14563
+ /* @__PURE__ */ jsx(CountBadge, { n: feed.events.length })
14564
+ ] }) : null,
13239
14565
  /* @__PURE__ */ jsxs(TabsTrigger, { value: "workers", children: [
13240
14566
  "Workers",
13241
14567
  /* @__PURE__ */ jsx(CountBadge, { n: state.workers.length })
@@ -13243,22 +14569,24 @@ function MissionDashboard({
13243
14569
  /* @__PURE__ */ jsx(TabsTrigger, { value: "metadata", children: "Metadata" })
13244
14570
  ] }) }),
13245
14571
  /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto bg-background px-5 py-4 sm:px-6", children: [
13246
- /* @__PURE__ */ jsx(TabsContent, { value: "activity", className: "mt-0", children: /* @__PURE__ */ jsx(ActivityTimeline, { entries: activity }) }),
13247
- /* @__PURE__ */ jsx(TabsContent, { value: "tasks", className: "mt-0", children: /* @__PURE__ */ jsx(
13248
- TasksList,
14572
+ /* @__PURE__ */ jsx(TabsContent, { value: "tasks", className: "mt-0 h-full", children: /* @__PURE__ */ jsx(
14573
+ MissionTasksTab,
13249
14574
  {
13250
- taskBuckets,
13251
- totalTasks: state.tasks.length
14575
+ tasks: state.tasks,
14576
+ feed,
14577
+ onOpenTranscript
13252
14578
  }
13253
14579
  ) }),
14580
+ feed.supported ? /* @__PURE__ */ jsx(TabsContent, { value: "activity", className: "mt-0", children: /* @__PURE__ */ jsx(MissionActivityTab, { feed }) }) : null,
13254
14581
  /* @__PURE__ */ jsx(TabsContent, { value: "workers", className: "mt-0", children: /* @__PURE__ */ jsx(
13255
- WorkersList,
14582
+ MissionWorkersTab,
13256
14583
  {
13257
14584
  workers: state.workers,
14585
+ tasks: state.tasks,
13258
14586
  onOpenTranscript
13259
14587
  }
13260
14588
  ) }),
13261
- /* @__PURE__ */ jsx(TabsContent, { value: "metadata", className: "mt-0", children: /* @__PURE__ */ jsx(MetadataPane, { mission }) })
14589
+ /* @__PURE__ */ jsx(TabsContent, { value: "metadata", className: "mt-0", children: /* @__PURE__ */ jsx(MissionMetadataTab, { mission }) })
13262
14590
  ] })
13263
14591
  ]
13264
14592
  }
@@ -13322,234 +14650,6 @@ function MissionDashboard({
13322
14650
  )
13323
14651
  ] }) });
13324
14652
  }
13325
- function ActivityTimeline({ entries }) {
13326
- if (entries.length === 0) {
13327
- return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No mission activity yet." });
13328
- }
13329
- return /* @__PURE__ */ jsx("ol", { className: "space-y-1", children: entries.map((e, i) => /* @__PURE__ */ jsxs(
13330
- "li",
13331
- {
13332
- className: "flex items-start gap-3 rounded px-2 py-1.5 text-sm hover:bg-muted/30",
13333
- children: [
13334
- /* @__PURE__ */ jsx("span", { className: "w-20 shrink-0 font-mono text-[10px] text-muted-foreground/60", children: formatTimestamp(e.at) }),
13335
- /* @__PURE__ */ jsx(
13336
- "span",
13337
- {
13338
- className: `shrink-0 rounded border px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wide ${ACTIVITY_KIND_TONE[e.kind]}`,
13339
- children: e.label
13340
- }
13341
- ),
13342
- e.detail ? /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-foreground/80", children: e.detail }) : null
13343
- ]
13344
- },
13345
- `${e.kind}-${e.at}-${i}`
13346
- )) });
13347
- }
13348
- function TaskRow({ task }) {
13349
- const [open, setOpen] = useState(false);
13350
- const goalPreview = firstLine3(task.goal, 160);
13351
- const hasMore = task.goal.length > 160 || Boolean(task.result) || Boolean(task.resultMetadata);
13352
- 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";
13353
- return /* @__PURE__ */ jsx(Collapsible, { open, onOpenChange: setOpen, asChild: true, children: /* @__PURE__ */ jsxs("li", { className: "rounded border border-border/40 text-sm", children: [
13354
- /* @__PURE__ */ jsx(
13355
- CollapsibleTrigger,
13356
- {
13357
- asChild: true,
13358
- disabled: !hasMore,
13359
- children: /* @__PURE__ */ jsxs(
13360
- "button",
13361
- {
13362
- type: "button",
13363
- className: "flex w-full items-start gap-3 px-3 py-2 text-left hover:bg-muted/30 disabled:hover:bg-transparent",
13364
- children: [
13365
- /* @__PURE__ */ jsx(
13366
- ChevronRight,
13367
- {
13368
- className: `mt-0.5 size-3.5 shrink-0 text-muted-foreground/60 transition-transform ${open ? "rotate-90" : ""} ${hasMore ? "" : "opacity-0"}`
13369
- }
13370
- ),
13371
- /* @__PURE__ */ jsx(
13372
- "span",
13373
- {
13374
- className: `shrink-0 rounded border px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wide ${statusTone}`,
13375
- children: task.status
13376
- }
13377
- ),
13378
- task.agentDefName ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground/70", children: task.agentDefName }) : null,
13379
- task.attemptCount > 1 ? /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-[10px] text-muted-foreground/60", children: [
13380
- "(",
13381
- task.attemptCount,
13382
- "/",
13383
- task.maxAttempts,
13384
- ")"
13385
- ] }) : null,
13386
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-foreground/80", children: goalPreview })
13387
- ]
13388
- }
13389
- )
13390
- }
13391
- ),
13392
- /* @__PURE__ */ jsxs(CollapsibleContent, { className: "border-t border-border/40 px-3 py-2 text-xs", children: [
13393
- /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
13394
- /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Goal" }),
13395
- /* @__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 })
13396
- ] }),
13397
- task.parentIds.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "mb-2 text-[10px] text-muted-foreground/70", children: [
13398
- "after: ",
13399
- task.parentIds.map((p) => p.slice(0, 8)).join(", ")
13400
- ] }) : null,
13401
- task.result ? /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
13402
- /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Result" }),
13403
- /* @__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 })
13404
- ] }) : null,
13405
- task.resultMetadata ? /* @__PURE__ */ jsxs("div", { children: [
13406
- /* @__PURE__ */ jsx("div", { className: "mb-1 font-mono text-[9px] uppercase tracking-wide text-muted-foreground/60", children: "Result metadata" }),
13407
- /* @__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) })
13408
- ] }) : null
13409
- ] })
13410
- ] }) });
13411
- }
13412
- function TasksList({
13413
- taskBuckets,
13414
- totalTasks
13415
- }) {
13416
- if (totalTasks === 0) {
13417
- return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No tasks spawned yet." });
13418
- }
13419
- const headings = {
13420
- in_flight: "In flight",
13421
- blocked: "Blocked",
13422
- done: "Done",
13423
- failed_or_cancelled: "Failed / cancelled"
13424
- };
13425
- return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: Object.keys(headings).map((bucket) => {
13426
- const rows = taskBuckets[bucket];
13427
- if (rows.length === 0) return null;
13428
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
13429
- /* @__PURE__ */ jsxs("div", { className: "font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: [
13430
- headings[bucket],
13431
- " (",
13432
- rows.length,
13433
- ")"
13434
- ] }),
13435
- /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: rows.map((task) => /* @__PURE__ */ jsx(TaskRow, { task }, task.id)) })
13436
- ] }, bucket);
13437
- }) });
13438
- }
13439
- function WorkersList({
13440
- workers,
13441
- onOpenTranscript
13442
- }) {
13443
- if (workers.length === 0) {
13444
- return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No workers attached to this mission right now." });
13445
- }
13446
- return /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: workers.map((w) => {
13447
- const onTranscriptClick = (e) => {
13448
- if (onOpenTranscript) {
13449
- e.preventDefault();
13450
- onOpenTranscript(w.workerSessionId);
13451
- }
13452
- };
13453
- return /* @__PURE__ */ jsxs(
13454
- "li",
13455
- {
13456
- 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",
13457
- children: [
13458
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-1", children: [
13459
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
13460
- /* @__PURE__ */ jsx(
13461
- Badge,
13462
- {
13463
- variant: "outline",
13464
- className: MISSION_WORKER_KIND_BADGE_CLASS[w.kind],
13465
- title: MISSION_WORKER_KIND_TOOLTIP[w.kind],
13466
- children: w.kind
13467
- }
13468
- ),
13469
- /* @__PURE__ */ jsx(Badge, { className: "text-foreground/70", children: w.kind === "task" ? w.taskStatus ?? "\u2014" : w.sessionStatus }),
13470
- w.agentDefName ? /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground/70", children: w.agentDefName }) : null,
13471
- w.latestEventAt ? /* @__PURE__ */ jsx("span", { className: "ml-auto font-mono text-[10px] text-muted-foreground/60", children: formatTimestamp(w.latestEventAt) }) : null
13472
- ] }),
13473
- /* @__PURE__ */ jsx("div", { className: "truncate text-sm text-foreground/80", children: deriveMissionWorkerActivityLabel(w) })
13474
- ] }),
13475
- /* @__PURE__ */ jsx(
13476
- "a",
13477
- {
13478
- href: w.transcriptUrl,
13479
- target: "_blank",
13480
- rel: "noreferrer",
13481
- onClick: onTranscriptClick,
13482
- className: "self-start text-xs text-primary hover:underline",
13483
- children: "View session"
13484
- }
13485
- )
13486
- ]
13487
- },
13488
- w.workerSessionId
13489
- );
13490
- }) });
13491
- }
13492
- function MetadataPane({ mission }) {
13493
- const rows = [];
13494
- rows.push({
13495
- label: "Mission ID",
13496
- value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.id })
13497
- });
13498
- rows.push({
13499
- label: "Session ID",
13500
- value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.sessionId })
13501
- });
13502
- rows.push({
13503
- label: "Agent ID",
13504
- value: /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.agentId })
13505
- });
13506
- rows.push({ label: "Status", value: mission.status });
13507
- rows.push({
13508
- label: "Iteration",
13509
- value: `${mission.iteration} / ${mission.maxIterations}`
13510
- });
13511
- rows.push({
13512
- label: "Owner",
13513
- value: mission.userId ? /* @__PURE__ */ jsxs(Fragment, { children: [
13514
- "user ",
13515
- /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.userId })
13516
- ] }) : mission.serviceAccountId ? /* @__PURE__ */ jsxs(Fragment, { children: [
13517
- "service account ",
13518
- /* @__PURE__ */ jsx("code", { className: "text-[11px]", children: mission.serviceAccountId })
13519
- ] }) : "\u2014"
13520
- });
13521
- rows.push({
13522
- label: "Created",
13523
- value: /* @__PURE__ */ jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.createdAt).toLocaleString() })
13524
- });
13525
- rows.push({
13526
- label: "Updated",
13527
- value: /* @__PURE__ */ jsx("span", { className: "font-mono text-[11px]", children: new Date(mission.updatedAt).toLocaleString() })
13528
- });
13529
- if (mission.pausedReason) {
13530
- rows.push({ label: "Paused reason", value: mission.pausedReason });
13531
- }
13532
- if (mission.cancelledReason) {
13533
- rows.push({ label: "Cancelled reason", value: mission.cancelledReason });
13534
- }
13535
- return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
13536
- mission.lastEvaluationResult ? /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
13537
- /* @__PURE__ */ jsxs("div", { className: "font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: [
13538
- "Last verdict \u2014 ",
13539
- mission.lastEvaluationResult
13540
- ] }),
13541
- mission.lastEvaluationFeedback ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-sm text-foreground/90", children: mission.lastEvaluationFeedback }) : null,
13542
- mission.lastEvaluationExplanation ? /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap text-xs text-muted-foreground/70", children: mission.lastEvaluationExplanation }) : null
13543
- ] }) : null,
13544
- /* @__PURE__ */ jsxs("section", { children: [
13545
- /* @__PURE__ */ jsx("div", { className: "mb-2 font-mono text-[10px] uppercase tracking-widest text-muted-foreground/70", children: "Identifiers" }),
13546
- /* @__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: [
13547
- /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground/70", children: r.label }),
13548
- /* @__PURE__ */ jsx("dd", { className: "break-all text-foreground/90", children: r.value })
13549
- ] }, r.label)) })
13550
- ] })
13551
- ] });
13552
- }
13553
14653
  var DEFAULT_POLL_INTERVAL_MS2 = 3e4;
13554
14654
  function fingerprint(items) {
13555
14655
  return items.map(
@@ -13788,7 +14888,7 @@ function MissionsPanel({
13788
14888
  if (!adapter.cancelMission || busyMissionId) return;
13789
14889
  setBusyMissionId(missionId);
13790
14890
  try {
13791
- await adapter.cancelMission({ missionId });
14891
+ await adapter.cancelMission({ missionId, cascadeToWorkers: true });
13792
14892
  setItems((current) => {
13793
14893
  const next = current.filter((m) => m.id !== missionId);
13794
14894
  lastFingerprint.current = fingerprint(next);
@@ -14574,6 +15674,6 @@ function SessionTreePanel({
14574
15674
  ] });
14575
15675
  }
14576
15676
 
14577
- export { ACTIVE_MISSION_STATUSES, AgentChat, AgentChatAdapterProvider, CitationText, ComposioConnectCard, InboxPanel, IntegrationsBand, IntegrationsPage, MessageResponse, MissionDashboard, MissionsPanel, ResearchSourcesPanel, ScheduledWorkPanel, SessionTreePanel, deriveMissionWorkerActivityLabel, groupMissionTasksByBucket, isTerminalMissionStatus, missionTaskBucket, splitCitations, useAgentChatAdapterContext, useAgentChatRuntime, useChatViewMode, useInboxUnreadCount };
15677
+ export { ACTIVE_MISSION_STATUSES, AgentChat, AgentChatAdapterProvider, CitationText, CodingAgentsPanel, ComposioConnectCard, InboxPanel, IntegrationsBand, IntegrationsPage, MISSION_EVENT_CATEGORIES, MessageResponse, MissionDashboard, MissionsPanel, ResearchSourcesPanel, ScheduledWorkPanel, SessionTreePanel, defaultSelectedMissionTaskId, deriveMissionWorkerActivityLabel, formatMissionTimestamp, groupMissionTasksByBucket, isTerminalMissionStatus, mergeMissionEvents, missionEventActorLabel, missionEventCategory, missionEventSummary, missionEventTaskId, missionTaskBlocks, missionTaskBucket, missionTaskRailGroups, missionTaskStatusDotClass, missionTaskTitle, missionWorkerTaskCounts, splitCitations, stripMissionControlMarkup, useAgentChatAdapterContext, useAgentChatRuntime, useChatViewMode, useInboxUnreadCount, useMissionEvents };
14578
15678
  //# sourceMappingURL=index.js.map
14579
15679
  //# sourceMappingURL=index.js.map