@invergent/agent-chat-react 2.8.0 → 2.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5117,25 +5117,6 @@ function Command({
5117
5117
  }
5118
5118
  );
5119
5119
  }
5120
- function CommandInput({
5121
- className,
5122
- ...props
5123
- }) {
5124
- return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "command-input-wrapper", className: "p-3", children: /* @__PURE__ */ jsxRuntime.jsxs(InputGroup, { className: "rounded-lg border-transparent bg-muted px-3", children: [
5125
- /* @__PURE__ */ jsxRuntime.jsx(
5126
- cmdk.Command.Input,
5127
- {
5128
- "data-slot": "command-input",
5129
- className: cn(
5130
- "w-full px-2 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
5131
- className
5132
- ),
5133
- ...props
5134
- }
5135
- ),
5136
- /* @__PURE__ */ jsxRuntime.jsx(InputGroupAddon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, { className: "size-3.5 shrink-0 opacity-50" }) })
5137
- ] }) });
5138
- }
5139
5120
  function CommandList({
5140
5121
  className,
5141
5122
  ...props
@@ -6358,6 +6339,168 @@ function Skeleton({ className, ...props }) {
6358
6339
  }
6359
6340
  );
6360
6341
  }
6342
+ var SEARCH_PLACEHOLDER = {
6343
+ commands: "Search commands\u2026",
6344
+ skills: "Search skills\u2026",
6345
+ scheduled: "Search scheduled tasks\u2026",
6346
+ all: "Type a command or search\u2026"
6347
+ };
6348
+ var NAV_HINT = "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc dismiss";
6349
+ var SEARCH_HINT = {
6350
+ commands: NAV_HINT,
6351
+ skills: "Esc dismiss",
6352
+ scheduled: NAV_HINT,
6353
+ all: NAV_HINT
6354
+ };
6355
+ var ROW_CLASS = "grid grid-cols-[120px_1fr] items-baseline gap-3 rounded-md px-3 py-[9px] data-[selected=true]:bg-foreground/[0.06] [&_svg]:hidden";
6356
+ function ComposerCommandMenu({
6357
+ menuMode,
6358
+ searchQuery,
6359
+ onSearchChange,
6360
+ skillsLoading,
6361
+ builtinCommands,
6362
+ adapterCommands,
6363
+ scheduledExamples,
6364
+ onCommandSelect,
6365
+ onEscapeDismiss
6366
+ }) {
6367
+ const controlledSearch = menuMode === "commands" || menuMode === "all";
6368
+ const showCommands = menuMode === "commands" || menuMode === "all";
6369
+ const showSkills = menuMode === "skills" || menuMode === "all";
6370
+ const skillsUnattached = menuMode === "skills" && !skillsLoading && adapterCommands.length === 0;
6371
+ return /* @__PURE__ */ jsxRuntime.jsx(
6372
+ PopoverContent,
6373
+ {
6374
+ side: "top",
6375
+ align: "start",
6376
+ className: "overflow-hidden rounded-xl p-0",
6377
+ style: { width: "var(--radix-popover-trigger-width)" },
6378
+ onCloseAutoFocus: (e) => e.preventDefault(),
6379
+ onEscapeKeyDown: () => {
6380
+ onEscapeDismiss();
6381
+ },
6382
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Command, { children: [
6383
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5 px-4 py-[13px]", children: [
6384
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SearchIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }),
6385
+ /* @__PURE__ */ jsxRuntime.jsx(
6386
+ cmdk.Command.Input,
6387
+ {
6388
+ "data-slot": "command-input",
6389
+ placeholder: SEARCH_PLACEHOLDER[menuMode],
6390
+ className: "min-w-0 flex-1 bg-transparent text-[13.5px] text-foreground outline-hidden placeholder:text-muted-foreground",
6391
+ ...controlledSearch ? { value: searchQuery, onValueChange: onSearchChange } : {}
6392
+ }
6393
+ ),
6394
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 whitespace-nowrap text-[11px] text-muted-foreground", children: SEARCH_HINT[menuMode] })
6395
+ ] }),
6396
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px w-full bg-foreground/[0.07]" }),
6397
+ skillsUnattached ? /* @__PURE__ */ jsxRuntime.jsx(SkillsEmptyState, {}) : /* @__PURE__ */ jsxRuntime.jsxs(CommandList, { className: "p-2", children: [
6398
+ !(skillsLoading && showSkills) && /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { className: "px-3 py-8 text-center text-sm text-muted-foreground", children: menuMode === "skills" ? "No skills match your search." : menuMode === "scheduled" ? "No scheduled tasks found." : "No commands found." }),
6399
+ showSkills && skillsLoading && adapterCommands.length === 0 && [0, 1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsxs(
6400
+ "div",
6401
+ {
6402
+ className: "grid grid-cols-[120px_1fr] items-baseline gap-3 px-3 py-[9px]",
6403
+ "aria-hidden": "true",
6404
+ children: [
6405
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-4 w-20" }),
6406
+ /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-3 w-full max-w-[16rem]" })
6407
+ ]
6408
+ },
6409
+ `skill-skeleton-${i}`
6410
+ )),
6411
+ menuMode === "scheduled" && scheduledExamples.map((cmd) => /* @__PURE__ */ jsxRuntime.jsx(
6412
+ MenuRow,
6413
+ {
6414
+ cmd,
6415
+ onSelect: onCommandSelect
6416
+ },
6417
+ cmd.value
6418
+ )),
6419
+ showCommands && builtinCommands.map((cmd) => /* @__PURE__ */ jsxRuntime.jsx(
6420
+ MenuRow,
6421
+ {
6422
+ cmd,
6423
+ onSelect: onCommandSelect
6424
+ },
6425
+ cmd.value
6426
+ )),
6427
+ showSkills && adapterCommands.map((cmd) => /* @__PURE__ */ jsxRuntime.jsx(
6428
+ MenuRow,
6429
+ {
6430
+ cmd,
6431
+ keywords: cmd.isExpert ? [cmd.description, "expert"] : void 0,
6432
+ badge: cmd.isExpert ? "expert" : void 0,
6433
+ onSelect: onCommandSelect
6434
+ },
6435
+ cmd.value
6436
+ ))
6437
+ ] })
6438
+ ] })
6439
+ }
6440
+ );
6441
+ }
6442
+ function MenuRow({
6443
+ cmd,
6444
+ keywords,
6445
+ badge,
6446
+ onSelect
6447
+ }) {
6448
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6449
+ CommandItem,
6450
+ {
6451
+ value: cmd.value,
6452
+ keywords: keywords ?? [cmd.description],
6453
+ onSelect: () => onSelect(cmd.value),
6454
+ className: ROW_CLASS,
6455
+ children: [
6456
+ /* @__PURE__ */ jsxRuntime.jsxs(
6457
+ "span",
6458
+ {
6459
+ className: "inline-flex min-w-0 max-w-full items-center gap-1.5",
6460
+ title: cmd.label,
6461
+ children: [
6462
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-mono text-[13px] font-medium text-amber-500", children: cmd.label }),
6463
+ badge && /* @__PURE__ */ jsxRuntime.jsx(
6464
+ "span",
6465
+ {
6466
+ className: "shrink-0 rounded-sm bg-amber-500/10 px-1 text-[9px] font-semibold uppercase tracking-wider text-amber-500",
6467
+ "aria-label": "Expert specialist",
6468
+ children: badge
6469
+ }
6470
+ )
6471
+ ]
6472
+ }
6473
+ ),
6474
+ /* @__PURE__ */ jsxRuntime.jsx(
6475
+ "span",
6476
+ {
6477
+ className: "min-w-0 truncate text-[12.5px] text-muted-foreground",
6478
+ title: cmd.description,
6479
+ children: cmd.description
6480
+ }
6481
+ )
6482
+ ]
6483
+ }
6484
+ );
6485
+ }
6486
+ function SkillsEmptyState() {
6487
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2.5 px-6 py-[30px] text-center", children: [
6488
+ /* @__PURE__ */ jsxRuntime.jsx(
6489
+ "span",
6490
+ {
6491
+ className: "text-2xl leading-none text-muted-foreground/70",
6492
+ "aria-hidden": "true",
6493
+ children: "\u2726"
6494
+ }
6495
+ ),
6496
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-foreground", children: "No skills attached" }),
6497
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-[12.5px] text-muted-foreground", children: [
6498
+ "Add them in",
6499
+ " ",
6500
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-amber-500", children: "Configure \u2192 Skills & Tools" })
6501
+ ] })
6502
+ ] });
6503
+ }
6361
6504
  function ChatComposer(props) {
6362
6505
  return /* @__PURE__ */ jsxRuntime.jsx(PromptInputProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(ChatComposerInner, { ...props }) });
