@agent-native/core 0.141.5 → 0.141.7

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 (235) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +3 -14
  3. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +20 -8
  4. package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +5 -5
  5. package/corpus/templates/analytics/AGENTS.md +2 -2
  6. package/corpus/templates/analytics/actions/compose-dashboard.ts +1 -1
  7. package/corpus/templates/analytics/actions/get-first-party-analytics-health.ts +15 -1
  8. package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +135 -0
  9. package/corpus/templates/analytics/actions/navigate.ts +1 -1
  10. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +2 -2
  11. package/corpus/templates/analytics/actions/update-dashboard.ts +0 -1
  12. package/corpus/templates/analytics/actions/view-screen.ts +0 -20
  13. package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
  14. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +5 -5
  15. package/corpus/templates/analytics/app/i18n-data.ts +330 -90
  16. package/corpus/templates/analytics/app/pages/Agents.tsx +0 -3
  17. package/corpus/templates/analytics/app/pages/DataSources.tsx +66 -30
  18. package/corpus/templates/analytics/app/pages/Settings.tsx +22 -43
  19. package/corpus/templates/analytics/app/pages/settings/settings-search.ts +23 -20
  20. package/corpus/templates/analytics/app/routes/extensions._index.tsx +1 -1
  21. package/corpus/templates/analytics/app/routes/settings.$.tsx +1 -0
  22. package/corpus/templates/analytics/app/routes/team.tsx +1 -1
  23. package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-now-repair-automatically-after-.md +6 -0
  24. package/corpus/templates/analytics/changelog/2026-08-05-settings-no-longer-includes-an-unnecessary-about-section.md +6 -0
  25. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +1 -1
  26. package/corpus/templates/analytics/netlify.toml +4 -0
  27. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +109 -0
  28. package/corpus/templates/analytics/scripts/first-party-analytics-bigquery.sql +104 -0
  29. package/corpus/templates/analytics/server/jobs/analytics-rollup-backfill.ts +342 -0
  30. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -2
  31. package/corpus/templates/analytics/server/lib/analytics-rollup-lock.ts +8 -0
  32. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +11 -29
  33. package/corpus/templates/analytics/server/lib/dashboards-store.ts +55 -0
  34. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +1058 -0
  35. package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +151 -46
  36. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +15 -9
  37. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +59 -17
  38. package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -3
  39. package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -4
  40. package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +61 -0
  41. package/corpus/templates/analytics/server/plugins/db.ts +58 -187
  42. package/corpus/templates/analytics/server/routes/api/analytics-rollups/backfill.post.ts +53 -0
  43. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +8 -6
  44. package/corpus/templates/assets/.agents/skills/library-management/SKILL.md +16 -1
  45. package/corpus/templates/assets/AGENTS.md +1 -0
  46. package/corpus/templates/assets/actions/_helpers.ts +12 -0
  47. package/corpus/templates/assets/actions/generate-image.ts +9 -3
  48. package/corpus/templates/assets/actions/import-style-from-url.ts +115 -0
  49. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +3 -1
  50. package/corpus/templates/assets/app/routes/extensions._index.tsx +1 -1
  51. package/corpus/templates/assets/app/routes/settings.$.tsx +1 -0
  52. package/corpus/templates/assets/app/routes/settings.tsx +5 -0
  53. package/corpus/templates/assets/app/routes/team.tsx +1 -1
  54. package/corpus/templates/assets/changelog/2026-08-05-brand-kits-can-import-a-website-s-hydrated-visual-language-a.md +6 -0
  55. package/corpus/templates/assets/changelog/2026-08-05-generated-images-now-hand-off-embeddable-previews-to-other-w.md +6 -0
  56. package/corpus/templates/assets/server/lib/generation.ts +58 -0
  57. package/corpus/templates/assets/shared/api.ts +12 -0
  58. package/corpus/templates/brain/app/routes/extensions._index.tsx +1 -1
  59. package/corpus/templates/brain/app/routes/team.tsx +1 -1
  60. package/corpus/templates/brain/app/routes.ts +1 -1
  61. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +3 -1
  62. package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +1 -1
  63. package/corpus/templates/calendar/app/routes/_app.settings.$.tsx +1 -0
  64. package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
  65. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
  66. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  67. package/corpus/templates/chat/app/root.tsx +1 -1
  68. package/corpus/templates/chat/app/routes/agent.tsx +7 -7
  69. package/corpus/templates/chat/app/routes/extensions._index.tsx +1 -1
  70. package/corpus/templates/chat/app/routes/settings.$.tsx +1 -0
  71. package/corpus/templates/chat/app/routes/team.tsx +1 -1
  72. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  73. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +1 -1
  74. package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +1 -1
  75. package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +1 -1
  76. package/corpus/templates/clips/app/routes/_app.settings.$.tsx +1 -0
  77. package/corpus/templates/clips/changelog/2026-08-05-clips-overlays-now-use-clean-surfaces-without-clipped-shadow.md +6 -0
  78. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +2 -2
  79. package/corpus/templates/clips/desktop/src/styles.css +3 -54
  80. package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +3 -3
  81. package/corpus/templates/content/app/routes/_app.extensions._index.tsx +1 -1
  82. package/corpus/templates/content/app/routes/_app.settings.$.tsx +1 -0
  83. package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
  84. package/corpus/templates/content/e2e/global-setup.ts +1 -1
  85. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +6 -1
  86. package/corpus/templates/design/actions/analyze-brand-assets.ts +7 -7
  87. package/corpus/templates/design/actions/get-design-system.ts +3 -1
  88. package/corpus/templates/design/actions/import-from-url.ts +6 -5
  89. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +2 -2
  90. package/corpus/templates/design/app/routes/extensions._index.tsx +1 -1
  91. package/corpus/templates/design/app/routes/settings.$.tsx +1 -0
  92. package/corpus/templates/design/app/routes/team.tsx +1 -1
  93. package/corpus/templates/design/changelog/2026-08-05-missing-design-systems-now-return-a-clear-not-found-response.md +6 -0
  94. package/corpus/templates/design/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-de.md +6 -0
  95. package/corpus/templates/design/e2e/global-setup.ts +1 -1
  96. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
  97. package/corpus/templates/dispatch/app/routes/settings.$.tsx +1 -0
  98. package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
  99. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +1 -1
  100. package/corpus/templates/factory/app/routes/extensions._index.tsx +1 -1
  101. package/corpus/templates/factory/app/routes/settings.$.tsx +1 -0
  102. package/corpus/templates/factory/app/routes/team.tsx +1 -1
  103. package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +1 -1
  104. package/corpus/templates/forms/app/routes/_app.settings.$.tsx +1 -0
  105. package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
  106. package/corpus/templates/forms/shared/navigation.ts +1 -1
  107. package/corpus/templates/macros/app/routes/extensions._index.tsx +1 -1
  108. package/corpus/templates/macros/app/routes/settings.$.tsx +1 -0
  109. package/corpus/templates/macros/app/routes/team.tsx +1 -1
  110. package/corpus/templates/mail/app/routes/extensions._index.tsx +1 -1
  111. package/corpus/templates/mail/app/routes/settings.$.tsx +1 -0
  112. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
  113. package/corpus/templates/plan/app/routes/extensions._index.tsx +1 -1
  114. package/corpus/templates/plan/app/routes/settings.$.tsx +1 -0
  115. package/corpus/templates/plan/app/routes/team.tsx +1 -1
  116. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +3 -1
  117. package/corpus/templates/slides/actions/analyze-brand-assets.ts +7 -7
  118. package/corpus/templates/slides/actions/import-from-url.ts +6 -6
  119. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -2
  120. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
  121. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -0
  122. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
  123. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +9 -3
  124. package/corpus/templates/slides/app/context/DeckContext.tsx +71 -20
  125. package/corpus/templates/slides/app/global.css +6 -0
  126. package/corpus/templates/slides/app/i18n/en-US.ts +5 -5
  127. package/corpus/templates/slides/app/lib/create-deck-generation.ts +9 -5
  128. package/corpus/templates/slides/app/pages/DeckEditor.tsx +17 -0
  129. package/corpus/templates/slides/app/pages/Index.tsx +16 -5
  130. package/corpus/templates/slides/app/routes/extensions._index.tsx +1 -1
  131. package/corpus/templates/slides/app/routes/settings.$.tsx +1 -0
  132. package/corpus/templates/slides/app/routes/team.tsx +1 -1
  133. package/corpus/templates/slides/changelog/2026-08-05-failed-deck-creation-and-reference-uploads-now-recover-clean.md +6 -0
  134. package/corpus/templates/slides/changelog/2026-08-05-new-presentation-prompts-now-clearly-describe-presentation-g.md +6 -0
  135. package/corpus/templates/slides/changelog/2026-08-05-slides-recover-completed-generation-results-after-a-sync-hic.md +6 -0
  136. package/corpus/templates/slides/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-st.md +6 -0
  137. package/corpus/templates/tasks/app/components/layout/Header.tsx +3 -1
  138. package/corpus/templates/tasks/app/routes/extensions._index.tsx +1 -1
  139. package/corpus/templates/tasks/app/routes/settings.$.tsx +1 -0
  140. package/dist/agent/engine/ai-sdk-engine.js +49 -3
  141. package/dist/agent/production-agent.d.ts +1 -0
  142. package/dist/agent/production-agent.js +8 -0
  143. package/dist/agent/types.d.ts +7 -0
  144. package/dist/client/AssistantChat.js +1 -1
  145. package/dist/client/agent-chat-adapter.d.ts +1 -1
  146. package/dist/client/agent-chat-adapter.js +30 -3
  147. package/dist/client/agent-page/AgentWorkspaceContent.d.ts +1 -1
  148. package/dist/client/agent-page/AgentWorkspaceContent.js +13 -13
  149. package/dist/client/chat/run-recovery.d.ts +2 -1
  150. package/dist/client/chat/run-recovery.js +14 -3
  151. package/dist/client/embed-auth.js +6 -2
  152. package/dist/client/error-format.d.ts +1 -0
  153. package/dist/client/error-format.js +16 -2
  154. package/dist/client/integrations/IntegrationsPanel.js +40 -6
  155. package/dist/client/org/OrgSwitcher.js +2 -2
  156. package/dist/client/org/TeamPage.js +92 -72
  157. package/dist/client/require-session.d.ts +1 -1
  158. package/dist/client/require-session.js +3 -3
  159. package/dist/client/resources/use-mcp-servers.d.ts +5 -0
  160. package/dist/client/resources/use-mcp-servers.js +36 -0
  161. package/dist/client/settings/AccountSettingsCard.js +40 -35
  162. package/dist/client/settings/AutomationsSection.js +1 -1
  163. package/dist/client/settings/DemoModeSection.d.ts +3 -1
  164. package/dist/client/settings/DemoModeSection.js +4 -1
  165. package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
  166. package/dist/client/settings/SchedulingTimezoneField.d.ts +3 -1
  167. package/dist/client/settings/SchedulingTimezoneField.js +9 -5
  168. package/dist/client/settings/SettingsPanel.d.ts +4 -1
  169. package/dist/client/settings/SettingsPanel.js +21 -21
  170. package/dist/client/settings/SettingsTabsPage.d.ts +2 -2
  171. package/dist/client/settings/SettingsTabsPage.js +98 -45
  172. package/dist/client/settings/VoiceTranscriptionSection.js +6 -1
  173. package/dist/client/settings/useSettingsPanelController.js +47 -8
  174. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  175. package/dist/ingestion/website.d.ts +30 -0
  176. package/dist/localization/default-messages.d.ts +5 -0
  177. package/dist/localization/default-messages.js +5 -0
  178. package/dist/mcp-client/oauth-routes.js +1 -1
  179. package/dist/mcp-client/routes.d.ts +1 -0
  180. package/dist/mcp-client/routes.js +49 -0
  181. package/dist/navigation/index.js +16 -5
  182. package/dist/observability/routes.d.ts +3 -3
  183. package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
  184. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  185. package/dist/scripts/call-agent.js +11 -0
  186. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  187. package/dist/server/auth.js +9 -7
  188. package/dist/server/identity-sso.js +2 -1
  189. package/dist/server/onboarding-html.js +57 -34
  190. package/dist/server/realtime-token.d.ts +1 -1
  191. package/dist/server/transcribe-voice.d.ts +1 -1
  192. package/dist/server/workspace-provider-oauth.js +1 -1
  193. package/dist/setup-connections/onboarding.js +1 -1
  194. package/dist/shared/index.d.ts +1 -1
  195. package/dist/shared/index.js +1 -1
  196. package/dist/shared/sign-in-journey.d.ts +5 -2
  197. package/dist/shared/sign-in-journey.js +10 -4
  198. package/dist/templates/chat/app/components/layout/Layout.tsx +1 -1
  199. package/dist/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  200. package/dist/templates/chat/app/root.tsx +1 -1
  201. package/dist/templates/chat/app/routes/agent.tsx +7 -7
  202. package/dist/templates/chat/app/routes/extensions._index.tsx +1 -1
  203. package/dist/templates/chat/app/routes/settings.$.tsx +1 -0
  204. package/dist/templates/chat/app/routes/team.tsx +1 -1
  205. package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
  206. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
  207. package/docs/content/authentication.mdx +4 -5
  208. package/docs/content/template-analytics-developers.mdx +1 -1
  209. package/docs/content/template-calendar-developers.mdx +1 -1
  210. package/docs/content/template-chat-developers.mdx +2 -2
  211. package/docs/content/template-content-developers.mdx +1 -1
  212. package/docs/content/template-mail-developers.mdx +1 -1
  213. package/docs/content/template-plan-developers.mdx +1 -1
  214. package/docs/content/toolkit-command-navigation.mdx +6 -6
  215. package/docs/content/toolkit-org-team.mdx +1 -1
  216. package/docs/content/toolkit-settings.mdx +8 -8
  217. package/docs/content/toolkit-setup-connections.mdx +1 -1
  218. package/package.json +1 -1
  219. package/src/templates/chat/app/components/layout/Layout.tsx +1 -1
  220. package/src/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  221. package/src/templates/chat/app/root.tsx +1 -1
  222. package/src/templates/chat/app/routes/agent.tsx +7 -7
  223. package/src/templates/chat/app/routes/extensions._index.tsx +1 -1
  224. package/src/templates/chat/app/routes/settings.$.tsx +1 -0
  225. package/src/templates/chat/app/routes/team.tsx +1 -1
  226. package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
  227. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
  228. package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +0 -62
  229. package/corpus/templates/analytics/actions/install-dashboard-template.ts +0 -369
  230. package/corpus/templates/analytics/actions/list-dashboard-templates.ts +0 -47
  231. package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +0 -34
  232. package/corpus/templates/analytics/app/routes/catalog.tsx +0 -240
  233. package/corpus/templates/analytics/changelog/2026-08-05-historical-analytics-rollups-stay-complete-and-atomic.md +0 -6
  234. package/corpus/templates/analytics/changelog/2026-08-05-historical-rollups-stay-complete-while-live-events-arrive.md +0 -6
  235. package/src/templates/default/actions/navigate.spec.ts +0 -53
