@agent-native/core 0.141.7 → 0.144.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/agent-native.eject.json +9 -0
  2. package/corpus/README.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +19 -0
  4. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +296 -0
  5. package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  6. package/corpus/templates/analytics/.agents/skills/turn-into-skill/SKILL.md +112 -0
  7. package/corpus/templates/analytics/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  8. package/corpus/templates/analytics/AGENTS.md +35 -38
  9. package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +1 -1
  10. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +17 -22
  11. package/corpus/templates/analytics/actions/navigate.ts +4 -5
  12. package/corpus/templates/analytics/actions/provider-api-register.ts +50 -0
  13. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +44 -11
  14. package/corpus/templates/analytics/actions/test-custom-api-connection.ts +106 -0
  15. package/corpus/templates/analytics/app/components/CustomApiCard.tsx +430 -0
  16. package/corpus/templates/analytics/app/i18n-data.ts +680 -0
  17. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +6 -0
  18. package/corpus/templates/analytics/app/lib/sql-query.ts +33 -6
  19. package/corpus/templates/analytics/app/pages/DataSources.tsx +4 -0
  20. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-load-reliably-during-background-data-sw.md +6 -0
  21. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-remain-responsive-while-historical-data.md +6 -0
  22. package/corpus/templates/analytics/changelog/2026-08-06-analytics-query-results-now-render-as-a-table-with-csv-downl.md +6 -0
  23. package/corpus/templates/analytics/changelog/2026-08-06-connect-public-https-custom-apis-and-hand-tested-endpoints-t.md +6 -0
  24. package/corpus/templates/analytics/changelog/2026-08-06-durable-agent-worker-memory.md +6 -0
  25. package/corpus/templates/analytics/changelog/2026-08-06-live-dashboard-panels-use-the-shared-query-timeout.md +6 -0
  26. package/corpus/templates/analytics/changelog/2026-08-06-on-demand-billing-is-available-as-a-native-dashboard-with-ta.md +6 -0
  27. package/corpus/templates/analytics/changelog/2026-08-06-visible-dashboard-names-are-unique.md +6 -0
  28. package/corpus/templates/analytics/netlify.toml +7 -0
  29. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +4 -0
  30. package/corpus/templates/analytics/server/db/index.ts +27 -0
  31. package/corpus/templates/analytics/server/db/schema.ts +10 -0
  32. package/corpus/templates/analytics/server/lib/dashboards-store.ts +227 -60
  33. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +133 -44
  34. package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +227 -1
  35. package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
  36. package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +1 -0
  37. package/corpus/templates/analytics/server/plugins/db.ts +52 -18
  38. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +28 -2
  39. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +16 -1
  40. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +296 -0
  41. package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  42. package/corpus/templates/assets/.agents/skills/turn-into-skill/SKILL.md +112 -0
  43. package/corpus/templates/assets/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  44. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +296 -0
  45. package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  46. package/corpus/templates/brain/.agents/skills/turn-into-skill/SKILL.md +112 -0
  47. package/corpus/templates/brain/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  48. package/corpus/templates/brain/actions/list-connection-providers.ts +24 -3
  49. package/corpus/templates/brain/app/lib/dispatch-links.ts +44 -0
  50. package/corpus/templates/brain/app/routes/sources.tsx +15 -7
  51. package/corpus/templates/brain/changelog/2026-08-06-brain-provider-setup-links-open-dispatch-correctly-in-standa.md +6 -0
  52. package/corpus/templates/brain/server/plugins/agent-chat.ts +1 -0
  53. package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +26 -0
  54. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +296 -0
  55. package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  56. package/corpus/templates/calendar/.agents/skills/turn-into-skill/SKILL.md +112 -0
  57. package/corpus/templates/calendar/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  58. package/corpus/templates/calendar/AGENTS.md +11 -32
  59. package/corpus/templates/calendar/actions/update-event.ts +107 -1
  60. package/corpus/templates/calendar/app/components/calendar/EventCalendarSelect.tsx +83 -0
  61. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +57 -0
  62. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +59 -73
  63. package/corpus/templates/calendar/app/hooks/use-events.ts +4 -1
  64. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  65. package/corpus/templates/calendar/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  66. package/corpus/templates/calendar/changelog/2026-08-06-existing-events-can-move-between-connected-google-account-ca.md +6 -0
  67. package/corpus/templates/calendar/server/lib/google-calendar.ts +101 -0
  68. package/corpus/templates/calendar/server/plugins/agent-chat.ts +7 -1
  69. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  70. package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  71. package/corpus/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  72. package/corpus/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  73. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +296 -0
  74. package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  75. package/corpus/templates/clips/.agents/skills/turn-into-skill/SKILL.md +112 -0
  76. package/corpus/templates/clips/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  77. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +9 -24
  78. package/corpus/templates/clips/app/components/editor/timeline-geometry.ts +15 -0
  79. package/corpus/templates/clips/app/components/editor/waveform.tsx +4 -17
  80. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +14 -3
  81. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +28 -38
  82. package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -27
  83. package/corpus/templates/clips/changelog/2026-08-06-clips-recovers-from-stalled-recording-setup-without-requirin.md +6 -0
  84. package/corpus/templates/clips/changelog/2026-08-06-clips-starts-faster-after-a-deploy-or-idle-period-startup-no.md +6 -0
  85. package/corpus/templates/clips/changelog/2026-08-06-deleting-a-recording-returns-cleanly-to-the-library-and-fit-.md +6 -0
  86. package/corpus/templates/clips/changelog/2026-08-06-hide-clip-insights-from-viewers-without-analytics-access.md +6 -0
  87. package/corpus/templates/clips/desktop/src/app.tsx +48 -20
  88. package/corpus/templates/clips/desktop/src/lib/recorder.ts +275 -74
  89. package/corpus/templates/clips/desktop/src/lib/recording-start-guard.ts +84 -0
  90. package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +14 -4
  91. package/corpus/templates/clips/server/plugins/db.ts +214 -26
  92. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +296 -0
  93. package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  94. package/corpus/templates/content/.agents/skills/turn-into-skill/SKILL.md +112 -0
  95. package/corpus/templates/content/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  96. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +296 -0
  97. package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  98. package/corpus/templates/crm/.agents/skills/turn-into-skill/SKILL.md +112 -0
  99. package/corpus/templates/crm/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  100. package/corpus/templates/crm/changelog/2026-08-06-crm-starts-faster-after-a-deploy-or-idle-period-one-time-dat.md +6 -0
  101. package/corpus/templates/crm/server/plugins/db.ts +11 -8
  102. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +36 -1
  103. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +296 -0
  104. package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  105. package/corpus/templates/design/.agents/skills/turn-into-skill/SKILL.md +112 -0
  106. package/corpus/templates/design/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  107. package/corpus/templates/design/actions/import-from-url.ts +1 -1
  108. package/corpus/templates/design/app/components/design/LayersPanel.tsx +27 -18
  109. package/corpus/templates/design/app/pages/Index.tsx +6 -2
  110. package/corpus/templates/design/changelog/2026-08-05-deleting-a-design-from-the-home-page-no-longer-leaves-the-ap.md +6 -0
  111. package/corpus/templates/design/changelog/2026-08-05-renaming-a-layer-now-focuses-its-name-field-automatically.md +6 -0
  112. package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
  113. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +296 -0
  114. package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  115. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/SKILL.md +112 -0
  116. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  117. package/corpus/templates/dispatch/changelog/2026-08-06-ready-workspace-apps-stay-one-click-away-in-a-compact-dispat.md +6 -0
  118. package/corpus/templates/dispatch/changelog/2026-08-06-shared-vault-values-and-management-are-now-restricted-to-wor.md +6 -0
  119. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +296 -0
  120. package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  121. package/corpus/templates/factory/.agents/skills/turn-into-skill/SKILL.md +112 -0
  122. package/corpus/templates/factory/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  123. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +296 -0
  124. package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  125. package/corpus/templates/forms/.agents/skills/turn-into-skill/SKILL.md +112 -0
  126. package/corpus/templates/forms/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  127. package/corpus/templates/forms/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  128. package/corpus/templates/forms/server/plugins/agent-chat.ts +4 -0
  129. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +296 -0
  130. package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  131. package/corpus/templates/macros/.agents/skills/turn-into-skill/SKILL.md +112 -0
  132. package/corpus/templates/macros/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  133. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +296 -0
  134. package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  135. package/corpus/templates/mail/.agents/skills/turn-into-skill/SKILL.md +112 -0
  136. package/corpus/templates/mail/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  137. package/corpus/templates/mail/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  138. package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
  139. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +296 -0
  140. package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  141. package/corpus/templates/plan/.agents/skills/turn-into-skill/SKILL.md +112 -0
  142. package/corpus/templates/plan/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  143. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +48 -5
  144. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +37 -1
  145. package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +6 -0
  146. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +15 -2
  147. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +29 -24
  148. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +296 -0
  149. package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  150. package/corpus/templates/slides/.agents/skills/turn-into-skill/SKILL.md +112 -0
  151. package/corpus/templates/slides/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  152. package/corpus/templates/slides/AGENTS.md +7 -9
  153. package/corpus/templates/slides/_gitignore +1 -0
  154. package/corpus/templates/slides/actions/export-pptx.ts +402 -36
  155. package/corpus/templates/slides/actions/import-file.ts +46 -85
  156. package/corpus/templates/slides/actions/import-google-slides-reference.ts +271 -12
  157. package/corpus/templates/slides/actions/import-pptx.ts +85 -60
  158. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -13
  159. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +5 -1
  160. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +25 -12
  161. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +112 -57
  162. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +202 -0
  163. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +26 -14
  164. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +173 -0
  165. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +182 -141
  166. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
  167. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +18 -0
  168. package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +85 -0
  169. package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -0
  170. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +4 -0
  171. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +27 -1
  172. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  173. package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -1
  174. package/corpus/templates/slides/app/lib/deck-preview-frame.ts +15 -0
  175. package/corpus/templates/slides/app/lib/deck-share-links.ts +9 -0
  176. package/corpus/templates/slides/app/lib/export-pptx-client.ts +89 -0
  177. package/corpus/templates/slides/app/lib/slide-animation-elements.ts +3 -0
  178. package/corpus/templates/slides/app/pages/Index.tsx +91 -1
  179. package/corpus/templates/slides/changelog/2026-08-06-clicking-the-gray-canvas-around-a-slide-clears-its-selection.md +6 -0
  180. package/corpus/templates/slides/changelog/2026-08-06-deck-thumbnails-keep-a-consistent-listing-frame-across-aspec.md +6 -0
  181. package/corpus/templates/slides/changelog/2026-08-06-deep-linked-decks-open-directly-instead-of-being-interrupted.md +6 -0
  182. package/corpus/templates/slides/changelog/2026-08-06-google-slides-exports-now-show-clear-import-steps-when-direc.md +6 -0
  183. package/corpus/templates/slides/changelog/2026-08-06-import-pdf-google-slides-and-powerpoint-decks-directly-from-.md +6 -0
  184. package/corpus/templates/slides/changelog/2026-08-06-imported-powerpoint-exports-keep-text-and-images-editable-an.md +6 -0
  185. package/corpus/templates/slides/changelog/2026-08-06-presentation-prompts-continue-adding-rendered-slides-until-t.md +6 -0
  186. package/corpus/templates/slides/changelog/2026-08-06-public-decks-now-share-read-only-presentation-links-by-defau.md +6 -0
  187. package/corpus/templates/slides/changelog/2026-08-06-slides-offers-a-direct-connect-google-button-when-a-drive-co.md +6 -0
  188. package/corpus/templates/slides/changelog/2026-08-06-slides-preserve-uploaded-pdf-layouts-accept-larger-reference.md +6 -0
  189. package/corpus/templates/slides/changelog/2026-08-06-styled-words-stay-part-of-their-text-box-instead-of-becoming.md +6 -0
  190. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +7 -20
  191. package/corpus/templates/slides/server/handlers/import/html-converter.ts +236 -13
  192. package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +67 -0
  193. package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +2 -0
  194. package/corpus/templates/slides/server/handlers/uploads.ts +7 -3
  195. package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -3
  196. package/corpus/templates/slides/server/lib/emails.ts +7 -2
  197. package/corpus/templates/slides/server/lib/google-docs-error.ts +50 -0
  198. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +1 -0
  199. package/corpus/templates/slides/server/lib/import-asset-storage.ts +127 -0
  200. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -3
  201. package/corpus/templates/slides/server/routes/api/import-assets/[token].get.ts +70 -0
  202. package/corpus/templates/slides/shared/upload-types.ts +3 -0
  203. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +296 -0
  204. package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  205. package/corpus/templates/tasks/.agents/skills/turn-into-skill/SKILL.md +112 -0
  206. package/corpus/templates/tasks/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  207. package/dist/agent/production-agent.d.ts +17 -0
  208. package/dist/agent/production-agent.js +72 -1
  209. package/dist/cli/agent-plugin.d.ts +112 -0
  210. package/dist/cli/agent-plugin.js +1081 -0
  211. package/dist/cli/app-skill.js +39 -1
  212. package/dist/cli/code-agent-executor.d.ts +3 -0
  213. package/dist/cli/code-agent-executor.js +51 -13
  214. package/dist/cli/index.js +13 -0
  215. package/dist/cli/templates-meta.js +1 -1
  216. package/dist/client/AgentPanel.d.ts +3 -1
  217. package/dist/client/AgentPanel.js +9 -2
  218. package/dist/client/AssistantChat.d.ts +8 -0
  219. package/dist/client/AssistantChat.js +23 -8
  220. package/dist/client/NewWorkspaceAppFlow.js +1 -0
  221. package/dist/client/agent-chat-adapter.js +123 -4
  222. package/dist/client/assistant-ui-recovery.d.ts +2 -1
  223. package/dist/client/assistant-ui-recovery.js +7 -3
  224. package/dist/client/onboarding/FirstRunOnboarding.js +11 -4
  225. package/dist/client/org/TeamPage.js +1 -1
  226. package/dist/client/require-session.js +1 -1
  227. package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
  228. package/dist/client/resources/McpConnectionSuggestion.js +27 -10
  229. package/dist/client/resources/McpIntegrationDialog.js +77 -45
  230. package/dist/client/resources/mcp-integration-catalog.d.ts +13 -1
  231. package/dist/client/resources/mcp-integration-catalog.js +255 -2
  232. package/dist/client/resources/mcp-integration-logos.js +18 -2
  233. package/dist/client/settings/AccountSettingsCard.js +2 -1
  234. package/dist/collab/routes.d.ts +1 -1
  235. package/dist/collab/struct-routes.d.ts +1 -1
  236. package/dist/db/client.d.ts +9 -0
  237. package/dist/db/client.js +51 -16
  238. package/dist/db/create-get-db.js +2 -2
  239. package/dist/db/ddl-guard.d.ts +11 -10
  240. package/dist/db/ddl-guard.js +40 -12
  241. package/dist/deploy/build.d.ts +2 -0
  242. package/dist/deploy/build.js +97 -4
  243. package/dist/deploy/workspace-deploy.js +0 -2
  244. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  245. package/dist/guards/no-env-credentials.js +9 -0
  246. package/dist/ingestion/index.d.ts +1 -1
  247. package/dist/ingestion/pptx.d.ts +68 -0
  248. package/dist/ingestion/pptx.js +660 -213
  249. package/dist/integrations/plugin.js +9 -6
  250. package/dist/localization/default-messages.d.ts +54 -0
  251. package/dist/localization/default-messages.js +57 -2
  252. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  253. package/dist/mcp-client/oauth-routes.d.ts +2 -0
  254. package/dist/mcp-client/oauth-routes.js +73 -6
  255. package/dist/notifications/routes.d.ts +1 -1
  256. package/dist/observability/routes.d.ts +3 -3
  257. package/dist/onboarding/app-profile.js +11 -0
  258. package/dist/resources/handlers.d.ts +1 -1
  259. package/dist/resources/store.js +15 -1
  260. package/dist/scripts/call-agent.js +34 -4
  261. package/dist/secrets/routes.d.ts +9 -9
  262. package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
  263. package/dist/server/agent-chat/action-filters-a2a.js +36 -1
  264. package/dist/server/agent-chat-plugin.js +29 -8
  265. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  266. package/dist/server/auth.js +47 -11
  267. package/dist/server/better-auth-instance.js +5 -3
  268. package/dist/server/core-routes-plugin.d.ts +8 -1
  269. package/dist/server/core-routes-plugin.js +28 -3
  270. package/dist/server/credential-provider.d.ts +3 -3
  271. package/dist/server/credential-provider.js +90 -4
  272. package/dist/server/onboarding-html.d.ts +2 -0
  273. package/dist/server/onboarding-html.js +115 -29
  274. package/dist/server/self-dispatch.d.ts +5 -4
  275. package/dist/server/self-dispatch.js +25 -14
  276. package/dist/server/ssr-handler.d.ts +1 -1
  277. package/dist/server/ssr-handler.js +1 -1
  278. package/dist/server/transcribe-voice.d.ts +1 -1
  279. package/dist/shared/cache-control.d.ts +26 -2
  280. package/dist/shared/cache-control.js +43 -2
  281. package/dist/shared/password-policy.d.ts +3 -0
  282. package/dist/shared/password-policy.js +3 -0
  283. package/dist/sharing/actions/set-resource-visibility.js +16 -4
  284. package/dist/sharing/registry.d.ts +14 -0
  285. package/dist/styles/agent-native.css +6 -0
  286. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  287. package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  288. package/dist/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  289. package/dist/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  290. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  291. package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  292. package/dist/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  293. package/dist/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  294. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  295. package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  296. package/dist/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  297. package/dist/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  298. package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  299. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  300. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  301. package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  302. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  303. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  304. package/dist/templates/workspace-root/AGENTS.md +7 -0
  305. package/dist/user-profile/actions/change-password.js +8 -3
  306. package/dist/user-profile/actions/set-password.js +5 -1
  307. package/dist/vite/action-types-plugin.js +59 -0
  308. package/docs/content/skills-guide.mdx +13 -0
  309. package/package.json +6 -2
  310. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  311. package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  312. package/src/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  313. package/src/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  314. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  315. package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  316. package/src/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  317. package/src/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  318. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  319. package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  320. package/src/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  321. package/src/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  322. package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  323. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  324. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  325. package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  326. package/src/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  327. package/src/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  328. package/src/templates/workspace-root/AGENTS.md +7 -0
