@agimon-ai/po-team 0.0.0-alpha.23 → 0.0.0-alpha.24

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.
@@ -1,12 +1,12 @@
1
- import { createApiClient, defineActivityGroup, defineApiRoutes, defineChannelFile, defineFill, defineNativePlugin, defineSessionStore, nativeApiTransport, sessionApiAddress } from "@agimon-ai/po-core/native";
2
- import { ArrowRightIcon, Badge, Button, Dot, Input, ListRow, SegmentedControl, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, Textarea, UsersIcon, fontOf } from "@agimon-ai/po-native-components";
1
+ import { createApiClient, defineActivityGroup, defineApiRoutes, defineChannelFile, defineFill, defineNativePlugin, defineSessionStore, defineSlot, nativeApiTransport, sessionApiAddress } from "@agimon-ai/po-core/native";
2
+ import { AgentAvatar, ArrowRightIcon, Badge, Button, ChevronDownIcon, Dot, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, Input, KebabIcon, ListRow, Panel, STATUS_EDGE, SegmentedControl, SendIcon, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, StatusBadge, Textarea, UsersIcon, fontOf } from "@agimon-ai/po-native-components";
3
3
  import { createElement, useCallback, useEffect, useState, useSyncExternalStore } from "react";
4
- import { ScrollView } from "react-native-unistyles/components/native/ScrollView";
5
4
  import { View } from "react-native-unistyles/components/native/View";
6
5
  import { Text } from "react-native-unistyles/components/native/Text";
7
- import { StyleSheet } from "react-native-unistyles";
8
- import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { ScrollView } from "react-native-unistyles/components/native/ScrollView";
9
7
  import { Pressable } from "react-native-unistyles/components/native/Pressable";