@@ -1,12 +1,12 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconPlus, IconBrandSlack, IconBrandTelegram, IconBrandWhatsapp, IconBrandGoogleDrive, IconTerminal2, IconBuildingSkyscraper, IconCopy, IconCheck, IconChevronLeft, IconChevronRight, IconExternalLink, IconCircleCheck, IconInfoCircle, IconSearch, IconServer, } from "@tabler/icons-react";
2
+ import { IconPlus, IconBrandSlack, IconBrandTelegram, IconBrandWhatsapp, IconBrandGoogleDrive, IconTerminal2, IconBuildingSkyscraper, IconCopy, IconCheck, IconChevronLeft, IconChevronRight, IconExternalLink, IconCircleCheck, IconInfoCircle, IconSearch, IconServer, IconLoader2, IconRefresh, } from "@tabler/icons-react";
3
3
  import { useState, useCallback, useEffect, useMemo } from "react";
4
4
  import { agentNativePath } from "../api-path.js";
5
5
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
6
6
  import { useT } from "../i18n.js";
7
7
  import { getDefaultMcpIntegrations, } from "../resources/mcp-integration-catalog.js";
8
8
  import { McpIntegrationDialog } from "../resources/McpIntegrationDialog.js";
9
- import { useCreateMcpServer, useDeleteMcpServer, useMcpServers, } from "../resources/use-mcp-servers.js";
9
+ import { useCreateMcpServer, useDeleteMcpServer, useMcpServers, useReconnectMcpServer, } from "../resources/use-mcp-servers.js";
10
10
  import { useIntegrationStatus, } from "./useIntegrationStatus.js";
11
11
  import { isNonPublicWebhookUrl } from "./webhook-url.js";
12
12
  const PLATFORMS = [
@@ -257,12 +257,19 @@ function McpLogo({ integration }) {
257
257
  const [failed, setFailed] = useState(false);
258
258
  return (_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg border border-border/70 bg-background text-xs font-semibold text-muted-foreground", children: failed ? (integration.name.slice(0, 1)) : (_jsx("img", { src: integration.logoUrl, alt: "", loading: "lazy", decoding: "async", className: "size-7 object-contain", onError: () => setFailed(true) })) }));
259
259
  }
260
- function McpServerStatus({ server }) {
260
+ function McpServerStatus({ server, onReconnect, reconnecting = false, reconnectError, }) {
261
+ const t = useT();
261
262
  if (server.status.state === "connected") {
262
263
  return (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-emerald-600 dark:text-emerald-400", children: [_jsx("span", { className: "size-1.5 rounded-full bg-emerald-500" }), "Connected \u00B7 ", server.status.toolCount, " tool", server.status.toolCount === 1 ? "" : "s"] }));
263
264
  }
264
265
  if (server.status.state === "error") {
265
- return (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-destructive", children: [_jsx("span", { className: "size-1.5 rounded-full bg-destructive" }), "Connection error"] }));
266
+ return (_jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-2 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "inline-flex items-center gap-1.5 text-xs text-destructive", children: [_jsx("span", { className: "size-1.5 rounded-full bg-destructive" }), t("mcpIntegrations.connectionError")] }), _jsx("p", { className: "mt-1 max-w-3xl break-words text-xs leading-5 text-destructive/85", children: t("mcpIntegrations.connectionErrorReason", {
267
+ reason: server.status.error,
268
+ }) }), reconnectError && (_jsx("p", { className: "mt-1 break-words text-xs leading-5 text-destructive", children: t("mcpIntegrations.reconnectFailed", {
269
+ error: reconnectError,
270
+ }) }))] }), onReconnect && (_jsxs("button", { type: "button", onClick: onReconnect, disabled: reconnecting, className: "inline-flex shrink-0 items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-wait disabled:opacity-60", children: [reconnecting ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : (_jsx(IconRefresh, { className: "size-3.5" })), reconnecting
271
+ ? t("mcpIntegrations.reconnecting")
272
+ : t("mcpIntegrations.reconnect")] }))] }));
266
273
  }
267
274
  return (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-muted-foreground", children: [_jsx("span", { className: "size-1.5 rounded-full bg-muted-foreground/50" }), "Status unknown"] }));
268
275
  }
@@ -273,10 +280,13 @@ function McpIntegrationsSection({ query }) {
273
280
  const serversQuery = useMcpServers();
274
281
  const createServer = useCreateMcpServer();
275
282
  const deleteServer = useDeleteMcpServer();
283
+ const reconnectServer = useReconnectMcpServer();
276
284
  const [dialogOpen, setDialogOpen] = useState(false);
277
285
  const [initialIntegrationId, setInitialIntegrationId] = useState(null);
278
286
  const [deleteTarget, setDeleteTarget] = useState(null);
279
287
  const [deleteError, setDeleteError] = useState(null);
288
+ const [reconnectingKey, setReconnectingKey] = useState(null);
289
+ const [reconnectError, setReconnectError] = useState(null);
280
290
  const catalog = useMemo(() => getDefaultMcpIntegrations(), []);
281
291
  const normalizedQuery = query.trim().toLowerCase();
282
292
  const filteredCatalog = useMemo(() => {
@@ -318,14 +328,38 @@ function McpIntegrationsSection({ query }) {
318
328
  : "Could not remove agent integration.");
319
329
  }
320
330
  }, [deleteServer, deleteTarget]);