@@ -8,6 +8,7 @@ type AssistantUiStaleIndexErrorBoundaryProps = {
8
8
  /** Remount children when the recovery scope changes. */
9
9
  remountOnResetKey?: boolean;
10
10
  componentName?: string;
11
+ fallback?: React.ReactNode;
11
12
  children: React.ReactNode;
12
13
  };
13
14
  type AssistantUiStaleIndexErrorBoundaryState = {
@@ -26,7 +27,7 @@ export declare class AssistantUiStaleIndexErrorBoundary extends React.Component<
26
27
  componentDidCatch(error: unknown, info: React.ErrorInfo): void;
27
28
  componentDidUpdate(prevProps: AssistantUiStaleIndexErrorBoundaryProps, prevState: AssistantUiStaleIndexErrorBoundaryState): void;
28
29
  componentWillUnmount(): void;
29
- render(): React.JSX.Element | null;
30
+ render(): string | number | bigint | boolean | React.JSX.Element | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | Iterable<React.ReactNode> | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | React.ReactPortal | null | undefined> | null;
30
31
  }
31
32
  export declare function AssistantMessageListErrorBoundary({ resetKey, children, }: {
32
33
  resetKey: string;
@@ -1,4 +1,5 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IconLoader2 } from "@tabler/icons-react";
2
3
  import React from "react";
3
4
  import { captureError } from "./analytics.js";
4
5
  export function assistantUiRecoverableRenderErrorKind(error) {
@@ -114,7 +115,7 @@ export class AssistantUiStaleIndexErrorBoundary extends React.Component {
114
115
  this.state.recovery.retryCount > MAX_ASSISTANT_UI_RECOVERABLE_RETRIES) {
115
116
  throw this.state.error;
116
117
  }
117
- return null;
118
+ return this.props.fallback ?? null;
118
119
  }
119
120
  const fragmentKey = this.props.remountOnResetKey === false
120
121
  ? String(this.state.retryToken)
@@ -123,5 +124,8 @@ export class AssistantUiStaleIndexErrorBoundary extends React.Component {
123
124
  }
124
125
  }
