@agent-native/dispatch 0.22.0 → 0.23.0

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.
Files changed (51) hide show
  1. package/dist/components/app-icon.d.ts +2 -1
  2. package/dist/components/app-icon.d.ts.map +1 -1
  3. package/dist/components/app-icon.js +4 -2
  4. package/dist/components/app-icon.js.map +1 -1
  5. package/dist/components/app-list-row.d.ts +1 -1
  6. package/dist/components/app-list-row.d.ts.map +1 -1
  7. package/dist/components/app-list-row.js +1 -1
  8. package/dist/components/app-list-row.js.map +1 -1
  9. package/dist/components/app-open-actions.d.ts +2 -1
  10. package/dist/components/app-open-actions.d.ts.map +1 -1
  11. package/dist/components/app-open-actions.js +2 -2
  12. package/dist/components/app-open-actions.js.map +1 -1
  13. package/dist/components/dispatch-control-plane.d.ts.map +1 -1
  14. package/dist/components/dispatch-control-plane.js +16 -17
  15. package/dist/components/dispatch-control-plane.js.map +1 -1
  16. package/dist/components/layout/Layout.d.ts.map +1 -1
  17. package/dist/components/layout/Layout.js +91 -57
  18. package/dist/components/layout/Layout.js.map +1 -1
  19. package/dist/components/layout/workspace-apps-rail.d.ts.map +1 -1
  20. package/dist/components/layout/workspace-apps-rail.js +1 -1
  21. package/dist/components/layout/workspace-apps-rail.js.map +1 -1
  22. package/dist/components/other-apps-section.d.ts +3 -1
  23. package/dist/components/other-apps-section.d.ts.map +1 -1
  24. package/dist/components/other-apps-section.js +9 -6
  25. package/dist/components/other-apps-section.js.map +1 -1
  26. package/dist/components/workspace-app-card.d.ts.map +1 -1
  27. package/dist/components/workspace-app-card.js +7 -2
  28. package/dist/components/workspace-app-card.js.map +1 -1
  29. package/dist/components/workspace-template-card.d.ts.map +1 -1
  30. package/dist/components/workspace-template-card.js +2 -5
  31. package/dist/components/workspace-template-card.js.map +1 -1
  32. package/dist/lib/overview-chat.d.ts.map +1 -1
  33. package/dist/lib/overview-chat.js +0 -8
  34. package/dist/lib/overview-chat.js.map +1 -1
  35. package/package.json +3 -3
  36. package/src/components/app-icon.tsx +6 -2
  37. package/src/components/app-list-row.tsx +1 -1
  38. package/src/components/app-open-actions.tsx +4 -2
  39. package/src/components/dispatch-control-plane.spec.tsx +43 -7
  40. package/src/components/dispatch-control-plane.tsx +56 -75
  41. package/src/components/layout/Layout.spec.tsx +121 -1
  42. package/src/components/layout/Layout.tsx +187 -114
  43. package/src/components/layout/workspace-apps-rail.tsx +1 -0
  44. package/src/components/other-apps-section.tsx +61 -40
  45. package/src/components/workspace-app-card.spec.tsx +63 -66
  46. package/src/components/workspace-app-card.tsx +10 -3
  47. package/src/components/workspace-template-card.spec.tsx +7 -8
  48. package/src/components/workspace-template-card.tsx +21 -11
  49. package/src/lib/overview-chat.spec.ts +0 -19
  50. package/src/lib/overview-chat.ts +0 -9
  51. package/src/styles/dispatch.css +2 -2