6363
6506
  }
@@ -6388,6 +6531,26 @@ function formatBytes2(n) {
6388
6531
  }
6389
6532
  return `${n} B`;
6390
6533
  }
6534
+ function ComposerMenuButton({
6535
+ icon: Icon,
6536
+ label,
6537
+ onClick
6538
+ }) {
6539
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6540
+ Button,
6541
+ {
6542
+ type: "button",
6543
+ variant: "secondary",
6544
+ size: "sm",
6545
+ className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6546
+ onClick,
6547
+ children: [
6548
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, {}),
6549
+ label
6550
+ ]
6551
+ }
6552
+ );
6553
+ }
6391
6554
  function AttachmentPreviewStrip() {
6392
6555
  const attachments = useProviderAttachments();
6393
6556
  if (attachments.files.length === 0) return null;
@@ -6592,6 +6755,11 @@ function ChatComposerInner({
6592
6755
  textarea.setSelectionRange(end, end);
6593
6756
  });
6594
6757
  }, []);
6758
+ const openMenu = react.useCallback((mode) => {
6759
+ setMenuMode(mode);
6760
+ setMenuDismissed(false);
6761
+ setButtonMenuOpen(true);
6762
+ }, []);
6595
6763
  const handleCommandSelect = react.useCallback(
6596
6764
  (commandValue) => {
6597
6765
  textInput.setInput(`${commandValue} `);
@@ -6683,58 +6851,28 @@ function ChatComposerInner({
6683
6851
  children: [
6684
6852
  /* @__PURE__ */ jsxRuntime.jsx(AttachmentPreviewStrip, {}),
6685
6853
  viewMode === "expert" && !disabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2 px-1 pb-2", children: [
6686
- /* @__PURE__ */ jsxRuntime.jsxs(
6687
- Button,
6854
+ /* @__PURE__ */ jsxRuntime.jsx(
6855
+ ComposerMenuButton,
6688
6856
  {
6689
- type: "button",
6690
- variant: "secondary",
6691
- size: "sm",
6692
- className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6693
- onClick: () => {
6694
- setMenuMode("commands");
6695
- setMenuDismissed(false);
6696
- setButtonMenuOpen(true);
6697
- },
6698
- children: [
6699
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TerminalIcon, {}),
6700
- "Commands"
6701
- ]
6857
+ icon: lucideReact.TerminalIcon,
6858
+ label: "Commands",
6859
+ onClick: () => openMenu("commands")
6702
6860
  }
6703
6861
  ),
6704
- /* @__PURE__ */ jsxRuntime.jsxs(
6705
- Button,
6862
+ /* @__PURE__ */ jsxRuntime.jsx(
6863
+ ComposerMenuButton,
6706
6864
  {
6707
- type: "button",
6708
- variant: "secondary",
6709
- size: "sm",
6710
- className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6711
- onClick: () => {
6712
- setMenuMode("skills");
6713
- setMenuDismissed(false);
6714
- setButtonMenuOpen(true);
6715
- },
6716
- children: [
6717
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SparklesIcon, {}),
6718
- "Skills"
6719
- ]
6865
+ icon: lucideReact.SparklesIcon,
6866
+ label: "Skills",
6867
+ onClick: () => openMenu("skills")
6720
6868
  }
6721
6869
  ),
6722
- loopsEnabled && /* @__PURE__ */ jsxRuntime.jsxs(
6723
- Button,
6870
+ loopsEnabled && /* @__PURE__ */ jsxRuntime.jsx(
6871
+ ComposerMenuButton,
6724
6872
  {
6725
- type: "button",
6726
- variant: "secondary",
6727
- size: "sm",
6728
- className: "rounded-sm -uppercase font-display bg-white dark:bg-accent border-2 border-accent cursor-pointer",
6729
- onClick: () => {
6730
- setMenuMode("scheduled");
6731
- setMenuDismissed(false);
6732
- setButtonMenuOpen(true);
6733
- },
6734
- children: [
6735
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClockIcon, {}),
6736
- "Scheduled Tasks"
6737
- ]
6873
+ icon: lucideReact.ClockIcon,
6874
+ label: "Scheduled Tasks",
6875
+ onClick: () => openMenu("scheduled")
6738
6876
  }
6739
6877
  )
6740
6878
  ] }),
@@ -6931,135 +7069,17 @@ function ChatComposerInner({
6931
7069
  }
6932
7070
  ) }),