8
+ import { StyleSheet } from "react-native-unistyles";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/extensions/workspaces/(frontend)/fill/Team.home.native.ts
11
11
  var Team_home_native_default = defineFill({ data: {
12
12
  version: 1,
@@ -209,6 +209,11 @@ function formatRunDuration(elapsedMs) {
209
209
  const minutes = Math.floor(elapsedMs % HOUR_MS / MINUTE_MS);
210
210
  return `${hours}h ${String(minutes).padStart(2, "0")}m`;
211
211
  }
212
+ function abbreviateCwd(cwd) {
213
+ const match = /^\/(?:Users|home)\/[^/]+/u.exec(cwd);
214
+ if (!match) return cwd;
215
+ return `~${cwd.slice(match[0].length)}`;
216
+ }
212
217
  /** What to call a run on screen: the identity's first name, else the agent name. Never a run id. */
213
218
  function agentRunLabel(run) {
214
219
  return agentDisplay(run).name;
@@ -265,6 +270,10 @@ function agentMeta(agent) {
265
270
  return `${agent.tools.length === 0 ? "all tools" : `tools ${agent.tools.slice(0, META_TOOL_LIMIT).join(", ")}${agent.tools.length > META_TOOL_LIMIT ? ` +${agent.tools.length - META_TOOL_LIMIT}` : ""}`}${agent.skills.length > 0 ? ` · ${agent.skills.length} skill${agent.skills.length === 1 ? "" : "s"}` : ""} · ${agent.defaultContext === "fork" ? "forks the session" : "fresh context"}`;
266
271
  }
267
272
  //#endregion
273
+ //#region src/extensions/workspaces/sessions/(frontend)/_lib/runActionsSlot.native.ts
274
+ /** The native twin of `runActionsSlot.ts`: the same slot name, declared from the native SDK. */
275
+ const RUN_ACTIONS_SLOT = defineSlot({ slot: "subagents.run-actions" });
276
+ //#endregion
268
277
  //#region src/extensions/workspaces/sessions/(frontend)/_lib/subagentsStore.native.ts
269
278
  const TERMINAL_STATES = /* @__PURE__ */ new Set([
270
279
  "done",
@@ -342,6 +351,18 @@ function clearPendingLaunch(sessionId) {
342
351
  pendingLaunch: void 0
343
352
  }));
344
353
  }
354
+ function clearAutoOpen(sessionId) {
355
+ subagents.update(sessionId, (current) => ({
356
+ ...current,
357
+ autoOpenRunId: void 0
358
+ }));
359
+ }
360
+ function openRun(sessionId, runId) {
361
+ subagents.update(sessionId, (current) => ({
362
+ ...current,
363
+ openRunId: runId
364
+ }));
365
+ }
345
366
  /** The plugin's session data channel: 'subagent_runs' payloads into the store. */
346
367
  const subagentRunsChannel = subagents.channel({
347
368
  channel: SUBAGENT_RUNS_TYPE,
@@ -369,6 +390,38 @@ const subagentRunsChannel = subagents.channel({
369
390
  });
370
391
  //#endregion
371
392
  //#region src/extensions/workspaces/sessions/(frontend)/_components/SubagentsPanel.native.tsx
393
+ const TICK_MS$1 = 1e4;
394
+ /** How much of a run's own conversation a card carries; the whole thread is one press away. */
395
+ const CARD_THREAD_ENTRIES = 8;
396
+ /** One run state, in the host's shared outcome vocabulary. */
397
+ const RUN_BADGE = {
398
+ queued: {
399
+ label: "QUEUED",
400
+ tone: "neutral"
401
+ },
402
+ running: {
403
+ label: "RUNNING",
404
+ tone: "running"
405
+ },
406
+ done: {
407
+ label: "DONE",
408
+ tone: "ok"
409
+ },
410
+ failed: {
411
+ label: "FAILED",
412
+ tone: "error"
413
+ },
414
+ stopped: {
415
+ label: "STOPPED",
416
+ tone: "neutral"
417
+ }
418
+ };
419
+ const NOT_REPORTED = "Not reported";
420
+ const END_NOTE = {
421
+ done: "This run has finished. Start a new run from Agents.",
422
+ failed: "This run failed. Start a new run from Agents.",
423
+ stopped: "This run was stopped. Start a new run from Agents."
424
+ };
372
425
  function useSubagents(sessionId) {
373
426
  const subscribe = useCallback((listener) => {
374
427
  const sub = subagents.store.subscribe(listener);
@@ -376,10 +429,23 @@ function useSubagents(sessionId) {
376
429
  }, []);
377
430
  return useSyncExternalStore(subscribe, () => subagents.select(subagents.store.state, sessionId));
378
431
  }
432
+ function useNow() {
433
+ const [now, setNow] = useState(() => Date.now());
434
+ useEffect(() => {
435
+ const timer = setInterval(() => setNow(Date.now()), TICK_MS$1);
436
+ return () => clearInterval(timer);
437
+ }, []);
438
+ return now;
439
+ }
440
+ /** How long the run has been going, or took; the clock only matters while it is active. */
441
+ function elapsedRun(run, now) {
442
+ const end = run.endedAt ?? (run.state === "running" || run.state === "queued" ? now : run.lastUpdate);
443
+ return formatRunDuration(Math.max(0, end - run.startedAt));
444
+ }
379
445
  function subagentsTab() {
380
446
  return {
381
447
  id: "subagents",
382
- label: "agents",
448
+ label: "Agents",
383
449
  panel: SubagentsPanel
384
450
  };
385
451
  }
@@ -391,40 +457,355 @@ function agentThreadTab(run) {
391
457
  panel: (props) => /* @__PURE__ */ jsx(AgentThreadPanel, {
392
458
  ...props,
393
459
  runId
394
- })
460
+ }, `${props.sessionId}:${runId}`)
395
461
  };
396
462
  }
397
- function AgentRunRow({ run, onPress }) {
398
- const detail = run.error ?? run.summary?.split("\n").find((line) => line.trim() !== "") ?? run.currentTool ?? run.tail.at(-1) ?? run.state;
399
- return /* @__PURE__ */ jsx(ListRow, {
400
- leading: /* @__PURE__ */ jsx(Dot, { tone: run.state === "failed" ? "red" : run.state === "running" ? "yellow" : run.state === "done" ? "green" : "muted" }),
401
- title: /* @__PURE__ */ jsx(Button, {
402
- variant: "ghost",
403
- onPress,
404
- testID: `activity-run-${run.runId}`,
405
- children: agentRunLabel(run)
463
+ /** The card's work line: a task binding wins; otherwise the delegation prompt. */
464
+ function WorkLine({ run }) {
465
+ const firstLine = run.task.split("\n").find((line) => line.trim() !== "") ?? "";
466
+ return /* @__PURE__ */ jsxs(View, {
467
+ style: styles$1.work,
468
+ children: [run.taskRef ? /* @__PURE__ */ jsxs(Badge, {
469
+ tone: "violet",
470
+ size: "xs",
471
+ children: ["TASK ", run.taskRef]
472
+ }) : /* @__PURE__ */ jsx(Text, {
473
+ style: styles$1.workLabel,
474
+ children: "Prompt"
475
+ }), /* @__PURE__ */ jsx(Text, {
476
+ testID: "run-work",
477
+ numberOfLines: 1,
478
+ style: run.taskRef ? styles$1.workHi : styles$1.workDim,
479
+ children: firstLine
480
+ })]
481
+ });
482
+ }
483
+ /** Everything a card can do, behind one control. */
484
+ function RunMenu({ sessionId, run, stopping, onOpenThread, onOpenDetail }) {
485
+ const [error, setError] = useState();
486
+ const stop = () => {
487
+ setError(void 0);
488
+ requestRunStop(sessionId, run.runId).catch((cause) => setError(cause instanceof Error ? cause.message : String(cause)));
489
+ };
490
+ return /* @__PURE__ */ jsxs(Fragment, { children: [error ? /* @__PURE__ */ jsx(Text, {
491
+ accessibilityRole: "alert",
492
+ testID: `run-menu-stop-error-${run.runId}`,
493
+ numberOfLines: 1,
494
+ style: styles$1.error,
495
+ children: error
496
+ }) : null, /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
497
+ variant: "ghost",
498
+ size: "icon",
499
+ testID: `run-menu-${run.runId}`,
500
+ accessibilityLabel: "run actions",
501
+ children: /* @__PURE__ */ jsx(KebabIcon, { size: 12 })
502
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, { children: [
503
+ /* @__PURE__ */ jsx(DropdownMenuItem, {
504
+ onSelect: onOpenThread,
505
+ children: "open thread"
506
+ }),
507
+ /* @__PURE__ */ jsx(DropdownMenuItem, {
508
+ onSelect: onOpenDetail,
509
+ children: "details"
406
510
  }),
407
- description: detail,
408
- trailing: /* @__PURE__ */ jsx(Badge, { children: run.state })
511
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
512
+ isTerminalRun(run) ? /* @__PURE__ */ jsx(DropdownMenuItem, {
513
+ onSelect: () => dismissRun(sessionId, run.runId),
514
+ children: "clear from the grid"
515
+ }) : /* @__PURE__ */ jsx(DropdownMenuItem, {
516
+ variant: "destructive",
517
+ disabled: stopping,
518
+ onSelect: stop,
519
+ children: stopping ? "stopping…" : "stop"
520
+ })
521
+ ] })] })] });
522
+ }
523
+ /** One run in the fleet: its live conversation under a header; the whole card is the way into the run's tab. */
524
+ function RunCard({ sessionId, run, now, stopping, renderThread, onOpenThread, onOpenDetail }) {
525
+ const badge = RUN_BADGE[run.state];
526
+ const who = agentDisplay(run);
527
+ return /* @__PURE__ */ jsxs(Panel, {
528
+ testID: `run-card-${run.runId}`,
529
+ style: styles$1.card(STATUS_EDGE[badge.tone]),
530
+ children: [/* @__PURE__ */ jsxs(Pressable, {
531
+ accessibilityRole: "button",
532
+ accessibilityLabel: `Open ${who.name}'s conversation`,
533
+ testID: `run-open-card-${run.runId}`,
534
+ onPress: onOpenThread,
535
+ style: styles$1.cardOpen,
536
+ children: [
537
+ /* @__PURE__ */ jsxs(View, {
538
+ style: styles$1.cardHead,
539
+ children: [
540
+ /* @__PURE__ */ jsx(AgentAvatar, {
541
+ name: who.name,
542
+ seed: who.seed,
543
+ size: "sm"
544
+ }),
545
+ /* @__PURE__ */ jsx(Text, {
546
+ testID: "run-agent",
547
+ numberOfLines: 1,
548
+ style: styles$1.name,
549
+ children: who.name
550
+ }),
551
+ who.role ? /* @__PURE__ */ jsx(Text, {
552
+ numberOfLines: 1,
553
+ style: styles$1.dim,
554
+ children: who.role
555
+ }) : null,
556
+ /* @__PURE__ */ jsx(View, { style: styles$1.spacer }),
557
+ /* @__PURE__ */ jsx(Text, {
558
+ style: styles$1.dim,
559
+ children: elapsedRun(run, now)
560
+ }),
561
+ /* @__PURE__ */ jsx(StatusBadge, {
562
+ tone: badge.tone,
563
+ testID: "run-state",
564
+ children: badge.label
565
+ })
566
+ ]
567
+ }),
568
+ /* @__PURE__ */ jsx(WorkLine, { run }),
569
+ /* @__PURE__ */ jsx(View, {
570
+ testID: "run-stream",
571
+ pointerEvents: "none",
572
+ style: styles$1.stream,
573
+ children: renderThread(run.runId, {
574
+ limit: CARD_THREAD_ENTRIES,
575
+ compact: true
576
+ })
577
+ }),
578
+ run.state === "failed" && run.error ? /* @__PURE__ */ jsx(Text, {
579
+ testID: "run-error",
580
+ numberOfLines: 1,
581
+ style: [styles$1.error, styles$1.cardError],
582
+ children: run.error
583
+ }) : null
584
+ ]
585
+ }), /* @__PURE__ */ jsxs(View, {
586
+ style: styles$1.cardFoot,
587
+ children: [
588
+ /* @__PURE__ */ jsxs(Text, {
589
+ numberOfLines: 1,
590
+ style: styles$1.dim,
591
+ children: [
592
+ run.toolCount !== void 0 ? `${run.toolCount} tools` : "—",
593
+ run.tokens !== void 0 ? ` · ${run.tokens.toLocaleString()} tk` : "",
594
+ run.model ? ` · ${run.model.split("/").pop() ?? run.model}` : ""
595
+ ]
596
+ }),
597
+ /* @__PURE__ */ jsx(View, { style: styles$1.spacer }),
598
+ /* @__PURE__ */ jsx(RunMenu, {
599
+ sessionId,
600
+ run,
601
+ stopping,
602
+ onOpenThread,
603
+ onOpenDetail
604
+ })
605
+ ]
606
+ })]
607
+ });
608
+ }
609
+ function SheetRow({ label, value, violet }) {
610
+ return /* @__PURE__ */ jsxs(View, {
611
+ style: styles$1.sheetRow,
612
+ children: [/* @__PURE__ */ jsx(Text, {
613
+ style: [styles$1.dim, styles$1.sheetRowLabel],
614
+ children: label
615
+ }), /* @__PURE__ */ jsx(Text, {
616
+ style: violet ? styles$1.violet : styles$1.bodyDim,
617
+ children: value
618
+ })]
619
+ });
620
+ }
621
+ function SheetBlock({ label, text, testId, failure }) {
622
+ return /* @__PURE__ */ jsxs(View, {
623
+ style: styles$1.sheetBlock,
624
+ children: [/* @__PURE__ */ jsx(Text, {
625
+ style: styles$1.sheetBlockLabel,
626
+ children: label
627
+ }), /* @__PURE__ */ jsx(Text, {
628
+ testID: testId,
629
+ style: failure ? styles$1.bodyRed : styles$1.bodyText,
630
+ children: text
631
+ })]
632
+ });
633
+ }
634
+ /** What the run was asked to do and what it was given to do it with, over the fleet. */
635
+ function RunDetailSheet({ sessionId, run, now, stopping, renderSlot, onClose }) {
636
+ const badge = RUN_BADGE[run.state];
637
+ return /* @__PURE__ */ jsx(Sheet, {
638
+ open: true,
639
+ onOpenChange: (open) => {
640
+ if (!open) onClose();
641
+ },
642
+ children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsxs(SheetHeader, { children: [
643
+ /* @__PURE__ */ jsx(SheetTitle, {
644
+ testID: "sheet-agent",
645
+ children: agentRunLabel(run)
646
+ }),
647
+ /* @__PURE__ */ jsx(StatusBadge, {
648
+ tone: badge.tone,
649
+ children: badge.label
650
+ }),
651
+ /* @__PURE__ */ jsx(View, { style: styles$1.spacer }),
652
+ /* @__PURE__ */ jsx(Text, {
653
+ style: styles$1.dim,
654
+ children: elapsedRun(run, now)
655
+ }),
656
+ renderSlot(RUN_ACTIONS_SLOT.slot),
657
+ /* @__PURE__ */ jsx(RunControl, {
658
+ sessionId,
659
+ run,
660
+ stopping
661
+ })
662
+ ] }), /* @__PURE__ */ jsxs(SheetBody, { children: [
663
+ /* @__PURE__ */ jsxs(View, {
664
+ style: styles$1.sheetRows,
665
+ children: [
666
+ /* @__PURE__ */ jsx(SheetRow, {
667
+ label: "run",
668
+ value: run.runId
669
+ }),
670
+ run.taskRef ? /* @__PURE__ */ jsx(SheetRow, {
671
+ label: "task",
672
+ value: run.taskRef,
673
+ violet: true
674
+ }) : null,
675
+ /* @__PURE__ */ jsx(SheetRow, {
676
+ label: "model",
677
+ value: run.model ?? "the runtime default"
678
+ }),
679
+ /* @__PURE__ */ jsx(SheetRow, {
680
+ label: "cwd",
681
+ value: abbreviateCwd(run.cwd)
682
+ }),
683
+ /* @__PURE__ */ jsx(SheetRow, {
684
+ label: "work",
685
+ value: `${run.toolCount === void 0 ? "no" : String(run.toolCount)} tools${run.tokens === void 0 ? "" : ` · ${run.tokens.toLocaleString()} tk`}`
686
+ })
687
+ ]
688
+ }),
689
+ /* @__PURE__ */ jsx(SheetBlock, {
690
+ label: "PROMPT FROM THE MAIN AGENT",
691
+ testId: "sheet-task",
692
+ text: run.task || "(no prompt recorded)"
693
+ }),
694
+ run.summary ? /* @__PURE__ */ jsx(SheetBlock, {
695
+ label: "REPORT",
696
+ testId: "sheet-summary",
697
+ text: run.summary
698
+ }) : null,
699
+ run.error ? /* @__PURE__ */ jsx(SheetBlock, {
700
+ label: "FAILURE",
701
+ testId: "sheet-error",
702
+ text: run.error,
703
+ failure: true
704
+ }) : null
705
+ ] })] })
409
706
  });
410
707
  }
708
+ /** The subagents tab: the focused session's fleet, one card per run. */
411
709
  function SubagentsPanel(props) {
412
- const state = useSubagents(props.sessionId);
413
- return /* @__PURE__ */ jsxs(ScrollView, {
414
- contentContainerStyle: styles$1.body,
710
+ const { sessionId, renderSlot, renderThread, openTransientTab } = props;
711
+ const state = useSubagents(sessionId);
712
+ const runs = visibleRuns(state);
713
+ const { openRunId, stopRequested, autoOpenRunId } = state;
714
+ const now = useNow();
715
+ useEffect(() => {
716
+ if (autoOpenRunId === void 0 || sessionId === null) return;
717
+ const run = runs.find((candidate) => candidate.runId === autoOpenRunId);
718
+ if (run) openTransientTab(agentThreadTab(run));
719
+ clearAutoOpen(sessionId);
720
+ }, [
721
+ autoOpenRunId,
722
+ runs,
723
+ sessionId,
724
+ openTransientTab
725
+ ]);
726
+ const shownRun = openRunId === void 0 ? void 0 : runs.find((run) => run.runId === openRunId);
727
+ const stopping = (run) => stopRequested.includes(run.runId);
728
+ const runningTally = runs.filter((run) => run.state === "running" || run.state === "queued").length;
729
+ const doneTally = runs.filter((run) => run.state === "done").length;
730
+ const failedTally = runs.filter((run) => run.state === "failed" || run.state === "stopped").length;
731
+ return /* @__PURE__ */ jsxs(View, {
732
+ testID: "subagents-panel",
733
+ style: styles$1.screen,
415
734
  children: [
416
- /* @__PURE__ */ jsx(Button, {
417
- testID: "activity-agents-launch",
418
- onPress: () => {
419
- if (props.sessionId !== null) openCatalog(props.sessionId);
420
- },
421
- children: "Launch an agent"
735
+ /* @__PURE__ */ jsxs(ScrollView, {
736
+ contentContainerStyle: styles$1.fleet,
737
+ children: [/* @__PURE__ */ jsxs(View, {
738
+ style: styles$1.fleetHead,
739
+ children: [
740
+ /* @__PURE__ */ jsx(Text, {
741
+ style: styles$1.heading,
742
+ children: "Agents · this session"
743
+ }),
744
+ /* @__PURE__ */ jsx(Button, {
745
+ variant: "primary",
746
+ testID: "subagents-launch",
747
+ style: styles$1.launch,
748
+ onPress: () => {
749
+ if (sessionId === null) return;
750
+ openRun(sessionId, void 0);
751
+ openCatalog(sessionId);
752
+ },
753
+ children: "New agent run"
754
+ }),
755
+ /* @__PURE__ */ jsx(Text, {
756
+ testID: "subagents-tally",
757
+ style: [styles$1.dim, styles$1.tally],
758
+ children: runs.length === 0 ? "no runs yet" : `${runningTally} running · ${doneTally} done · ${failedTally} failed`
759
+ })
760
+ ]
761
+ }), runs.length === 0 ? /* @__PURE__ */ jsxs(View, {
762
+ testID: "subagents-empty",
763
+ children: [
764
+ /* @__PURE__ */ jsx(Text, {
765
+ style: styles$1.bodyDim,
766
+ children: "No runs yet"
767
+ }),
768
+ /* @__PURE__ */ jsx(Text, {
769
+ style: styles$1.bodyDim,
770
+ children: "Start an agent run to get help with your work."
771
+ }),
772
+ /* @__PURE__ */ jsx(Text, {
773
+ style: [styles$1.dim, styles$1.emptyHint],
774
+ children: "Agent runs will appear here once you start one."
775
+ })
776
+ ]
777
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(View, {
778
+ testID: "subagents-grid",
779
+ style: styles$1.grid,
780
+ children: sessionId === null ? null : runs.map((run) => /* @__PURE__ */ jsx(RunCard, {
781
+ sessionId,
782
+ run,
783
+ now,
784
+ stopping: stopping(run),
785
+ renderThread,
786
+ onOpenThread: () => {
787
+ closeCatalog(sessionId);
788
+ openTransientTab(agentThreadTab(run));
789
+ },
790
+ onOpenDetail: () => {
791
+ closeCatalog(sessionId);
792
+ openRun(sessionId, run.runId);
793
+ }
794
+ }, run.runId))
795
+ }), /* @__PURE__ */ jsx(Text, {
796
+ style: styles$1.dim,
797
+ children: "tap a card to open the run's thread · the card menu holds details, stop and clear · finished runs leave the grid after 10m"
798
+ })] })]
422
799
  }),
423
- visibleRuns(state).map((run) => /* @__PURE__ */ jsx(AgentRunRow, {
424
- run,
425
- onPress: () => props.openTransientTab(agentThreadTab(run))
426
- }, run.runId)),
427
- /* @__PURE__ */ jsx(AgentCatalog, { ...props })
800
+ /* @__PURE__ */ jsx(AgentCatalog, { ...props }),
801
+ shownRun && sessionId !== null ? /* @__PURE__ */ jsx(RunDetailSheet, {
802
+ sessionId,
803
+ run: shownRun,
804
+ now,
805
+ stopping: stopping(shownRun),
806
+ renderSlot,
807
+ onClose: () => openRun(sessionId, void 0)
808
+ }) : null
428
809
  ]
429
810
  });
430
811
  }
@@ -564,135 +945,669 @@ function AgentLaunch({ sessionId, agent, models, initialTask, onClose }) {
564
945
  ]
565
946
  });
566
947
  }
948
+ /**
949
+ * The one control a run offers: stop while it is active, clear once it is not.
950
+ * Stop is a request the runtime acknowledges in its own time, so the button
951
+ * reads "stopping" until the run's own status says otherwise.
952
+ */
953
+ function RunControl({ sessionId, run, stopping }) {
954
+ const [error, setError] = useState();
955
+ if (isTerminalRun(run)) return /* @__PURE__ */ jsx(Button, {
956
+ variant: "outline",
957
+ size: "xs",
958
+ testID: `run-clear-${run.runId}`,
959
+ onPress: () => dismissRun(sessionId, run.runId),
960
+ children: "clear"
961
+ });
962
+ return /* @__PURE__ */ jsxs(Fragment, { children: [error ? /* @__PURE__ */ jsx(Text, {
963
+ accessibilityRole: "alert",
964
+ testID: `run-stop-error-${run.runId}`,
965
+ numberOfLines: 1,
966
+ style: styles$1.error,
967
+ children: error
968
+ }) : null, /* @__PURE__ */ jsx(Button, {
969
+ variant: stopping ? "outline" : "danger-outline",
970
+ size: "xs",
971
+ testID: `run-stop-${run.runId}`,
972
+ disabled: stopping,
973
+ onPress: () => {
974
+ setError(void 0);
975
+ requestRunStop(sessionId, run.runId).catch((cause) => setError(cause instanceof Error ? cause.message : String(cause)));
976
+ },
977
+ children: stopping ? "stopping…" : "stop"
978
+ })] });
979
+ }
980
+ function InfoRow({ label, children }) {
981
+ return /* @__PURE__ */ jsxs(View, {
982
+ style: styles$1.infoRow,
983
+ children: [/* @__PURE__ */ jsx(Text, {
984
+ style: [styles$1.dim, styles$1.infoLabel],
985
+ children: label
986
+ }), /* @__PURE__ */ jsx(View, {
987
+ style: styles$1.infoValue,
988
+ children
989
+ })]
990
+ });
991
+ }
992
+ /** What the run is: the agent, what it was asked, and how it thinks. Only what the runtime recorded. */
993
+ function RunInfo({ run }) {
994
+ const usage = [run?.toolCount === void 0 ? void 0 : `${run.toolCount} tools`, run?.tokens === void 0 ? void 0 : `${run.tokens.toLocaleString()} tokens`].filter(Boolean).join(" · ");
995
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
996
+ /* @__PURE__ */ jsxs(InfoRow, {
997
+ label: "Agent",
998
+ children: [
999
+ /* @__PURE__ */ jsx(Text, {
1000
+ style: styles$1.name,
1001
+ children: run?.agent ?? NOT_REPORTED
1002
+ }),
1003
+ run?.agentDescription ? /* @__PURE__ */ jsx(Text, {
1004
+ style: styles$1.bodyDim,
1005
+ children: run.agentDescription
1006
+ }) : null,
1007
+ run?.agentFilePath ? /* @__PURE__ */ jsx(Text, {
1008
+ style: styles$1.monoDim,
1009
+ children: run.agentFilePath
1010
+ }) : null
1011
+ ]
1012
+ }),
1013
+ /* @__PURE__ */ jsx(InfoRow, {
1014
+ label: "Model",
1015
+ children: /* @__PURE__ */ jsxs(Text, {
1016
+ style: styles$1.bodyText,
1017
+ children: [run?.model ?? NOT_REPORTED, run?.model && run.modelSource === "configured" ? /* @__PURE__ */ jsx(Text, {
1018
+ style: styles$1.bodyDim,
1019
+ children: " · configured, not confirmed by the runtime"
1020
+ }) : null]
1021
+ })
1022
+ }),
1023
+ /* @__PURE__ */ jsx(InfoRow, {
1024
+ label: "Thinking",
1025
+ children: /* @__PURE__ */ jsx(Text, {
1026
+ style: [styles$1.bodyText, styles$1.capitalize],
1027
+ children: run?.thinking ?? NOT_REPORTED
1028
+ })
1029
+ }),
1030
+ /* @__PURE__ */ jsx(InfoRow, {
1031
+ label: "Prompt",
1032
+ children: run?.promptWithheld ? /* @__PURE__ */ jsx(Text, {
1033
+ style: styles$1.bodyDim,
1034
+ children: "Withheld: this task was marked sensitive."
1035
+ }) : /* @__PURE__ */ jsx(ScrollView, {
1036
+ style: styles$1.prompt,
1037
+ nestedScrollEnabled: true,
1038
+ children: /* @__PURE__ */ jsx(Text, {
1039
+ style: styles$1.bodyText,
1040
+ children: run?.task || NOT_REPORTED
1041
+ })
1042
+ })
1043
+ }),
1044
+ run?.taskRef ? /* @__PURE__ */ jsx(InfoRow, {
1045
+ label: "Task",
1046
+ children: /* @__PURE__ */ jsx(Badge, {
1047
+ tone: "violet",
1048
+ size: "xs",
1049
+ children: run.taskRef
1050
+ })
1051
+ }) : null,
1052
+ /* @__PURE__ */ jsx(InfoRow, {
1053
+ label: "Folder",
1054
+ children: /* @__PURE__ */ jsx(Text, {
1055
+ style: styles$1.mono,
1056
+ children: run?.cwd ? abbreviateCwd(run.cwd) : NOT_REPORTED
1057
+ })
1058
+ }),
1059
+ /* @__PURE__ */ jsx(InfoRow, {
1060
+ label: "Usage",
1061
+ children: /* @__PURE__ */ jsx(Text, {
1062
+ style: styles$1.bodyDim,
1063
+ children: usage || NOT_REPORTED
1064
+ })
1065
+ })
1066
+ ] });
1067
+ }
1068
+ function RunChip({ dot, open, onPress, children }) {
1069
+ return /* @__PURE__ */ jsxs(Button, {
1070
+ variant: "outline",
1071
+ size: "md",
1072
+ accessibilityState: { expanded: open },
1073
+ onPress,
1074
+ style: styles$1.chip,
1075
+ children: [
1076
+ /* @__PURE__ */ jsx(Dot, {
1077
+ tone: dot,
1078
+ size: "sm"
1079
+ }),
1080
+ children,
1081
+ /* @__PURE__ */ jsx(ChevronDownIcon, { size: 14 })
1082
+ ]
1083
+ });
1084
+ }
1085
+ /**
1086
+ * A run's own conversation on the host's transcript, with its live actions.
1087
+ * The run can leave the fleet feed before the reader is done; the thread and
1088
+ * what the run last reported stay, and the panel says so.
1089
+ */
567
1090
  function AgentThreadPanel({ sessionId, runId, renderThread }) {
568
- const state = useSubagents(sessionId);
569
- const run = state.runs.find((item) => item.runId === runId);
1091
+ const { runs, stopRequested } = useSubagents(sessionId);
1092
+ const listed = runs.find((candidate) => candidate.runId === runId);
1093
+ const [seen, setSeen] = useState(listed);
1094
+ if (listed !== void 0 && listed !== seen) setSeen(listed);
1095
+ const run = listed ?? seen;
1096
+ const gone = listed === void 0;
1097
+ const now = useNow();
570
1098
  const [guidance, setGuidance] = useState("");
571
- const [busy, setBusy] = useState(false);
1099
+ const [sending, setSending] = useState(false);
1100
+ const [error, setError] = useState();
572
1101
  const [notice, setNotice] = useState();
573
- const [confirmClear, setConfirmClear] = useState(false);
574
- const act = async (action) => {
575
- setBusy(true);
1102
+ const [infoOpen, setInfoOpen] = useState(false);
1103
+ const live = sessionId !== null && listed !== void 0 && !isTerminalRun(listed);
1104
+ const stopping = stopRequested.includes(runId);
1105
+ const canSteer = live && listed.canSteer !== false;
1106
+ const submitGuidance = async () => {
1107
+ const message = guidance.trim();
1108
+ if (!canSteer || stopping || !message || sending) return;
1109
+ setSending(true);
1110
+ setError(void 0);
576
1111
  setNotice(void 0);
577
1112
  try {
578
- await action();
1113
+ const result = await steerRun(sessionId, runId, message);
1114
+ if (result.state === "failed") {
1115
+ setError(result.message);
1116
+ return;
1117
+ }
1118
+ setGuidance("");
1119
+ if (result.state === "pending") setNotice(result.message);
579
1120
  } catch (cause) {
580
- setNotice(cause instanceof Error ? cause.message : String(cause));
1121
+ setError(cause instanceof Error ? cause.message : String(cause));
581
1122
  } finally {
582
- setBusy(false);
1123
+ setSending(false);
583
1124
  }
584
1125
  };
1126
+ const who = run ? agentDisplay(run) : void 0;
1127
+ const badge = run ? RUN_BADGE[run.state] : void 0;
1128
+ const elapsed = run ? elapsedRun(gone ? {
1129
+ ...run,
1130
+ endedAt: run.endedAt ?? run.lastUpdate
1131
+ } : run, now) : void 0;
1132
+ const endNote = run && isTerminalRun(run) ? END_NOTE[run.state] : run?.canSteer === false && !gone ? "This runtime does not take guidance while it runs." : "Guidance is unavailable for this run.";
1133
+ const toggleInfo = () => setInfoOpen((current) => !current);
585
1134
  return /* @__PURE__ */ jsxs(View, {
1135
+ testID: "agent-thread-panel",
586
1136
  style: styles$1.screen,
587
1137
  children: [
588
- run ? /* @__PURE__ */ jsxs(View, {
589
- style: styles$1.body,
1138
+ /* @__PURE__ */ jsxs(View, {
1139
+ testID: "agent-thread-header",
1140
+ style: styles$1.threadHead,
590
1141
  children: [
591
- /* @__PURE__ */ jsxs(Text, {
592
- style: styles$1.title,
593
- children: [
594
- agentRunLabel(run),
595
- " · ",
596
- run.state
597
- ]
1142
+ run && who ? /* @__PURE__ */ jsx(AgentAvatar, {
1143
+ name: who.name,
1144
+ seed: who.seed,
1145
+ size: "sm"
1146
+ }) : null,
1147
+ /* @__PURE__ */ jsx(Text, {
1148
+ testID: "agent-thread-agent",
1149
+ numberOfLines: 1,
1150
+ style: styles$1.name,
1151
+ children: run ? agentRunLabel(run) : "Agent run"
598
1152
  }),
599
- /* @__PURE__ */ jsxs(Text, {
600
- style: styles$1.meta,
601
- children: [
602
- run.model,
603
- "\\n",
604
- run.task,
605
- "\\n",
606
- formatRunDuration(Math.max(0, (run.endedAt ?? run.lastUpdate) - run.startedAt))
607
- ]
1153
+ who?.role ? /* @__PURE__ */ jsx(Text, {
1154
+ numberOfLines: 1,
1155
+ style: styles$1.dim,
1156
+ children: who.role
1157
+ }) : null,
1158
+ badge && run ? /* @__PURE__ */ jsx(StatusBadge, {
1159
+ tone: badge.tone,
1160
+ testID: "agent-thread-state",
1161
+ children: stopping && !isTerminalRun(run) ? "STOPPING…" : badge.label
1162
+ }) : null,
1163
+ /* @__PURE__ */ jsx(Text, {
1164
+ numberOfLines: 1,
1165
+ style: [styles$1.dim, styles$1.grow],
1166
+ children: elapsed
608
1167
  }),
609
- sessionId !== null ? isTerminalRun(run) ? /* @__PURE__ */ jsx(Button, {
610
- variant: "outline",
611
- onPress: () => setConfirmClear(true),
612
- children: "Clear run"
613
- }) : /* @__PURE__ */ jsx(Button, {
614
- variant: "danger-outline",
615
- disabled: busy || state.stopRequested.includes(runId),
616
- onPress: () => void act(() => requestRunStop(sessionId, runId)),
617
- children: state.stopRequested.includes(runId) ? "Stopping…" : "Stop"
1168
+ live ? /* @__PURE__ */ jsx(RunControl, {
1169
+ sessionId,
1170
+ run: listed,
1171
+ stopping
618
1172
  }) : null
619
1173
  ]
620
- }) : /* @__PURE__ */ jsx(Text, {
621
- style: styles$1.meta,
622
- children: "This run is no longer listed; its transcript stays readable."
623
1174
  }),
1175
+ gone ? /* @__PURE__ */ jsx(Text, {
1176
+ testID: "agent-thread-gone",
1177
+ style: [styles$1.dim, styles$1.gone],
1178
+ children: "This run is no longer listed. Its thread stays readable."
1179
+ }) : null,
624
1180
  /* @__PURE__ */ jsx(View, {
625
1181
  style: styles$1.transcript,
626
1182
  children: renderThread(runId)
627
1183
  }),
628
- run && sessionId !== null && !isTerminalRun(run) ? /* @__PURE__ */ jsxs(View, {
629
- style: styles$1.body,
630
- children: [/* @__PURE__ */ jsx(Textarea, {
631
- accessibilityLabel: "Steering guidance",
632
- value: guidance,
633
- onChangeText: setGuidance,
634
- placeholder: "Guide this agent…"
635
- }), /* @__PURE__ */ jsx(Button, {
636
- disabled: busy || guidance.trim() === "",
637
- onPress: () => void act(async () => {
638
- const result = await steerRun(sessionId, runId, guidance.trim());
639
- setNotice(result.message);
640
- if (result.state !== "failed") setGuidance("");
641
- }),
642
- children: "Send guidance"
643
- })]
644
- }) : null,
645
- notice ? /* @__PURE__ */ jsx(Text, {
646
- style: styles$1.meta,
647
- children: notice
1184
+ infoOpen ? /* @__PURE__ */ jsx(ScrollView, {
1185
+ accessibilityLabel: "Run info",
1186
+ testID: "run-info",
1187
+ style: styles$1.info,
1188
+ contentContainerStyle: styles$1.infoBody,
1189
+ children: /* @__PURE__ */ jsx(RunInfo, { run })
648
1190
  }) : null,
649
- /* @__PURE__ */ jsx(Sheet, {
650
- open: confirmClear,
651
- onOpenChange: setConfirmClear,
652
- children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: "Clear this run?" }) }), /* @__PURE__ */ jsxs(SheetBody, { children: [/* @__PURE__ */ jsx(Text, {
653
- style: styles$1.meta,
654
- children: "This hides the finished run. Its transcript stays on disk."
655
- }), /* @__PURE__ */ jsx(Button, {
656
- variant: "danger-outline",
657
- onPress: () => {
658
- if (sessionId !== null) dismissRun(sessionId, runId);
659
- setConfirmClear(false);
660
- },
661
- children: "Clear"
662
- })] })] })
1191
+ canSteer ? /* @__PURE__ */ jsx(View, {
1192
+ testID: "agent-steer-composer",
1193
+ style: styles$1.composerWrap,
1194
+ children: /* @__PURE__ */ jsxs(View, {
1195
+ style: styles$1.composer,
1196
+ children: [
1197
+ /* @__PURE__ */ jsx(Textarea, {
1198
+ variant: "bare",
1199
+ testID: "agent-steer-input",
1200
+ accessibilityLabel: "Steering guidance",
1201
+ rows: 2,
1202
+ value: guidance,
1203
+ readOnly: sending,
1204
+ disabled: stopping,
1205
+ placeholder: stopping ? "Stopping, guidance paused" : "Guide this agent · it reads this at its next step",
1206
+ style: styles$1.composerInput,
1207
+ onChangeText: setGuidance
1208
+ }),
1209
+ error ? /* @__PURE__ */ jsx(Text, {
1210
+ accessibilityRole: "alert",
1211
+ testID: "agent-steer-error",
1212
+ style: [styles$1.error, styles$1.composerPad],
1213
+ children: error
1214
+ }) : null,
1215
+ /* @__PURE__ */ jsxs(View, {
1216
+ style: styles$1.composerFoot,
1217
+ children: [/* @__PURE__ */ jsx(Text, {
1218
+ testID: "agent-steer-hint",
1219
+ numberOfLines: 1,
1220
+ style: [styles$1.dim, styles$1.grow],
1221
+ children: notice
1222
+ }), /* @__PURE__ */ jsxs(Button, {
1223
+ testID: "agent-steer-submit",
1224
+ variant: "primary",
1225
+ size: "lg",
1226
+ disabled: stopping || sending || guidance.trim() === "",
1227
+ onPress: () => void submitGuidance(),
1228
+ children: [/* @__PURE__ */ jsx(SendIcon, { size: 16 }), sending ? "Sending…" : "Send"]
1229
+ })]
1230
+ })
1231
+ ]
1232
+ })
1233
+ }) : /* @__PURE__ */ jsx(Text, {
1234
+ testID: "agent-thread-end",
1235
+ style: [styles$1.dim, styles$1.end],
1236
+ children: endNote
1237
+ }),
1238
+ /* @__PURE__ */ jsxs(View, {
1239
+ style: styles$1.chips,
1240
+ children: [
1241
+ /* @__PURE__ */ jsx(RunChip, {
1242
+ dot: "magenta",
1243
+ open: infoOpen,
1244
+ onPress: toggleInfo,
1245
+ children: run?.agent ?? "Agent"
1246
+ }),
1247
+ /* @__PURE__ */ jsxs(RunChip, {
1248
+ dot: "green",
1249
+ open: infoOpen,
1250
+ onPress: toggleInfo,
1251
+ children: [run?.model ? run.model.split("/").pop() ?? run.model : "Model not reported", run?.thinking ? /* @__PURE__ */ jsxs(Text, {
1252
+ style: styles$1.dim,
1253
+ children: [" ", run.thinking]
1254
+ }) : null]
1255
+ }),
1256
+ /* @__PURE__ */ jsx(RunChip, {
1257
+ dot: "blue",
1258
+ open: infoOpen,
1259
+ onPress: toggleInfo,
1260
+ children: "Prompt"
1261
+ })
1262
+ ]
663
1263
  })
664
1264
  ]
665
1265
  });
666
1266
  }
667
- const styles$1 = StyleSheet.create((theme) => ({
668
- screen: {
669
- flex: 1,
670
- backgroundColor: theme.colors.bg,
671
- uni__dependencies: [0]
672
- },
673
- transcript: { flex: 1 },
674
- body: {
675
- padding: theme.spacing(3),
676
- gap: theme.spacing(2),
677
- uni__dependencies: [0]
678
- },
679
- title: {
680
- color: theme.colors.hi,
681
- fontSize: theme.fontSize.base,
682
- fontWeight: "600",
683
- uni__dependencies: [0]
684
- },
685
- meta: {
686
- color: theme.colors.dim,
1267
+ /** `px-[26px]`: the cockpit's gutter. */
1268
+ const GUTTER = 26;
1269
+ const styles$1 = StyleSheet.create((theme) => {
1270
+ const sans = fontOf(theme.fontFamily.sans);
1271
+ const mono = fontOf(theme.fontFamily.mono);
1272
+ const sm = {
1273
+ fontFamily: sans,
687
1274
  fontSize: theme.fontSize.sm,
688
- uni__dependencies: [0]
689
- },
690
- error: {
691
- color: theme.colors.red,
692
- fontSize: theme.fontSize.sm,
693
- uni__dependencies: [0]
694
- }
695
- }));
1275
+ lineHeight: theme.lineHeight.sm
1276
+ };
1277
+ const base = {
1278
+ fontFamily: sans,
1279
+ fontSize: theme.fontSize.base,
1280
+ lineHeight: theme.lineHeight.base
1281
+ };
1282
+ return {
1283
+ screen: {
1284
+ flex: 1,
1285
+ backgroundColor: theme.colors.bg,
1286
+ uni__dependencies: [0]
1287
+ },
1288
+ transcript: {
1289
+ flex: 1,
1290
+ minHeight: 0
1291
+ },
1292
+ body: {
1293
+ padding: theme.spacing(3),
1294
+ gap: theme.spacing(2),
1295
+ uni__dependencies: [0]
1296
+ },
1297
+ grow: {
1298
+ flex: 1,
1299
+ minWidth: 0
1300
+ },
1301
+ spacer: { flex: 1 },
1302
+ title: {
1303
+ color: theme.colors.hi,
1304
+ fontSize: theme.fontSize.base,
1305
+ fontWeight: "600",
1306
+ uni__dependencies: [0]
1307
+ },
1308
+ meta: {
1309
+ color: theme.colors.dim,
1310
+ fontSize: theme.fontSize.sm,
1311
+ uni__dependencies: [0]
1312
+ },
1313
+ dim: {
1314
+ ...sm,
1315
+ color: theme.colors.dim,
1316
+ flexShrink: 1,
1317
+ uni__dependencies: [0]
1318
+ },
1319
+ error: {
1320
+ ...sm,
1321
+ color: theme.colors.red,
1322
+ flexShrink: 1,
1323
+ uni__dependencies: [0]
1324
+ },
1325
+ name: {
1326
+ ...base,
1327
+ fontWeight: theme.fontWeight.semibold,
1328
+ color: theme.colors.hi,
1329
+ flexShrink: 1,
1330
+ uni__dependencies: [0]
1331
+ },
1332
+ bodyText: {
1333
+ ...base,
1334
+ color: theme.colors.text,
1335
+ uni__dependencies: [0]
1336
+ },
1337
+ bodyDim: {
1338
+ ...base,
1339
+ color: theme.colors.dim,
1340
+ uni__dependencies: [0]
1341
+ },
1342
+ bodyRed: {
1343
+ ...base,
1344
+ color: theme.colors.red,
1345
+ uni__dependencies: [0]
1346
+ },
1347
+ violet: {
1348
+ ...base,
1349
+ color: theme.colors.violet,
1350
+ uni__dependencies: [0]
1351
+ },
1352
+ mono: {
1353
+ fontFamily: mono,
1354
+ fontSize: theme.fontSize.sm,
1355
+ lineHeight: theme.lineHeight.sm,
1356
+ color: theme.colors.text,
1357
+ uni__dependencies: [0]
1358
+ },
1359
+ monoDim: {
1360
+ fontFamily: mono,
1361
+ fontSize: theme.fontSize.sm,
1362
+ lineHeight: theme.lineHeight.sm,
1363
+ color: theme.colors.dim,
1364
+ uni__dependencies: [0]
1365
+ },
1366
+ capitalize: { textTransform: "capitalize" },
1367
+ fleet: {
1368
+ padding: theme.spacing(3),
1369
+ gap: theme.spacing(3),
1370
+ uni__dependencies: [0]
1371
+ },
1372
+ fleetHead: {
1373
+ flexDirection: "row",
1374
+ flexWrap: "wrap",
1375
+ alignItems: "center",
1376
+ columnGap: theme.spacing(3),
1377
+ rowGap: theme.spacing(2),
1378
+ uni__dependencies: [0]
1379
+ },
1380
+ heading: {
1381
+ fontFamily: sans,
1382
+ fontSize: theme.fontSize.lg,
1383
+ lineHeight: theme.lineHeight.lg,
1384
+ fontWeight: theme.fontWeight.semibold,
1385
+ color: theme.colors.hi,
1386
+ uni__dependencies: [0]
1387
+ },
1388
+ launch: { marginLeft: "auto" },
1389
+ tally: { width: "100%" },
1390
+ emptyHint: {
1391
+ paddingVertical: theme.spacing(32),
1392
+ textAlign: "center",
1393
+ uni__dependencies: [0]
1394
+ },
1395
+ grid: {
1396
+ gap: theme.spacing(4),
1397
+ uni__dependencies: [0]
1398
+ },
1399
+ card: (edge) => ({
1400
+ height: 280,
1401
+ overflow: "hidden",
1402
+ borderColor: theme.colors[edge],
1403
+ uni__dependencies: [0]
1404
+ }),
1405
+ cardOpen: {
1406
+ flex: 1,
1407
+ minHeight: 0
1408
+ },
1409
+ cardHead: {
1410
+ flexDirection: "row",
1411
+ alignItems: "center",
1412
+ gap: theme.spacing(2),
1413
+ paddingHorizontal: theme.spacing(3),
1414
+ paddingTop: theme.spacing(2.5),
1415
+ paddingBottom: theme.spacing(1.5),
1416
+ uni__dependencies: [0]
1417
+ },
1418
+ work: {
1419
+ flexDirection: "row",
1420
+ alignItems: "center",
1421
+ gap: theme.spacing(2),
1422
+ paddingHorizontal: theme.spacing(3),
1423
+ paddingBottom: theme.spacing(2.5),
1424
+ uni__dependencies: [0]
1425
+ },
1426
+ workLabel: {
1427
+ ...base,
1428
+ fontWeight: theme.fontWeight.medium,
1429
+ color: theme.colors.dim,
1430
+ uni__dependencies: [0]
1431
+ },
1432
+ workHi: {
1433
+ ...base,
1434
+ color: theme.colors.hi,
1435
+ flexShrink: 1,
1436
+ uni__dependencies: [0]
1437
+ },
1438
+ workDim: {
1439
+ ...base,
1440
+ color: theme.colors.dim,
1441
+ flexShrink: 1,
1442
+ uni__dependencies: [0]
1443
+ },
1444
+ stream: {
1445
+ flex: 1,
1446
+ minHeight: 0,
1447
+ overflow: "hidden",
1448
+ borderTopWidth: 1,
1449
+ borderTopColor: theme.colors["border-soft"],
1450
+ backgroundColor: theme.colors.deep,
1451
+ uni__dependencies: [0]
1452
+ },
1453
+ cardError: {
1454
+ borderTopWidth: 1,
1455
+ borderTopColor: theme.colors["border-soft"],
1456
+ paddingHorizontal: theme.spacing(3),
1457
+ paddingVertical: theme.spacing(1.5),
1458
+ uni__dependencies: [0]
1459
+ },
1460
+ cardFoot: {
1461
+ flexDirection: "row",
1462
+ alignItems: "center",
1463
+ gap: theme.spacing(3),
1464
+ borderTopWidth: 1,
1465
+ borderTopColor: theme.colors["border-soft"],
1466
+ paddingHorizontal: theme.spacing(3),
1467
+ paddingVertical: theme.spacing(1.5),
1468
+ uni__dependencies: [0]
1469
+ },
1470
+ sheetRows: {
1471
+ gap: theme.spacing(1.5),
1472
+ uni__dependencies: [0]
1473
+ },
1474
+ sheetRow: {
1475
+ flexDirection: "row",
1476
+ gap: theme.spacing(2.5),
1477
+ uni__dependencies: [0]
1478
+ },
1479
+ sheetRowLabel: {
1480
+ width: 44,
1481
+ flexShrink: 0
1482
+ },
1483
+ sheetBlock: {
1484
+ gap: theme.spacing(1),
1485
+ borderRadius: theme.borderRadius.md,
1486
+ borderWidth: 1,
1487
+ borderColor: theme.colors.border,
1488
+ backgroundColor: theme.colors.deep,
1489
+ paddingHorizontal: theme.spacing(3),
1490
+ paddingVertical: theme.spacing(2.5),
1491
+ uni__dependencies: [0]
1492
+ },
1493
+ sheetBlockLabel: {
1494
+ ...base,
1495
+ fontWeight: theme.fontWeight.medium,
1496
+ color: theme.colors.dim,
1497
+ uni__dependencies: [0]
1498
+ },
1499
+ threadHead: {
1500
+ flexDirection: "row",
1501
+ alignItems: "center",
1502
+ gap: theme.spacing(2.5),
1503
+ height: 44,
1504
+ paddingHorizontal: GUTTER,
1505
+ borderBottomWidth: 1,
1506
+ borderBottomColor: theme.colors["border-soft"],
1507
+ backgroundColor: theme.colors.rail,
1508
+ uni__dependencies: [0]
1509
+ },
1510
+ gone: {
1511
+ paddingHorizontal: GUTTER,
1512
+ paddingVertical: theme.spacing(2),
1513
+ borderBottomWidth: 1,
1514
+ borderBottomColor: theme.colors["border-soft"],
1515
+ uni__dependencies: [0]
1516
+ },
1517
+ info: {
1518
+ marginHorizontal: GUTTER,
1519
+ marginBottom: theme.spacing(2),
1520
+ maxHeight: "40%",
1521
+ flexGrow: 0,
1522
+ borderRadius: theme.borderRadius.lg,
1523
+ borderWidth: 1,
1524
+ borderColor: theme.colors.border,
1525
+ backgroundColor: theme.colors.panel,
1526
+ uni__dependencies: [0]
1527
+ },
1528
+ infoBody: {
1529
+ gap: theme.spacing(3),
1530
+ paddingHorizontal: theme.spacing(4),
1531
+ paddingVertical: theme.spacing(3),
1532
+ uni__dependencies: [0]
1533
+ },
1534
+ infoRow: {
1535
+ flexDirection: "row",
1536
+ gap: theme.spacing(3),
1537
+ uni__dependencies: [0]
1538
+ },
1539
+ infoLabel: {
1540
+ width: 96,
1541
+ flexShrink: 0
1542
+ },
1543
+ infoValue: {
1544
+ flex: 1,
1545
+ minWidth: 0
1546
+ },
1547
+ prompt: {
1548
+ maxHeight: 160,
1549
+ borderRadius: theme.borderRadius.md,
1550
+ backgroundColor: theme.colors.deep,
1551
+ paddingHorizontal: theme.spacing(3),
1552
+ paddingVertical: theme.spacing(2),
1553
+ uni__dependencies: [0]
1554
+ },
1555
+ composerWrap: {
1556
+ paddingHorizontal: GUTTER,
1557
+ paddingTop: theme.spacing(2),
1558
+ paddingBottom: theme.spacing(2),
1559
+ uni__dependencies: [0]
1560
+ },
1561
+ composer: {
1562
+ borderRadius: theme.borderRadius.lg,
1563
+ borderWidth: 1,
1564
+ borderColor: theme.colors.border,
1565
+ backgroundColor: theme.colors.panel,
1566
+ uni__dependencies: [0]
1567
+ },
1568
+ composerInput: {
1569
+ paddingHorizontal: theme.spacing(4),
1570
+ paddingTop: theme.spacing(3),
1571
+ fontSize: theme.fontSize.lg,
1572
+ lineHeight: theme.lineHeightRelaxed.lg,
1573
+ uni__dependencies: [0]
1574
+ },
1575
+ composerPad: {
1576
+ paddingHorizontal: theme.spacing(4),
1577
+ paddingTop: theme.spacing(1),
1578
+ uni__dependencies: [0]
1579
+ },
1580
+ composerFoot: {
1581
+ flexDirection: "row",
1582
+ alignItems: "center",
1583
+ gap: theme.spacing(3),
1584
+ paddingHorizontal: theme.spacing(4),
1585
+ paddingTop: theme.spacing(1),
1586
+ paddingBottom: theme.spacing(3),
1587
+ uni__dependencies: [0]
1588
+ },
1589
+ end: {
1590
+ paddingHorizontal: GUTTER,
1591
+ paddingTop: theme.spacing(3),
1592
+ paddingBottom: theme.spacing(2),
1593
+ uni__dependencies: [0]
1594
+ },
1595
+ chips: {
1596
+ flexDirection: "row",
1597
+ flexWrap: "wrap",
1598
+ alignItems: "center",
1599
+ gap: theme.spacing(2),
1600
+ paddingHorizontal: GUTTER,
1601
+ paddingBottom: theme.spacing(4),
1602
+ uni__dependencies: [0]
1603
+ },
1604
+ chip: {
1605
+ maxWidth: "100%",
1606
+ gap: theme.spacing(2),
1607
+ uni__dependencies: [0]
1608
+ }
1609
+ };
1610
+ });
696
1611
  //#endregion
697
1612
  //#region src/extensions/workspaces/sessions/(frontend)/activity-group/agents.native.ts
698
1613
  var agents_native_default = defineActivityGroup({
@@ -719,14 +1634,35 @@ var subagent_catalog_native_default = defineChannelFile(subagentCatalogChannel);
719
1634
  var subagent_runs_native_default = defineChannelFile(subagentRunsChannel);
720
1635
  //#endregion
721
1636
  //#region src/extensions/workspaces/sessions/(frontend)/fill/_components/AgentsActivitySection.native.tsx
1637
+ const TICK_MS = 1e4;
1638
+ const AVATAR_STATE = {
1639
+ queued: "waiting",
1640
+ running: "running",
1641
+ done: "done",
1642
+ failed: "failed",
1643
+ stopped: "done"
1644
+ };
1645
+ function elapsed(run, now) {
1646
+ const end = run.endedAt ?? (isTerminalRun(run) ? run.lastUpdate : now);
1647
+ return formatRunDuration(Math.max(0, end - run.startedAt));
1648
+ }
1649
+ /** The one-liner under a row: what the run is doing, or how it ended. */
1650
+ function detail(run) {
1651
+ if (run.state === "failed" && run.error) return run.error;
1652
+ if (run.summary) return run.summary.split("\n").find((line) => line.trim() !== "") ?? "";
1653
+ return run.currentTool ?? run.tail.at(-1) ?? (run.state === "running" ? "" : run.state);
1654
+ }
722
1655
  function AgentsActivitySection({ sessionId, openTransientTab }) {
723
1656
  const runs = activityRuns(useSubagents(sessionId));
724
- return /* @__PURE__ */ jsxs(View, { children: [runs.map((run) => /* @__PURE__ */ jsx(AgentRunRow, {
725
- run,
726
- onPress: () => openTransientTab(agentThreadTab(run))
727
- }, run.runId)), runs.length === 0 ? /* @__PURE__ */ jsxs(View, {
1657
+ const [now, setNow] = useState(() => Date.now());
1658
+ useEffect(() => {
1659
+ const timer = setInterval(() => setNow(Date.now()), TICK_MS);
1660
+ return () => clearInterval(timer);
1661
+ }, []);
1662
+ if (runs.length === 0) return /* @__PURE__ */ jsxs(View, {
728
1663
  style: styles.idle,
729
1664
  children: [/* @__PURE__ */ jsx(Text, {
1665
+ testID: "activity-summary-agents",
730
1666
  style: styles.status,
731
1667
  children: "Idle"
732
1668
  }), /* @__PURE__ */ jsxs(Pressable, {
@@ -750,38 +1686,139 @@ function AgentsActivitySection({ sessionId, openTransientTab }) {
750
1686
  color: sessionId === null ? "dim" : "green"
751
1687
  })]
752
1688
  })]
753
- }) : null] });
754
- }
755
- const styles = StyleSheet.create((theme) => ({
756
- idle: {
757
- flexDirection: "row",
758
- alignItems: "center",
759
- flexWrap: "wrap",
760
- gap: theme.spacing(4),
761
- uni__dependencies: [0]
762
- },
763
- status: {
1689
+ });
1690
+ return /* @__PURE__ */ jsx(View, {
1691
+ testID: "activity-agent-runs",
1692
+ style: styles.runs,
1693
+ children: runs.map((run) => {
1694
+ const who = agentDisplay(run);
1695
+ const description = detail(run);
1696
+ return /* @__PURE__ */ jsx(Button, {
1697
+ variant: "ghost",
1698
+ size: "card",
1699
+ testID: `activity-run-${run.runId}`,
1700
+ accessibilityLabel: `Open ${who.name}'s conversation`,
1701
+ onPress: () => {
1702
+ if (sessionId !== null) openTransientTab(agentThreadTab(run));
1703
+ },
1704
+ style: styles.run,
1705
+ children: /* @__PURE__ */ jsxs(View, {
1706
+ style: styles.line,
1707
+ children: [
1708
+ /* @__PURE__ */ jsx(AgentAvatar, {
1709
+ name: who.name,
1710
+ seed: who.seed,
1711
+ state: AVATAR_STATE[run.state],
1712
+ size: "sm"
1713
+ }),
1714
+ /* @__PURE__ */ jsxs(View, {
1715
+ style: styles.text,
1716
+ children: [/* @__PURE__ */ jsxs(View, {
1717
+ style: styles.who,
1718
+ children: [/* @__PURE__ */ jsx(Text, {
1719
+ numberOfLines: 1,
1720
+ style: styles.name,
1721
+ children: who.name
1722
+ }), who.role ? /* @__PURE__ */ jsx(Text, {
1723
+ numberOfLines: 1,
1724
+ style: styles.dim,
1725
+ children: who.role
1726
+ }) : null]
1727
+ }), description ? /* @__PURE__ */ jsx(Text, {
1728
+ numberOfLines: 1,
1729
+ style: run.state === "failed" ? styles.failed : styles.dim,
1730
+ children: description
1731
+ }) : null]
1732
+ }),
1733
+ /* @__PURE__ */ jsxs(Text, {
1734
+ style: styles.dim,
1735
+ children: [elapsed(run, now), run.toolCount !== void 0 ? ` · ${run.toolCount} tools` : ""]
1736
+ })
1737
+ ]
1738
+ })
1739
+ }, run.runId);
1740
+ })
1741
+ });
1742
+ }
1743
+ const styles = StyleSheet.create((theme) => {
1744
+ const small = {
764
1745
  fontFamily: fontOf(theme.fontFamily.sans),
765
1746
  fontSize: theme.fontSize.sm,
766
- lineHeight: theme.lineHeight.sm,
767
- color: theme.colors.dim,
768
- uni__dependencies: [0]
769
- },
770
- action: {
771
- flexDirection: "row",
772
- alignItems: "center",
773
- gap: theme.spacing(1),
774
- uni__dependencies: [0]
775
- },
776
- actionText: (disabled) => ({
777
- fontFamily: fontOf(theme.fontFamily.sans),
778
- fontSize: theme.fontSize.base,
779
- lineHeight: theme.lineHeight.base,
780
- fontWeight: theme.fontWeight.medium,
781
- color: disabled ? theme.colors.dim : theme.colors.green,
782
- uni__dependencies: [0]
783
- })
784
- }));
1747
+ lineHeight: theme.lineHeight.sm
1748
+ };
1749
+ return {
1750
+ idle: {
1751
+ flexDirection: "row",
1752
+ alignItems: "center",
1753
+ flexWrap: "wrap",
1754
+ gap: theme.spacing(4),
1755
+ uni__dependencies: [0]
1756
+ },
1757
+ status: {
1758
+ ...small,
1759
+ color: theme.colors.dim,
1760
+ uni__dependencies: [0]
1761
+ },
1762
+ action: {
1763
+ flexDirection: "row",
1764
+ alignItems: "center",
1765
+ gap: theme.spacing(1),
1766
+ uni__dependencies: [0]
1767
+ },
1768
+ actionText: (disabled) => ({
1769
+ fontFamily: fontOf(theme.fontFamily.sans),
1770
+ fontSize: theme.fontSize.base,
1771
+ lineHeight: theme.lineHeight.base,
1772
+ fontWeight: theme.fontWeight.medium,
1773
+ color: disabled ? theme.colors.dim : theme.colors.green,
1774
+ uni__dependencies: [0]
1775
+ }),
1776
+ runs: { gap: 2 },
1777
+ run: {
1778
+ paddingHorizontal: theme.spacing(1),
1779
+ paddingVertical: theme.spacing(1),
1780
+ uni__dependencies: [0]
1781
+ },
1782
+ line: {
1783
+ flexDirection: "row",
1784
+ alignItems: "center",
1785
+ gap: theme.spacing(2),
1786
+ minWidth: 0,
1787
+ uni__dependencies: [0]
1788
+ },
1789
+ text: {
1790
+ flex: 1,
1791
+ minWidth: 0
1792
+ },
1793
+ who: {
1794
+ flexDirection: "row",
1795
+ alignItems: "baseline",
1796
+ gap: theme.spacing(1.5),
1797
+ minWidth: 0,
1798
+ uni__dependencies: [0]
1799
+ },
1800
+ name: {
1801
+ fontFamily: fontOf(theme.fontFamily.sans),
1802
+ fontSize: theme.fontSize.base,
1803
+ lineHeight: theme.lineHeight.base,
1804
+ fontWeight: theme.fontWeight.semibold,
1805
+ color: theme.colors.hi,
1806
+ flexShrink: 1,
1807
+ uni__dependencies: [0]
1808
+ },
1809
+ dim: {
1810
+ ...small,
1811
+ color: theme.colors.dim,
1812
+ flexShrink: 1,
1813
+ uni__dependencies: [0]
1814
+ },
1815
+ failed: {
1816
+ ...small,
1817
+ color: theme.colors.red,
1818
+ uni__dependencies: [0]
1819
+ }
1820
+ };
1821
+ });
785
1822
  //#endregion
786
1823
  //#region src/extensions/workspaces/sessions/(frontend)/fill/Agents.activity.agents.native.tsx
787
1824
  var Agents_activity_agents_native_default = defineFill({ component: AgentsActivitySection });