@@ -417,7 +417,7 @@ function DispatchChatsSection({ onNavigate, showNewChat = false, prelude, chatFi
417
417
  if (threadId)
418
418
  openThread(threadId, { isNew: true });
419
419
  }
420
- return (_jsxs("div", { className: cn("ms-4 min-w-0 space-y-0.5", showNewChat && "dispatch-chat-first-chats"), children: [showNewChat && chatFirstNavigation ? (_jsx("nav", { className: "space-y-0.5 px-2 py-2", children: _jsx(ChatFirstPrimaryNavigation, { copy: chatFirstCopy, onNewChat: () => void handleNewChat(), onOpenIntegrations: chatFirstNavigation.onOpenIntegrations, onOpenScheduled: chatFirstNavigation.onOpenScheduled, onSearch: openCommandMenu }) })) : null, prelude, !chatFirstMode ? (_jsx("div", { className: "flex justify-end px-2 pt-0.5", children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "data-dispatch-chat-source-toggle": true, "aria-pressed": includeExternal, "aria-label": includeExternal
420
+ return (_jsxs("div", { className: cn("min-w-0 space-y-0.5", showNewChat && "dispatch-chat-first-chats"), children: [showNewChat && chatFirstNavigation ? (_jsx("nav", { className: "space-y-0.5 px-2 py-2", children: _jsx(ChatFirstPrimaryNavigation, { copy: chatFirstCopy, onNewChat: () => void handleNewChat(), onOpenIntegrations: chatFirstNavigation.onOpenIntegrations, onOpenScheduled: chatFirstNavigation.onOpenScheduled, onSearch: openCommandMenu }) })) : null, prelude, !chatFirstMode ? (_jsx("div", { className: "flex justify-end px-2 pt-0.5", children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "data-dispatch-chat-source-toggle": true, "aria-pressed": includeExternal, "aria-label": includeExternal
421
421
  ? t("dispatch.sidebar.showLocalChats", {
422
422
  defaultValue: "Show local chats",
423
423
  })
@@ -432,7 +432,7 @@ function DispatchChatsSection({ onNavigate, showNewChat = false, prelude, chatFi
432
432
  }) })] }) })) : null, !chatFirstMode &&
433
433
  chatsLoading &&
434
434
  visibleThreads.length === 0 &&
435
- Array.from({ length: 3 }).map((_, index) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-1", children: [_jsx(Skeleton, { className: "size-3.5 shrink-0 rounded-sm" }), _jsx(Skeleton, { className: "h-3 w-3/4 rounded" })] }, `chat-skeleton-${index}`))), chatFirstMode ? (_jsx(ChatFirstChatHistory, { items: chatItems, activeId: displayedActiveThreadId, loading: chatsLoading && visibleThreads.length === 0, loadingLabel: _jsx("div", { className: "space-y-1 px-2 py-1", children: [0, 1, 2].map((index) => (_jsxs("div", { className: "flex items-center gap-2 px-1 py-1", children: [_jsx(Skeleton, { className: "size-3.5 shrink-0 rounded-sm" }), _jsx(Skeleton, { className: "h-3 w-3/4 rounded" })] }, index))) }), label: t("dispatch.sidebar.chats", { defaultValue: "Chats" }), onSelect: (threadId) => openThread(threadId), renameMaxLength: 160, onRename: (threadId, title) => void renameThread(threadId, title), labels: {
435
+ Array.from({ length: 3 }).map((_, index) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-1", children: [_jsx(Skeleton, { className: "size-3.5 shrink-0 rounded-sm" }), _jsx(Skeleton, { className: "h-3 w-3/4 rounded" })] }, `chat-skeleton-${index}`))), chatFirstMode && (chatsLoading || visibleThreads.length > 0) ? (_jsx(ChatFirstChatHistory, { items: chatItems, activeId: displayedActiveThreadId, loading: chatsLoading && visibleThreads.length === 0, loadingLabel: _jsx("div", { className: "space-y-1 px-2 py-1", children: [0, 1, 2].map((index) => (_jsxs("div", { className: "flex items-center gap-2 px-1 py-1", children: [_jsx(Skeleton, { className: "size-3.5 shrink-0 rounded-sm" }), _jsx(Skeleton, { className: "h-3 w-3/4 rounded" })] }, index))) }), label: t("dispatch.sidebar.chats", { defaultValue: "Chats" }), onSelect: (threadId) => openThread(threadId), renameMaxLength: 160, onRename: (threadId, title) => void renameThread(threadId, title), labels: {
436
436
  options: (item) => t("dispatch.sidebar.chatOptions", {
437
437
  title: item.titleText ?? "",
438
438
  }),
@@ -512,7 +512,10 @@ export function NavContent({ onNavigate, extensions, chatFirstMode = false, chat
512
512
  const chatFirstAppsRail = (_jsx(ChatFirstAppsRail, { apps: chatFirstApps, activeAppId: chatFirstActiveAppId, collapsed: collapsed, loading: chatFirstAppsLoading, error: chatFirstAppsError, layout: chatFirstAppLayout, onLayoutChange: onChatFirstAppLayoutChange, onRetry: onChatFirstAppsRetry, onOpenApp: (app) => {
513
513
  onChatFirstAppOpen?.(app);
514
514
  onNavigate?.();
515
- }, createAppTrigger: chatFirstCreateAppTrigger, renderIcon: (app) => (_jsx(AppIcon, { id: app.id, name: app.name, size: "sm", className: "size-5 rounded-md" })), copy: chatFirstCopy }));
515
+ }, onOpenAllApps: () => {
516
+ navigate(dispatchNavLinkTarget("/apps"));
517
+ onNavigate?.();
518
+ }, createAppTrigger: chatFirstCreateAppTrigger, renderIcon: (app) => (_jsx(AppIcon, { id: app.id, name: app.name, size: "sm", monochrome: true, className: "size-5 rounded-md" })), copy: chatFirstCopy }));
516
519
  const renderNavItem = (item) => {
517
520
  const Icon = item.icon;
518
521
  const itemMatchesLocalPath = navItemMatchesPath(item, localPathname);
@@ -549,6 +552,9 @@ export function NavContent({ onNavigate, extensions, chatFirstMode = false, chat
549
552
  ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
550
553
  : "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), children: [Icon ? (_jsx(Icon, { size: 16, className: "shrink-0" })) : (_jsx("span", { className: "h-4 w-4 shrink-0", "aria-hidden": "true" })), _jsx("span", { className: "truncate", children: label })] })), !collapsed && item.id === "chat" && itemMatchesLocalPath ? (_jsx(DispatchChatsSection, { onNavigate: onNavigate, chatFirstMode: chatFirstMode, chatFirstEmbedded: chatFirstEmbedded })) : null] }, item.id));
551
554
  };
555
+ const bottomNavigation = (_jsx("nav", { className: cn("py-1", collapsed ? "px-1.5" : "px-2"), children: _jsx("ul", { className: cn(collapsed ? "flex flex-col items-center gap-1" : "space-y-0.5"), children: BOTTOM_NAV_ITEMS.map(renderNavItem) }) }));
556
+ const organizationPicker = (_jsx("div", { className: cn("py-2", collapsed ? "flex justify-center px-1" : "px-3"), children: _jsx(OrgSwitcher, { compact: collapsed, reserveSpace: true }) }));
557
+ const sidebarFooterActions = (_jsx(SidebarFooterActions, { collapsed: collapsed, feedback: feedbackButton, search: searchButton, collapse: collapseButton }));
552
558
  return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn("flex h-12 shrink-0 items-center border-b border-sidebar-border", collapsed ? "justify-center px-0" : "px-4"), children: _jsxs("div", { className: cn("flex items-center", collapsed ? "justify-center" : "gap-2"), children: [_jsx("img", { src: appPath("/agent-native-icon-light.svg"), alt: "", "aria-hidden": "true", width: 35, height: 20, className: cn("block shrink-0 object-contain object-center dark:hidden", collapsed ? "h-4 w-7" : "h-5 w-[35px]") }), _jsx("img", { src: appPath("/agent-native-icon-dark.svg"), alt: "", "aria-hidden": "true", width: 35, height: 20, className: cn("hidden shrink-0 object-contain object-center dark:block", collapsed ? "h-4 w-7" : "h-5 w-[35px]") }), !collapsed && (_jsx("div", { className: "min-w-0 flex-1", children: _jsx("div", { "data-dispatch-sidebar-label": true, className: "truncate text-lg font-bold tracking-tight text-foreground", children: DISPATCH_SIDEBAR_LABEL }) }))] }) }), chatFirstMode ? (_jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto", children: !collapsed ? (_jsx(DispatchChatsSection, { onNavigate: onNavigate, showNewChat: true, chatFirstMode: true, chatFirstEmbedded: chatFirstEmbedded, chatFirstNavigation: {
553
559
  onOpenIntegrations: () => {
554
560
  navigate(dispatchNavLinkTarget("/admin/integrations"));
@@ -558,7 +564,7 @@ export function NavContent({ onNavigate, extensions, chatFirstMode = false, chat
558
564
  navigate(dispatchNavLinkTarget("/admin/automations"));
559
565
  onNavigate?.();
560
566
  },
561
- }, prelude: chatFirstAppsRail })) : (chatFirstAppsRail) })) : null, _jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col overflow-y-auto", chatFirstMode && "hidden"), children: [_jsx("nav", { className: cn("py-2", collapsed ? "px-1.5" : "px-2"), children: _jsx("ul", { className: cn(collapsed ? "flex flex-col items-center gap-1" : "space-y-0.5"), children: primaryNavItems.map(renderNavItem) }) }), _jsxs("div", { className: "mt-auto shrink-0", children: [_jsx("nav", { className: cn("py-1", collapsed ? "px-1.5" : "px-2"), children: _jsx("ul", { className: cn(collapsed ? "flex flex-col items-center gap-1" : "space-y-0.5"), children: BOTTOM_NAV_ITEMS.map(renderNavItem) }) }), _jsx("div", { className: cn("py-2", collapsed ? "flex justify-center px-1" : "px-3"), children: _jsx(OrgSwitcher, { compact: collapsed, reserveSpace: true }) })] }), _jsx(SidebarFooterActions, { collapsed: collapsed, feedback: feedbackButton, search: searchButton, collapse: collapseButton })] }), chatFirstMode && collapsed ? (_jsx("div", { className: "mt-auto shrink-0", children: _jsx(SidebarFooterActions, { collapsed: true, feedback: feedbackButton, search: searchButton, collapse: collapseButton }) })) : null] }));
567
+ }, prelude: chatFirstAppsRail })) : (chatFirstAppsRail) })) : null, _jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col overflow-y-auto", chatFirstMode && "hidden"), children: [_jsx("nav", { className: cn("py-2", collapsed ? "px-1.5" : "px-2"), children: _jsx("ul", { className: cn(collapsed ? "flex flex-col items-center gap-1" : "space-y-0.5"), children: primaryNavItems.map(renderNavItem) }) }), _jsxs("div", { className: "mt-auto shrink-0", children: [bottomNavigation, organizationPicker] }), sidebarFooterActions] }), chatFirstMode ? (_jsxs("div", { className: "mt-auto shrink-0", children: [bottomNavigation, organizationPicker, collapsed ? sidebarFooterActions : null] })) : null] }));
562
568
  }