331
+ const reconnect = useCallback(async (server) => {
332
+ const key = `${server.scope}:${server.id}`;
333
+ setReconnectingKey(key);
334
+ setReconnectError(null);
335
+ try {
336
+ await reconnectServer.mutateAsync({
337
+ id: server.id,
338
+ scope: server.scope,
339
+ });
340
+ }
341
+ catch (error) {
342
+ setReconnectError({
343
+ key,
344
+ message: error instanceof Error ? error.message : String(error),
345
+ });
346
+ }
347
+ finally {
348
+ setReconnectingKey(null);
349
+ }
350
+ }, [reconnectServer]);
321
351
  return (_jsxs("section", { "data-testid": "mcp-integrations", className: "space-y-5", children: [_jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(IconServer, { className: "size-4 text-muted-foreground" }), _jsx("h2", { className: "text-sm font-semibold text-foreground", children: "Agent integrations" })] }), _jsx("p", { className: "mt-1 text-xs leading-5 text-muted-foreground", children: "Give your agent tools and context from the services you use." })] }), _jsxs("button", { type: "button", onClick: () => openCatalog(), className: "inline-flex w-fit items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90", children: [_jsx(IconPlus, { className: "size-3.5" }), "Add integration"] })] }), deleteError && (_jsx("p", { className: "border-y border-destructive/20 bg-destructive/5 py-3 text-xs text-destructive", children: deleteError })), serversQuery.isError ? (_jsx("p", { className: "border-y border-destructive/20 bg-destructive/5 py-3 text-xs text-destructive", children: "Could not load connected agent integrations. The catalog is still available." })) : serversQuery.isLoading ? (_jsxs("div", { className: "space-y-3 rounded-xl border border-border/70 bg-card px-4 py-4", children: [_jsx("div", { className: "h-5 w-1/2 animate-pulse rounded bg-muted" }), _jsx("div", { className: "h-5 w-3/4 animate-pulse rounded bg-muted" })] })) : servers.length > 0 && !normalizedQuery ? (_jsxs("section", { className: "space-y-2", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Installed" }), _jsx("div", { className: "overflow-hidden rounded-xl border border-border/70 bg-card text-card-foreground", children: _jsx("div", { className: "divide-y divide-border/60 px-4", children: servers.map((server) => {
322
352
  const key = `${server.scope}:${server.id}`;
323
353
  const canRemove = server.scope === "user" ||
324
354
  serversQuery.data?.role === "owner" ||
325
355
  serversQuery.data?.role === "admin";
326
- return (_jsxs("div", { className: "flex items-center gap-3 py-3.5", children: [_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-lg border border-border/70 bg-background text-muted-foreground", children: _jsx(IconServer, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "truncate text-sm font-medium text-foreground", children: server.name }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: server.scope === "user"
356
+ return (_jsxs("div", { className: "flex items-start gap-3 py-3.5", children: [_jsx("span", { className: "mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-lg border border-border/70 bg-background text-muted-foreground", children: _jsx(IconServer, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "truncate text-sm font-medium text-foreground", children: server.name }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: server.scope === "user"
327
357
  ? "Personal"
328
- : "Organization" })] }), _jsx(McpServerStatus, { server: server })] }), canRemove && (_jsx("button", { type: "button", onClick: () => void removeServer(server), disabled: deleteServer.isPending, className: "shrink-0 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:opacity-50", children: deleteTarget === key ? "Confirm" : "Remove" }))] }, key));
358
+ : "Organization" })] }), _jsx(McpServerStatus, { server: server, onReconnect: server.status.state === "error"
359
+ ? () => void reconnect(server)
360
+ : undefined, reconnecting: reconnectingKey === key, reconnectError: reconnectError?.key === key
361
+ ? reconnectError.message
362
+ : undefined })] }), canRemove && (_jsx("button", { type: "button", onClick: () => void removeServer(server), disabled: deleteServer.isPending, className: "shrink-0 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:opacity-50", children: deleteTarget === key ? "Confirm" : "Remove" }))] }, key));
329
363
  }) }) })] })) : null, filteredCatalog.length > 0 && (_jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between gap-3", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Available integrations" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: [filteredCatalog.length, " integrations"] })] }), _jsx("div", { className: "grid gap-x-8 overflow-hidden rounded-xl border border-border/70 bg-card px-4 sm:grid-cols-2", children: filteredCatalog.map((integration) => (_jsx(McpCatalogItem, { integration: integration, connected: connectedUrls.has(compareMcpUrl(integration.url)), onConnect: openCatalog }, integration.id))) })] })), filteredCatalog.length === 0 && normalizedQuery && (_jsxs("p", { className: "border-y border-border/60 py-4 text-xs text-muted-foreground", children: ["No agent integrations match \u201C", query, "\u201D."] })), _jsx(McpIntegrationDialog, { open: dialogOpen, onOpenChange: setDialogOpen, initialIntegrationId: initialIntegrationId, defaultScope: "user", canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrg, onCreateMcpServer: (args) => createServer.mutateAsync(args) })] }));
330
364
  }