6933
7071
  /* @__PURE__ */ jsxRuntime.jsx(
6934
- PopoverContent,
7072
+ ComposerCommandMenu,
6935
7073
  {
6936
- side: "top",
6937
- align: "start",
6938
- className: "overflow-hidden rounded-xl p-0",
6939
- style: { width: "var(--radix-popover-trigger-width)" },
6940
- onCloseAutoFocus: (e) => e.preventDefault(),
6941
- onEscapeKeyDown: () => {
6942
- focusTextareaAtEnd();
6943
- },
6944
- children: /* @__PURE__ */ jsxRuntime.jsxs(Command, { children: [
6945
- menuMode === "skills" ? /* @__PURE__ */ jsxRuntime.jsx(CommandInput, { placeholder: "Search skills..." }) : menuMode === "scheduled" ? /* @__PURE__ */ jsxRuntime.jsx(CommandInput, { placeholder: "Search scheduled tasks..." }) : /* @__PURE__ */ jsxRuntime.jsx(
6946
- CommandInput,
6947
- {
6948
- placeholder: "Type a command or search...",
6949
- value: searchQuery,
6950
- onValueChange: handleSearchChange
6951
- }
6952
- ),
6953
- /* @__PURE__ */ jsxRuntime.jsxs(CommandList, { children: [
6954
- !(skillsLoading && (menuMode === "skills" || menuMode === "all")) && /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: menuMode === "skills" ? "No skills found." : menuMode === "scheduled" ? "No scheduled tasks found." : "No commands found." }),
6955
- (menuMode === "skills" || menuMode === "all") && skillsLoading && adapterCommands.length === 0 && [0, 1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsxs(
6956
- "div",
6957
- {
6958
- className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 px-2 py-2",
6959
- "aria-hidden": "true",
6960
- children: [
6961
- /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-4 w-28" }),
6962
- /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "h-3 w-full max-w-[16rem]" })
6963
- ]
6964
- },
6965
- `skill-skeleton-${i}`
6966
- )),
6967
- menuMode === "scheduled" && scheduledExamples.map((cmd) => /* @__PURE__ */ jsxRuntime.jsxs(
6968
- CommandItem,
6969
- {
6970
- value: cmd.value,
6971
- keywords: [cmd.description],
6972
- onSelect: () => handleCommandSelect(cmd.value),
6973
- className: "grid grid-cols-[14rem_1fr] items-baseline gap-3 [&_svg]:hidden",
6974
- children: [
6975
- /* @__PURE__ */ jsxRuntime.jsx(
6976
- "span",
6977
- {
6978
- className: "font-mono font-semibold text-foreground truncate",
6979
- title: cmd.label,
6980
- children: cmd.label
6981
- }
6982
- ),
6983
- /* @__PURE__ */ jsxRuntime.jsx(
6984
- "span",
6985
- {
6986
- className: "min-w-0 truncate text-sm text-muted-foreground",
6987
- title: cmd.description,
6988
- children: cmd.description
6989
- }
6990
- )
6991
- ]
6992
- },
6993
- cmd.value
6994
- )),
6995
- (menuMode === "commands" || menuMode === "all") && builtinCommands.map((cmd) => /* @__PURE__ */ jsxRuntime.jsxs(
6996
- CommandItem,
6997
- {
6998
- value: cmd.value,
6999
- keywords: [cmd.description],
7000
- onSelect: () => handleCommandSelect(cmd.value),
7001
- className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 [&_svg]:hidden",
7002
- children: [
7003
- /* @__PURE__ */ jsxRuntime.jsx(
7004
- "span",
7005
- {
7006
- className: "font-mono font-semibold text-foreground truncate",
7007
- title: cmd.label,
7008
- children: cmd.label
7009
- }
7010
- ),
7011
- /* @__PURE__ */ jsxRuntime.jsx(
7012
- "span",
7013
- {
7014
- className: "min-w-0 truncate text-sm text-muted-foreground",
7015
- title: cmd.description,
7016
- children: cmd.description
7017
- }
7018
- )
7019
- ]
7020
- },
7021
- cmd.value
7022
- )),
7023
- (menuMode === "skills" || menuMode === "all") && adapterCommands.map((cmd) => /* @__PURE__ */ jsxRuntime.jsxs(
7024
- CommandItem,
7025
- {
7026
- value: cmd.value,
7027
- keywords: cmd.isExpert ? [cmd.description, "expert"] : [cmd.description],
7028
- onSelect: () => handleCommandSelect(cmd.value),
7029
- className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 [&_svg]:hidden",
7030
- children: [
7031
- /* @__PURE__ */ jsxRuntime.jsxs(
7032
- "span",
7033
- {
7034
- className: "inline-flex items-center gap-1.5 min-w-0 max-w-full",
7035
- title: cmd.label,
7036
- children: [
7037
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-semibold text-foreground truncate", children: cmd.label }),
7038
- cmd.isExpert && /* @__PURE__ */ jsxRuntime.jsx(
7039
- "span",
7040
- {
7041
- className: "shrink-0 rounded-sm bg-primary/10 px-1 text-[9px] font-semibold uppercase tracking-wider text-primary",
7042
- "aria-label": "Expert specialist",
7043
- children: "expert"
7044
- }
7045
- )
7046
- ]
7047
- }
7048
- ),
7049
- /* @__PURE__ */ jsxRuntime.jsx(
7050
- "span",
7051
- {
7052
- className: "min-w-0 truncate text-sm text-muted-foreground",
7053
- title: cmd.description,
7054
- children: cmd.description
7055
- }
7056
- )
7057
- ]
7058
- },
7059
- cmd.value
7060
- ))
7061
- ] })
7062
- ] })
7074
+ menuMode,
7075
+ searchQuery,
7076
+ onSearchChange: handleSearchChange,
7077
+ skillsLoading,
7078
+ builtinCommands,
7079
+ adapterCommands,
7080
+ scheduledExamples,
7081
+ onCommandSelect: handleCommandSelect,
7082
+ onEscapeDismiss: focusTextareaAtEnd
7063
7083
  }