563
569
  export function Layout({ children, extensions, agentPageHref, }) {
564
570
  const t = useT();
@@ -578,22 +584,43 @@ export function Layout({ children, extensions, agentPageHref, }) {
578
584
  const localPathname = localDispatchPath(location.pathname);
579
585
  const isChatRoute = localPathname === "/chat" || localPathname.startsWith("/chat/");
580
586
  const chatFirstSurfaceScope = threadIdFromPath(localPathname) ?? "new";
581
- const isWorkspaceAppHostRoute = localPathname.startsWith("/apps/");
587
+ const isWorkspaceAppRoute = localPathname.startsWith("/apps/");
588
+ const isWorkspaceAppHostRoute = isWorkspaceAppRoute &&
589
+ typeof window !== "undefined" &&
590
+ new URLSearchParams(window.location.search).get("embedded") === "1";
582
591
  const [chatFirstPreference, setChatFirstPreference] = useState(() => readChatFirstMode());
583
592
  const chatFirstEmbedded = typeof window !== "undefined" &&
584
593
  new URLSearchParams(window.location.search).get("chatFirst") === "1";
585
594
  const chatFirstMode = extensions?.chatFirst === true || chatFirstPreference || chatFirstEmbedded;
586
595
  const [chatFirstAppLayout, setChatFirstAppLayout] = useState(() => readChatFirstAppLayout());
587
596
  const chatFirstAppLayoutHydratedRef = useRef(false);
588
- const chatFirstAppsQuery = useActionQuery("list-workspace-apps", { includeAgentCards: false }, { enabled: chatFirstMode && isChatRoute });
597
+ const chatFirstAppsQuery = useActionQuery("list-workspace-apps", { includeAgentCards: false }, { enabled: chatFirstMode });
598
+ const chatFirstGrantedAppsQuery = useActionQuery("list_apps", {}, { enabled: chatFirstMode });
589
599
  const chatFirstWorkspaceApps = useMemo(() => mergeChatFirstWorkspaceApps(chatFirstAppsQuery.data), [chatFirstAppsQuery.data]);
590
- const chatFirstAppRegistrations = useMemo(() => chatFirstWorkspaceApps.map((app) => ({
591
- id: app.id,
592
- name: app.name,
593
- path: app.path,
594
- url: app.url,
595
- enabled: app.status !== "pending" && app.archived !== true,
596
- })), [chatFirstWorkspaceApps]);
600
+ const chatFirstAppRegistrations = useMemo(() => {
601
+ const registrations = new Map();
602
+ for (const app of chatFirstWorkspaceApps) {
603
+ registrations.set(app.id.toLowerCase(), {
604
+ id: app.id,
605
+ name: app.name,
606
+ path: app.path,
607
+ url: app.url,
608
+ enabled: app.status !== "pending" && app.archived !== true,
609
+ });
610
+ }
611
+ for (const app of chatFirstGrantedAppsQuery.data?.apps ?? []) {
612
+ const id = app.id.trim();
613
+ if (!id || registrations.has(id.toLowerCase()))
614
+ continue;
615
+ registrations.set(id.toLowerCase(), {
616
+ id,
617
+ name: app.name,
618
+ url: app.url,
619
+ enabled: true,
620
+ });
621
+ }
622
+ return [...registrations.values()];
623
+ }, [chatFirstGrantedAppsQuery.data?.apps, chatFirstWorkspaceApps]);
597
624
  const chatFirstAppItems = useMemo(() => chatFirstWorkspaceApps.map((app) => ({
598
625
  id: app.id,
599
626
  name: app.name,
@@ -621,10 +648,18 @@ export function Layout({ children, extensions, agentPageHref, }) {
621
648
  const previousChatFirstSurfaceScopeRef = useRef(chatFirstSurfaceScope);
622
649
  const previousChatFirstSurfaceTabCountRef = useRef(null);
623
650
  const activeChatFirstSurfaceTab = useMemo(() => chatFirstSurfaceTabs.tabs.find((tab) => tab.id === chatFirstSurfaceTabs.activeTabId) ?? null, [chatFirstSurfaceTabs]);
624
- const activeChatFirstApp = useMemo(() => activeChatFirstSurfaceTab?.kind === "app" &&
651
+ const chatFirstAppTakesMain = chatFirstMode && isChatRoute && activeChatFirstSurfaceTab?.kind === "app";
652
+ const activeChatFirstAppRegistration = useMemo(() => activeChatFirstSurfaceTab?.kind === "app" &&
625
653
  activeChatFirstSurfaceTab.appId
626
- ? (chatFirstWorkspaceApps.find((app) => app.id === activeChatFirstSurfaceTab.appId) ?? null)
627
- : null, [activeChatFirstSurfaceTab, chatFirstWorkspaceApps]);
654
+ ? (chatFirstAppRegistrations.find((app) => app.id === activeChatFirstSurfaceTab.appId) ?? null)
655
+ : null, [activeChatFirstSurfaceTab, chatFirstAppRegistrations]);
656
+ const activeChatFirstApp = useMemo(() => activeChatFirstAppRegistration
657
+ ? {
658
+ id: activeChatFirstAppRegistration.id,
659
+ name: activeChatFirstAppRegistration.name ??
660
+ activeChatFirstAppRegistration.id,
661
+ }
662
+ : null, [activeChatFirstAppRegistration]);
628
663
  const chatFirstAgentActivities = useMemo(() => (chatFirstAgentsQuery.data?.threads ?? []).map((thread) => ({
629
664
  sessionId: thread.id,
630
665
  title: thread.title || chatFirstCopy("agentsTitle", { name: thread.id }),
@@ -635,7 +670,8 @@ export function Layout({ children, extensions, agentPageHref, }) {
635
670
  const chatFirstEmbedPath = activeChatFirstSurfaceTab?.kind === "app"
636
671
  ? (activeChatFirstSurfaceTab.path ??
637
672
  chatFirstPane?.path ??
638
- activeChatFirstApp?.path)
673
+ activeChatFirstAppRegistration?.path ??
674
+ "/")
639
675
  : null;
640
676
  useEffect(() => {
641
677
  if (!chatFirstMode || !isChatRoute || !activeChatFirstApp) {
@@ -685,6 +721,9 @@ export function Layout({ children, extensions, agentPageHref, }) {
685
721
  const openChatFirstPane = useCallback((pane) => {
686
722
  setChatFirstNotice(null);
687
723
  closeChatFirstSessionWatch();
724
+ if (!isChatRoute) {
725
+ navigateWithAgentChatViewTransition(navigate, dispatchNavLinkTarget("/chat"));
726
+ }
688
727
  const app = chatFirstAppRegistrations.find((candidate) => candidate.id === pane.appId);
689
728
  chatFirstSurfaceTabsStore.open({
690
729
  id: chatFirstSurfaceTabId("app", `${pane.appId}:${pane.path ?? pane.view ?? "/"}`),
@@ -694,11 +733,15 @@ export function Layout({ children, extensions, agentPageHref, }) {
694
733
  ...(pane.path ? { path: pane.path } : {}),
695
734
  ...(pane.view ? { view: pane.view } : {}),
696
735
  });
736
+ setChatFirstSurfacePanelOpen(true);
697
737
  persistChatFirstPane(pane);
698
738
  }, [
699
739
  chatFirstAppRegistrations,
700
740
  chatFirstSurfaceTabsStore,
701
741
  persistChatFirstPane,
742
+ isChatRoute,
743
+ navigate,
744
+ setChatFirstSurfacePanelOpen,
702
745
  ]);
703
746
  const openChatFirstSurface = useCallback((kind) => {
704
747
  if (kind !== "agents")
@@ -728,7 +771,7 @@ export function Layout({ children, extensions, agentPageHref, }) {
728
771
  });
729
772
  }, [chatFirstSurfaceTabsStore, persistChatFirstPane]);
730
773
  const resolveChatFirstOpenApp = useCallback((detail) => {
731
- if (chatFirstAppsQuery.isLoading) {
774
+ if (chatFirstAppsQuery.isLoading || chatFirstGrantedAppsQuery.isLoading) {
732
775
  pendingChatFirstOpenAppRef.current = detail;
733
776
  return;
734
777
  }
@@ -750,10 +793,9 @@ export function Layout({ children, extensions, agentPageHref, }) {
750
793
  chatFirstAppRegistrations,
751
794
  chatFirstAppsQuery.isError,
752
795
  chatFirstAppsQuery.isLoading,
796
+ chatFirstGrantedAppsQuery.isLoading,
753
797
  openChatFirstPane,
754
798
  ]);
755
- const sidebarBeforeAppRef = useRef(null);
756
- const sidebarAutoCollapsedRef = useRef(false);
757
799
  const chatHomeHandoffActive = useAgentChatHomeHandoff({
758
800
  storageKey: "dispatch",
759
801
  activePath: localPathname,
@@ -805,7 +847,7 @@ export function Layout({ children, extensions, agentPageHref, }) {
805
847
  });
806
848
  }, []);
807
849
  useEffect(() => {
808
- if (!chatFirstMode || !isChatRoute) {
850
+ if (!chatFirstMode) {
809
851
  setChatFirstPane(null);
810
852
  closeChatFirstSessionWatch();
811
853
  chatFirstSurfaceTabsStore.closeAll();
@@ -898,7 +940,7 @@ export function Layout({ children, extensions, agentPageHref, }) {
898
940
  useEffect(() => {
899
941
  const tabCount = chatFirstSurfaceTabs.tabs.length;
900
942
  const previousTabCount = previousChatFirstSurfaceTabCountRef.current;
901
- if (!chatFirstMode || !isChatRoute) {
943
+ if (!chatFirstMode) {
902
944
  setChatFirstSurfacePanelOpen(false);
903
945
  }
904
946
  else if (tabCount > 0 &&
@@ -927,13 +969,17 @@ export function Layout({ children, extensions, agentPageHref, }) {
927
969
  }, [activeChatFirstSurfaceTab, chatFirstSessionWatch.target]);
928
970
  useEffect(() => {
929
971
  const pending = pendingChatFirstOpenAppRef.current;
930
- if (!pending || chatFirstAppsQuery.isLoading)
972
+ if (!pending ||
973
+ chatFirstAppsQuery.isLoading ||
974
+ chatFirstGrantedAppsQuery.isLoading)
931
975
  return;
932
976
  resolveChatFirstOpenApp(pending);
933
977
  }, [
934
978
  chatFirstAppsQuery.data,
935
979
  chatFirstAppsQuery.isError,
936
980
  chatFirstAppsQuery.isLoading,
981
+ chatFirstGrantedAppsQuery.data,
982
+ chatFirstGrantedAppsQuery.isLoading,
937
983
  resolveChatFirstOpenApp,
938
984
  ]);
939
985
  useEffect(() => {
@@ -953,26 +999,6 @@ export function Layout({ children, extensions, agentPageHref, }) {
953
999
  chatFirstSurfaceTabsStore,
954
1000
  isChatRoute,
955
1001
  ]);
956
- useEffect(() => {
957
- if (isWorkspaceAppHostRoute) {
958
- if (!sidebarAutoCollapsedRef.current) {
959
- sidebarAutoCollapsedRef.current = true;
960
- sidebarBeforeAppRef.current = sidebarCollapsed;
961
- }
962
- if (!sidebarCollapsed)
963
- setSidebarCollapsed(true);
964
- return;
965
- }
966
- if (!sidebarAutoCollapsedRef.current)
967
- return;
968
- sidebarAutoCollapsedRef.current = false;
969
- const previousSidebarState = sidebarBeforeAppRef.current;
970
- sidebarBeforeAppRef.current = null;
971
- if (previousSidebarState !== null &&
972
- previousSidebarState !== sidebarCollapsed) {
973
- setSidebarCollapsed(previousSidebarState);
974
- }
975
- }, [isWorkspaceAppHostRoute, sidebarCollapsed]);
976
1002
  useEffect(() => {
977
1003
  if (typeof window === "undefined" || isWorkspaceAppHostRoute)
978
1004
  return;
@@ -1036,8 +1062,14 @@ export function Layout({ children, extensions, agentPageHref, }) {
1036
1062
  if (tab.kind === "app") {
1037
1063
  if (tab.id !== chatFirstSurfaceTabs.activeTabId)
1038
1064
  return null;
1039
- const app = tab.appId
1040
- ? (chatFirstWorkspaceApps.find((candidate) => candidate.id === tab.appId) ?? null)
1065
+ const registration = tab.appId
1066
+ ? (chatFirstAppRegistrations.find((candidate) => candidate.id === tab.appId) ?? null)
1067
+ : null;
1068
+ const app = registration
1069
+ ? {
1070
+ id: registration.id,
1071
+ name: registration.name ?? registration.id,
1072
+ }
1041
1073
  : null;
1042
1074
  return (_jsx(ChatFirstAppPane, { app: app, status: chatFirstEmbedError
1043
1075
  ? "error"
@@ -1081,7 +1113,7 @@ export function Layout({ children, extensions, agentPageHref, }) {
1081
1113
  chatFirstEmbedUrl,
1082
1114
  chatFirstSessionWatch.target,
1083
1115
  chatFirstSurfaceTabs.activeTabId,
1084
- chatFirstWorkspaceApps,
1116
+ chatFirstAppRegistrations,
1085
1117
  closeChatFirstSurfaceTab,
1086
1118
  renderChatFirstWatchChat,
1087
1119
  ]);
@@ -1101,19 +1133,21 @@ export function Layout({ children, extensions, agentPageHref, }) {
1101
1133
  t("dispatch.sidebar.suggestionRouteSlack"),
1102
1134
  t("dispatch.sidebar.suggestionGrantKey"),
1103
1135
  ];
1104
- const appContent = (_jsxs("div", { className: "relative flex h-full min-w-0 flex-1 flex-col overflow-hidden", children: [showHeader ? _jsx(Header, { onOpenMobile: () => setMobileOpen(true) }) : null, _jsx(InvitationBanner, {}), isChatRoute && chatFirstMode ? (_jsx(ChatFirstSurfacePanelToggle, { open: chatFirstSurfacePanel.open, onToggle: chatFirstSurfacePanel.toggle, className: "absolute right-3 top-2 z-[4]" })) : null, isChatRoute && chatFirstMode && chatFirstNotice ? (_jsxs("div", { className: "dispatch-chat-first-notice", role: "status", "aria-live": "polite", children: [_jsx("span", { children: chatFirstNotice }), _jsx("button", { type: "button", onClick: () => setChatFirstNotice(null), "aria-label": "Dismiss app notice", children: "Dismiss" })] })) : null, _jsx("main", { className: cn("flex-1", isChatRoute || isWorkspaceAppHostRoute
1136
+ const appContent = (_jsxs("div", { className: "relative flex h-full min-w-0 flex-1 flex-col overflow-hidden", children: [showHeader ? _jsx(Header, { onOpenMobile: () => setMobileOpen(true) }) : null, _jsx(InvitationBanner, {}), isChatRoute && chatFirstMode ? (_jsx(ChatFirstSurfacePanelToggle, { open: chatFirstSurfacePanel.open, onToggle: chatFirstSurfacePanel.toggle, className: "absolute right-3 top-2 z-[4]" })) : null, isChatRoute && chatFirstMode && chatFirstNotice ? (_jsxs("div", { className: "dispatch-chat-first-notice", role: "status", "aria-live": "polite", children: [_jsx("span", { children: chatFirstNotice }), _jsx("button", { type: "button", onClick: () => setChatFirstNotice(null), "aria-label": "Dismiss app notice", children: "Dismiss" })] })) : null, _jsx("main", { className: cn("flex-1", isChatRoute || isWorkspaceAppRoute
1105
1137
  ? "min-h-0 overflow-hidden"
1106
1138
  : "overflow-y-auto"), children: showHeader ? (_jsx("div", { className: "mx-auto max-w-7xl space-y-10 px-4 py-6 sm:px-6", children: children })) : (children) })] }));
1107
- const content = isChatRoute ? (_jsxs("div", { className: cn("agent-layout-main-surface flex min-w-0 flex-1 overflow-hidden", chatFirstMode && "dispatch-chat-first-surface"), children: [appContent, chatFirstMode && chatFirstSurfacePanel.open ? (_jsxs(ChatFirstSurfacePanel, { width: chatFirstSurfaceResize.width, onResizePointerDown: chatFirstSurfaceResize.onPointerDown, copy: chatFirstCopy, children: [_jsx(ChatFirstSurfaceTabs, { tabs: chatFirstSurfaceTabs.tabs, activeTabId: chatFirstSurfaceTabs.activeTabId, onActivate: activateChatFirstSurfaceTab, onClose: closeChatFirstSurfaceTab, onCloseOthers: (tab) => {
1108
- activateChatFirstSurfaceTab(tab);
1109
- chatFirstSurfaceTabsStore.closeOthers(tab.id);
1110
- }, onCloseToRight: (tab) => {
1111
- const targetIndex = chatFirstSurfaceTabs.tabs.findIndex((candidate) => candidate.id === tab.id);
1112
- const activeIndex = chatFirstSurfaceTabs.tabs.findIndex((candidate) => candidate.id === chatFirstSurfaceTabs.activeTabId);
1113
- if (activeIndex > targetIndex)
1114
- activateChatFirstSurfaceTab(tab);
1115
- chatFirstSurfaceTabsStore.closeToRight(tab.id);
1116
- }, onCloseAll: closeAllChatFirstSurfaceTabs, onOpenSurface: openChatFirstSurface, copy: chatFirstCopy }), chatFirstSurfaceTabs.tabs.length > 0 ? (_jsx(ChatFirstSurfaceContent, { tabs: chatFirstSurfaceTabs.tabs, activeTabId: chatFirstSurfaceTabs.activeTabId, renderTab: renderChatFirstSurfaceTab })) : null] })) : null] })) : (_jsx(AgentSidebar, { position: "right", defaultOpen: false, agentPageHref: agentPageHref, chatViewTransition: true, storageKey: "dispatch", openOnChatRunning: chatHomeHandoffActive, onFullscreenRequest: openAskAgentFullscreen, emptyStateText: t("dispatch.sidebar.emptyAgentText"), suggestions: sidebarSuggestions, children: appContent }));
1139
+ const chatFirstSurfaceTabsBar = activeChatFirstSurfaceTab?.kind === "app" ? null : (_jsx(ChatFirstSurfaceTabs, { tabs: chatFirstSurfaceTabs.tabs, activeTabId: chatFirstSurfaceTabs.activeTabId, onActivate: activateChatFirstSurfaceTab, onClose: closeChatFirstSurfaceTab, onCloseOthers: (tab) => {
1140
+ activateChatFirstSurfaceTab(tab);
1141
+ chatFirstSurfaceTabsStore.closeOthers(tab.id);
1142
+ }, onCloseToRight: (tab) => {
1143
+ const targetIndex = chatFirstSurfaceTabs.tabs.findIndex((candidate) => candidate.id === tab.id);
1144
+ const activeIndex = chatFirstSurfaceTabs.tabs.findIndex((candidate) => candidate.id === chatFirstSurfaceTabs.activeTabId);
1145
+ if (activeIndex > targetIndex)
1146
+ activateChatFirstSurfaceTab(tab);
1147
+ chatFirstSurfaceTabsStore.closeToRight(tab.id);
1148
+ }, onCloseAll: closeAllChatFirstSurfaceTabs, onOpenSurface: openChatFirstSurface, copy: chatFirstCopy }));
1149
+ const chatFirstSurfaceContent = chatFirstSurfaceTabs.tabs.length > 0 ? (_jsx(ChatFirstSurfaceContent, { tabs: chatFirstSurfaceTabs.tabs, activeTabId: chatFirstSurfaceTabs.activeTabId, renderTab: renderChatFirstSurfaceTab })) : null;
1150
+ const content = isChatRoute ? (_jsx("div", { className: cn("agent-layout-main-surface flex min-w-0 flex-1 overflow-hidden", chatFirstMode && "dispatch-chat-first-surface"), children: chatFirstAppTakesMain ? (_jsx("div", { className: "flex min-w-0 flex-1 flex-col overflow-hidden", "data-dispatch-chat-first-main-app": true, children: chatFirstSurfaceContent })) : (_jsxs(_Fragment, { children: [appContent, chatFirstMode && chatFirstSurfacePanel.open ? (_jsxs(ChatFirstSurfacePanel, { width: chatFirstSurfaceResize.width, onResizePointerDown: chatFirstSurfaceResize.onPointerDown, copy: chatFirstCopy, children: [chatFirstSurfaceTabsBar, chatFirstSurfaceContent] })) : null] })) })) : isWorkspaceAppRoute ? (appContent) : (_jsx(AgentSidebar, { position: "right", defaultOpen: false, agentPageHref: agentPageHref, chatViewTransition: true, storageKey: "dispatch", openOnChatRunning: chatHomeHandoffActive, onFullscreenRequest: openAskAgentFullscreen, emptyStateText: t("dispatch.sidebar.emptyAgentText"), suggestions: sidebarSuggestions, children: appContent }));
1117
1151
  return (_jsx(DispatchExtensionsContext.Provider, { value: extensions, children: _jsx(HeaderActionsProvider, { children: _jsxs("div", { className: "agent-layout-shell flex h-screen w-full overflow-hidden bg-background", children: [_jsx("aside", { "data-collapsed": sidebarCollapsed ? "true" : "false", className: cn("agent-layout-left-drawer hidden shrink-0 flex-col border-e !border-e-sidebar-border bg-sidebar text-sidebar-foreground transition-[width] duration-200 ease-out lg:flex", sidebarCollapsed ? "w-14" : "w-56"), children: _jsx(NavContent, { extensions: extensions, chatFirstMode: chatFirstMode, chatFirstEmbedded: chatFirstEmbedded, collapsed: sidebarCollapsed, chatFirstAppLayout: chatFirstAppLayout, onChatFirstAppLayoutChange: persistChatFirstAppLayout, chatFirstApps: chatFirstAppItems, chatFirstAppsLoading: chatFirstAppsQuery.isLoading, chatFirstAppsError: chatFirstAppsQuery.isError
1118
1152
  ? chatFirstCopy("appsLoadError")
1119
1153
  : null, chatFirstActiveAppId: activeChatFirstSurfaceTab?.kind === "app"