331
365
  export function IntegrationsPanel() {
@@ -30,8 +30,8 @@ const SECTION_LABEL_CLASS = "px-2.5 pt-1 pb-0.5 text-[10px] uppercase tracking-w
30
30
  const APP_SUBMENU_CONTENT_CLASS = "z-50 w-72 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2";
31
31
  const SWITCHER_BUTTON_CLASS = "flex w-full items-center gap-2 rounded-md border-0 bg-accent/50 px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent/70 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60 cursor-pointer";
32
32
  const COMPACT_SWITCHER_BUTTON_CLASS = "flex items-center justify-center rounded-md border-0 bg-accent/50 p-1.5 text-muted-foreground hover:bg-accent/70 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60 cursor-pointer";
33
- const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings#organization";
34
- const DEFAULT_PROFILE_PATH = "/settings#account";
33
+ const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings/organization";
34
+ const DEFAULT_PROFILE_PATH = "/settings/account";
35
35
  const DEFAULT_AGENT_PATH = "/agent";
36
36
  const APP_ICON_MAP = {
37
37
  Mail: IconMail,
@@ -3,11 +3,11 @@ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent,
3
3
  import { Button as ToolkitButton } from "@agent-native/toolkit/ui/button";
4
4
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@agent-native/toolkit/ui/select";
5
5
  import { Switch } from "@agent-native/toolkit/ui/switch";
6
- import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@agent-native/toolkit/ui/table";
7
6
  import { IconUserPlus, IconTrash, IconCrown, IconShieldCheck, IconLoader2, IconCheck, IconPencil, IconAt, IconX, IconKey, IconCopy, IconRefresh, IconEye, IconEyeOff, IconCloudUpload, IconFileImport, IconPlus, IconAlertTriangle, IconUsersGroup, IconHelpCircle, IconExternalLink, } from "@tabler/icons-react";
8
7
  import { forwardRef, useMemo, useRef, useState, } from "react";
9
8
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "../components/ui/tooltip.js";
10
9
  import { useT } from "../i18n.js";
10
+ import { SettingsGroup, SettingsRow } from "../settings/SettingsRow.js";
11
11
  import { cn } from "../utils.js";
12
12
  import { useOrg, useOrgMembers, useOrgInvitations, useCreateOrg, useUpdateOrg, useBulkInviteMembers, useChangeMemberRole, useAcceptInvitation, useRemoveMember, useDeleteOrg, useSwitchOrg, useSetOrgDomain, useSetOrgWorkspaceUrl, useSetOrgAuthProvider, useRevealA2ASecret, useSetA2ASecret, useSyncA2ASecret, useJoinByDomain, useAppRoles, useSetAppMemberRole, } from "./hooks.js";
13
13
  const Button = forwardRef(({ className, ...props }, ref) => (_jsx(ToolkitButton, { ref: ref, variant: "ghost", className: cn("h-auto p-0 hover:bg-transparent hover:text-inherit active:scale-100 [&_svg]:!size-auto", className), ...props })));
@@ -24,6 +24,12 @@ function ErrorText({ error }) {
24
24
  return null;
25
25
  return (_jsx("p", { className: "text-xs text-destructive", children: error instanceof Error ? error.message : String(error) }));
26
26
  }
27
+ function OrganizationHelpIcon({ content, docsUrl, }) {
28
+ return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", "aria-label": "More information", className: "inline-flex size-3.5 shrink-0 items-center justify-center rounded-full text-muted-foreground/70 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", children: _jsx(IconHelpCircle, { className: "size-3" }) }) }), _jsxs(TooltipContent, { className: "max-w-xs leading-5", children: [_jsx("p", { children: content }), docsUrl ? (_jsx("a", { href: docsUrl, target: "_blank", rel: "noreferrer", className: "mt-1 inline-block underline underline-offset-2", children: "Learn more" })) : null] })] }));
29
+ }
30
+ function OrganizationDescription({ children, help, docsUrl, }) {
31
+ return (_jsxs("span", { className: "inline-flex max-w-full items-center gap-1.5", children: [_jsx("span", { children: children }), help ? _jsx(OrganizationHelpIcon, { content: help, docsUrl: docsUrl }) : null] }));
32
+ }
27
33
  function PendingInvitationsCard() {
28
34
  const t = useT();
29
35
  const { data: org } = useOrg();
@@ -100,7 +106,7 @@ function MembersCard({ appRoles }) {
100
106
  const members = membersData?.members ?? [];
101
107
  const pendingInvites = invitationsData?.invitations ?? [];
102
108
  const hasMultipleOrgs = (org.orgs?.length ?? 0) > 1;
103
- return (_jsxs("div", { className: "space-y-4", children: [_jsxs("section", { className: "rounded-lg border border-border bg-card p-4 space-y-4", children: [_jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [_jsx("div", { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-primary/10", children: _jsx(IconUsersGroup, { className: "h-5 w-5 text-primary" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx(OrgNameDisplay, { name: org.orgName ?? "", canEdit: isOwnerOrAdmin }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [t("org.memberCount", { count: members.length }), " \u00B7", " ", t("org.youAreRole", { role: org.role })] })] })] }), hasMultipleOrgs && (_jsxs(Select, { value: org.orgId ?? "", onValueChange: (value) => switchOrg.mutate(value || null), disabled: switchOrg.isPending, children: [_jsx(SelectTrigger, { className: "h-auto w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs sm:w-auto", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: org.orgs.map((o) => (_jsx(SelectItem, { value: o.orgId, children: o.orgName }, o.orgId))) })] }))] }), isOwnerOrAdmin && (_jsxs("div", { className: "grid gap-5 border-t border-border pt-4 lg:grid-cols-2", children: [_jsx(DomainSettingsSection, { domain: org.allowedDomain, ownerEmail: org.email }), _jsx(WorkspaceUrlSettingsSection, { workspaceUrl: org.workspaceUrl }), _jsx(AuthProviderSettingsSection, { requiredAuthProvider: org.requiredAuthProvider }), isOwner && _jsx(A2ASecretSection, { isSet: Boolean(org.a2aSecretSet) })] })), _jsx(ErrorText, { error: switchOrg.error })] }), _jsx(MembersTableCard, { members: members, pendingInvites: pendingInvites, isLoadingMembers: isLoadingMembers, currentUserEmail: org.email, currentUserRole: org.role ?? null, appRoles: appRoles }), isOwner && _jsx(DangerZoneCard, { orgName: org.orgName ?? "" })] }));
109
+ return (_jsxs("div", { className: "space-y-6", children: [_jsxs(SettingsGroup, { title: "Organization", children: [_jsx(SettingsRow, { id: "organization", label: _jsxs("span", { className: "flex items-center gap-2", children: [_jsx(IconUsersGroup, { className: "size-4 text-muted-foreground" }), _jsx(OrgNameDisplay, { name: org.orgName ?? "", canEdit: isOwnerOrAdmin })] }), description: `${t("org.memberCount", { count: members.length })} · ${t("org.youAreRole", { role: org.role })}`, control: hasMultipleOrgs ? (_jsxs(Select, { value: org.orgId ?? "", onValueChange: (value) => switchOrg.mutate(value || null), disabled: switchOrg.isPending, children: [_jsx(SelectTrigger, { className: "h-auto w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-xs sm:w-auto", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: org.orgs.map((o) => (_jsx(SelectItem, { value: o.orgId, children: o.orgName }, o.orgId))) })] })) : undefined }), isOwnerOrAdmin && (_jsxs(_Fragment, { children: [_jsx(DomainSettingsSection, { domain: org.allowedDomain, ownerEmail: org.email }), _jsx(WorkspaceUrlSettingsSection, { workspaceUrl: org.workspaceUrl }), _jsx(AuthProviderSettingsSection, { requiredAuthProvider: org.requiredAuthProvider }), isOwner && _jsx(A2ASecretSection, { isSet: Boolean(org.a2aSecretSet) })] })), switchOrg.error && (_jsx("div", { className: "px-5 pb-4", children: _jsx(ErrorText, { error: switchOrg.error }) }))] }), _jsx(MembersTableCard, { members: members, pendingInvites: pendingInvites, isLoadingMembers: isLoadingMembers, currentUserEmail: org.email, currentUserRole: org.role ?? null, appRoles: appRoles }), isOwner && _jsx(DangerZoneCard, { orgName: org.orgName ?? "" })] }));
104
110
  }
105
111
  function MembersTableCard({ members, pendingInvites, isLoadingMembers, currentUserEmail, currentUserRole, appRoles, }) {
106
112
  const t = useT();
@@ -111,8 +117,7 @@ function MembersTableCard({ members, pendingInvites, isLoadingMembers, currentUs
111
117
  a.email.toLowerCase(),
112
118
  a.role,
113
119
  ]));
114
- const columnCount = appRoles ? 5 : 4;
115
- return (_jsxs("section", { className: "rounded-lg border border-border bg-card", children: [_jsxs("div", { className: "flex flex-col gap-3 border-b border-border px-4 py-3 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-medium", children: t("org.members") }), _jsx("p", { className: "text-xs text-muted-foreground", children: t("org.memberCount", { count: members.length }) })] }), canInvite && !showInviteForm && (_jsxs(Button, { type: "button", intent: "primary", emphasis: "solid", onClick: () => setShowInviteForm(true), className: "inline-flex items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90", children: [_jsx(IconUserPlus, { size: 14 }), t("org.inviteMembers")] }))] }), canInvite && showInviteForm && (_jsx("div", { className: "border-b border-border p-4", children: _jsx(BulkInviteForm, { currentUserRole: currentUserRole, onClose: () => setShowInviteForm(false) }) })), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: t("org.member") }), _jsx(TableHead, { children: t("org.role") }), appRoles && (_jsx(TableHead, { children: appRoles.label ?? appRoles.appId })), _jsx(TableHead, { children: t("org.status") }), _jsx(TableHead, { className: "text-end", children: t("org.actions") })] }) }), _jsx(TableBody, { children: isLoadingMembers && members.length === 0 ? ([0, 1, 2].map((i) => (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columnCount, children: _jsx("div", { className: "h-3.5 rounded bg-muted animate-pulse", style: { width: `${180 + i * 48}px` } }) }) }, i)))) : members.length === 0 && pendingInvites.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columnCount, className: "py-8 text-center text-sm text-muted-foreground", children: t("org.noMembers") }) })) : (_jsxs(_Fragment, { children: [members.map((m) => (_jsx(MemberRow, { email: m.email, role: m.role, isCurrentUser: m.email === currentUserEmail, currentUserRole: currentUserRole, appRoles: appRoles, appRole: appRoleByEmail.get(m.email.toLowerCase()) ?? null, canManageAppRoles: Boolean(appRoleData?.canManage) }, m.email))), pendingInvites.map((inv) => (_jsx(PendingInviteRow, { invite: inv, hasAppRoleColumn: Boolean(appRoles) }, inv.id)))] })) })] })] }));
120
+ return (_jsxs("section", { className: "overflow-hidden rounded-xl border border-border/70 bg-card text-card-foreground", children: [_jsxs("div", { className: "flex flex-col gap-3 px-5 py-4 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-medium", children: t("org.members") }), _jsx("p", { className: "text-xs text-muted-foreground", children: t("org.memberCount", { count: members.length }) })] }), canInvite && !showInviteForm && (_jsxs(Button, { type: "button", intent: "primary", emphasis: "solid", onClick: () => setShowInviteForm(true), className: "inline-flex items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90", children: [_jsx(IconUserPlus, { size: 14 }), t("org.inviteMembers")] }))] }), canInvite && showInviteForm && (_jsx("div", { className: "border-b border-border p-4", children: _jsx(BulkInviteForm, { currentUserRole: currentUserRole, onClose: () => setShowInviteForm(false) }) })), _jsx("div", { className: "divide-y divide-border/60 border-t border-border/60", children: isLoadingMembers && members.length === 0 ? ([0, 1, 2].map((i) => (_jsxs("div", { className: "flex items-center gap-3 px-5 py-4", children: [_jsx("div", { className: "size-8 animate-pulse rounded-full bg-muted" }), _jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "h-3.5 animate-pulse rounded bg-muted", style: { width: `${180 + i * 48}px` } }), _jsx("div", { className: "h-3 w-20 animate-pulse rounded bg-muted" })] })] }, i)))) : members.length === 0 && pendingInvites.length === 0 ? (_jsx("div", { className: "px-5 py-10 text-center text-sm text-muted-foreground", children: t("org.noMembers") })) : (_jsxs(_Fragment, { children: [members.map((m) => (_jsx(MemberRow, { email: m.email, role: m.role, isCurrentUser: m.email === currentUserEmail, currentUserRole: currentUserRole, appRoles: appRoles, appRole: appRoleByEmail.get(m.email.toLowerCase()) ?? null, canManageAppRoles: Boolean(appRoleData?.canManage) }, m.email))), pendingInvites.map((inv) => (_jsx(PendingInviteRow, { invite: inv }, inv.id)))] })) })] }));
116
121
  }
117
122
  function DangerZoneCard({ orgName }) {
118
123
  const t = useT();
@@ -126,11 +131,11 @@ function DangerZoneCard({ orgName }) {
126
131
  return;
127
132
  deleteOrg.mutate(orgName, { onSuccess: () => setOpen(false) });
128
133
  }
129
- return (_jsxs("section", { className: "rounded-lg border border-destructive/40 bg-card p-4 space-y-3", children: [_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx(IconAlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-destructive" }), _jsxs("div", { className: "space-y-1", children: [_jsx("h3", { className: "text-sm font-medium text-destructive", children: t("org.dangerZone") }), _jsx("p", { className: "text-sm text-muted-foreground", children: t("org.deleteOrgDescription") })] })] }), _jsxs(AlertDialog, { open: open, onOpenChange: (next) => {
130
- setOpen(next);
131
- if (!next)
132
- setConfirmText("");
133
- }, children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { type: "button", intent: "danger", emphasis: "outline", className: "cursor-pointer rounded-md border border-destructive/40 px-3 py-1.5 text-xs font-medium text-destructive hover:bg-destructive/10", children: t("org.deleteOrg") }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: t("org.deleteOrg") }), _jsx(AlertDialogDescription, { children: t("org.deleteOrgConfirmPrompt", { name: orgName }) })] }), _jsx("input", { type: "text", value: confirmText, onChange: (e) => setConfirmText(e.target.value), placeholder: t("org.deleteOrgConfirmPlaceholder"), className: "w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-destructive", autoFocus: true }), _jsx(ErrorText, { error: deleteOrg.error }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { className: "cursor-pointer", children: t("org.cancel") }), _jsx(AlertDialogAction, { disabled: !canConfirm || deleteOrg.isPending, onClick: handleConfirm, className: "cursor-pointer bg-destructive text-destructive-foreground hover:bg-destructive/90 disabled:cursor-not-allowed disabled:opacity-50", children: deleteOrg.isPending ? (_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [_jsx(IconLoader2, { size: 14, className: "animate-spin" }), t("org.deleteOrgPending")] })) : (t("org.deleteOrgConfirmCta")) })] })] })] })] }));
134
+ return (_jsx("section", { className: "rounded-lg border border-destructive/40 bg-card p-4 space-y-3", children: _jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx(IconAlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-destructive" }), _jsxs("div", { className: "min-w-0 space-y-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("h3", { className: "text-sm font-medium text-destructive", children: t("org.dangerZone") }), _jsx("p", { className: "text-sm leading-6 text-muted-foreground", children: _jsx(OrganizationDescription, { help: t("org.deleteOrgDescription"), children: "Delete this organization and all of its members." }) })] }), _jsxs(AlertDialog, { open: open, onOpenChange: (next) => {
135
+ setOpen(next);
136
+ if (!next)
137
+ setConfirmText("");
138
+ }, children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { type: "button", intent: "danger", emphasis: "outline", className: "cursor-pointer rounded-md border border-destructive/40 px-3 py-1.5 text-xs font-medium text-destructive hover:bg-destructive/10", children: t("org.deleteOrg") }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: t("org.deleteOrg") }), _jsx(AlertDialogDescription, { children: t("org.deleteOrgConfirmPrompt", { name: orgName }) })] }), _jsx("input", { type: "text", value: confirmText, onChange: (e) => setConfirmText(e.target.value), placeholder: t("org.deleteOrgConfirmPlaceholder"), className: "w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-destructive", autoFocus: true }), _jsx(ErrorText, { error: deleteOrg.error }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { className: "cursor-pointer", children: t("org.cancel") }), _jsx(AlertDialogAction, { disabled: !canConfirm || deleteOrg.isPending, onClick: handleConfirm, className: "cursor-pointer bg-destructive text-destructive-foreground hover:bg-destructive/90 disabled:cursor-not-allowed disabled:opacity-50", children: deleteOrg.isPending ? (_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [_jsx(IconLoader2, { size: 14, className: "animate-spin" }), t("org.deleteOrgPending")] })) : (t("org.deleteOrgConfirmCta")) })] })] })] })] })] }) }));
134
139
  }
