@agimon-ai/po-team 0.0.0-alpha.22 → 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,11 +1,12 @@
1
- import { createApiClient, defineActivityGroup, defineApiRoutes, defineChannelFile, defineFill, defineNativePlugin, defineSessionStore, nativeApiTransport, sessionApiAddress } from "@agimon-ai/po-core/native";
2
- import { Badge, Button, Dot, Input, ListRow, SegmentedControl, Sheet, SheetBody, SheetContent, SheetHeader, SheetTitle, Textarea, UsersIcon } 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";
6
+ import { ScrollView } from "react-native-unistyles/components/native/ScrollView";
7
+ import { Pressable } from "react-native-unistyles/components/native/Pressable";
7
8
  import { StyleSheet } from "react-native-unistyles";
8
- import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
10
  //#region src/extensions/workspaces/(frontend)/fill/Team.home.native.ts
10
11
  var Team_home_native_default = defineFill({ data: {
11
12
  version: 1,
@@ -208,6 +209,11 @@ function formatRunDuration(elapsedMs) {
208
209
  const minutes = Math.floor(elapsedMs % HOUR_MS / MINUTE_MS);
209
210
  return `${hours}h ${String(minutes).padStart(2, "0")}m`;
210
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
+ }
211
217
  /** What to call a run on screen: the identity's first name, else the agent name. Never a run id. */
212
218
  function agentRunLabel(run) {
213
219
  return agentDisplay(run).name;
@@ -264,6 +270,10 @@ function agentMeta(agent) {
264
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"}`;
265
271
  }
266
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
267
277
  //#region src/extensions/workspaces/sessions/(frontend)/_lib/subagentsStore.native.ts
268
278
  const TERMINAL_STATES = /* @__PURE__ */ new Set([
269
279
  "done",
@@ -341,6 +351,18 @@ function clearPendingLaunch(sessionId) {
341
351
  pendingLaunch: void 0
342
352
  }));
343
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
+ }
344
366
  /** The plugin's session data channel: 'subagent_runs' payloads into the store. */
345
367
  const subagentRunsChannel = subagents.channel({
346
368
  channel: SUBAGENT_RUNS_TYPE,
@@ -368,6 +390,38 @@ const subagentRunsChannel = subagents.channel({
368
390
  });
369
391
  //#endregion
370
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
+ };
371
425
  function useSubagents(sessionId) {
372
426
  const subscribe = useCallback((listener) => {
373
427
  const sub = subagents.store.subscribe(listener);
@@ -375,10 +429,23 @@ function useSubagents(sessionId) {
375
429
  }, []);
376
430
  return useSyncExternalStore(subscribe, () => subagents.select(subagents.store.state, sessionId));
377
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
+ }
378
445
  function subagentsTab() {
379
446
  return {
380
447
  id: "subagents",
381
- label: "agents",
448
+ label: "Agents",
382
449
  panel: SubagentsPanel
383
450
  };
384
451
  }
@@ -390,40 +457,355 @@ function agentThreadTab(run) {
390
457
  panel: (props) => /* @__PURE__ */ jsx(AgentThreadPanel, {
391
458
  ...props,
392
459
  runId
393
- })
460
+ }, `${props.sessionId}:${runId}`)
394
461
  };
395
462
  }
396
- function AgentRunRow({ run, onPress }) {
397
- const detail = run.error ?? run.summary?.split("\n").find((line) => line.trim() !== "") ?? run.currentTool ?? run.tail.at(-1) ?? run.state;
398
- return /* @__PURE__ */ jsx(ListRow, {
399
- leading: /* @__PURE__ */ jsx(Dot, { tone: run.state === "failed" ? "red" : run.state === "running" ? "yellow" : run.state === "done" ? "green" : "muted" }),
400
- title: /* @__PURE__ */ jsx(Button, {
401
- variant: "ghost",
402
- onPress,
403
- testID: `activity-run-${run.runId}`,
404
- 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"
405
510
  }),
406
- description: detail,
407
- 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
+ })]
408
619
  });
