@agent-native/dispatch 0.13.1 → 0.13.3

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 (30) hide show
  1. package/dist/actions/create-pylon-ticket.js +2 -1
  2. package/dist/actions/create-pylon-ticket.js.map +1 -1
  3. package/dist/actions/send-platform-message.js +7 -7
  4. package/dist/actions/send-platform-message.js.map +1 -1
  5. package/dist/components/dispatch-control-plane.js +1 -1
  6. package/dist/components/dispatch-control-plane.js.map +1 -1
  7. package/dist/components/layout/Header.d.ts.map +1 -1
  8. package/dist/components/layout/Header.js +0 -1
  9. package/dist/components/layout/Header.js.map +1 -1
  10. package/dist/components/layout/Layout.d.ts +4 -1
  11. package/dist/components/layout/Layout.d.ts.map +1 -1
  12. package/dist/components/layout/Layout.js +55 -17
  13. package/dist/components/layout/Layout.js.map +1 -1
  14. package/dist/hooks/use-navigation-state.js +2 -2
  15. package/dist/hooks/use-navigation-state.js.map +1 -1
  16. package/dist/routes/pages/settings.d.ts.map +1 -1
  17. package/dist/routes/pages/settings.js +4 -2
  18. package/dist/routes/pages/settings.js.map +1 -1
  19. package/dist/routes/pages/team.d.ts.map +1 -1
  20. package/dist/routes/pages/team.js +2 -3
  21. package/dist/routes/pages/team.js.map +1 -1
  22. package/package.json +2 -2
  23. package/src/actions/create-pylon-ticket.ts +2 -1
  24. package/src/actions/send-platform-message.ts +12 -8
  25. package/src/components/dispatch-control-plane.tsx +1 -1
  26. package/src/components/layout/Header.tsx +0 -1
  27. package/src/components/layout/Layout.tsx +229 -102
  28. package/src/hooks/use-navigation-state.ts +2 -2
  29. package/src/routes/pages/settings.tsx +70 -47
  30. package/src/routes/pages/team.tsx +2 -17