125
126
  export function AssistantMessageListErrorBoundary({ resetKey, children, }) {
126
- return (_jsx(AssistantUiStaleIndexErrorBoundary, { resetKey: resetKey, remountOnResetKey: false, componentName: "AssistantMessageList", children: children }));
127
+ return (_jsx(AssistantUiStaleIndexErrorBoundary, { resetKey: resetKey, remountOnResetKey: false, componentName: "AssistantMessageList", fallback: _jsx(AssistantUiRecoverableRenderFallback, {}), children: children }));
128
+ }
129
+ function AssistantUiRecoverableRenderFallback() {
130
+ return (_jsxs("div", { "aria-label": "Updating chat", className: "flex min-h-8 items-center justify-center text-muted-foreground", role: "status", children: [_jsx(IconLoader2, { className: "size-3.5 animate-spin", "aria-hidden": "true" }), _jsx("span", { className: "sr-only", children: "Updating chat..." })] }));
127
131
  }
@@ -4,7 +4,7 @@ import { IconArrowRight, IconBrandGithub, IconCheck, IconExternalLink, IconInfoC
4
4
  import React, { useMemo, useState } from "react";
5
5
  import { appPath } from "../api-path.js";
6
6
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
7
- import { buildMcpOAuthStartUrl, filterMcpIntegrations, getDefaultMcpIntegrations, navigateToMcpOAuthStart, } from "../resources/mcp-integration-catalog.js";
7
+ import { buildMcpOAuthStartUrl, filterMcpIntegrations, getDefaultMcpIntegrations, navigateToMcpOAuthStart, shouldOfferMcpIntegrationOrganizationScope, } from "../resources/mcp-integration-catalog.js";
8
8
  import { McpIntegrationDialog } from "../resources/McpIntegrationDialog.js";
9
9
  import { formatMcpServerError, useCreateMcpServer, useMcpServers, } from "../resources/use-mcp-servers.js";
10
10
  import { useBuilderConnectFlow } from "../settings/useBuilderStatus.js";
@@ -112,6 +112,10 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
112
112
  connectingIntegrationId === integration.id) {
113
113
  return;
114
114
  }
115
+ if (shouldOfferMcpIntegrationOrganizationScope(integration, hasOrg, canCreateOrgMcp)) {
116
+ setIntegrationDialogId(integration.id);
117
+ return;
118
+ }
115
119
  if (integration.authMode === "none" &&
116
120
  integration.connectionMode === "direct") {
117
121
  setConnectingIntegrationId(integration.id);
@@ -165,7 +169,7 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
165
169
  return (_jsx(OnboardingShell, { profile: profile, screen: "intro", children: _jsxs("div", { className: "mx-auto flex w-full max-w-lg flex-col items-center text-center", children: [_jsxs("h1", { className: "text-3xl font-semibold tracking-[-0.05em] sm:text-4xl", children: ["Free forever.", _jsx("br", {}), _jsx("span", { className: "text-primary", children: "Open source for life." })] }), _jsxs("div", { className: "mt-7 grid w-full gap-2 text-left sm:grid-cols-3", children: [_jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Fully customizable" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Change the UI, code, and behavior." })] }), _jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Bring your own keys" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Use your own providers and accounts." })] }), _jsxs("div", { className: "rounded-lg border border-border bg-card px-3 py-3", children: [_jsx("p", { className: "text-xs font-medium", children: "Build your own" }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: "Mix and match toolkit pieces in your own apps." })] })] }), _jsxs("button", { type: "button", className: cn(primaryButtonClass, "mt-6"), onClick: () => setScreen("choice"), children: ["Continue", _jsx(IconArrowRight, { size: 15 })] }), _jsxs("a", { href: "https://github.com/builderio/agent-native", target: "_blank", rel: "noreferrer", className: "mt-3 inline-flex items-center gap-1.5 text-xs text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx(IconBrandGithub, { size: 14 }), _jsx("span", { children: "View source" }), _jsx(IconExternalLink, { size: 13 })] })] }) }));
166
170
  }
167
171
  if (screen === "choice") {
168
- return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-4", children: [_jsx("h1", { className: "text-center text-xl font-semibold tracking-[-0.04em] sm:text-2xl", children: "Choose your setup." }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [_jsxs("section", { className: "rounded-xl border border-primary/50 bg-primary/[0.06] p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold", children: "Connect Builder.io free credits" }), _jsxs("p", { className: "mt-1 max-w-xs text-xs leading-5 text-muted-foreground", children: ["One click connects", " ", _jsx("a", { href: "https://www.builder.io/", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: "Builder.io free credits" }), " ", "with the services this app needs."] })] }), _jsx(IconArrowRight, { className: "mt-0.5 text-primary", size: 17 })] }), _jsxs("div", { className: "mt-5 border-t border-primary/15 pt-3", children: [_jsx("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Included with Builder.io free credits" }), _jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-[11px]", children: [builderCapabilities.map((capability, index) => (_jsxs(React.Fragment, { children: [index > 0 && (_jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" })), _jsx("span", { children: capability.label })] }, capability.id))), _jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "text-primary underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": `See ${BUILDER_MORE_SERVICES.length} more services included with Builder.io free credits`, children: ["+", BUILDER_MORE_SERVICES.length, " more"] }) }), _jsxs(TooltipContent, { side: "top", className: "max-w-sm text-xs", children: [_jsx("p", { className: "font-medium", children: "Also included with Builder.io free credits" }), _jsx("p", { className: "mt-1 leading-5", children: BUILDER_MORE_SERVICES.join(" · ") })] })] })] })] }), _jsxs("button", { type: "button", "data-testid": "first-run-connect-builder", className: cn(primaryButtonClass, "mt-5 w-full"), onClick: handleBuilder, children: ["Connect Builder.io free credits", _jsx(IconArrowRight, { size: 15 })] })] }), _jsxs("div", { role: "button", tabIndex: 0, "aria-label": "Use my own keys", "data-testid": "first-run-use-own-keys", className: "rounded-xl border border-border bg-card p-4 text-left transition-colors hover:border-foreground/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => setScreen("manual"), onKeyDown: (event) => {
172
+ return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-3xl flex-col gap-4", children: [_jsx("h1", { className: "text-center text-xl font-semibold tracking-[-0.04em] sm:text-2xl", children: "Choose your setup." }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [_jsxs("section", { className: "rounded-xl border border-primary/50 bg-primary/[0.06] p-4 shadow-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold", children: "Connect Builder.io free credits" }), _jsxs("p", { className: "mt-1 max-w-xs text-xs leading-5 text-muted-foreground", children: ["One click connects", " ", _jsx("a", { href: "https://www.builder.io/", target: "_blank", rel: "noreferrer", className: "text-foreground underline decoration-border underline-offset-2 hover:decoration-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: "Builder.io free credits" }), " ", "with the services this app needs."] })] }), _jsx(IconArrowRight, { className: "mt-0.5 text-primary", size: 17 })] }), _jsxs("div", { className: "mt-5 border-t border-primary/15 pt-3", children: [_jsx("p", { className: "text-[11px] font-medium text-muted-foreground", children: "Included with Builder.io free credits" }), _jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-x-1.5 gap-y-1 text-[11px]", children: [builderCapabilities.map((capability, index) => (_jsxs(React.Fragment, { children: [index > 0 && (_jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" })), _jsxs("span", { className: "inline-flex items-center gap-0.5", children: [_jsx("span", { children: capability.label }), capability.id === "design-system-intelligence" && (_jsx(CapabilityInfoButton, { capability: capability, ariaLabel: `About ${capability.label}` }))] })] }, capability.id))), _jsx("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u00B7" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "text-primary underline-offset-2 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": `See ${BUILDER_MORE_SERVICES.length} more services included with Builder.io free credits`, children: ["+", BUILDER_MORE_SERVICES.length, " more"] }) }), _jsxs(TooltipContent, { side: "top", className: "max-w-sm text-xs", children: [_jsx("p", { className: "font-medium", children: "Also included with Builder.io free credits" }), _jsx("p", { className: "mt-1 leading-5", children: BUILDER_MORE_SERVICES.join(" · ") })] })] })] })] }), _jsxs("button", { type: "button", "data-testid": "first-run-connect-builder", className: cn(primaryButtonClass, "mt-5 w-full"), onClick: handleBuilder, children: ["Connect Builder.io free credits", _jsx(IconArrowRight, { size: 15 })] })] }), _jsxs("div", { role: "button", tabIndex: 0, "aria-label": "Use my own keys", "data-testid": "first-run-use-own-keys", className: "rounded-xl border border-border bg-card p-4 text-left transition-colors hover:border-foreground/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: () => setScreen("manual"), onKeyDown: (event) => {
169
173
  if (event.key !== "Enter" && event.key !== " ")
170
174
  return;
171
175
  event.preventDefault();
@@ -179,7 +183,7 @@ export function FirstRunOnboarding({ skipIntegrations = shouldSkipFirstRunIntegr
179
183
  return (_jsxs(OnboardingShell, { profile: profile, screen: "tools", footer: _jsxs("div", { "data-testid": "onboarding-tools-footer", className: "mx-auto flex w-full max-w-3xl flex-wrap items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: secondaryButtonClass, onClick: handleFinish, children: "Skip for now" }), _jsxs("button", { type: "button", className: primaryButtonClass, onClick: handleFinish, children: ["Continue", _jsx(IconArrowRight, { size: 15 })] })] }), children: [_jsxs("div", { className: "mx-auto flex w-full max-w-4xl flex-col gap-5", children: [_jsxs("div", { className: "text-center", children: [_jsx("div", { className: "mx-auto flex size-11 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: _jsx(IconPlugConnected, { size: 22 }) }), _jsx("h1", { className: "mt-5 text-2xl font-semibold tracking-[-0.05em] sm:text-3xl", children: "This app is an agent." }), _jsx("p", { className: "mt-3 text-sm leading-6 text-muted-foreground", children: "Search the catalog and connect what you need. The onboarding stays open while you add integrations." })] }), _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-3 border-b border-border pb-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "Agent integrations" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: [mcpIntegrations.length, " of ", mcpCatalog.length] })] }), _jsxs("label", { className: "relative", children: [_jsx(IconSearch, { className: "pointer-events-none absolute start-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }), _jsx("input", { value: integrationQuery, onChange: (event) => setIntegrationQuery(event.target.value), className: "h-9 w-full rounded-md border border-border bg-background pe-3 ps-8 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: "Search integrations", "aria-label": "Search integrations" })] }), connectError && (_jsx("p", { className: "text-xs leading-5 text-destructive", children: connectError }))] }), _jsx("div", { children: mcpIntegrations.length > 0 ? (_jsx("div", { className: "grid gap-x-8 sm:grid-cols-2", children: mcpIntegrations.map((integration) => (_jsx(McpIntegrationCard, { integration: integration, connected: connectedUrls.has(compareUrl(integration.url)), busy: connectingIntegrationId === integration.id, onConnect: connectIntegration }, integration.id))) })) : (_jsx("div", { className: "border-y border-dashed border-border px-4 py-8 text-center text-xs text-muted-foreground", children: "No integrations match." })) })] })] }), integrationDialogId && (_jsx(McpIntegrationDialog, { open: true, onOpenChange: (open) => {
180
184
  if (!open)
181
185
  setIntegrationDialogId(null);
182
- }, initialIntegrationId: integrationDialogId, defaultScope: canCreateOrgMcp ? "org" : "user", canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrg, onCreateMcpServer: createMcpServer.mutateAsync }))] }));
186
+ }, initialIntegrationId: integrationDialogId, defaultScope: "user", canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrg, onCreateMcpServer: createMcpServer.mutateAsync }))] }));
183
187
  }
