@agent-native/dispatch 0.23.5 → 0.24.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.
Files changed (224) hide show
  1. package/dist/actions/list-connected-agents.d.ts +1 -0
  2. package/dist/actions/list-connected-agents.js +5 -1
  3. package/dist/actions/list-connected-agents.js.map +1 -1
  4. package/dist/actions/list-dispatch-usage-metrics.d.ts +2 -0
  5. package/dist/actions/list-dispatch-usage-metrics.js +11 -1
  6. package/dist/actions/list-dispatch-usage-metrics.js.map +1 -1
  7. package/dist/actions/provider-api-register.d.ts +12 -12
  8. package/dist/actions/remix-workspace-template.js +4 -3
  9. package/dist/actions/remix-workspace-template.js.map +1 -1
  10. package/dist/actions/scaffold-workspace-app.js +3 -2
  11. package/dist/actions/scaffold-workspace-app.js.map +1 -1
  12. package/dist/actions/start-workspace-app-creation.js +3 -2
  13. package/dist/actions/start-workspace-app-creation.js.map +1 -1
  14. package/dist/actions/view-screen.js +11 -1
  15. package/dist/actions/view-screen.js.map +1 -1
  16. package/dist/components/admin-navigation.d.ts.map +1 -1
  17. package/dist/components/admin-navigation.js +21 -5
  18. package/dist/components/admin-navigation.js.map +1 -1
  19. package/dist/components/app-icon.js +1 -1
  20. package/dist/components/app-icon.js.map +1 -1
  21. package/dist/components/app-list-row.d.ts +1 -1
  22. package/dist/components/app-list-row.d.ts.map +1 -1
  23. package/dist/components/app-list-row.js +1 -1
  24. package/dist/components/app-list-row.js.map +1 -1
  25. package/dist/components/app-open-actions.d.ts +1 -17
  26. package/dist/components/app-open-actions.d.ts.map +1 -1
  27. package/dist/components/app-open-actions.js +1 -20
  28. package/dist/components/app-open-actions.js.map +1 -1
  29. package/dist/components/app-row-settings.d.ts +6 -0
  30. package/dist/components/app-row-settings.d.ts.map +1 -0
  31. package/dist/components/app-row-settings.js +11 -0
  32. package/dist/components/app-row-settings.js.map +1 -0
  33. package/dist/components/automation-run-history-dialog.d.ts.map +1 -1
  34. package/dist/components/automation-run-history-dialog.js +3 -2
  35. package/dist/components/automation-run-history-dialog.js.map +1 -1
  36. package/dist/components/connected-app-card.d.ts.map +1 -1
  37. package/dist/components/connected-app-card.js +3 -2
  38. package/dist/components/connected-app-card.js.map +1 -1
  39. package/dist/components/create-app-popover.js +2 -2
  40. package/dist/components/create-app-popover.js.map +1 -1
  41. package/dist/components/dispatch-control-plane.d.ts.map +1 -1
  42. package/dist/components/dispatch-control-plane.js +23 -7
  43. package/dist/components/dispatch-control-plane.js.map +1 -1
  44. package/dist/components/dispatch-shell.d.ts.map +1 -1
  45. package/dist/components/dispatch-shell.js +5 -1
  46. package/dist/components/dispatch-shell.js.map +1 -1
  47. package/dist/components/docs-link.d.ts +16 -0
  48. package/dist/components/docs-link.d.ts.map +1 -0
  49. package/dist/components/docs-link.js +34 -0
  50. package/dist/components/docs-link.js.map +1 -0
  51. package/dist/components/layout/Layout.d.ts +1 -0
  52. package/dist/components/layout/Layout.d.ts.map +1 -1
  53. package/dist/components/layout/Layout.js +43 -35
  54. package/dist/components/layout/Layout.js.map +1 -1
  55. package/dist/components/messaging-setup-panel.d.ts.map +1 -1
  56. package/dist/components/messaging-setup-panel.js +3 -2
  57. package/dist/components/messaging-setup-panel.js.map +1 -1
  58. package/dist/components/usage-alerts-panel.d.ts +11 -0
  59. package/dist/components/usage-alerts-panel.d.ts.map +1 -0
  60. package/dist/components/usage-alerts-panel.js +125 -0
  61. package/dist/components/usage-alerts-panel.js.map +1 -0
  62. package/dist/components/workspace-app-card.d.ts +3 -1
  63. package/dist/components/workspace-app-card.d.ts.map +1 -1
  64. package/dist/components/workspace-app-card.js +70 -29
  65. package/dist/components/workspace-app-card.js.map +1 -1
  66. package/dist/components/workspace-app-search.d.ts +10 -0
  67. package/dist/components/workspace-app-search.d.ts.map +1 -0
  68. package/dist/components/workspace-app-search.js +27 -0
  69. package/dist/components/workspace-app-search.js.map +1 -0
  70. package/dist/components/workspace-resource-effective-stack.d.ts.map +1 -1
  71. package/dist/components/workspace-resource-effective-stack.js +3 -2
  72. package/dist/components/workspace-resource-effective-stack.js.map +1 -1
  73. package/dist/components/workspace-template-card.d.ts.map +1 -1
  74. package/dist/components/workspace-template-card.js +10 -15
  75. package/dist/components/workspace-template-card.js.map +1 -1
  76. package/dist/hooks/use-navigation-state.d.ts +2 -0
  77. package/dist/hooks/use-navigation-state.d.ts.map +1 -1
  78. package/dist/hooks/use-navigation-state.js +10 -0
  79. package/dist/hooks/use-navigation-state.js.map +1 -1
  80. package/dist/lib/embed-session-recovery.d.ts +3 -0
  81. package/dist/lib/embed-session-recovery.d.ts.map +1 -0
  82. package/dist/lib/embed-session-recovery.js +18 -0
  83. package/dist/lib/embed-session-recovery.js.map +1 -0
  84. package/dist/lib/other-apps.d.ts +2 -0
  85. package/dist/lib/other-apps.d.ts.map +1 -1
  86. package/dist/lib/other-apps.js.map +1 -1
  87. package/dist/lib/workspace-app-layout.d.ts +19 -0
  88. package/dist/lib/workspace-app-layout.d.ts.map +1 -0
  89. package/dist/lib/workspace-app-layout.js +75 -0
  90. package/dist/lib/workspace-app-layout.js.map +1 -0
  91. package/dist/lib/workspace-apps.d.ts +14 -0
  92. package/dist/lib/workspace-apps.d.ts.map +1 -1
  93. package/dist/lib/workspace-apps.js +66 -0
  94. package/dist/lib/workspace-apps.js.map +1 -1
  95. package/dist/lib/workspace-apps.test.d.ts +2 -0
  96. package/dist/lib/workspace-apps.test.d.ts.map +1 -0
  97. package/dist/lib/workspace-apps.test.js +33 -0
  98. package/dist/lib/workspace-apps.test.js.map +1 -0
  99. package/dist/routes/pages/$appId.d.ts.map +1 -1
  100. package/dist/routes/pages/$appId.js +4 -2
  101. package/dist/routes/pages/$appId.js.map +1 -1
  102. package/dist/routes/pages/agents.d.ts.map +1 -1
  103. package/dist/routes/pages/agents.js +2 -3
  104. package/dist/routes/pages/agents.js.map +1 -1
  105. package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
  106. package/dist/routes/pages/apps.$appId.js +17 -13
  107. package/dist/routes/pages/apps.$appId.js.map +1 -1
  108. package/dist/routes/pages/apps.d.ts.map +1 -1
  109. package/dist/routes/pages/apps.js +31 -16
  110. package/dist/routes/pages/apps.js.map +1 -1
  111. package/dist/routes/pages/audit.d.ts.map +1 -1
  112. package/dist/routes/pages/audit.js +2 -1
  113. package/dist/routes/pages/audit.js.map +1 -1
  114. package/dist/routes/pages/chat.d.ts.map +1 -1
  115. package/dist/routes/pages/chat.js +7 -2
  116. package/dist/routes/pages/chat.js.map +1 -1
  117. package/dist/routes/pages/dreams.d.ts.map +1 -1
  118. package/dist/routes/pages/dreams.js +14 -18
  119. package/dist/routes/pages/dreams.js.map +1 -1
  120. package/dist/routes/pages/integrations.d.ts.map +1 -1
  121. package/dist/routes/pages/integrations.js +51 -14
  122. package/dist/routes/pages/integrations.js.map +1 -1
  123. package/dist/routes/pages/metrics.d.ts.map +1 -1
  124. package/dist/routes/pages/metrics.js +146 -17
  125. package/dist/routes/pages/metrics.js.map +1 -1
  126. package/dist/routes/pages/operations.js +1 -1
  127. package/dist/routes/pages/operations.js.map +1 -1
  128. package/dist/routes/pages/settings.d.ts.map +1 -1
  129. package/dist/routes/pages/settings.js +19 -2
  130. package/dist/routes/pages/settings.js.map +1 -1
  131. package/dist/routes/pages/thread-debug.d.ts.map +1 -1
  132. package/dist/routes/pages/thread-debug.js +5 -8
  133. package/dist/routes/pages/thread-debug.js.map +1 -1
  134. package/dist/routes/pages/vault.d.ts.map +1 -1
  135. package/dist/routes/pages/vault.js +1 -1
  136. package/dist/routes/pages/vault.js.map +1 -1
  137. package/dist/routes/pages/workspace.d.ts.map +1 -1
  138. package/dist/routes/pages/workspace.js +13 -10
  139. package/dist/routes/pages/workspace.js.map +1 -1
  140. package/dist/server/index.d.ts.map +1 -1
  141. package/dist/server/index.js +3 -0
  142. package/dist/server/index.js.map +1 -1
  143. package/dist/server/lib/app-creation-store.d.ts.map +1 -1
  144. package/dist/server/lib/app-creation-store.js +12 -52
  145. package/dist/server/lib/app-creation-store.js.map +1 -1
  146. package/dist/server/lib/usage-metrics-store.d.ts +17 -0
  147. package/dist/server/lib/usage-metrics-store.d.ts.map +1 -1
  148. package/dist/server/lib/usage-metrics-store.js +187 -30
  149. package/dist/server/lib/usage-metrics-store.js.map +1 -1
  150. package/dist/server/plugins/agent-chat.js +2 -0
  151. package/dist/server/plugins/agent-chat.js.map +1 -1
  152. package/dist/server/plugins/integrations.d.ts.map +1 -1
  153. package/dist/server/plugins/integrations.js +1 -0
  154. package/dist/server/plugins/integrations.js.map +1 -1
  155. package/dist/shared/app-roles.d.ts +9 -0
  156. package/dist/shared/app-roles.d.ts.map +1 -0
  157. package/dist/shared/app-roles.js +7 -0
  158. package/dist/shared/app-roles.js.map +1 -0
  159. package/package.json +4 -3
  160. package/src/actions/list-connected-agents.spec.ts +73 -0
  161. package/src/actions/list-connected-agents.ts +6 -2
  162. package/src/actions/list-dispatch-usage-metrics.ts +11 -1
  163. package/src/actions/remix-workspace-template.spec.ts +29 -0
  164. package/src/actions/remix-workspace-template.ts +13 -6
  165. package/src/actions/scaffold-workspace-app.ts +12 -5
  166. package/src/actions/start-workspace-app-creation.ts +8 -2
  167. package/src/actions/view-screen.ts +13 -1
  168. package/src/components/admin-navigation.tsx +57 -11
  169. package/src/components/app-icon.spec.tsx +34 -0
  170. package/src/components/app-icon.tsx +1 -1
  171. package/src/components/app-list-row.tsx +1 -2
  172. package/src/components/app-open-actions.tsx +5 -114
  173. package/src/components/app-row-settings.tsx +54 -0
  174. package/src/components/automation-run-history-dialog.tsx +8 -4
  175. package/src/components/connected-app-card.tsx +3 -2
  176. package/src/components/create-app-popover.spec.tsx +1 -1
  177. package/src/components/create-app-popover.tsx +2 -2
  178. package/src/components/dispatch-control-plane.spec.tsx +44 -3
  179. package/src/components/dispatch-control-plane.tsx +83 -27
  180. package/src/components/dispatch-shell.tsx +7 -1
  181. package/src/components/docs-link.tsx +52 -0
  182. package/src/components/layout/Layout.spec.tsx +13 -0
  183. package/src/components/layout/Layout.tsx +63 -32
  184. package/src/components/messaging-setup-panel.tsx +10 -3
  185. package/src/components/usage-alerts-panel.tsx +445 -0
  186. package/src/components/workspace-app-card.spec.tsx +130 -9
  187. package/src/components/workspace-app-card.tsx +128 -71
  188. package/src/components/workspace-app-search.tsx +96 -0
  189. package/src/components/workspace-resource-effective-stack.tsx +10 -5
  190. package/src/components/workspace-template-card.spec.tsx +53 -24
  191. package/src/components/workspace-template-card.tsx +16 -26
  192. package/src/hooks/use-navigation-state.ts +12 -0
  193. package/src/lib/embed-session-recovery.spec.ts +63 -0
  194. package/src/lib/embed-session-recovery.ts +26 -0
  195. package/src/lib/other-apps.ts +2 -0
  196. package/src/lib/workspace-app-layout.spec.ts +47 -0
  197. package/src/lib/workspace-app-layout.ts +121 -0
  198. package/src/lib/workspace-apps.test.ts +64 -0
  199. package/src/lib/workspace-apps.ts +82 -0
  200. package/src/routes/pages/$appId.tsx +3 -6
  201. package/src/routes/pages/agents.tsx +6 -3
  202. package/src/routes/pages/apps.$appId.tsx +16 -17
  203. package/src/routes/pages/apps.tsx +116 -62
  204. package/src/routes/pages/audit.tsx +28 -8
  205. package/src/routes/pages/chat.spec.tsx +10 -0
  206. package/src/routes/pages/chat.tsx +8 -0
  207. package/src/routes/pages/dreams.tsx +92 -142
  208. package/src/routes/pages/integrations.tsx +147 -68
  209. package/src/routes/pages/metrics.tsx +460 -102
  210. package/src/routes/pages/operations.tsx +2 -2
  211. package/src/routes/pages/settings.tsx +27 -10
  212. package/src/routes/pages/thread-debug.tsx +18 -36
  213. package/src/routes/pages/vault.tsx +7 -2
  214. package/src/routes/pages/workspace.tsx +92 -56
  215. package/src/server/index.ts +4 -0
  216. package/src/server/lib/app-creation-store.spec.ts +90 -43
  217. package/src/server/lib/app-creation-store.ts +15 -61
  218. package/src/server/lib/usage-metrics-store.spec.ts +117 -0
  219. package/src/server/lib/usage-metrics-store.ts +249 -30
  220. package/src/server/plugins/agent-chat.spec.ts +4 -0
  221. package/src/server/plugins/agent-chat.ts +2 -0
  222. package/src/server/plugins/integrations.ts +1 -0
  223. package/src/shared/app-roles.ts +8 -0
  224. package/src/styles/dispatch.css +9 -0