135
140
  function roleLabel(role, t) {
136
141
  if (role === "owner")
@@ -143,33 +148,43 @@ function RoleBadge({ role }) {
143
148
  const t = useT();
144
149
  return (_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded border border-border px-2 py-1 text-xs text-muted-foreground", children: [_jsx(RoleIcon, { role: role }), roleLabel(role, t)] }));
145
150
  }
146
- function PendingInviteRow({ invite, hasAppRoleColumn, }) {
151
+ function memberInitials(email) {
152
+ const localPart = email.split("@", 1)[0] ?? email;
153
+ const initials = localPart
154
+ .split(/[._-]+/)
155
+ .filter(Boolean)
156
+ .slice(0, 2)
157
+ .map((part) => part[0]?.toUpperCase())
158
+ .join("");
159
+ return initials || "?";
160
+ }
161
+ function PendingInviteRow({ invite }) {
147
162
  const t = useT();
148
- return (_jsxs(TableRow, { className: "opacity-70", children: [_jsx(TableCell, { className: "min-w-56", children: _jsx("span", { className: "truncate text-sm", children: invite.email }) }), _jsx(TableCell, { children: _jsx(RoleBadge, { role: invite.role }) }), hasAppRoleColumn && (_jsx(TableCell, { children: _jsx("span", { className: "text-muted-foreground", children: "-" }) })), _jsx(TableCell, { children: _jsx("span", { className: "rounded border border-border px-1.5 py-0.5 text-[10px] text-muted-foreground", children: t("org.invited") }) }), _jsx(TableCell, { className: "text-end text-muted-foreground", children: "-" })] }));
163
+ return (_jsxs("div", { className: "flex flex-col gap-3 px-5 py-3.5 opacity-70 sm:flex-row sm:items-center", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [_jsx("div", { className: "flex size-8 shrink-0 items-center justify-center rounded-full border border-border bg-background text-xs font-medium text-muted-foreground", children: memberInitials(invite.email) }), _jsx("span", { className: "min-w-0 truncate text-sm", children: invite.email })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:justify-end", children: [_jsx(RoleBadge, { role: invite.role }), _jsx("span", { className: "rounded border border-border px-1.5 py-0.5 text-[10px] text-muted-foreground", children: t("org.invited") })] })] }));
149
164
  }
150
165
  /** Sentinel for "clear the assignment" — Select cannot carry an empty value. */
151
166
  const UNASSIGNED = "__unassigned__";
152
- function AppRoleCell({ email, appRoles, appRole, canManage, }) {
167
+ function AppRoleControl({ email, appRoles, appRole, canManage, }) {
153
168
  const [editing, setEditing] = useState(false);
154
169
  const setAppRole = useSetAppMemberRole(appRoles.appId);
155
170
  const labelFor = (r) => appRoles.roleLabels?.[r] ?? r;
156
171
  if (editing) {
157
- return (_jsx(TableCell, { children: _jsxs(Select, { defaultOpen: true, value: appRole ?? UNASSIGNED, onOpenChange: (open) => {
158
- if (!open)
159
- setEditing(false);
160
- }, onValueChange: (value) => {
161
- const next = value === UNASSIGNED ? null : value;
162
- if (next === appRole) {
163
- setEditing(false);
164
- return;
165
- }
166
- setAppRole.mutate({ email, role: next }, { onSuccess: () => setEditing(false) });
167
- }, disabled: setAppRole.isPending, children: [_jsx(SelectTrigger, { autoFocus: true, className: "h-auto w-auto rounded-md border border-border bg-background px-1.5 py-0.5 text-[11px]", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: UNASSIGNED, children: appRoles.defaultRole ? labelFor(appRoles.defaultRole) : "—" }), appRoles.roles.map((r) => (_jsx(SelectItem, { value: r, children: labelFor(r) }, r)))] })] }) }));
172
+ return (_jsxs(Select, { defaultOpen: true, value: appRole ?? UNASSIGNED, onOpenChange: (open) => {
173
+ if (!open)
174
+ setEditing(false);
175
+ }, onValueChange: (value) => {
176
+ const next = value === UNASSIGNED ? null : value;
177
+ if (next === appRole) {
178
+ setEditing(false);
179
+ return;
180
+ }
181
+ setAppRole.mutate({ email, role: next }, { onSuccess: () => setEditing(false) });
182
+ }, disabled: setAppRole.isPending, children: [_jsx(SelectTrigger, { autoFocus: true, className: "h-auto w-auto rounded-md border border-border bg-background px-2 py-1 text-xs", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: UNASSIGNED, children: appRoles.defaultRole ? labelFor(appRoles.defaultRole) : "—" }), appRoles.roles.map((r) => (_jsx(SelectItem, { value: r, children: labelFor(r) }, r)))] })] }));
168
183
  }
169
184
  // An unassigned member shows the app's default only as a hint. The default
170
185
  // never satisfies a server guard, so it must not read as a granted role.
171
186
  const display = appRole ? (_jsx("span", { className: "inline-flex items-center rounded border border-border px-2 py-1 text-xs text-muted-foreground", children: labelFor(appRole) })) : (_jsx("span", { className: "text-xs text-muted-foreground/70", children: appRoles.defaultRole ? labelFor(appRoles.defaultRole) : "—" }));
172
- return (_jsx(TableCell, { children: canManage ? (_jsx(Button, { type: "button", onClick: () => setEditing(true), className: "cursor-pointer rounded hover:opacity-80", children: display })) : (display) }));
187
+ return canManage ? (_jsx(Button, { type: "button", onClick: () => setEditing(true), className: "cursor-pointer rounded hover:opacity-80", children: display })) : (display);
173
188
  }
174
189
  function MemberRow({ email, role, isCurrentUser, currentUserRole, appRoles, appRole, canManageAppRoles, }) {
175
190
  const t = useT();
@@ -184,20 +199,20 @@ function MemberRow({ email, role, isCurrentUser, currentUserRole, appRoles, appR
184
199
  !isCurrentUser &&
185
200
  (currentUserRole === "owner" ||
186
201
  (currentUserRole === "admin" && role === "member"));
187
- return (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "min-w-56", children: _jsx("span", { className: "truncate text-sm", children: email }) }), _jsx(TableCell, { children: _jsx(RoleBadge, { role: role }) }), appRoles && (_jsx(AppRoleCell, { email: email, appRoles: appRoles, appRole: appRole ?? null, canManage: Boolean(canManageAppRoles) })), _jsx(TableCell, { children: isCurrentUser ? (_jsx("span", { className: "rounded border border-border px-1.5 py-0.5 text-[10px] text-muted-foreground", children: t("org.you") })) : (_jsx("span", { className: "text-muted-foreground", children: "-" })) }), _jsx(TableCell, { children: canManage ? (_jsxs("div", { className: "flex shrink-0 items-center justify-end gap-1", children: [editing ? (_jsxs(Select, { defaultOpen: true, value: role, onOpenChange: (open) => {
188
- if (!open)
189
- setEditing(false);
190
- }, onValueChange: (value) => {
191
- const next = value === "admin" ? "admin" : "member";
192
- if (next !== role) {
193
- changeRole.mutate({ email, role: next }, { onSuccess: () => setEditing(false) });
194
- }
195
- else {
196
- setEditing(false);
197
- }
198
- }, disabled: changeRole.isPending, children: [_jsx(SelectTrigger, { autoFocus: true, className: "h-auto w-auto rounded-md border border-border bg-background px-1.5 py-0.5 text-[11px]", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "member", children: t("org.member") }), _jsx(SelectItem, { value: "admin", children: t("org.admin") })] })] })) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: () => setEditing(true), className: "text-muted-foreground hover:text-foreground", children: _jsx(IconPencil, { size: 14 }) }) }), _jsx(TooltipContent, { children: t("org.changeRole") })] })), confirmingRemove ? (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Button, { type: "button", intent: "neutral", emphasis: "ghost", onClick: () => setConfirmingRemove(false), className: "rounded px-1.5 py-0.5 text-[11px] text-muted-foreground hover:bg-accent hover:text-foreground", children: t("org.cancel") }), _jsx(Button, { type: "button", intent: "danger", emphasis: "solid", disabled: removeMember.isPending, onClick: () => removeMember.mutate(email, {
199
- onSettled: () => setConfirmingRemove(false),
200
- }), className: "rounded bg-destructive px-1.5 py-0.5 text-[11px] text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50", children: t("org.remove") })] })) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", intent: "danger", emphasis: "ghost", disabled: removeMember.isPending, onClick: () => setConfirmingRemove(true), className: "text-muted-foreground hover:text-destructive disabled:opacity-50", children: _jsx(IconTrash, { size: 14 }) }) }), _jsx(TooltipContent, { children: t("org.removeMember") })] }))] })) : (_jsx("div", { className: "text-end text-muted-foreground", children: "-" })) })] }));
202
+ return (_jsxs("div", { className: "flex flex-col gap-3 px-5 py-3.5 sm:flex-row sm:items-center", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [_jsx("div", { className: "flex size-8 shrink-0 items-center justify-center rounded-full border border-border bg-background text-xs font-medium text-muted-foreground", children: memberInitials(email) }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-sm", children: email }), isCurrentUser && (_jsx("div", { className: "mt-0.5 text-xs text-muted-foreground", children: t("org.you") }))] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 sm:justify-end", children: [_jsx(RoleBadge, { role: role }), appRoles && (_jsx(AppRoleControl, { email: email, appRoles: appRoles, appRole: appRole ?? null, canManage: Boolean(canManageAppRoles) })), canManage && (_jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [editing ? (_jsxs(Select, { defaultOpen: true, value: role, onOpenChange: (open) => {
203
+ if (!open)
204
+ setEditing(false);
205
+ }, onValueChange: (value) => {
206
+ const next = value === "admin" ? "admin" : "member";
207
+ if (next !== role) {
208
+ changeRole.mutate({ email, role: next }, { onSuccess: () => setEditing(false) });
209
+ }
210
+ else {
211
+ setEditing(false);
212
+ }
213
+ }, disabled: changeRole.isPending, children: [_jsx(SelectTrigger, { autoFocus: true, className: "h-auto w-auto rounded-md border border-border bg-background px-2 py-1 text-xs", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "member", children: t("org.member") }), _jsx(SelectItem, { value: "admin", children: t("org.admin") })] })] })) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: () => setEditing(true), className: "text-muted-foreground hover:text-foreground", children: _jsx(IconPencil, { size: 14 }) }) }), _jsx(TooltipContent, { children: t("org.changeRole") })] })), confirmingRemove ? (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Button, { type: "button", intent: "neutral", emphasis: "ghost", onClick: () => setConfirmingRemove(false), className: "rounded px-1.5 py-0.5 text-[11px] text-muted-foreground hover:bg-accent hover:text-foreground", children: t("org.cancel") }), _jsx(Button, { type: "button", intent: "danger", emphasis: "solid", disabled: removeMember.isPending, onClick: () => removeMember.mutate(email, {
214
+ onSettled: () => setConfirmingRemove(false),
215
+ }), className: "rounded bg-destructive px-1.5 py-0.5 text-[11px] text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50", children: t("org.remove") })] })) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", intent: "danger", emphasis: "ghost", disabled: removeMember.isPending, onClick: () => setConfirmingRemove(true), className: "text-muted-foreground hover:text-destructive disabled:opacity-50", children: _jsx(IconTrash, { size: 14 }) }) }), _jsx(TooltipContent, { children: t("org.removeMember") })] }))] }))] })] }));
201
216
  }