7064
7084
  )
7065
7085
  ]
@@ -16405,10 +16425,20 @@ function fallbackSessionTitle(entry) {
16405
16425
  if (entry.runKind === "scheduled") return "Scheduled run";
16406
16426
  return "New session";
16407
16427
  }
16428
+ function rowStateClass(isActive, isInActiveGroup) {
16429
+ if (isActive) {
16430
+ return "bg-faint/30 dark:bg-[#1e2840] text-foreground border-l-primary";
16431
+ }
16432
+ if (isInActiveGroup) {
16433
+ return "bg-line/70 dark:bg-line/60 text-foreground/80 hover:bg-input hover:text-foreground border-l-transparent";
16434
+ }
16435
+ return "bg-transparent text-foreground/80 hover:bg-input hover:text-foreground border-l-transparent";
16436
+ }
16408
16437
  function TreeNodeRow({
16409
16438
  entry,
16410
16439
  depth,
16411
16440
  activeSessionId,
16441
+ activeGroupRootId,
16412
16442
  canStop,
16413
16443
  canDelete,
16414
16444
  onSelect,
@@ -16420,11 +16450,15 @@ function TreeNodeRow({
16420
16450
  const isActive = entry.id === activeSessionId;
16421
16451
  const isRunning = entry.status === "active";
16422
16452
  const isChildSession = entry.parentId != null;
16453
+ const isInActiveGroup = activeGroupRootId !== null && (entry.id === activeGroupRootId || entry.parentId === activeGroupRootId);
16423
16454
  const title = entry.title ?? fallbackSessionTitle(entry);
16424
16455
  const subtitle = [
16425
16456
  formatRunKind(entry.runKind),
16426
16457
  formatSessionTime(entry.updatedAt)
16427
16458
  ].filter(Boolean).join(" \xB7 ");
16459
+ react.useEffect(() => {
16460
+ if (hasChildren) setExpanded(isInActiveGroup);
16461
+ }, [isInActiveGroup, hasChildren]);
16428
16462
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16429
16463
  /* @__PURE__ */ jsxRuntime.jsxs(
16430
16464
  "div",
@@ -16438,7 +16472,7 @@ function TreeNodeRow({
16438
16472
  className: cn(
16439
16473
  "group flex items-center gap-2 w-full py-2 pr-2 text-left cursor-pointer transition-colors border-l-2",
16440
16474
  "min-h-11 md:min-h-0",
16441
- isActive ? "bg-line text-foreground border-l-primary" : "bg-transparent text-foreground/80 hover:bg-input hover:text-foreground border-l-transparent"
16475
+ rowStateClass(isActive, isInActiveGroup)
16442
16476
  ),
16443
16477
  style: { paddingLeft: `${depth * 12 + 12}px` },
16444
16478
  children: [
@@ -16497,6 +16531,7 @@ function TreeNodeRow({
16497
16531
  entry: child,
16498
16532
  depth: depth + 1,
16499
16533
  activeSessionId,
16534
+ activeGroupRootId,
16500
16535
  canStop,
16501
16536
  canDelete,
16502
16537
  onSelect,
@@ -16613,6 +16648,21 @@ function SessionTreePanel({
16613
16648
  return () => clearInterval(id);
16614
16649
  }, [refetch, runningCount]);
16615
16650
  const roots = react.useMemo(() => buildTree(nodes), [nodes]);
16651
+ const activeGroupRootId = react.useMemo(() => {
16652
+ if (!activeSessionId) return null;
16653
+ const parentOf = /* @__PURE__ */ new Map();
16654
+ for (const n of nodes) parentOf.set(n.id, n.parentId ?? null);
16655
+ const visited = /* @__PURE__ */ new Set();
16656
+ let current = activeSessionId;
16657
+ let parent = parentOf.get(current);
16658
+ while (parent != null) {
16659
+ if (visited.has(parent)) break;
16660
+ visited.add(current);
16661
+ current = parent;
16662
+ parent = parentOf.get(current);
16663
+ }
16664
+ return parentOf.has(current) ? current : null;
16665
+ }, [activeSessionId, nodes]);
16616
16666
  const handleSelect = react.useCallback(
16617
16667
  (id) => {
16618
16668
  onSessionSelect?.(id);
@@ -16676,6 +16726,7 @@ function SessionTreePanel({
16676
16726
  entry,
16677
16727
  depth: 0,
16678
16728
  activeSessionId: activeSessionId ?? "",
16729
+ activeGroupRootId,
16679
16730
  canStop: Boolean(adapter.stopSession),
16680
16731
  canDelete: Boolean(adapter.deleteSession),
16681
16732
  onSelect: handleSelect,