@@ -102,11 +102,13 @@ import {
102
102
  import { Link, useLocation, useNavigate } from "react-router";
103
103
  import { toast } from "sonner";
104
104
 
105
+ import { isEmbedSessionExpiredMessage } from "../../lib/embed-session-recovery";
105
106
  import { cn } from "../../lib/utils";
106
107
  import {
107
108
  isDispatchWorkspaceAppId,
108
109
  isWorkspaceAppVisibleInDefaultLaunchers,
109
110
  mergeChatFirstWorkspaceApps,
111
+ workspaceAppDirectHref,
110
112
  workspaceAppIdFromRoute,
111
113
  workspaceAppRoute,
112
114
  type WorkspaceAppSummary,
@@ -305,6 +307,10 @@ export function isElectronEmbeddedSearch(search: string): boolean {
305
307
  return new URLSearchParams(search).get("electron") === "1";
306
308
  }
307
309
 
310
+ export function shouldAutoCollapseDispatchSidebar(pathname: string): boolean {
311
+ return localDispatchPath(pathname).startsWith("/apps/");
312
+ }
313
+
308
314
  function chatFirstPrimaryTabForPath(
309
315
  pathname: string,
310
316
  ): ChatFirstPrimaryTab | undefined {
@@ -533,16 +539,6 @@ function threadTitle(thread: ChatThreadSummary, fallback: string) {
533
539
  return thread.title || thread.preview || fallback;
534
540
  }
535
541
 
536
- function readChatHistoryIncludesExternal(): boolean {
537
- if (typeof window === "undefined") return false;
538
- try {
539
- return localStorage.getItem(CHAT_HISTORY_SOURCE_KEY) === "all";
540
- } catch {
541
- // coercion-ok: localStorage is optional browser persistence.
542
- return false;
543
- }
544
- }
545
-
546
542
  function threadSourceIcon(platform: string | undefined): ReactNode {
547
543
  const normalized = platform?.trim().toLowerCase();
548
544
  if (!normalized) return null;
@@ -555,6 +551,16 @@ function threadSourceIcon(platform: string | undefined): ReactNode {
555
551
  return <IconWorld size={13} aria-hidden="true" />;
556
552
  }
557
553
 
554
+ function readChatHistoryIncludesExternal(): boolean {
555
+ if (typeof window === "undefined") return false;
556
+ try {
557
+ return localStorage.getItem(CHAT_HISTORY_SOURCE_KEY) === "all";
558
+ } catch {
559
+ // coercion-ok: localStorage is optional browser persistence.
560
+ return false;
561
+ }
562
+ }
563
+
558
564
  function threadUpdatedAt(thread: ChatThreadSummary) {
559
565
  return Number.isFinite(thread.updatedAt)
560
566
  ? thread.updatedAt
@@ -594,6 +600,7 @@ function DispatchChatsSection({
594
600
  threads,
595
601
  activeThreadId,
596
602
  isLoading: chatsLoading,
603
+ threadsLoadError,
597
604
  createThread,
598
605
  switchThread,
599
606
  renameThread,
@@ -610,7 +617,7 @@ function DispatchChatsSection({
610
617
  (thread) => thread.messageCount > 0 || thread.id === activeThreadId,
611
618
  )
612
619
  .sort((a, b) => threadUpdatedAt(b) - threadUpdatedAt(a))
613
- .slice(0, 15),
620
+ .slice(0, 8),
614
621
  [activeThreadId, threads],
615
622
  );
616
623
  const localPathname = localDispatchPath(location.pathname);
@@ -649,6 +656,16 @@ function DispatchChatsSection({
649
656
  : formatThreadAge(threadUpdatedAt(thread)),
650
657
  };
651
658
  });
659
+ const chatHistoryError = threadsLoadError ? (
660
+ <button
661
+ type="button"
662
+ onClick={() => void refreshThreads()}
663
+ className="flex w-full items-center justify-between gap-2 rounded-md px-2 py-1.5 text-xs text-sidebar-foreground/65 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"
664
+ >
665
+ <span>Could not load chats</span>
666
+ <span className="font-medium">Retry</span>
667
+ </button>
668
+ ) : undefined;
652
669
 
653
670
  useEffect(() => {
654
671
  setIncludeExternal(readChatHistoryIncludesExternal());
@@ -801,6 +818,7 @@ function DispatchChatsSection({
801
818
  </div>
802
819
  }
803
820
  label={t("dispatch.sidebar.chats", { defaultValue: "Chats" })}
821
+ error={chatHistoryError}
804
822
  onSelect={(threadId) => openThread(threadId)}
805
823
  renameMaxLength={160}
806
824
  onRename={(threadId, title) => void renameThread(threadId, title)}
@@ -869,6 +887,7 @@ function DispatchChatsSection({
869
887
  showMore: t("dispatch.sidebar.chats"),
870
888
  showLess: t("dispatch.sidebar.chats"),
871
889
  }}
890
+ error={chatHistoryError}
872
891
  renameMaxLength={160}
873
892
  onRename={(threadId, title) => void renameThread(threadId, title)}
874
893
  labels={{
@@ -923,7 +942,7 @@ function DispatchChatsSection({
923
942
  ) : null}
924
943
  </>
925
944
  )}
926
- className={cn("min-w-0", chatFirstMode && "px-2")}
945
+ className="min-w-0 px-2"
927
946
  />
928
947
  )}
929
948
  </div>
@@ -1193,7 +1212,7 @@ export function NavContent({
1193
1212
  <div
1194
1213
  className={cn("py-2", collapsed ? "flex justify-center px-1" : "px-3")}
1195
1214
  >
1196
- <OrgSwitcher compact={collapsed} reserveSpace />
1215
+ <OrgSwitcher compact={collapsed} reserveSpace currentAppId="dispatch" />
1197
1216
  </div>
1198
1217
  );
1199
1218
  const sidebarFooterActions = (
@@ -1213,9 +1232,12 @@ export function NavContent({
1213
1232
  collapsed ? "justify-center px-0" : "px-4",
1214
1233
  )}
1215
1234
  >
1216
- <div
1235
+ <Link
1236
+ to={dispatchNavLinkTarget("/overview")}
1237
+ aria-label={`${DISPATCH_SIDEBAR_LABEL} overview`}
1238
+ data-dispatch-logo
1217
1239
  className={cn(
1218
- "flex items-center",
1240
+ "flex items-center rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring",
1219
1241
  collapsed ? "justify-center" : "gap-2",
1220
1242
  )}
1221
1243
  >
@@ -1251,7 +1273,7 @@ export function NavContent({
1251
1273
  </div>
1252
1274
  </div>
1253
1275
  )}
1254
- </div>
1276
+ </Link>
1255
1277
  </div>
1256
1278
 
1257
1279
  {chatFirstMode ? (
@@ -1344,7 +1366,9 @@ export function Layout({
1344
1366
  const isChatRoute =
1345
1367
  localPathname === "/chat" || localPathname.startsWith("/chat/");
1346
1368
  const chatFirstSurfaceScope = threadIdFromPath(localPathname) ?? "new";
1347
- const isWorkspaceAppRoute = localPathname.startsWith("/apps/");
1369
+ const isWorkspaceAppRoute = shouldAutoCollapseDispatchSidebar(
1370
+ location.pathname,
1371
+ );
1348
1372
  const isWorkspaceAppHostRoute =
1349
1373
  isWorkspaceAppRoute &&
1350
1374
  typeof window !== "undefined" &&
@@ -1369,12 +1393,6 @@ export function Layout({
1369
1393
  `${url.pathname}${url.search}${url.hash}`,
1370
1394
  );
1371
1395
  }, [electronEmbedded, location.pathname, location.search]);
1372
- useEffect(() => {
1373
- if (!chatFirstMode || chatFirstEmbedded || localPathname !== "/overview") {
1374
- return;
1375
- }
1376
- navigate(dispatchNavLinkTarget("/chat"), { replace: true });
1377
- }, [chatFirstEmbedded, chatFirstMode, localPathname, navigate]);
1378
1396
  const [chatFirstAppLayout, setChatFirstAppLayout] =
1379
1397
  useState<ChatFirstAppLayoutPreference>(() => readChatFirstAppLayout());
1380
1398
  const chatFirstAppLayoutHydratedRef = useRef(false);
@@ -1561,6 +1579,13 @@ export function Layout({
1561
1579
  })
1562
1580
  .catch((cause: unknown) => {
1563
1581
  if (!cancelled) {
1582
+ const directAppUrl = activeChatFirstAppRegistration
1583
+ ? workspaceAppDirectHref(
1584
+ activeChatFirstAppRegistration,
1585
+ chatFirstEmbedPath,
1586
+ )
1587
+ : null;
1588
+ if (directAppUrl) setChatFirstEmbedUrl(directAppUrl);
1564
1589
  setChatFirstEmbedError(
1565
1590
  cause instanceof Error
1566
1591
  ? cause.message
@@ -1586,11 +1611,9 @@ export function Layout({
1586
1611
 
1587
1612
  const handleEmbedSessionExpired = (event: MessageEvent) => {
1588
1613
  if (
1589
- event.data?.type !== "agentNative.embedSessionExpired" ||
1590
- event.source !== chatFirstAppFrameRef.current?.contentWindow
1591
- ) {
1614
+ !isEmbedSessionExpiredMessage(event, chatFirstAppFrameRef.current, null)
1615
+ )
1592
1616
  return;
1593
- }
1594
1617
  setChatFirstEmbedAttempt((attempt) => attempt + 1);
1595
1618
  };
1596
1619
 
@@ -1627,6 +1650,7 @@ export function Layout({
1627
1650
  placement: ChatFirstAppSurfacePlacement = "side",
1628
1651
  ) => {
1629
1652
  if (placement === "side" && !chatFirstHasActiveChat) return;
1653
+ setSidebarCollapsed(true);
1630
1654
  setChatFirstNotice(null);
1631
1655
  closeChatFirstSessionWatch();
1632
1656
  if (!isChatRoute) {
@@ -2025,6 +2049,11 @@ export function Layout({
2025
2049
  isChatRoute,
2026
2050
  ]);
2027
2051
 
2052
+ useEffect(() => {
2053
+ if (!isWorkspaceAppRoute) return;
2054
+ setSidebarCollapsed(true);
2055
+ }, [isWorkspaceAppRoute, localPathname]);
2056
+
2028
2057
  useEffect(() => {
2029
2058
  if (typeof window === "undefined" || isWorkspaceAppHostRoute) return;
2030
2059
  try {
@@ -2109,13 +2138,14 @@ export function Layout({
2109
2138
  chatOnly
2110
2139
  dynamicSuggestions={false}
2111
2140
  suggestions={[]}
2141
+ suppressInlineOpenApp={chatFirstMode}
2112
2142
  emptyStateDisplay="hidden"
2113
2143
  composerPlaceholder={t(
2114
2144
  "dispatch.pages.chatFirstSessionMessagePlaceholder",
2115
2145
  )}
2116
2146
  />
2117
2147
  ),
2118
- [t],
2148
+ [chatFirstMode, t],
2119
2149
  );
2120
2150
 
2121
2151
  const renderChatFirstSurfaceTab = useCallback(
@@ -2137,10 +2167,10 @@ export function Layout({
2137
2167
  <ChatFirstAppPane
2138
2168
  app={app}
2139
2169
  status={
2140
- chatFirstEmbedError
2141
- ? "error"
2142
- : chatFirstEmbedUrl
2143
- ? "ready"
2170
+ chatFirstEmbedUrl
2171
+ ? "ready"
2172
+ : chatFirstEmbedError
2173
+ ? "error"
2144
2174
  : chatFirstAppsQuery.isLoading
2145
2175
  ? "loading"
2146
2176
  : app
@@ -2152,6 +2182,7 @@ export function Layout({
2152
2182
  onRetry={() => setChatFirstEmbedAttempt((value) => value + 1)}
2153
2183
  renderEmbed={({ url, title }: ChatFirstEmbedTarget) => (
2154
2184
  <iframe
2185
+ key={`${url}:${chatFirstEmbedAttempt}`}
2155
2186
  data-dispatch-chat-first-app-frame
2156
2187
  src={url}
2157
2188
  title={title ?? chatFirstCopy("appUnavailable")}
@@ -57,6 +57,7 @@ import {
57
57
  CollapsibleTrigger,
58
58
  } from "./ui/collapsible";
59
59
  import { Input } from "./ui/input";
60
+ import { Skeleton } from "./ui/skeleton";
60
61
  import { Switch } from "./ui/switch";
61
62
  import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
62
63
 
@@ -553,7 +554,11 @@ export function MessagingSetupPanel() {
553
554
  : "Finish setup to connect"}
554
555
  </p>
555
556
  <p className="mt-0.5 text-xs text-muted-foreground">
556
- {credentialSummary}
557
+ {envLoading ? (
558
+ <Skeleton className="h-3 w-32" />
559
+ ) : (
560
+ credentialSummary
561
+ )}
557
562
  </p>
558
563
  </div>
559
564
  <div className="flex flex-wrap items-center gap-2">
@@ -1115,8 +1120,10 @@ export function MessagingSetupPanel() {
1115
1120
  </Accordion>
1116
1121
 
1117
1122
  {loading ? (
1118
- <div className="rounded-2xl border border-dashed px-4 py-6 text-sm text-muted-foreground">
1119
- Loading messaging status...
1123
+ <div className="space-y-3 rounded-2xl border border-dashed px-4 py-6">
1124
+ <Skeleton className="h-4 w-40" />
1125
+ <Skeleton className="h-3 w-2/3 max-w-md" />
1126
+ <Skeleton className="h-9 w-full max-w-sm" />
1120
1127
  </div>
1121
1128
  ) : null}
1122
1129
  </div>