184
188
  if (screen === "connecting") {
185
189
  return (_jsx(OnboardingShell, { profile: profile, screen: "choice", children: _jsxs("div", { className: "mx-auto flex w-full max-w-md flex-col items-center text-center", children: [_jsx("div", { className: "flex size-10 items-center justify-center rounded-full bg-primary/10 text-primary", children: _jsx(IconLoader2, { className: "animate-spin", size: 19 }) }), _jsx("h1", { className: "mt-5 text-xl font-semibold tracking-[-0.04em]", children: "Connecting Builder.io free credits" }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: "Finish the one-click connection in the new window." }), _jsxs("div", { className: "mt-7 w-full rounded-xl border border-border bg-card p-4 text-left", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(Skeleton, { className: "h-3 w-28" }), _jsx(Skeleton, { className: "h-5 w-16 rounded-full" })] }), _jsx(Skeleton, { className: "mt-4 h-8 w-full" }), _jsxs("div", { className: "mt-3 grid grid-cols-3 gap-2", children: [_jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" }), _jsx(Skeleton, { className: "h-7 w-full" })] })] }), connectFlow.error && (_jsxs("div", { className: "mt-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-xs text-destructive", children: connectFlow.error }), _jsx("button", { type: "button", className: secondaryButtonClass, onClick: () => setScreen("choice"), children: "Try again" })] }))] }) }));
@@ -231,7 +235,10 @@ function McpIntegrationCard({ integration, connected, busy, onConnect, }) {
231
235
  } })] }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h3", { className: "truncate text-sm font-medium text-foreground", children: integration.name }), connected ? (_jsx("span", { className: "rounded-full border border-border bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: "Connected" })) : null] }), _jsx("p", { className: "mt-1 line-clamp-2 text-[11px] leading-4 text-muted-foreground", children: integration.description })] })] }), _jsxs("button", { type: "button", onClick: () => onConnect(integration), disabled: connected || busy, "aria-label": `${actionLabel} ${integration.name}`, className: "inline-flex min-h-8 shrink-0 items-center justify-center gap-1.5 rounded-md border border-border bg-background px-3 text-[11px] font-medium text-foreground transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50", children: [busy ? _jsx(IconLoader2, { className: "animate-spin", size: 13 }) : null, connected ? "Connected" : actionLabel] })] }));
232
236
  }
233
237
  function CapabilityRow({ capability, compact, }) {
234
- return (_jsxs("div", { className: cn("flex items-start justify-between gap-3", compact ? "py-2" : "py-3"), children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: cn("font-medium", compact ? "text-[11px]" : "text-sm"), children: capability.label }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": `Why ${capability.label} is needed`, className: "inline-flex size-4 items-center justify-center rounded-full text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(IconInfoCircle, { size: 13 }) }) }), _jsx(TooltipContent, { side: "top", className: "max-w-xs text-xs", children: capability.why })] })] }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: capability.keySummary })] }), _jsx("span", { className: cn("shrink-0 text-[10px] uppercase tracking-[0.08em]", capability.required ? "text-primary" : "text-muted-foreground"), children: capability.required ? "Required" : "Optional" })] }));
238
+ return (_jsxs("div", { className: cn("flex items-start justify-between gap-3", compact ? "py-2" : "py-3"), children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: cn("font-medium", compact ? "text-[11px]" : "text-sm"), children: capability.label }), _jsx(CapabilityInfoButton, { capability: capability, ariaLabel: `Why ${capability.label} is needed` })] }), _jsx("p", { className: "mt-1 text-[11px] leading-4 text-muted-foreground", children: capability.keySummary })] }), _jsx("span", { className: cn("shrink-0 text-[10px] uppercase tracking-[0.08em]", capability.required ? "text-primary" : "text-muted-foreground"), children: capability.required ? "Required" : "Optional" })] }));
239
+ }
240
+ function CapabilityInfoButton({ capability, ariaLabel, }) {
241
+ return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": ariaLabel, className: "inline-flex size-4 items-center justify-center rounded-full text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: _jsx(IconInfoCircle, { size: 13 }) }) }), _jsx(TooltipContent, { side: "top", className: "max-w-xs text-xs", children: capability.why })] }));
235
242
  }
236
243
  const primaryButtonClass = "inline-flex min-h-9 items-center justify-center gap-2 rounded-lg bg-primary px-4 text-xs font-medium text-primary-foreground shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
237
244
  const secondaryButtonClass = "inline-flex min-h-9 items-center justify-center gap-2 rounded-lg border border-border bg-background px-4 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
@@ -25,7 +25,7 @@ function ErrorText({ error }) {
25
25
  return (_jsx("p", { className: "text-xs text-destructive", children: error instanceof Error ? error.message : String(error) }));
26
26
  }
27
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] })] }));
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 [&_svg]:!size-3", 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
29
  }
30
30
  function OrganizationDescription({ children, help, docsUrl, }) {
31
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] }));
@@ -113,5 +113,5 @@ function ResolvedSessionGate({ children, fallback, redirect = true, signedOut, }
113
113
  return _jsx(_Fragment, { children: children });
114
114
  }
115
115
  function SessionUnavailableNotice({ retry }) {
116
- return (_jsxs("div", { className: "flex h-screen w-full flex-col items-center justify-center gap-4 px-6 text-center", children: [_jsx("p", { className: "max-w-md text-sm text-muted-foreground", children: "We couldn't reach the server to confirm you're signed in. This is usually temporary." }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { type: "button", onClick: retry, className: "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground", children: "Try again" }), _jsx("button", { type: "button", onClick: () => window.location.reload(), className: "rounded-md border border-border px-3 py-1.5 text-sm font-medium", children: "Reload page" })] })] }));
116
+ return (_jsxs("div", { className: "flex h-screen w-full flex-col items-center justify-center gap-4 px-6 text-center", children: [_jsx("p", { className: "max-w-md text-sm text-muted-foreground", children: "We couldn't reach the server to confirm your session. This is usually temporary." }), _jsx("p", { className: "max-w-md text-xs text-muted-foreground", children: "Retry connection checks your session here. Reload page starts the app over." }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { type: "button", onClick: retry, className: "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground", children: "Retry connection" }), _jsx("button", { type: "button", onClick: () => window.location.reload(), className: "rounded-md border border-border px-3 py-1.5 text-sm font-medium", children: "Reload page" })] })] }));
117
117
  }