202
217
  const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
203
218
  function parseEmailList(input) {
@@ -334,18 +349,18 @@ function DomainSettingsSection({ domain, ownerEmail, }) {
334
349
  onSuccess: () => setEditing(false),
335
350
  });
336
351
  }
337
- return (_jsxs("div", { className: "space-y-2 border-t border-border pt-3 first:border-t-0 first:pt-0", children: [_jsx("div", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: "Email domain auto-join" }), _jsxs("p", { className: "text-[11px] text-muted-foreground", children: ["Anyone who signs up with an email at this domain will join your organization automatically. You can only set your own email domain (", ownDomain || "—", "); free email providers like gmail.com or outlook.com aren't allowed."] }), !editing ? (_jsx("div", { className: "flex items-center gap-2", children: domain ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm", children: [_jsx(IconAt, { className: "h-3.5 w-3.5 text-muted-foreground" }), domain] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: () => {
338
- setDraft(domain);
339
- setEditing(true);
340
- }, className: "text-muted-foreground hover:text-foreground", children: _jsx(IconPencil, { size: 14 }) }) }), _jsx(TooltipContent, { children: "Edit domain" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", intent: "danger", emphasis: "ghost", disabled: setOrgDomain.isPending, onClick: () => setOrgDomain.mutate(null), className: "text-muted-foreground hover:text-destructive disabled:opacity-50", children: _jsx(IconX, { size: 14 }) }) }), _jsx(TooltipContent, { children: "Remove domain" })] })] })) : (_jsxs(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => {
341
- setDraft(ownDomain);
342
- setEditing(true);
343
- }, className: "flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50", children: [_jsx(IconAt, { size: 14 }), "Allow ", ownDomain || "your domain", " to auto-join"] })) })) : (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "text", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: (e) => {
344
- if (e.key === "Enter")
345
- save();
346
- if (e.key === "Escape")
347
- setEditing(false);
348
- }, placeholder: ownDomain || "example.com", className: "rounded-md border border-border bg-background px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-foreground", autoFocus: true }), _jsx(Button, { type: "button", intent: "primary", emphasis: "solid", disabled: setOrgDomain.isPending, onClick: save, className: "rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50", children: setOrgDomain.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : ("Save") }), _jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => setEditing(false), className: "rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground hover:text-foreground", children: "Cancel" })] })), _jsx(ErrorText, { error: setOrgDomain.error })] }));
352
+ return (_jsx(SettingsRow, { id: "email-domain", label: "Email domain auto-join", description: _jsx(OrganizationDescription, { help: `Anyone who signs up with an email at this domain joins the organization automatically. Only your own email domain (${ownDomain || "—"}) can be used; free email providers are not allowed.`, docsUrl: "https://www.builder.io/c/docs/agent-native-authentication?utm_source=agent-native&utm_medium=product&utm_campaign=organization_settings&utm_content=domain_auto_join", children: "Automatically add members with your work email." }), control: !editing ? (_jsx("div", { className: "flex flex-wrap items-center justify-end gap-2", children: domain ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm", children: [_jsx(IconAt, { className: "h-3.5 w-3.5 text-muted-foreground" }), domain] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: () => {
353
+ setDraft(domain);
354
+ setEditing(true);
355
+ }, className: "text-muted-foreground hover:text-foreground", children: _jsx(IconPencil, { size: 14 }) }) }), _jsx(TooltipContent, { children: "Edit domain" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", intent: "danger", emphasis: "ghost", disabled: setOrgDomain.isPending, onClick: () => setOrgDomain.mutate(null), className: "text-muted-foreground hover:text-destructive disabled:opacity-50", children: _jsx(IconX, { size: 14 }) }) }), _jsx(TooltipContent, { children: "Remove domain" })] })] })) : (_jsxs(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => {
356
+ setDraft(ownDomain);
357
+ setEditing(true);
358
+ }, className: "flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50", children: [_jsx(IconAt, { size: 14 }), "Set domain"] })) })) : (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "text", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: (e) => {
359
+ if (e.key === "Enter")
360
+ save();
361
+ if (e.key === "Escape")
362
+ setEditing(false);
363
+ }, placeholder: ownDomain || "example.com", className: "w-44 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-foreground", autoFocus: true }), _jsx(Button, { type: "button", intent: "primary", emphasis: "solid", disabled: setOrgDomain.isPending, onClick: save, className: "rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50", children: setOrgDomain.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : ("Save") }), _jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => setEditing(false), className: "rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground hover:text-foreground", children: "Cancel" })] })), children: setOrgDomain.error ? _jsx(ErrorText, { error: setOrgDomain.error }) : null }));
349
364
  }
350
365
  function WorkspaceUrlSettingsSection({ workspaceUrl, }) {
351
366
  const setWorkspaceUrl = useSetOrgWorkspaceUrl();
@@ -361,15 +376,15 @@ function WorkspaceUrlSettingsSection({ workspaceUrl, }) {
361
376
  onSuccess: () => setEditing(false),
362
377
  });
363
378
  }
364
- return (_jsxs("div", { className: "space-y-2 border-t border-border pt-3 first:border-t-0 first:pt-0", children: [_jsx("div", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: "Your workspace" }), _jsx("p", { className: "text-[11px] text-muted-foreground", children: "If your team runs its own workspace, members who land on a different deployment \u2014 opening a template from the catalog, for instance \u2014 get pointed here instead of an app that looks empty." }), !editing ? (_jsx("div", { className: "flex items-center gap-2", children: workspaceUrl ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm", children: [_jsx(IconExternalLink, { className: "h-3.5 w-3.5 text-muted-foreground" }), workspaceUrl] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: () => {
365
- setDraft(workspaceUrl);
366
- setEditing(true);
367
- }, className: "text-muted-foreground hover:text-foreground", children: _jsx(IconPencil, { size: 14 }) }) }), _jsx(TooltipContent, { children: "Edit workspace URL" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", intent: "danger", emphasis: "ghost", disabled: setWorkspaceUrl.isPending, onClick: () => setWorkspaceUrl.mutate(null), className: "text-muted-foreground hover:text-destructive disabled:opacity-50", children: _jsx(IconX, { size: 14 }) }) }), _jsx(TooltipContent, { children: "Remove workspace URL" })] })] })) : (_jsxs(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => setEditing(true), className: "flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50", children: [_jsx(IconExternalLink, { size: 14 }), "Set workspace URL"] })) })) : (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "text", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: (e) => {
368
- if (e.key === "Enter")
369
- save();
370
- if (e.key === "Escape")
371
- setEditing(false);
372
- }, placeholder: "workspace.example.com", className: "rounded-md border border-border bg-background px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-foreground", autoFocus: true }), _jsx(Button, { type: "button", intent: "primary", emphasis: "solid", disabled: setWorkspaceUrl.isPending, onClick: save, className: "rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50", children: setWorkspaceUrl.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : ("Save") }), _jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => setEditing(false), className: "rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground hover:text-foreground", children: "Cancel" })] })), _jsx(ErrorText, { error: setWorkspaceUrl.error })] }));
379
+ return (_jsx(SettingsRow, { id: "workspace-url", label: "Workspace URL", description: _jsx(OrganizationDescription, { help: "Members who land on another deployment can be sent to this workspace URL instead of an empty app.", docsUrl: "https://www.builder.io/c/docs/agent-native-deployment?utm_source=agent-native&utm_medium=product&utm_campaign=organization_settings&utm_content=workspace_url", children: "Send members to this workspace from another deployment." }), control: !editing ? (_jsx("div", { className: "flex flex-wrap items-center justify-end gap-2", children: workspaceUrl ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "inline-flex max-w-72 items-center gap-1.5 truncate rounded-md border border-border bg-background px-2.5 py-1.5 text-sm", children: [_jsx(IconExternalLink, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "truncate", children: workspaceUrl })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: () => {
380
+ setDraft(workspaceUrl);
381
+ setEditing(true);
382
+ }, className: "text-muted-foreground hover:text-foreground", children: _jsx(IconPencil, { size: 14 }) }) }), _jsx(TooltipContent, { children: "Edit workspace URL" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", intent: "danger", emphasis: "ghost", disabled: setWorkspaceUrl.isPending, onClick: () => setWorkspaceUrl.mutate(null), className: "text-muted-foreground hover:text-destructive disabled:opacity-50", children: _jsx(IconX, { size: 14 }) }) }), _jsx(TooltipContent, { children: "Remove workspace URL" })] })] })) : (_jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => setEditing(true), className: "flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50", children: "Set URL" })) })) : (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "text", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: (e) => {
383
+ if (e.key === "Enter")
384
+ save();
385
+ if (e.key === "Escape")
386
+ setEditing(false);
387
+ }, placeholder: "workspace.example.com", className: "w-56 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-foreground", autoFocus: true }), _jsx(Button, { type: "button", intent: "primary", emphasis: "solid", disabled: setWorkspaceUrl.isPending, onClick: save, className: "rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50", children: setWorkspaceUrl.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : ("Save") }), _jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => setEditing(false), className: "rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground hover:text-foreground", children: "Cancel" })] })), children: setWorkspaceUrl.error ? (_jsx(ErrorText, { error: setWorkspaceUrl.error })) : null }));
373
388
  }