409
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
+ ] })] })
706
+ });
707
+ }
708
+ /** The subagents tab: the focused session's fleet, one card per run. */
410
709
  function SubagentsPanel(props) {
411
- const state = useSubagents(props.sessionId);
412
- return /* @__PURE__ */ jsxs(ScrollView, {
413
- contentContainerStyle: styles.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,
414
734
  children: [
415
- /* @__PURE__ */ jsx(Button, {
416
- testID: "activity-agents-launch",
417
- onPress: () => {
418
- if (props.sessionId !== null) openCatalog(props.sessionId);
419
- },
420
- 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
+ })] })]
421
799
  }),
422
- visibleRuns(state).map((run) => /* @__PURE__ */ jsx(AgentRunRow, {
423
- run,
424
- onPress: () => props.openTransientTab(agentThreadTab(run))
425
- }, run.runId)),
426
- /* @__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
427
809
  ]
428
810
  });
429
811
  }
@@ -457,7 +839,7 @@ function AgentCatalog({ sessionId }) {
457
839
  setAgent(void 0);
458
840
  }
459
841
  }, agent.name) : /* @__PURE__ */ jsxs(View, {
460
- style: styles.body,
842
+ style: styles$1.body,
461
843
  children: [
462
844
  /* @__PURE__ */ jsx(Input, {
463
845
  accessibilityLabel: "Filter agents",
@@ -466,11 +848,11 @@ function AgentCatalog({ sessionId }) {
466
848
  onChangeText: setFilter
467
849
  }),
468
850
  state.loading ? /* @__PURE__ */ jsx(Text, {
469
- style: styles.meta,
851
+ style: styles$1.meta,
470
852
  children: "Loading agents…"
471
853
  }) : null,
472
854
  state.warning ? /* @__PURE__ */ jsx(Text, {
473
- style: styles.error,
855
+ style: styles$1.error,
474
856
  children: state.warning
475
857
  }) : null,
476
858
  filterCatalog(state.agents, filter).map((item) => /* @__PURE__ */ jsx(ListRow, {
@@ -512,10 +894,10 @@ function AgentLaunch({ sessionId, agent, models, initialTask, onClose }) {
512
894
  }
513
895
  };
514
896
  return /* @__PURE__ */ jsxs(View, {
515
- style: styles.body,
897
+ style: styles$1.body,
516
898
  children: [
517
899
  /* @__PURE__ */ jsx(Text, {
518
- style: styles.meta,
900
+ style: styles$1.meta,
519
901
  children: agent.description
520
902
  }),
521
903
  /* @__PURE__ */ jsx(Textarea, {
@@ -536,7 +918,7 @@ function AgentLaunch({ sessionId, agent, models, initialTask, onClose }) {
536
918
  }]
537
919
  }),
538
920
  /* @__PURE__ */ jsx(Text, {
539
- style: styles.meta,
921
+ style: styles$1.meta,
540
922
  children: "Model"
541
923
  }),
542
924
  /* @__PURE__ */ jsxs(Button, {
@@ -551,7 +933,7 @@ function AgentLaunch({ sessionId, agent, models, initialTask, onClose }) {
551
933
  children: choice
552
934
  }, choice)),
553
935
  error ? /* @__PURE__ */ jsx(Text, {
554
- style: styles.error,
936
+ style: styles$1.error,
555
937
  children: error
556
938
  }) : null,
557
939
  /* @__PURE__ */ jsx(Button, {
@@ -563,135 +945,669 @@ function AgentLaunch({ sessionId, agent, models, initialTask, onClose }) {
563
945
  ]
564
946
  });
565
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
+ */
566
1090
  function AgentThreadPanel({ sessionId, runId, renderThread }) {
567
- const state = useSubagents(sessionId);
568
- 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();
569
1098
  const [guidance, setGuidance] = useState("");
570
- const [busy, setBusy] = useState(false);
1099
+ const [sending, setSending] = useState(false);
1100
+ const [error, setError] = useState();
571
1101
  const [notice, setNotice] = useState();
572
- const [confirmClear, setConfirmClear] = useState(false);
573
- const act = async (action) => {
574
- 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);
575
1111
  setNotice(void 0);
576
1112
  try {
577
- 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);
578
1120
  } catch (cause) {
579
- setNotice(cause instanceof Error ? cause.message : String(cause));
1121
+ setError(cause instanceof Error ? cause.message : String(cause));
580
1122
  } finally {
581
- setBusy(false);
1123
+ setSending(false);
582
1124
  }
583
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);
584
1134
  return /* @__PURE__ */ jsxs(View, {
585
- style: styles.screen,
1135
+ testID: "agent-thread-panel",
1136
+ style: styles$1.screen,
586
1137
  children: [
587
- run ? /* @__PURE__ */ jsxs(View, {
588
- style: styles.body,
1138
+ /* @__PURE__ */ jsxs(View, {
1139
+ testID: "agent-thread-header",
1140
+ style: styles$1.threadHead,
589
1141
  children: [
590
- /* @__PURE__ */ jsxs(Text, {
591
- style: styles.title,
592
- children: [
593
- agentRunLabel(run),
594
- " · ",
595
- run.state
596
- ]
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"
597
1152
  }),
598
- /* @__PURE__ */ jsxs(Text, {
599
- style: styles.meta,
600
- children: [
601
- run.model,
602
- "\\n",
603
- run.task,
604
- "\\n",
605
- formatRunDuration(Math.max(0, (run.endedAt ?? run.lastUpdate) - run.startedAt))
606
- ]
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
607
1167
  }),
608
- sessionId !== null ? isTerminalRun(run) ? /* @__PURE__ */ jsx(Button, {
609
- variant: "outline",
610
- onPress: () => setConfirmClear(true),
611
- children: "Clear run"
612
- }) : /* @__PURE__ */ jsx(Button, {
613
- variant: "danger-outline",
614
- disabled: busy || state.stopRequested.includes(runId),
615
- onPress: () => void act(() => requestRunStop(sessionId, runId)),
616
- children: state.stopRequested.includes(runId) ? "Stopping…" : "Stop"
1168
+ live ? /* @__PURE__ */ jsx(RunControl, {
1169
+ sessionId,
1170
+ run: listed,
1171
+ stopping
617
1172
  }) : null
618
1173
  ]
619
- }) : /* @__PURE__ */ jsx(Text, {
620
- style: styles.meta,
621
- children: "This run is no longer listed; its transcript stays readable."
622
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,
623
1180
  /* @__PURE__ */ jsx(View, {
624
- style: styles.transcript,
1181
+ style: styles$1.transcript,
625
1182
  children: renderThread(runId)
626
1183
  }),
627
- run && sessionId !== null && !isTerminalRun(run) ? /* @__PURE__ */ jsxs(View, {
628
- style: styles.body,
629
- children: [/* @__PURE__ */ jsx(Textarea, {
630
- accessibilityLabel: "Steering guidance",
631
- value: guidance,
632
- onChangeText: setGuidance,
633
- placeholder: "Guide this agent…"
634
- }), /* @__PURE__ */ jsx(Button, {
635
- disabled: busy || guidance.trim() === "",
636
- onPress: () => void act(async () => {
637
- const result = await steerRun(sessionId, runId, guidance.trim());
638
- setNotice(result.message);
639
- if (result.state !== "failed") setGuidance("");
640
- }),
641
- children: "Send guidance"
642
- })]
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 })
643
1190
  }) : null,
644
- notice ? /* @__PURE__ */ jsx(Text, {
645
- style: styles.meta,
646
- children: notice
647
- }) : null,
648
- /* @__PURE__ */ jsx(Sheet, {
649
- open: confirmClear,
650
- onOpenChange: setConfirmClear,
651
- children: /* @__PURE__ */ jsxs(SheetContent, { children: [/* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: "Clear this run?" }) }), /* @__PURE__ */ jsxs(SheetBody, { children: [/* @__PURE__ */ jsx(Text, {
652
- style: styles.meta,
653
- children: "This hides the finished run. Its transcript stays on disk."
654
- }), /* @__PURE__ */ jsx(Button, {
655
- variant: "danger-outline",
656
- onPress: () => {
657
- if (sessionId !== null) dismissRun(sessionId, runId);
658
- setConfirmClear(false);
659
- },
660
- children: "Clear"
661
- })] })] })
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
+ ]
662
1263
  })
663
1264
  ]
664
1265
  });
665
1266
  }
666
- const styles = StyleSheet.create((theme) => ({
667
- screen: {
668
- flex: 1,
669
- backgroundColor: theme.colors.bg,
670
- uni__dependencies: [0]
671
- },
672
- transcript: { flex: 1 },
673
- body: {
674
- padding: theme.spacing(3),
675
- gap: theme.spacing(2),
676
- uni__dependencies: [0]
677
- },
678
- title: {
679
- color: theme.colors.hi,
680
- fontSize: theme.fontSize.base,
681
- fontWeight: "600",
682
- uni__dependencies: [0]
683
- },
684
- meta: {
685
- color: theme.colors.dim,
686
- fontSize: theme.fontSize.sm,
687
- uni__dependencies: [0]
688
- },
689
- error: {
690
- color: theme.colors.red,
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,
691
1274
  fontSize: theme.fontSize.sm,
692
- uni__dependencies: [0]
693
- }
694
- }));
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
+ });
695
1611
  //#endregion
696
1612
  //#region src/extensions/workspaces/sessions/(frontend)/activity-group/agents.native.ts
697
1613
  var agents_native_default = defineActivityGroup({
@@ -718,24 +1634,191 @@ var subagent_catalog_native_default = defineChannelFile(subagentCatalogChannel);
718
1634
  var subagent_runs_native_default = defineChannelFile(subagentRunsChannel);
719
1635
  //#endregion
720
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
+ }
721
1655
  function AgentsActivitySection({ sessionId, openTransientTab }) {
722
1656
  const runs = activityRuns(useSubagents(sessionId));
723
- return /* @__PURE__ */ jsxs(View, { children: [runs.map((run) => /* @__PURE__ */ jsx(AgentRunRow, {
724
- run,
725
- onPress: () => openTransientTab(agentThreadTab(run))
726
- }, run.runId)), runs.length === 0 ? /* @__PURE__ */ jsx(Button, {
727
- variant: "ghost",
728
- testID: "activity-agents-launch",
729
- disabled: sessionId === null,
730
- onPress: () => {
731
- if (sessionId !== null) {
732
- openCatalog(sessionId);
733
- openTransientTab(subagentsTab());
734
- }
735
- },
736
- children: "Launch an agent"
737
- }) : null] });
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, {
1663
+ style: styles.idle,
1664
+ children: [/* @__PURE__ */ jsx(Text, {
1665
+ testID: "activity-summary-agents",
1666
+ style: styles.status,
1667
+ children: "Idle"
1668
+ }), /* @__PURE__ */ jsxs(Pressable, {
1669
+ accessibilityRole: "button",
1670
+ accessibilityState: { disabled: sessionId === null },
1671
+ testID: "activity-agents-launch",
1672
+ disabled: sessionId === null,
1673
+ hitSlop: 10,
1674
+ onPress: () => {
1675
+ if (sessionId !== null) {
1676
+ openCatalog(sessionId);
1677
+ openTransientTab(subagentsTab());
1678
+ }
1679
+ },
1680
+ style: styles.action,
1681
+ children: [/* @__PURE__ */ jsx(Text, {
1682
+ style: styles.actionText(sessionId === null),
1683
+ children: "Launch an agent"
1684
+ }), /* @__PURE__ */ jsx(ArrowRightIcon, {
1685
+ size: 14,
1686
+ color: sessionId === null ? "dim" : "green"
1687
+ })]
1688
+ })]
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
+ });
738
1742
  }
1743
+ const styles = StyleSheet.create((theme) => {
1744
+ const small = {
1745
+ fontFamily: fontOf(theme.fontFamily.sans),
1746
+ fontSize: theme.fontSize.sm,
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
+ });
739
1822
  //#endregion
740
1823
  //#region src/extensions/workspaces/sessions/(frontend)/fill/Agents.activity.agents.native.tsx
741
1824
  var Agents_activity_agents_native_default = defineFill({ component: AgentsActivitySection });