@@ -7,4 +7,5 @@ export interface McpConnectionSuggestionProps {
7
7
  integrations?: DefaultMcpIntegration[];
8
8
  }
9
9
  export declare function findMcpConnectionSuggestionIntegration({ text, contextText, variant, integrations, }: McpConnectionSuggestionProps): DefaultMcpIntegration | null;
10
+ export declare function shouldRenderMcpIntegrationFallback(logoUrl: string, logoLoadFailed: boolean): boolean;
10
11
  export declare function McpConnectionSuggestion({ text, contextText, variant, integrations: integrationOptions, }: McpConnectionSuggestionProps): import("react").JSX.Element | null;
@@ -5,12 +5,15 @@ import { agentNativePath } from "../api-path.js";
5
5
  import { openAgentSettings } from "../CommandMenu.js";
6
6
  import { useT } from "../i18n.js";
7
7
  import { clearMcpConnectionResume, notifyMcpConnectionComplete, saveMcpConnectionResume, } from "./mcp-connection-resume.js";
8
- import { buildMcpOAuthStartUrl, findMcpIntegrationForText, getMcpIntegrationApiFallback, getDefaultMcpIntegrations, isMcpConnectionFailureText, navigateToMcpOAuthStart, } from "./mcp-integration-catalog.js";
8
+ import { buildMcpOAuthStartUrl, findMcpIntegrationForText, getMcpIntegrationApiFallback, getDefaultMcpIntegrations, isMcpConnectionFailureText, navigateToMcpOAuthStart, shouldOfferMcpIntegrationOrganizationScope, } from "./mcp-integration-catalog.js";
9
9
  import { McpIntegrationDialog } from "./McpIntegrationDialog.js";
10
10
  import { useCreateMcpServer, useMcpServers, } from "./use-mcp-servers.js";
11
11
  export function findMcpConnectionSuggestionIntegration({ text, contextText = "", variant = "composer", integrations = getDefaultMcpIntegrations(), }) {
12
12
  return findMcpIntegrationForText(variant === "response" ? contextText : text, integrations);
13
13
  }