374
389
  function AuthProviderSettingsSection({ requiredAuthProvider, }) {
375
390
  const setAuthProvider = useSetOrgAuthProvider();
@@ -382,7 +397,7 @@ function AuthProviderSettingsSection({ requiredAuthProvider, }) {
382
397
  }
383
398
  setAuthProvider.mutate(null);
384
399
  }
385
- return (_jsxs("div", { className: "space-y-2 border-t border-border pt-3 first:border-t-0 first:pt-0", children: [_jsx("div", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: "Organization sign-in" }), _jsx("p", { className: "text-[11px] text-muted-foreground", children: "Require Google sign-in for every member of this organization. Enabling this revokes all current sessions, and future password or non-Google sign-ins will be rejected." }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Switch, { checked: enabled, disabled: setAuthProvider.isPending, onCheckedChange: changeProvider, "aria-label": "Require Google sign-in" }), _jsx("span", { className: "text-sm font-medium", children: enabled ? "Google sign-in required" : "Google sign-in optional" })] }), _jsx(ErrorText, { error: setAuthProvider.error }), _jsx(AlertDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Require Google sign-in?" }), _jsx(AlertDialogDescription, { children: "Every current session in this organization will be revoked. Members must use their Google Workspace account the next time they sign in. Continue only after Google sign-in is configured for this app." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: setAuthProvider.isPending, children: "Cancel" }), _jsx(AlertDialogAction, { disabled: setAuthProvider.isPending, onClick: () => {
400
+ return (_jsxs(_Fragment, { children: [_jsx(SettingsRow, { id: "organization-sign-in", label: "Organization sign-in", description: _jsx(OrganizationDescription, { help: "Require Google sign-in for every member. Enabling this revokes current sessions and rejects future password or non-Google sign-ins.", docsUrl: "https://www.builder.io/c/docs/agent-native-authentication?utm_source=agent-native&utm_medium=product&utm_campaign=organization_settings&utm_content=organization_sign_in", children: "Choose how members sign in." }), control: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: "text-sm font-medium", children: enabled ? "Google required" : "Google optional" }), _jsx(Switch, { checked: enabled, disabled: setAuthProvider.isPending, onCheckedChange: changeProvider, "aria-label": "Require Google sign-in" })] }), children: setAuthProvider.error ? (_jsx(ErrorText, { error: setAuthProvider.error })) : null }), _jsx(AlertDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Require Google sign-in?" }), _jsx(AlertDialogDescription, { children: "Every current session in this organization will be revoked. Members must use their Google Workspace account the next time they sign in. Continue only after Google sign-in is configured for this app." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: setAuthProvider.isPending, children: "Cancel" }), _jsx(AlertDialogAction, { disabled: setAuthProvider.isPending, onClick: () => {
386
401
  setAuthProvider.mutate("google", {
387
402
  onSuccess: () => setConfirmOpen(false),
388
403
  });
@@ -463,19 +478,24 @@ function A2ASecretSection({ isSet }) {
463
478
  });
464
479
  }
465
480
  const masked = isSet ? "••••••••••••" : "Not set";
466
- return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center gap-1 text-xs font-medium text-muted-foreground uppercase tracking-wide", children: [_jsx("span", { children: "Cross-app authentication" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("a", { href: "/docs/a2a-protocol#organization-secret-sync", target: "_blank", rel: "noopener noreferrer", "aria-label": "Read the cross-app authentication documentation", className: "inline-flex size-3.5 items-center justify-center rounded-full text-muted-foreground hover:text-foreground", children: _jsx(IconHelpCircle, { className: "size-3" }) }) }), _jsx(TooltipContent, { children: "Read the cross-app authentication documentation" })] })] }), _jsx("p", { className: "text-[11px] text-muted-foreground", children: "This secret authenticates cross-app delegation (e.g. Dispatch to Analytics). All apps in your organization need the same secret." }), _jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm font-mono", children: [_jsx(IconKey, { className: "h-3.5 w-3.5 text-muted-foreground" }), secret ?? masked] }), isSet && (_jsxs(_Fragment, { children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: toggleReveal, disabled: revealA2ASecret.isPending, className: "text-muted-foreground hover:text-foreground", children: secret ? _jsx(IconEyeOff, { size: 14 }) : _jsx(IconEye, { size: 14 }) }) }), _jsx(TooltipContent, { children: secret ? "Hide secret" : "Reveal secret" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: copyToClipboard, disabled: revealA2ASecret.isPending, className: "text-muted-foreground hover:text-foreground", children: copied ? (_jsx(IconCheck, { size: 14, className: "text-primary" })) : (_jsx(IconCopy, { size: 14 })) }) }), _jsx(TooltipContent, { children: "Copy secret" })] })] })), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(Button, { type: "button", intent: "danger", emphasis: "outline", onClick: regenerate, disabled: setA2ASecret.isPending || syncA2ASecret.isPending, className: "inline-flex items-center gap-1 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50 disabled:opacity-50", children: [setA2ASecret.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : (_jsx(IconRefresh, { size: 14 })), "Regenerate"] }) }), _jsx(TooltipContent, { children: "Regenerate secret and sync to connected apps" })] }), isSet && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => syncToApps(), disabled: setA2ASecret.isPending || syncA2ASecret.isPending, className: "inline-flex items-center gap-1 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50 disabled:opacity-50", children: [syncA2ASecret.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : (_jsx(IconCloudUpload, { size: 14 })), "Sync to apps"] }) }), _jsx(TooltipContent, { children: "Push this secret to every connected app" })] }))] }), syncA2ASecret.isPending && (_jsx("p", { className: "text-[11px] text-muted-foreground", children: "Syncing to connected apps\u2026" })), syncResult && !syncA2ASecret.isPending && (_jsxs("div", { className: "space-y-1", children: [_jsxs("p", { className: "text-[11px] text-muted-foreground", children: ["Synced to ", syncResult.succeeded, "/", syncResult.total, " app", syncResult.total === 1 ? "" : "s", syncResult.failed > 0 ? ` (${syncResult.failed} failed)` : "", "."] }), syncResult.failed > 0 && (_jsx("ul", { className: "text-[11px] text-destructive list-disc ps-5 space-y-0.5", children: syncResult.results
467
- .filter((r) => !r.ok)
468
- .map((r) => (_jsxs("li", { children: [r.name, ": ", r.error || `HTTP ${r.status ?? "?"}`] }, r.id))) }))] })), !pasteMode ? (_jsxs(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => setPasteMode(true), className: "flex items-center gap-1.5 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50", children: [_jsx(IconKey, { size: 14 }), "Paste secret from another app"] })) : (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "text", value: pasteValue, onChange: (e) => setPasteValue(e.target.value), onKeyDown: (e) => {
469
- if (e.key === "Enter")
470
- saveSecret();
471
- if (e.key === "Escape") {
481
+ return (_jsx(SettingsRow, { id: "cross-app-authentication", label: "Cross-app authentication", description: _jsx(OrganizationDescription, { help: "This secret authenticates cross-app delegation. Every app in the organization must share it.", children: "Share one secret across connected apps." }), control: _jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2", children: [_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm font-mono", children: [_jsx(IconKey, { className: "h-3.5 w-3.5 text-muted-foreground" }), secret ?? masked] }), isSet && (_jsxs(_Fragment, { children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: toggleReveal, disabled: revealA2ASecret.isPending, className: "text-muted-foreground hover:text-foreground", children: secret ? _jsx(IconEyeOff, { size: 14 }) : _jsx(IconEye, { size: 14 }) }) }), _jsx(TooltipContent, { children: secret ? "Hide secret" : "Reveal secret" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { type: "button", onClick: copyToClipboard, disabled: revealA2ASecret.isPending, className: "text-muted-foreground hover:text-foreground", children: copied ? (_jsx(IconCheck, { size: 14, className: "text-primary" })) : (_jsx(IconCopy, { size: 14 })) }) }), _jsx(TooltipContent, { children: "Copy secret" })] })] })), _jsxs(Button, { type: "button", intent: "danger", emphasis: "outline", onClick: regenerate, disabled: setA2ASecret.isPending || syncA2ASecret.isPending, className: "inline-flex items-center gap-1 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50 disabled:opacity-50", children: [setA2ASecret.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : (_jsx(IconRefresh, { size: 14 })), "Regenerate"] }), isSet && (_jsxs(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => syncToApps(), disabled: setA2ASecret.isPending || syncA2ASecret.isPending, className: "inline-flex items-center gap-1 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50 disabled:opacity-50", children: [syncA2ASecret.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : (_jsx(IconCloudUpload, { size: 14 })), "Sync"] })), !pasteMode && (_jsxs(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => setPasteMode(true), className: "inline-flex items-center gap-1 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium hover:bg-accent/50", children: [_jsx(IconKey, { size: 14 }), "Paste secret"] }))] }), children: (pasteMode ||
482
+ syncA2ASecret.isPending ||
483
+ syncResult ||
484
+ revealA2ASecret.error ||
485
+ setA2ASecret.error ||
486
+ syncA2ASecret.error) && (_jsxs("div", { className: "space-y-3", children: [syncA2ASecret.isPending && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Syncing to connected apps\u2026" })), syncResult && !syncA2ASecret.isPending && (_jsxs("div", { className: "space-y-1", children: [_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Synced to ", syncResult.succeeded, "/", syncResult.total, " app", syncResult.total === 1 ? "" : "s", syncResult.failed > 0 ? ` (${syncResult.failed} failed)` : "", "."] }), syncResult.failed > 0 && (_jsx("ul", { className: "list-disc space-y-0.5 ps-5 text-xs text-destructive", children: syncResult.results
487
+ .filter((r) => !r.ok)
488
+ .map((r) => (_jsxs("li", { children: [r.name, ": ", r.error || `HTTP ${r.status ?? "?"}`] }, r.id))) }))] })), pasteMode ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "text", value: pasteValue, onChange: (e) => setPasteValue(e.target.value), onKeyDown: (e) => {
489
+ if (e.key === "Enter")
490
+ saveSecret();
491
+ if (e.key === "Escape") {
492
+ setPasteMode(false);
493
+ setPasteValue("");
494
+ }
495
+ }, placeholder: "Paste A2A secret", className: "min-w-0 flex-1 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm font-mono focus:outline-none focus:ring-1 focus:ring-foreground", autoFocus: true }), _jsx(Button, { type: "button", intent: "primary", emphasis: "solid", disabled: !pasteValue.trim() || setA2ASecret.isPending, onClick: saveSecret, className: "rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50", children: setA2ASecret.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : ("Save") }), _jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => {
472
496
  setPasteMode(false);
473
497
  setPasteValue("");
474
- }
475
- }, placeholder: "Paste A2A secret", className: "flex-1 rounded-md border border-border bg-background px-2.5 py-1.5 text-sm font-mono focus:outline-none focus:ring-1 focus:ring-foreground", autoFocus: true }), _jsx(Button, { type: "button", intent: "primary", emphasis: "solid", disabled: !pasteValue.trim() || setA2ASecret.isPending, onClick: saveSecret, className: "rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50", children: setA2ASecret.isPending ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : ("Save") }), _jsx(Button, { type: "button", intent: "neutral", emphasis: "outline", onClick: () => {
476
- setPasteMode(false);
477
- setPasteValue("");
478
- }, className: "rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground hover:text-foreground", children: "Cancel" })] })), _jsx(ErrorText, { error: revealA2ASecret.error }), _jsx(ErrorText, { error: setA2ASecret.error }), _jsx(ErrorText, { error: syncA2ASecret.error })] }));
498
+ }, className: "rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground hover:text-foreground", children: "Cancel" })] })) : null, _jsx(ErrorText, { error: revealA2ASecret.error }), _jsx(ErrorText, { error: setA2ASecret.error }), _jsx(ErrorText, { error: syncA2ASecret.error })] })) }));
479
499
  }