@@ -1 +1 @@
1
- {"version":3,"file":"team.js","sourceRoot":"","sources":["../../../src/routes/pages/team.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,OAAO,CACL,KAAC,QAAQ,IACP,KAAK,EAAC,MAAM,EACZ,oBAAoB,EAAC,kFAAkF,EACvG,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CACpB,KAAC,aAAa,IACZ,KAAK,EAAC,MAAM,EACZ,WAAW,EAAC,8CAA8C,YAEzD,QAAQ,GACK,CACjB,GACD,CACH,CAAC;AACJ,CAAC","sourcesContent":["import { TeamPage } from \"@agent-native/core/client/org\";\n\nimport { DispatchShell } from \"@/components/dispatch-shell\";\n\nexport function meta() {\n return [{ title: \"Team — Dispatch\" }];\n}\n\nexport default function TeamRoute() {\n return (\n <TeamPage\n title=\"Team\"\n createOrgDescription=\"Set up a team to share dispatch destinations and approvals with your colleagues.\"\n layout={(children) => (\n <DispatchShell\n title=\"Team\"\n description=\"Workspace membership and approval ownership.\"\n >\n {children}\n </DispatchShell>\n )}\n />\n );\n}\n"]}
1
+ {"version":3,"file":"team.js","sourceRoot":"","sources":["../../../src/routes/pages/team.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,SAAS;IAC/B,OAAO,KAAC,QAAQ,IAAC,EAAE,EAAC,gBAAgB,EAAC,OAAO,SAAG,CAAC;AAClD,CAAC","sourcesContent":["import { Navigate } from \"react-router\";\n\nexport function meta() {\n return [{ title: \"Team — Dispatch\" }];\n}\n\nexport default function TeamRoute() {\n return <Navigate to=\"/settings#team\" replace />;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/dispatch",
3
- "version": "0.13.1",
3
+ "version": "0.13.3",
4
4
  "description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -94,7 +94,7 @@
94
94
  "typescript": "^6.0.3",
95
95
  "vite": "8.1.0",
96
96
  "vitest": "^4.1.5",
97
- "@agent-native/core": "0.79.15"
97
+ "@agent-native/core": "0.80.0"
98
98
  },
99
99
  "peerDependencies": {
100
100
  "@agent-native/core": ">=0.8.0",
@@ -1,4 +1,5 @@
1
1
  import { defineAction } from "@agent-native/core";
2
+ import { resolveSecret } from "@agent-native/core/server";
2
3
  import { z } from "zod";
3
4
 
4
5
  import { recordAudit } from "../server/lib/dispatch-store.js";
@@ -33,7 +34,7 @@ export default defineAction({
33
34
  teamId: z.string().optional(),
34
35
  }),
35
36
  run: async (input) => {
36
- const apiKey = process.env.PYLON_API_KEY;
37
+ const apiKey = await resolveSecret("PYLON_API_KEY");
37
38
  if (!apiKey) {
38
39
  throw new Error(
39
40
  "PYLON_API_KEY is not set. Add it to the Dispatch Vault.",
@@ -3,6 +3,8 @@ import {
3
3
  slackAdapter,
4
4
  telegramAdapter,
5
5
  emailAdapter,
6
+ isEmailConfigured,
7
+ resolveSecret,
6
8
  } from "@agent-native/core/server";
7
9
  import { z } from "zod";
8
10
 
@@ -16,18 +18,20 @@ function getAdapter(platform: "slack" | "telegram" | "email") {
16
18
  return platform === "slack" ? slackAdapter() : telegramAdapter();
17
19
  }
18
20
 
19
- function assertOutboundConfigured(platform: "slack" | "telegram" | "email") {
20
- if (platform === "slack" && !process.env.SLACK_BOT_TOKEN) {
21
+ async function assertOutboundConfigured(
22
+ platform: "slack" | "telegram" | "email",
23
+ ) {
24
+ if (platform === "slack" && !(await resolveSecret("SLACK_BOT_TOKEN"))) {
21
25
  throw new Error("Slack outbound messaging is not configured");
22
26
  }
23
- if (platform === "telegram" && !process.env.TELEGRAM_BOT_TOKEN) {
27
+ if (platform === "telegram" && !(await resolveSecret("TELEGRAM_BOT_TOKEN"))) {
24
28
  throw new Error("Telegram outbound messaging is not configured");
25
29
  }
26
30
  if (platform === "email") {
27
- const hasProvider = !!(
28
- process.env.RESEND_API_KEY || process.env.SENDGRID_API_KEY
29
- );
30
- if (!process.env.EMAIL_AGENT_ADDRESS || !hasProvider) {
31
+ if (
32
+ !(await resolveSecret("EMAIL_AGENT_ADDRESS")) ||
33
+ !(await isEmailConfigured())
34
+ ) {
31
35
  throw new Error("Email outbound messaging is not configured");
32
36
  }
33
37
  }
@@ -59,7 +63,7 @@ export default defineAction({
59
63
  throw new Error("A platform and destination are required");
60
64
  }
61
65
 
62
- assertOutboundConfigured(resolvedPlatform);
66
+ await assertOutboundConfigured(resolvedPlatform);
63
67
 
64
68
  const adapter = getAdapter(resolvedPlatform);
65
69
  if (!adapter.sendMessageToTarget) {
@@ -1120,7 +1120,7 @@ function ReadinessPanel({
1120
1120
  label: "Team",
1121
1121
  detail: `${overview?.counts?.linkedIdentities ?? 0} linked identities`,
1122
1122
  ok: (overview?.counts?.linkedIdentities ?? 0) > 0,
1123
- to: "/team",
1123
+ to: "/settings#team",
1124
1124
  icon: IconUsersGroup,
1125
1125
  },
1126
1126
  ];
@@ -20,7 +20,6 @@ const pageTitles: Record<string, string> = {
20
20
  "/approvals": "Approvals",
21
21
  "/audit": "Audit",
22
22
  "/settings": "Settings",
23
- "/team": "Team",
24
23
  };
25
24
 
26
25
  function resolveTitle(pathname: string): string {
@@ -33,10 +33,11 @@ import {
33
33
  IconBroadcast,
34
34
  IconFingerprint,
35
35
  IconHistory,
36
+ IconLayoutSidebarLeftCollapse,
37
+ IconLayoutSidebarLeftExpand,
36
38
  IconPuzzle,
37
39
  IconSettings,
38
40
  IconShieldCheck,
39
- IconUsersGroup,
40
41
  } from "@tabler/icons-react";
41
42
  import {
42
43
  useEffect,
@@ -215,18 +216,12 @@ const OPERATIONS_NAV_ITEMS = [
215
216
  icon: IconSettings,
216
217
  section: "operations",
217
218
  },
218
- {
219
- id: "team",
220
- to: "/team",
221
- label: "Team",
222
- icon: IconUsersGroup,
223
- section: "operations",
224
- },
225
219
  ] as const satisfies readonly DispatchNavItem[];
226
220
 
227
221
  const EMPTY_NAV_ITEMS: readonly DispatchNavItem[] = [];
228
222
 
229
223
  const CHROMELESS_PATHS = ["/approval"];
224
+ const SIDEBAR_COLLAPSE_KEY = "dispatch.sidebar.collapsed";
230
225
 
231
226
  // Routes whose page renders its own toolbar (with NotificationsBell + AgentToggleButton).
232
227
  // Layout still mounts the sidebar + AgentSidebar, but skips its own Header so
@@ -581,9 +576,15 @@ function DispatchChatsSection({ onNavigate }: { onNavigate?: () => void }) {
581
576
  export function NavContent({
582
577
  onNavigate,
583
578
  extensions,
579
+ collapsed = false,
580
+ collapsible = false,
581
+ onCollapsedChange,
584
582
  }: {
585
583
  onNavigate?: () => void;
586
584
  extensions?: DispatchExtensionConfig;
585
+ collapsed?: boolean;
586
+ collapsible?: boolean;
587
+ onCollapsedChange?: (collapsed: boolean) => void;
587
588
  }) {
588
589
  const t = useT();
589
590
  const location = useLocation();
@@ -624,45 +625,91 @@ export function NavContent({
624
625
  const label = navLabel(item);
625
626
  return (
626
627
  <li key={item.id}>
627
- <NavLink
628
- to={dispatchNavLinkTarget(item.to)}
629
- onClick={(event) => {
630
- if (
631
- item.id === "chat" &&
632
- localPathname !== "/chat" &&
633
- !event.metaKey &&
634
- !event.ctrlKey &&
635
- !event.shiftKey &&
636
- !event.altKey
637
- ) {
638
- event.preventDefault();
639
- navigateWithAgentChatViewTransition(
640
- navigate,
641
- dispatchNavLinkTarget("/chat"),
642
- );
628
+ {collapsed ? (
629
+ <Tooltip>
630
+ <TooltipTrigger asChild>
631
+ <NavLink
632
+ to={dispatchNavLinkTarget(item.to)}
633
+ onClick={(event) => {
634
+ if (
635
+ item.id === "chat" &&
636
+ localPathname !== "/chat" &&
637
+ !event.metaKey &&
638
+ !event.ctrlKey &&
639
+ !event.shiftKey &&
640
+ !event.altKey
641
+ ) {
642
+ event.preventDefault();
643
+ navigateWithAgentChatViewTransition(
644
+ navigate,
645
+ dispatchNavLinkTarget("/chat"),
646
+ );
647
+ onNavigate?.();
648
+ return;
649
+ }
650
+ onNavigate?.();
651
+ }}
652
+ aria-label={label}
653
+ className={({ isActive }) => {
654
+ const active = isActive || itemMatchesLocalPath;
655
+ return cn(
656
+ "flex h-10 w-10 items-center justify-center rounded-md text-sm",
657
+ active
658
+ ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
659
+ : "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
660
+ );
661
+ }}
662
+ >
663
+ {Icon ? (
664
+ <Icon size={16} className="shrink-0" />
665
+ ) : (
666
+ <span className="h-4 w-4 shrink-0" aria-hidden="true" />
667
+ )}
668
+ </NavLink>
669
+ </TooltipTrigger>
670
+ <TooltipContent side="right">{label}</TooltipContent>
671
+ </Tooltip>
672
+ ) : (
673
+ <NavLink
674
+ to={dispatchNavLinkTarget(item.to)}
675
+ onClick={(event) => {
676
+ if (
677
+ item.id === "chat" &&
678
+ localPathname !== "/chat" &&
679
+ !event.metaKey &&
680
+ !event.ctrlKey &&
681
+ !event.shiftKey &&
682
+ !event.altKey
683
+ ) {
684
+ event.preventDefault();
685
+ navigateWithAgentChatViewTransition(
686
+ navigate,
687
+ dispatchNavLinkTarget("/chat"),
688
+ );
689
+ onNavigate?.();
690
+ return;
691
+ }
643
692
  onNavigate?.();
644
- return;
645
- }
646
- onNavigate?.();
647
- }}
648
- className={({ isActive }) => {
649
- const active = isActive || itemMatchesLocalPath;
650
- return cn(
651
- "flex h-8 w-full items-center gap-2 rounded-md px-2 text-sm",
652
- active
653
- ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
654
- : "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
655
- );
656
- }}
657
- >
658
- {Icon ? (
659
- <Icon size={16} className="shrink-0" />
660
- ) : (
661
- <span className="h-4 w-4 shrink-0" aria-hidden="true" />
662
- )}
663
- <span className="truncate">{label}</span>
664
- </NavLink>
665
- {item.id === "chat" && itemMatchesLocalPath ? (
693
+ }}
694
+ className={({ isActive }) => {
695
+ const active = isActive || itemMatchesLocalPath;
696
+ return cn(
697
+ "flex h-8 w-full items-center gap-2 rounded-md px-2 text-sm",
698
+ active
699
+ ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
700
+ : "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
701
+ );
702
+ }}
703
+ >
704
+ {Icon ? (
705
+ <Icon size={16} className="shrink-0" />
706
+ ) : (
707
+ <span className="h-4 w-4 shrink-0" aria-hidden="true" />
708
+ )}
709
+ <span className="truncate">{label}</span>
710
+ </NavLink>
711
+ )}
712
+ {!collapsed && item.id === "chat" && itemMatchesLocalPath ? (
666
713
  <DispatchChatsSection onNavigate={onNavigate} />
667
714
  ) : null}
668
715
  </li>
@@ -671,70 +718,118 @@ export function NavContent({
671
718
 
672
719
  return (
673
720
  <>
674
- <div className="border-b px-4 py-3">
675
- <div className="flex items-center gap-3">
676
- <div className="flex h-9 w-9 items-center justify-center rounded-xl border bg-card text-foreground">
677
- <img
678
- src={appPath("/agent-native-icon-light.svg")}
679
- alt=""
680
- aria-hidden="true"
681
- className="block h-4 w-auto shrink-0 dark:hidden"
682
- />
683
- <img
684
- src={appPath("/agent-native-icon-dark.svg")}
685
- alt=""
686
- aria-hidden="true"
687
- className="hidden h-4 w-auto shrink-0 dark:block"
688
- />
689
- </div>
690
- <div className="min-w-0">
691
- <div className="truncate text-sm font-semibold text-foreground">
692
- {workspaceLabel ?? "Dispatch"}
693
- </div>
694
- <div className="truncate text-xs text-muted-foreground">
695
- {workspaceLabel
696
- ? t("dispatch.sidebar.workspaceSubtitle", {
697
- count: ws?.appCount ?? 0,
698
- })
699
- : t("dispatch.sidebar.workspaceControlPlane")}
700
- </div>
701
- </div>
721
+ <div className={cn("border-b py-3", collapsed ? "px-1" : "px-4")}>
722
+ <div
723
+ className={cn(
724
+ "flex items-center",
725
+ collapsed ? "justify-center" : "gap-3",
726
+ )}
727
+ >
728
+ {!collapsed && (
729
+ <>
730
+ <div className="flex h-9 w-9 items-center justify-center rounded-xl border bg-card text-foreground">
731
+ <img
732
+ src={appPath("/agent-native-icon-light.svg")}
733
+ alt=""
734
+ aria-hidden="true"
735
+ className="block h-4 w-auto shrink-0 dark:hidden"
736
+ />
737
+ <img
738
+ src={appPath("/agent-native-icon-dark.svg")}
739
+ alt=""
740
+ aria-hidden="true"
741
+ className="hidden h-4 w-auto shrink-0 dark:block"
742
+ />
743
+ </div>
744
+ <div className="min-w-0 flex-1">
745
+ <div className="truncate text-sm font-semibold text-foreground">
746
+ {workspaceLabel ?? "Dispatch"}
747
+ </div>
748
+ <div className="truncate text-xs text-muted-foreground">
749
+ {workspaceLabel
750
+ ? t("dispatch.sidebar.workspaceSubtitle", {
751
+ count: ws?.appCount ?? 0,
752
+ })
753
+ : t("dispatch.sidebar.workspaceControlPlane")}
754
+ </div>
755
+ </div>
756
+ </>
757
+ )}
758
+ {collapsible ? (
759
+ <Tooltip>
760
+ <TooltipTrigger asChild>
761
+ <button
762
+ type="button"
763
+ onClick={() => onCollapsedChange?.(!collapsed)}
764
+ aria-label={
765
+ collapsed
766
+ ? t("sidebar.expandSidebar")
767
+ : t("sidebar.collapseSidebar")
768
+ }
769
+ className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
770
+ >
771
+ {collapsed ? (
772
+ <IconLayoutSidebarLeftExpand className="h-4 w-4 rtl:-scale-x-100" />
773
+ ) : (
774
+ <IconLayoutSidebarLeftCollapse className="h-4 w-4 rtl:-scale-x-100" />
775
+ )}
776
+ </button>
777
+ </TooltipTrigger>
778
+ <TooltipContent side="right">
779
+ {collapsed
780
+ ? t("sidebar.expandSidebar")
781
+ : t("sidebar.collapseSidebar")}
782
+ </TooltipContent>
783
+ </Tooltip>
784
+ ) : null}
702
785
  </div>
703
786
  </div>
704
787
 
705
788
  <div className="flex min-h-0 flex-1 flex-col overflow-y-auto">
706
- <nav className="px-2 py-3">
707
- <ul className="space-y-0.5">{primaryNavItems.map(renderNavItem)}</ul>
789
+ <nav className={cn("py-3", collapsed ? "px-1" : "px-2")}>
790
+ <ul
791
+ className={cn(
792
+ "space-y-0.5",
793
+ collapsed && "flex flex-col items-center",
794
+ )}
795
+ >
796
+ {(collapsed
797
+ ? [...primaryNavItems, ...operationsNavItems]
798
+ : primaryNavItems
799
+ ).map(renderNavItem)}
800
+ </ul>
708
801
  </nav>
709
802
 
710
- <div className="mt-auto shrink-0">
711
- <div className="border-t px-2 py-2">
712
- <details className="group" open={operationsOpen}>
713
- <summary className="flex h-8 cursor-pointer list-none items-center justify-between rounded-md px-2 text-xs font-medium uppercase text-sidebar-foreground/50 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground [&::-webkit-details-marker]:hidden">
714
- <span>{t("dispatch.nav.operations")}</span>
715
- <IconChevronDown
716
- size={14}
717
- className="transition-transform group-open:rotate-180"
718
- />
719
- </summary>
720
- <ul className="mt-1 space-y-0.5">
721
- {operationsNavItems.map(renderNavItem)}
722
- </ul>
723
- </details>
724
- </div>
803
+ {!collapsed ? (
804
+ <div className="mt-auto shrink-0">
805
+ <div className="px-2 py-2">
806
+ <details className="group" open={operationsOpen}>
807
+ <summary className="flex h-8 cursor-pointer list-none items-center justify-between rounded-md px-2 text-xs font-medium uppercase text-sidebar-foreground/50 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground [&::-webkit-details-marker]:hidden">
808
+ <span>{t("dispatch.nav.operations")}</span>
809
+ <IconChevronDown
810
+ size={14}
811
+ className="transition-transform group-open:rotate-180"
812
+ />
813
+ </summary>
814
+ <ul className="mt-1 space-y-0.5">
815
+ {operationsNavItems.map(renderNavItem)}
816
+ </ul>
817
+ </details>
818
+ </div>
725
819
 
726
- <div className="border-t px-2 py-1">
727
- <ExtensionsSidebarSection />
728
- </div>
820
+ <div className="px-2 py-1">
821
+ <ExtensionsSidebarSection />
822
+ </div>
729
823
 
730
- <div className="border-t px-3 py-2">
731
- <OrgSwitcher />
732
- </div>
824
+ <div className="px-3 py-2">
825
+ <OrgSwitcher />
826
+ </div>
733
827
 
734
- <div className="border-t px-3 py-2">
735
- <FeedbackButton />
828
+ <div className="px-3 py-2">
829
+ <FeedbackButton />
830
+ </div>
736
831
  </div>
737
- </div>
832
+ ) : null}
738
833
  </div>
739
834
  </>
740
835
  );
@@ -751,6 +846,14 @@ export function Layout({
751
846
  const location = useLocation();
752
847
  const navigate = useNavigate();
753
848
  const [mobileOpen, setMobileOpen] = useState(false);
849
+ const [sidebarCollapsed, setSidebarCollapsed] = useState(() => {
850
+ if (typeof window === "undefined") return false;
851
+ try {
852
+ return window.localStorage.getItem(SIDEBAR_COLLAPSE_KEY) === "1";
853
+ } catch {
854
+ return false;
855
+ }
856
+ });
754
857
  const localPathname = localDispatchPath(location.pathname);
755
858
  const isChatRoute =
756
859
  localPathname === "/chat" || localPathname.startsWith("/chat/");
@@ -766,6 +869,18 @@ export function Layout({
766
869
  };
767
870
  useAgentChatHomeHandoffLinks(chatHandoffLinkOptions);
768
871
 
872
+ useEffect(() => {
873
+ if (typeof window === "undefined") return;
874
+ try {
875
+ window.localStorage.setItem(
876
+ SIDEBAR_COLLAPSE_KEY,
877
+ sidebarCollapsed ? "1" : "0",
878
+ );
879
+ } catch {
880
+ // Ignore storage failures; the in-memory preference still works.
881
+ }
882
+ }, [sidebarCollapsed]);
883
+
769
884
  if (CHROMELESS_PATHS.some((path) => localPathname === path)) {
770
885
  return <>{children}</>;
771
886
  }
@@ -825,8 +940,19 @@ export function Layout({
825
940
  return (
826
941
  <HeaderActionsProvider>
827
942
  <div className="agent-layout-shell flex h-screen w-full overflow-hidden bg-background">
828
- <aside className="agent-layout-left-drawer hidden lg:flex w-64 shrink-0 flex-col border-e bg-sidebar text-sidebar-foreground">
829
- <NavContent extensions={extensions} />
943
+ <aside
944
+ data-collapsed={sidebarCollapsed ? "true" : "false"}
945
+ className={cn(
946
+ "agent-layout-left-drawer hidden shrink-0 flex-col border-e bg-sidebar text-sidebar-foreground transition-[width] duration-200 ease-out lg:flex",
947
+ sidebarCollapsed ? "w-12" : "w-64",
948
+ )}
949
+ >
950
+ <NavContent
951
+ extensions={extensions}
952
+ collapsed={sidebarCollapsed}
953
+ collapsible
954
+ onCollapsedChange={setSidebarCollapsed}
955
+ />
830
956
  </aside>
831
957
 
832
958
  <Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
@@ -843,6 +969,7 @@ export function Layout({
843
969
  <div className="flex h-full w-full flex-col">
844
970
  <NavContent
845
971
  extensions={extensions}
972
+ collapsed={false}
846
973
  onNavigate={() => setMobileOpen(false)}
847
974
  />
848
975
  </div>
@@ -219,7 +219,7 @@ function resolveView(
219
219
  if (pathname.startsWith("/audit")) return "audit";
220
220
  if (pathname.startsWith("/dreams")) return "dreams";
221
221
  if (pathname.startsWith("/thread-debug")) return "thread-debug";
222
- if (pathname.startsWith("/team")) return "team";
222
+ if (pathname.startsWith("/team")) return "settings";
223
223
  return "overview";
224
224
  }
225
225
 
@@ -271,7 +271,7 @@ function resolvePath(
271
271
  case "threads":
272
272
  return "/thread-debug";
273
273
  case "team":
274
- return "/team";
274
+ return "/settings#team";
275
275
  case "extensions":
276
276
  return command?.extensionId
277
277
  ? `/extensions/${encodeURIComponent(command.extensionId)}`