14
+ export function shouldRenderMcpIntegrationFallback(logoUrl, logoLoadFailed) {
15
+ return !logoUrl || logoLoadFailed;
16
+ }
14
17
  function compareUrl(value) {
15
18
  try {
16
19
  const url = new URL(value.trim());
@@ -33,8 +36,9 @@ function returnUrl() {
33
36
  }
34
37
  function canStartOAuth(integration) {
35
38
  return (integration.authMode === "oauth" &&
36
- integration.connectionMode === "oauth" &&
37
- integration.availability === "ready");
39
+ ((integration.connectionMode === "oauth" &&
40
+ integration.availability === "ready") ||
41
+ integration.managedOAuth === true));
38
42
  }
39
43
  function hasApiFallback(apiFallback) {
40
44
  return Boolean(apiFallback);
@@ -47,6 +51,7 @@ export function McpConnectionSuggestion({ text, contextText = "", variant = "com
47
51
  const [dismissedId, setDismissedId] = useState(null);
48
52
  const [connecting, setConnecting] = useState(false);
49
53
  const [error, setError] = useState(null);
54
+ const [logoLoadFailed, setLogoLoadFailed] = useState(false);
50
55
  const integrations = useMemo(() => integrationOptions ?? getDefaultMcpIntegrations(), [integrationOptions]);
51
56
  const integration = useMemo(() => findMcpConnectionSuggestionIntegration({
52
57
  text,
@@ -62,6 +67,12 @@ export function McpConnectionSuggestion({ text, contextText = "", variant = "com
62
67
  ...(mcpServersQuery.data?.org ?? []),
63
68
  ], [mcpServersQuery.data]);
64
69
  const connected = integration ? isConnected(integration, servers) : false;
70
+ const hasOrg = Boolean(mcpServersQuery.data?.orgId);
71
+ const canCreateOrgMcp = Boolean(hasOrg &&
72
+ (mcpServersQuery.data?.role === "owner" ||
73
+ mcpServersQuery.data?.role === "admin"));
74
+ const shouldChooseScope = Boolean(integration &&
75
+ shouldOfferMcpIntegrationOrganizationScope(integration, hasOrg, canCreateOrgMcp));
65
76
  const shouldSuggest = mcpServersQuery.isSuccess &&
66
77
  integration &&
67
78
  !connected &&
@@ -70,7 +81,8 @@ export function McpConnectionSuggestion({ text, contextText = "", variant = "com
70
81
  useEffect(() => {
71
82
  setError(null);
72
83
  setConnecting(false);
73
- }, [integration?.id, variant]);
84
+ setLogoLoadFailed(false);
85
+ }, [integration?.id, integration?.logoUrl, variant]);
74
86
  if (!shouldSuggest)
75
87
  return null;
76
88
  const connect = async () => {
@@ -81,6 +93,11 @@ export function McpConnectionSuggestion({ text, contextText = "", variant = "com
81
93
  openAgentSettings(`secrets:${apiFallback.secretKey}`);
82
94
  return;
83
95
  }
96
+ if (shouldChooseScope) {
97
+ saveMcpConnectionResume(variant === "response" ? contextText : text);
98
+ setDialogOpen(true);
99
+ return;
100
+ }
84
101
  if (canStartOAuth(integration)) {
85
102
  setConnecting(true);
86
103
  saveMcpConnectionResume(variant === "response" ? contextText : text);
@@ -128,20 +145,20 @@ export function McpConnectionSuggestion({ text, contextText = "", variant = "com
128
145
  ? t("mcpIntegrations.viewSetup")
129
146
  : t("mcpIntegrations.connect");
130
147
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: variant === "response"
131
- ? "mt-3 flex max-w-[520px] items-center gap-2 rounded-lg border border-primary/20 bg-primary/5 px-3 py-2 text-[12px]"
132
- : "mx-auto mb-2 flex w-[min(calc(100%_-_1.5rem),680px)] items-center gap-2 rounded-lg border border-primary/20 bg-primary/5 px-3 py-2 text-[12px]", "data-mcp-connection-suggestion": integration.id, children: [_jsxs("div", { className: "relative flex h-6 w-6 shrink-0 items-center justify-center overflow-hidden rounded-md border border-border bg-background text-[10px] font-semibold text-muted-foreground", children: [_jsx("span", { "aria-hidden": "true", children: integration.name.slice(0, 1) }), integration.logoUrl && (_jsx("img", { src: integration.logoUrl, alt: "", className: "absolute h-5 w-5 object-contain", onError: (event) => {
133
- event.currentTarget.hidden = true;
134
- } }))] }), _jsx("span", { className: "min-w-0 flex-1 leading-snug text-foreground", children: t(hasApiFallback(apiFallback)
148
+ ? "agent-mcp-connection-suggestion agent-mcp-connection-suggestion--response mt-3 flex max-w-[520px] items-center gap-2 rounded-lg border border-primary/20 bg-primary/5 px-3 py-2 text-[12px]"
149
+ : "agent-mcp-connection-suggestion agent-mcp-connection-suggestion--composer mx-auto mb-2 flex w-[min(calc(100%_-_1.5rem),684px)] items-center gap-2 rounded-lg border border-primary/20 bg-primary/5 px-3 py-2 text-[12px]", "data-mcp-connection-suggestion": integration.id, "data-mcp-connection-suggestion-variant": variant, children: [_jsxs("div", { className: "relative flex h-6 w-6 shrink-0 items-center justify-center overflow-hidden rounded-md border border-border bg-background text-[10px] font-semibold text-muted-foreground", children: [shouldRenderMcpIntegrationFallback(integration.logoUrl, logoLoadFailed) ? (_jsx("span", { "aria-hidden": "true", children: integration.name.slice(0, 1) })) : null, integration.logoUrl && (_jsx("img", { src: integration.logoUrl, alt: "", className: `absolute h-5 w-5 object-contain${logoLoadFailed ? " hidden" : ""}`, onError: () => setLogoLoadFailed(true) }))] }), _jsx("span", { className: "min-w-0 flex-1 leading-snug text-foreground", children: t(hasApiFallback(apiFallback)
135
150
  ? "mcpIntegrations.connectSuggestionWithApiToken"
136
151
  : "mcpIntegrations.connectSuggestion", { name: integration.name }) }), _jsxs("button", { type: "button", onClick: () => void connect(), disabled: connecting, "aria-busy": connecting, className: "inline-flex shrink-0 items-center gap-1 rounded-md bg-primary px-2.5 py-1.5 text-[11px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-60", children: [connecting && _jsx(IconLoader2, { className: "h-3 w-3 animate-spin" }), !connecting &&
137
152
  canStartOAuth(integration) &&
138
153
  !hasApiFallback(apiFallback) && (_jsx(IconPlugConnected, { className: "h-3 w-3" })), !connecting && hasApiFallback(apiFallback) && (_jsx(IconPlugConnected, { className: "h-3 w-3" })), actionLabel, !connecting &&
139
154
  !canStartOAuth(integration) &&
140
- !hasApiFallback(apiFallback) && (_jsx(IconArrowUpRight, { className: "h-3 w-3" }))] }), _jsx("button", { type: "button", onClick: () => setDismissedId(integration.id), className: "inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-background hover:text-foreground", "aria-label": t("mcpIntegrations.dismissSuggestion"), children: _jsx(IconX, { className: "h-3.5 w-3.5" }) })] }), error && (_jsx("div", { className: "mx-auto mb-2 w-[min(100%,680px)] text-[11px] text-destructive", children: error })), _jsx(McpIntegrationDialog, { open: dialogOpen, onOpenChange: (open) => {
155
+ !hasApiFallback(apiFallback) && (_jsx(IconArrowUpRight, { className: "h-3 w-3" }))] }), _jsx("button", { type: "button", onClick: () => setDismissedId(integration.id), className: "inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-background hover:text-foreground", "aria-label": t("mcpIntegrations.dismissSuggestion"), children: _jsx(IconX, { className: "h-3.5 w-3.5" }) })] }), error && (_jsx("div", { className: variant === "response"
156
+ ? "agent-mcp-connection-suggestion-error agent-mcp-connection-suggestion-error--response mt-1 max-w-[520px] text-[11px] text-destructive"
157
+ : "agent-mcp-connection-suggestion-error agent-mcp-connection-suggestion-error--composer mx-auto mb-2 w-[min(calc(100%_-_1.5rem),684px)] text-[11px] text-destructive", children: error })), _jsx(McpIntegrationDialog, { open: dialogOpen, onOpenChange: (open) => {
141
158
  setDialogOpen(open);
142
159
  if (!open)
143
160
  clearMcpConnectionResume();
144
- }, initialIntegrationId: integration.id, defaultScope: "user", canCreateOrgMcp: false, hasOrg: Boolean(mcpServersQuery.data?.orgId), onCreateMcpServer: (args) => createMcpServer.mutateAsync(args), onCreated: () => {
161
+ }, initialIntegrationId: integration.id, defaultScope: "user", canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrg, onCreateMcpServer: (args) => createMcpServer.mutateAsync(args), onCreated: () => {
145
162
  setDismissedId(integration.id);
146
163
  saveMcpConnectionResume(variant === "response" ? contextText : text);
147
164
  notifyMcpConnectionComplete();
@@ -7,7 +7,7 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, }
7
7
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
8
8
  import { useT } from "../i18n.js";
9
9
  import { cn } from "../utils.js";
10
- import { buildMcpOAuthStartUrl, createMcpIntegrationFormDefaults, filterMcpIntegrations, getMcpIntegrationApiFallback, getDefaultMcpIntegrations, isCustomMcpIntegrationEnabled, navigateToMcpOAuthStart, resolveMcpIntegrationScope, shouldOfferMcpOrganizationScope, } from "./mcp-integration-catalog.js";
10
+ import { buildMcpOAuthStartUrl, createMcpIntegrationFormDefaults, filterMcpIntegrations, getMcpIntegrationApiFallback, getDefaultMcpIntegrations, isCustomMcpIntegrationEnabled, navigateToMcpOAuthStart, resolveMcpIntegrationScope, shouldOfferMcpIntegrationOrganizationScope, shouldOfferMcpOrganizationScope, } from "./mcp-integration-catalog.js";
11
11
  import { formatMcpServerError, getMcpUrlValidationError, testMcpServerUrl, useMcpServers, } from "./use-mcp-servers.js";
12
12
  function IntegrationLogo({ name, logoUrl }) {
13
13
  const [loaded, setLoaded] = useState(false);
@@ -51,6 +51,17 @@ function compareUrl(value) {
51
51
  return value.trim().replace(/\/+$/, "");
52
52
  }
53
53
  }
54
+ function requiresMcpIntegrationSetup(integration) {
55
+ return Boolean(!integration.managedOAuth &&
56
+ (integration.connectionMode === "manual" ||
57
+ integration.availability === "provider-setup" ||
58
+ integration.availability === "client-restricted"));
59
+ }
60
+ function resolveIntegrationScope(integration, defaultScope, hasOrg, canCreateOrgMcp) {
61
+ return resolveMcpIntegrationScope(defaultScope, hasOrg, canCreateOrgMcp, !integration ||
62
+ (integration.supportsOrganizationScope === true &&
63
+ integration.managedOAuth !== true));
64
+ }
54
65
  export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId = null, defaultScope, canCreateOrgMcp, hasOrg, onCreateMcpServer, onCreated, integrations, }) {
55
66
  const t = useT();
56
67
  const [mode, setMode] = useState("catalog");
@@ -84,10 +95,7 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
84
95
  .map((server) => compareUrl(server.url)));
85
96
  }, [mcpServersQuery.data]);
86
97
  const filteredIntegrations = useMemo(() => filterMcpIntegrations(query, defaultIntegrations), [defaultIntegrations, query]);
87
- const selectedRequiresSetup = Boolean(selected &&
88
- (selected.connectionMode === "manual" ||
89
- selected.availability === "provider-setup" ||
90
- selected.availability === "client-restricted"));
98
+ const selectedRequiresSetup = Boolean(selected && requiresMcpIntegrationSetup(selected));
91
99
  useEffect(() => {
92
100
  if (!open)
93
101
  return;
@@ -98,7 +106,7 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
98
106
  setMode(initialIntegration || !showCatalog ? "form" : "catalog");
99
107
  setQuery("");
100
108
  setSelected(initialIntegration ?? null);
101
- setScope(safeDefaultScope);
109
+ setScope(resolveIntegrationScope(initialIntegration, defaultScope, hasOrg, canCreateOrgMcp));
102
110
  setName(initialDefaults.name);
103
111
  setUrl(initialDefaults.url);
104
112
  setDescription(initialDefaults.description);
@@ -110,6 +118,9 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
110
118
  }, [
111
119
  defaultIntegrations,
112
120
  initialIntegrationId,
121
+ canCreateOrgMcp,
122
+ defaultScope,
123
+ hasOrg,
113
124
  open,
114
125
  safeDefaultScope,
115
126
  showCatalog,
@@ -127,7 +138,7 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
127
138
  const openForm = (integration) => {
128
139
  const defaults = createMcpIntegrationFormDefaults(integration);
129
140
  setSelected(integration ?? null);
130
- setScope(safeDefaultScope);
141
+ setScope(resolveIntegrationScope(integration, defaultScope, hasOrg, canCreateOrgMcp));
131
142
  setName(defaults.name);
132
143
  setUrl(defaults.url);
133
144
  setDescription(defaults.description);
@@ -154,7 +165,7 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
154
165
  name: args.name,
155
166
  url: args.url,
156
167
  description: args.description,
157
- scope,
168
+ scope: options?.scope ?? scope,
158
169
  returnUrl,
159
170
  })));
160
171
  };
@@ -162,7 +173,13 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
162
173
  name: integration.name,
163
174
  url: integration.url,
164
175
  description: integration.description,
165
- }, options);
176
+ }, {
177
+ ...options,
178
+ scope: integration.supportsOrganizationScope === true &&
179
+ integration.managedOAuth !== true
180
+ ? scope
181
+ : "user",
182
+ });
166
183
  const connectCustomWithOAuth = () => {
167
184
  if (!name.trim()) {
168
185
  setError(t("mcpIntegrations.serverNameRequired"));
@@ -212,10 +229,12 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
212
229
  });
213
230
  };
214
231
  const quickConnect = (integration) => {
215
- if (integration.connectionMode === "manual" ||
216
- integration.availability === "provider-setup") {
232
+ if (shouldOfferMcpIntegrationOrganizationScope(integration, hasOrg, canCreateOrgMcp)) {
233
+ openForm(integration);
217
234
  return;
218
235
  }
236
+ if (requiresMcpIntegrationSetup(integration))
237
+ return;
219
238
  if (integration.authMode === "oauth") {
220
239
  connectWithOAuth(integration, { quickId: integration.id });
221
240
  return;
@@ -225,7 +244,7 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
225
244
  return;
226
245
  }
227
246
  void createServer({
228
- scope: safeDefaultScope,
247
+ scope: resolveIntegrationScope(integration, defaultScope, hasOrg, canCreateOrgMcp),
229
248
  name: integration.name,
230
249
  url: integration.url,
231
250
  description: integration.description,
@@ -263,13 +282,20 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
263
282
  }
264
283
  };
265
284
  const renderScopeSelector = () => {
266
- if (!shouldOfferMcpOrganizationScope(hasOrg, canCreateOrgMcp))
285
+ if (selected?.managedOAuth)
286
+ return null;
287
+ const canSelectScope = selected
288
+ ? shouldOfferMcpIntegrationOrganizationScope(selected, hasOrg, canCreateOrgMcp)
289
+ : shouldOfferMcpOrganizationScope(hasOrg, canCreateOrgMcp);
290
+ if (!canSelectScope)
267
291
  return null;
268
- return (_jsxs("div", { className: "flex gap-1 rounded-md border border-border bg-background p-0.5", children: [_jsx("button", { type: "button", onClick: () => setScope("user"), className: cn("flex-1 rounded px-2 py-1.5 text-[11px] font-medium", scope === "user"
269
- ? "bg-accent text-foreground"
270
- : "text-muted-foreground hover:text-foreground"), children: t("mcpIntegrations.personal") }), _jsx("button", { type: "button", onClick: () => setScope("org"), className: cn("flex-1 rounded px-2 py-1.5 text-[11px] font-medium", scope === "org"
271
- ? "bg-accent text-foreground"
272
- : "text-muted-foreground hover:text-foreground"), children: t("mcpIntegrations.organization") })] }));
292
+ return (_jsxs("div", { className: "space-y-1.5", children: [_jsx("p", { className: "text-[11px] font-medium text-foreground", children: t("mcpIntegrations.scopeQuestion") }), _jsxs("div", { className: "flex gap-1 rounded-md border border-border bg-background p-0.5", children: [_jsx("button", { type: "button", onClick: () => setScope("user"), "aria-pressed": scope === "user", className: cn("flex-1 rounded px-2 py-1.5 text-[11px] font-medium", scope === "user"
293
+ ? "bg-accent text-foreground"
294
+ : "text-muted-foreground hover:text-foreground"), children: t("mcpIntegrations.personal") }), _jsx("button", { type: "button", onClick: () => setScope("org"), "aria-pressed": scope === "org", className: cn("flex-1 rounded px-2 py-1.5 text-[11px] font-medium", scope === "org"
295
+ ? "bg-accent text-foreground"
296
+ : "text-muted-foreground hover:text-foreground"), children: t("mcpIntegrations.sharedWithWorkspace") })] }), _jsx("p", { className: "text-[11px] leading-relaxed text-muted-foreground", children: t(scope === "user"
297
+ ? "mcpIntegrations.personalDescription"
298
+ : "mcpIntegrations.organizationDescription") })] }));
273
299
  };
274
300
  if (!showCatalog && !customIntegrationEnabled)
275
301
  return null;
@@ -279,9 +305,7 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
279
305
  const apiFallback = getMcpIntegrationApiFallback(integration);
280
306
  const connected = connectedUrls.has(compareUrl(integration.url));
281
307
  const requiresHeaders = integration.authMode === "headers";
282
- const setupOnly = integration.connectionMode === "manual" ||
283
- integration.availability === "provider-setup" ||
284
- integration.availability === "client-restricted";
308
+ const setupOnly = requiresMcpIntegrationSetup(integration);
285
309
  return (_jsxs("article", { className: "flex min-h-[128px] flex-col rounded-md border border-border bg-card p-4 transition-colors hover:border-border/80 hover:bg-accent/20", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(IntegrationLogo, { name: integration.name, logoUrl: integration.logoUrl }), _jsxs("div", { className: "min-w-0", children: [_jsx("h3", { className: "truncate text-[13px] font-semibold text-foreground", children: integration.name }), integration.availability !== "ready" && (_jsx("span", { className: "mt-0.5 inline-flex rounded-full border border-border/70 bg-muted/40 px-1.5 py-0.5 text-[9px] font-medium text-muted-foreground", children: integration.availability === "beta"
286
310
  ? t("mcpIntegrations.status.beta")
287
311
  : integration.availability ===
@@ -291,7 +315,7 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
291
315
  ? t("mcpIntegrations.status.verified")
292
316
  : integration.verification === "restricted"
293
317
  ? t("mcpIntegrations.status.restricted")
294
- : t("mcpIntegrations.status.preflightOnly") })] })] }), _jsx("p", { className: "mt-1 line-clamp-2 flex-1 text-[12px] leading-relaxed text-muted-foreground", children: t(integration.descriptionKey) }), _jsxs("div", { className: "mt-3 flex items-center gap-2", children: [connected ? (_jsx("button", { type: "button", disabled: true, className: "inline-flex h-8 flex-1 cursor-not-allowed items-center justify-center gap-1.5 rounded-md border border-border bg-muted px-2.5 text-[12px] font-medium text-muted-foreground opacity-70", children: t("mcpIntegrations.connected") })) : setupOnly ? (_jsxs(_Fragment, { children: [apiFallback && (_jsx("button", { type: "button", onClick: () => openAgentSettings(`secrets:${apiFallback.secretKey}`), className: "inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md bg-primary px-2.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90", children: t("mcpIntegrations.useApiToken") })), _jsxs("a", { href: integration.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[12px] font-medium text-foreground hover:bg-accent", children: [t("mcpIntegrations.viewSetup"), _jsx(IconExternalLink, { className: "h-3.5 w-3.5" })] })] })) : (_jsxs("button", { type: "button", onClick: () => quickConnect(integration), disabled: busy, "aria-busy": quickBusyId === integration.id, className: cn("inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md bg-primary px-2.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90", busy && "cursor-not-allowed opacity-70"), children: [quickBusyId === integration.id ? (_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" })) : null, integration.authMode === "oauth"
318
+ : t("mcpIntegrations.status.preflightOnly") })] })] }), _jsx("p", { className: "mt-1 line-clamp-2 flex-1 text-[12px] leading-relaxed text-muted-foreground", children: t(integration.descriptionKey) }), _jsxs("div", { className: "mt-3 flex items-center gap-2", children: [connected ? (_jsx("button", { type: "button", disabled: true, className: "inline-flex h-8 flex-1 cursor-not-allowed items-center justify-center gap-1.5 rounded-md border border-border bg-muted px-2.5 text-[12px] font-medium text-muted-foreground opacity-70", children: t("mcpIntegrations.connected") })) : setupOnly ? (_jsxs(_Fragment, { children: [apiFallback && (_jsx("button", { type: "button", onClick: () => openAgentSettings(`secrets:${apiFallback.secretKey}`), className: "inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md bg-primary px-2.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90", children: t("mcpIntegrations.useApiToken") })), _jsx("button", { type: "button", onClick: () => openForm(integration), className: "inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md border border-border bg-background px-2.5 text-[12px] font-medium text-foreground hover:bg-accent", children: t("mcpIntegrations.viewSetup") })] })) : (_jsxs("button", { type: "button", onClick: () => quickConnect(integration), disabled: busy, "aria-busy": quickBusyId === integration.id, className: cn("inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md bg-primary px-2.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90", busy && "cursor-not-allowed opacity-70"), children: [quickBusyId === integration.id ? (_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" })) : null, integration.authMode === "oauth"
295
319
  ? t("mcpIntegrations.connectWithOAuth")
296
320
  : requiresHeaders
297
321
  ? t("mcpIntegrations.configure")
@@ -304,29 +328,37 @@ export function McpIntegrationDialog({ open, onOpenChange, initialIntegrationId
304
328
  clearFeedback();
305
329
  setMode("catalog");
306
330
  }, className: cn("mb-1 inline-flex w-fit items-center gap-1 text-[11px] text-muted-foreground hover:text-foreground", !showCatalog && "hidden"), children: [_jsx(IconArrowLeft, { className: "h-3 w-3 rtl:-scale-x-100" }), t("mcpIntegrations.backToIntegrations")] }), _jsx(DialogTitle, { children: selected
307
- ? t("mcpIntegrations.configureTitle", {
308
- name: selected.name,
309
- })
331
+ ? selectedRequiresSetup
332
+ ? t("mcpIntegrations.setupTitle", {
333
+ name: selected.name,
334
+ })
335
+ : t("mcpIntegrations.configureTitle", {
336
+ name: selected.name,
337
+ })
310
338
  : t("mcpIntegrations.customTitle") }), _jsx(DialogDescription, { children: selected
311
- ? selected.authMode === "none"
312
- ? t("mcpIntegrations.presetNoAuthDescription")
313
- : t("mcpIntegrations.presetAuthDescription")
314
- : t("mcpIntegrations.customDescription") })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-7 py-5", children: _jsxs("div", { className: "space-y-3", children: [renderScopeSelector(), selected?.setupNoteKey && (_jsx("div", { className: "rounded-md border border-border bg-muted/40 px-3 py-2 text-[11px] leading-relaxed text-muted-foreground", children: t(selected.setupNoteKey) })), selected?.authMode === "oauth" && (_jsx("div", { className: "rounded-md border border-blue-500/20 bg-blue-500/5 px-3 py-2 text-[11px] leading-relaxed text-blue-700 dark:text-blue-300", children: t("mcpIntegrations.oauthNotice") })), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.serverName") }), _jsx("input", { ref: inputRef, value: name, onChange: (event) => {
315
- setName(event.target.value);
316
- clearFeedback();
317
- }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.serverNamePlaceholder") })] }), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.url") }), _jsx("input", { value: url, onChange: (event) => {
318
- setUrl(event.target.value);
319
- clearFeedback();
320
- }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.urlPlaceholder") })] }), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.fieldDescription") }), _jsx("input", { value: description, onChange: (event) => {
321
- setDescription(event.target.value);
322
- clearFeedback();
323
- }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.descriptionPlaceholder") })] }), selected?.authMode !== "oauth" && (_jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.headers") }), _jsx("textarea", { value: headersText, onChange: (event) => {
324
- setHeadersText(event.target.value);
325
- clearFeedback();
326
- }, rows: 3, className: "w-full resize-y rounded-md border border-border bg-background px-2.5 py-1.5 text-[12px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", style: {
327
- fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
328
- }, placeholder: selected?.headerPlaceholder ??
329
- t("mcpIntegrations.headersPlaceholder") })] })), selected?.docsUrl && (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 text-[11px] text-muted-foreground underline hover:text-foreground", children: [t("mcpIntegrations.openSetupDocs"), _jsx(IconExternalLink, { className: "h-3 w-3" })] })), testResult && (_jsxs("div", { className: cn("flex items-start gap-1 rounded-md px-3 py-2 text-[11px] leading-snug", testResult.ok
339
+ ? selectedRequiresSetup
340
+ ? t("mcpIntegrations.providerSetupFormDescription")
341
+ : selected.authMode === "none"
342
+ ? t("mcpIntegrations.presetNoAuthDescription")
343
+ : t("mcpIntegrations.presetAuthDescription")
344
+ : t("mcpIntegrations.customDescription") })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-7 py-5", children: _jsxs("div", { className: "space-y-3", children: [renderScopeSelector(), selected?.setupNoteKey && (_jsx("div", { className: "rounded-md border border-border bg-muted/40 px-3 py-2 text-[11px] leading-relaxed text-muted-foreground", children: t(selected.setupNoteKey) })), selectedRequiresSetup && selected && (_jsxs("div", { className: "rounded-md border border-border bg-muted/40 px-3 py-2 text-[11px] leading-relaxed", children: [_jsx("p", { className: "font-medium text-foreground", children: t("mcpIntegrations.providerSetupRequired") }), _jsx("p", { className: "mt-0.5 text-muted-foreground", children: t("mcpIntegrations.providerSetupDescription", {
345
+ name: selected.name,
346
+ }) })] })), !selectedRequiresSetup && (_jsxs(_Fragment, { children: [selected?.authMode === "oauth" && (_jsx("div", { className: "rounded-md border border-primary/20 bg-primary/5 px-3 py-2 text-[11px] leading-relaxed text-primary", children: t("mcpIntegrations.oauthNotice") })), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.serverName") }), _jsx("input", { ref: inputRef, value: name, onChange: (event) => {
347
+ setName(event.target.value);
348
+ clearFeedback();
349
+ }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.serverNamePlaceholder") })] }), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.url") }), _jsx("input", { value: url, onChange: (event) => {
350
+ setUrl(event.target.value);
351
+ clearFeedback();
352
+ }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.urlPlaceholder") })] }), _jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.fieldDescription") }), _jsx("input", { value: description, onChange: (event) => {
353
+ setDescription(event.target.value);
354
+ clearFeedback();
355
+ }, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", placeholder: t("mcpIntegrations.descriptionPlaceholder") })] }), selected?.authMode !== "oauth" && (_jsxs("label", { className: "block", children: [_jsx("span", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: t("mcpIntegrations.headers") }), _jsx("textarea", { value: headersText, onChange: (event) => {
356
+ setHeadersText(event.target.value);
357
+ clearFeedback();
358
+ }, rows: 3, className: "w-full resize-y rounded-md border border-border bg-background px-2.5 py-1.5 text-[12px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-ring", style: {
359
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
360
+ }, placeholder: selected?.headerPlaceholder ??
361
+ t("mcpIntegrations.headersPlaceholder") })] })), selected?.docsUrl && (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 text-[11px] text-muted-foreground underline hover:text-foreground", children: [t("mcpIntegrations.openSetupDocs"), _jsx(IconExternalLink, { className: "h-3 w-3" })] }))] })), testResult && (_jsxs("div", { className: cn("flex items-start gap-1 rounded-md px-3 py-2 text-[11px] leading-snug", testResult.ok
330
362
  ? "bg-green-500/5 text-green-600 dark:text-green-400"
331
- : "bg-red-500/5 text-red-600 dark:text-red-400"), children: [testResult.ok && (_jsx(IconCheck, { className: "mt-0.5 h-3 w-3 shrink-0" })), _jsx("span", { className: "min-w-0 break-words", children: testResult.message })] })), error && (_jsx("div", { className: "break-words rounded-md bg-red-500/5 px-3 py-2 text-[11px] leading-snug text-red-600 dark:text-red-400", children: error }))] }) }), _jsxs("div", { className: "flex shrink-0 items-center justify-between gap-2 border-t border-border px-7 py-4", children: [!selectedRequiresSetup && (_jsx("button", { type: "button", onClick: runTest, disabled: !url.trim() || busy, className: "rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40", children: t("mcpIntegrations.test") })), !selected ? (_jsxs("button", { type: "button", onClick: connectCustomWithOAuth, disabled: !name.trim() || !url.trim() || busy, "aria-busy": busy, className: "rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40", children: [busy && (_jsx(IconLoader2, { className: "me-1.5 inline h-3.5 w-3.5 animate-spin" })), t("mcpIntegrations.connectWithOAuth")] })) : null, selectedRequiresSetup ? (selected?.docsUrl ? (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "ms-auto inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90", children: [t("mcpIntegrations.viewSetup"), _jsx(IconExternalLink, { className: "h-3 w-3" })] })) : null) : selected?.authMode === "oauth" ? (_jsxs("button", { type: "button", onClick: () => connectWithOAuth(selected), disabled: !name.trim() || !url.trim() || busy, "aria-busy": busy, className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && _jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), t("mcpIntegrations.connectWithOAuth")] })) : (_jsxs("button", { type: "button", onClick: submitForm, disabled: !name.trim() || !url.trim() || busy, className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && _jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), t("mcpIntegrations.connect")] }))] })] })) }) }));
363
+ : "bg-red-500/5 text-red-600 dark:text-red-400"), children: [testResult.ok && (_jsx(IconCheck, { className: "mt-0.5 h-3 w-3 shrink-0" })), _jsx("span", { className: "min-w-0 break-words", children: testResult.message })] })), error && (_jsx("div", { className: "break-words rounded-md bg-red-500/5 px-3 py-2 text-[11px] leading-snug text-red-600 dark:text-red-400", children: error }))] }) }), _jsxs("div", { className: "flex shrink-0 items-center justify-between gap-2 border-t border-border px-7 py-4", children: [!selectedRequiresSetup && (_jsx("button", { type: "button", onClick: runTest, disabled: !url.trim() || busy, className: "rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40", children: t("mcpIntegrations.test") })), !selected ? (_jsxs("button", { type: "button", onClick: connectCustomWithOAuth, disabled: !name.trim() || !url.trim() || busy, "aria-busy": busy, className: "rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent disabled:pointer-events-none disabled:opacity-40", children: [busy && (_jsx(IconLoader2, { className: "me-1.5 inline h-3.5 w-3.5 animate-spin" })), t("mcpIntegrations.connectWithOAuth")] })) : null, selectedRequiresSetup ? (_jsxs("div", { className: "ms-auto flex items-center gap-2", children: [selected?.docsUrl ? (_jsxs("a", { href: selected.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent", children: [t("mcpIntegrations.viewSetup"), _jsx(IconExternalLink, { className: "h-3 w-3" })] })) : null, selected?.authMode === "oauth" && (_jsxs("button", { type: "button", onClick: () => connectWithOAuth(selected), disabled: busy, "aria-busy": busy, className: "inline-flex min-w-[132px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && (_jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" })), t("mcpIntegrations.continueToConnect")] }))] })) : selected?.authMode === "oauth" ? (_jsxs("button", { type: "button", onClick: () => connectWithOAuth(selected), disabled: !name.trim() || !url.trim() || busy, "aria-busy": busy, className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && _jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), t("mcpIntegrations.connectWithOAuth")] })) : (_jsxs("button", { type: "button", onClick: submitForm, disabled: !name.trim() || !url.trim() || busy, className: "inline-flex min-w-[92px] items-center justify-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-[12px] font-medium text-primary-foreground hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-40", children: [busy && _jsx(IconLoader2, { className: "h-3.5 w-3.5 animate-spin" }), t("mcpIntegrations.connect")] }))] })] })) }) }));
332
364
  }
@@ -17,6 +17,17 @@ export interface DefaultMcpIntegration {
17
17
  availability: McpIntegrationAvailability;
18
18
  verification: McpIntegrationVerification;
19
19
  logoUrl: string;
20
+ /**
21
+ * The server has a first-party OAuth client configured for this provider.
22
+ * Keep the connection user-scoped even when the client itself is shared.
23
+ */
24
+ managedOAuth?: boolean;
25
+ /**
26
+ * The provider supports a workspace connection whose access can be shared
27
+ * with permitted workspace members. Keep this opt-in until provider scope
28
+ * semantics are verified.
29
+ */
30
+ supportsOrganizationScope?: boolean;
20
31
  docsUrl?: string;
21
32
  setupNoteKey?: string;
22
33
  apiFallback?: {
@@ -51,8 +62,9 @@ export declare function isMcpIntegrationCatalogAvailable(config?: McpIntegration
51
62
  export declare function mcpIntegrationAuthLabel(mode: McpIntegrationAuthMode): string;
52
63
  export declare function buildMcpOAuthStartUrl({ name, url, description, scope, returnUrl, }: McpOAuthStartParams): string;
53
64
  export declare function navigateToMcpOAuthStart(url: string): void;
54
- export declare function resolveMcpIntegrationScope(defaultScope: "user" | "org", hasOrg: boolean, canCreateOrgMcp: boolean): "user" | "org";
65
+ export declare function resolveMcpIntegrationScope(defaultScope: "user" | "org", hasOrg: boolean, canCreateOrgMcp: boolean, supportsOrganizationScope?: boolean): "user" | "org";
55
66
  export declare function shouldOfferMcpOrganizationScope(hasOrg: boolean, canCreateOrgMcp: boolean): boolean;
67
+ export declare function shouldOfferMcpIntegrationOrganizationScope(integration: DefaultMcpIntegration, hasOrg: boolean, canCreateOrgMcp: boolean): boolean;
56
68
  export declare function filterMcpIntegrations(query: string, integrations?: DefaultMcpIntegration[]): DefaultMcpIntegration[];
57
69
  export declare function findMcpIntegrationForText(text: string, integrations?: DefaultMcpIntegration[]): DefaultMcpIntegration | null;
58
70
  /**