480
500
  /**
481
501
  * Default Team management page. Templates can route directly to this component
@@ -484,7 +504,7 @@ function A2ASecretSection({ isSet }) {
484
504
  export function TeamPage({ layout, title, showTitle = true, createOrgDescription, className, appRoles, }) {
485
505
  const t = useT();
486
506
  const { data: org, isLoading } = useOrg();
487
- const content = (_jsxs("div", { className: `space-y-6 ${className ?? "max-w-2xl"}`, children: [showTitle ? (_jsx("h2", { className: "text-2xl font-bold tracking-tight", children: title ?? t("org.team") })) : null, isLoading && (_jsx("section", { className: "rounded-lg border border-border bg-card p-6", children: _jsx("div", { className: "text-sm text-muted-foreground", children: t("org.loading") }) })), !isLoading && (_jsxs(_Fragment, { children: [_jsx(PendingInvitationsCard, {}), org?.domainMatches && org.domainMatches.length > 0 && (_jsx(JoinByDomainCard, { matches: org.domainMatches })), !org?.orgId ? (_jsx(CreateOrgCard, { description: createOrgDescription })) : (_jsx(MembersCard, { appRoles: appRoles }))] }))] }));
507
+ const content = (_jsxs("div", { className: `w-full space-y-6 ${className ?? ""}`, children: [showTitle ? (_jsx("h2", { className: "text-2xl font-bold tracking-tight", children: title ?? t("org.team") })) : null, isLoading && (_jsx("section", { className: "rounded-lg border border-border bg-card p-6", children: _jsx("div", { className: "text-sm text-muted-foreground", children: t("org.loading") }) })), !isLoading && (_jsxs(_Fragment, { children: [_jsx(PendingInvitationsCard, {}), org?.domainMatches && org.domainMatches.length > 0 && (_jsx(JoinByDomainCard, { matches: org.domainMatches })), !org?.orgId ? (_jsx(CreateOrgCard, { description: createOrgDescription })) : (_jsx(MembersCard, { appRoles: appRoles }))] }))] }));
488
508
  const wrapped = (_jsx(TooltipProvider, { delayDuration: 200, children: content }));
489
509
  return layout ? _jsx(_Fragment, { children: layout(wrapped) }) : wrapped;
490
510
  }
@@ -37,7 +37,7 @@ export interface RequireSessionProps {
37
37
  fallback?: React.ReactNode;
38
38
  /**
39
39
  * When true (default), unauthenticated visitors are redirected to the
40
- * framework sign-in entry point (`/_agent-native/sign-in`) carrying a `c`
40
+ * framework sign-in entry point (`/sign-in`) carrying a `c`
41
41
  * continuation for the current URL — so they land back here once signed in.
42
42
  * When false, `signedOut` is rendered instead and no navigation happens.
43
43
  */
@@ -29,8 +29,8 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
29
29
  * surfaces that authenticate by another mechanism.
30
30
  */
31
31
  import { useEffect, useRef } from "react";
32
- import { signInJourney } from "../shared/sign-in-journey.js";
33
- import { agentNativePath, appBasePath } from "./api-path.js";
32
+ import { SIGN_IN_ENTRY_PATH, signInJourney, } from "../shared/sign-in-journey.js";
33
+ import { appBasePath, appPath } from "./api-path.js";
34
34
  import { DefaultSpinner } from "./DefaultSpinner.js";
35
35
  import { useSession } from "./use-session.js";
36
36
  /**
@@ -59,7 +59,7 @@ function currentJourney(returnTo) {
59
59
  * directly and honour its `signInHref: null`.
60
60
  */
61
61
  export function buildSignInReturnHref(opts) {
62
- const base = agentNativePath("/_agent-native/sign-in");
62
+ const base = appPath(SIGN_IN_ENTRY_PATH);
63
63
  if (typeof window === "undefined")
64
64
  return base;
65
65
  return currentJourney(opts?.returnTo).signInHref ?? base;
@@ -46,10 +46,15 @@ export interface CreateMcpServerArgs {
46
46
  description?: string;
47
47
  }
48
48
  export declare function useCreateMcpServer(): import("@tanstack/react-query").UseMutationResult<McpServer, Error, CreateMcpServerArgs, unknown>;
49
+ export interface ReconnectMcpServerArgs {
50
+ id: string;
51
+ scope: McpServerScope;
52
+ }
49
53
  export declare function useDeleteMcpServer(): import("@tanstack/react-query").UseMutationResult<void, Error, {
50
54
  id: string;
51
55
  scope: McpServerScope;
52
56
  }, unknown>;
57
+ export declare function useReconnectMcpServer(): import("@tanstack/react-query").UseMutationResult<void, Error, ReconnectMcpServerArgs, unknown>;
53
58
  export interface TestMcpUrlResult {
54
59
  ok: boolean;
55
60
  error?: string;
@@ -59,6 +59,42 @@ export function useDeleteMcpServer() {
59
59
  onSuccess: () => qc.invalidateQueries({ queryKey: LIST_KEY }),
60
60
  });
61
61
  }
62
+ async function readMcpMutationBody(res) {
63
+ const text = (await res.text()).trim();
64
+ if (!text)
65
+ return null;
66
+ try {
67
+ return JSON.parse(text);
68
+ }
69
+ catch (cause) {
70
+ throw new Error(`Reconnect response was not valid JSON (HTTP ${res.status}).`, { cause });
71
+ }
72
+ }
73
+ function reconnectMcpServerUrl(args) {
74
+ return `${ENDPOINT}/${encodeURIComponent(args.id)}/reconnect?scope=${args.scope}`;
75
+ }
76
+ export function useReconnectMcpServer() {
77
+ const qc = useQueryClient();
78
+ return useMutation({
79
+ mutationFn: async (args) => {
80
+ const res = await fetch(reconnectMcpServerUrl(args), {
81
+ method: "POST",
82
+ credentials: "include",
83
+ });
84
+ const body = await readMcpMutationBody(res);
85
+ const error = typeof body?.error === "string" && body.error.trim()
86
+ ? body.error.trim()
87
+ : undefined;
88
+ if (!res.ok) {
89
+ throw new Error(error || `Reconnect failed (${res.status})`);
90
+ }
91
+ if (body?.ok !== true) {
92
+ throw new Error(error || "Reconnect failed");
93
+ }
94
+ },
95
+ onSuccess: () => qc.invalidateQueries({ queryKey: LIST_KEY }),
96
+ });
97
+ }
62
98
  export function getMcpUrlValidationError(rawUrl) {
63
99
  const trimmed = rawUrl.trim();
64
100
  if (!trimmed)