@agent-native/core 0.106.3 → 0.107.1

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 (292) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +23 -0
  3. package/corpus/core/docs/content/integrations.mdx +597 -0
  4. package/corpus/core/docs/content/locales/ar-SA/mcp-clients.mdx +19 -1
  5. package/corpus/core/docs/content/locales/de-DE/mcp-clients.mdx +22 -1
  6. package/corpus/core/docs/content/locales/es-ES/mcp-clients.mdx +23 -1
  7. package/corpus/core/docs/content/locales/fr-FR/mcp-clients.mdx +23 -1
  8. package/corpus/core/docs/content/locales/hi-IN/mcp-clients.mdx +22 -1
  9. package/corpus/core/docs/content/locales/ja-JP/mcp-clients.mdx +21 -1
  10. package/corpus/core/docs/content/locales/ko-KR/mcp-clients.mdx +20 -1
  11. package/corpus/core/docs/content/locales/pt-BR/mcp-clients.mdx +22 -1
  12. package/corpus/core/docs/content/locales/zh-CN/mcp-clients.mdx +17 -1
  13. package/corpus/core/docs/content/locales/zh-TW/mcp-clients.mdx +17 -1
  14. package/corpus/core/docs/content/mcp-clients.mdx +51 -1
  15. package/corpus/core/docs/content/organizations-teams-permissions.mdx +413 -0
  16. package/corpus/core/package.json +1 -1
  17. package/corpus/core/src/agent/production-agent.ts +19 -0
  18. package/corpus/core/src/agent/run-store.ts +98 -2
  19. package/corpus/core/src/client/AssistantChat.tsx +26 -1
  20. package/corpus/core/src/client/CommandMenu.tsx +5 -0
  21. package/corpus/core/src/client/active-run-state.ts +34 -0
  22. package/corpus/core/src/client/agent-chat-adapter.ts +4 -0
  23. package/corpus/core/src/client/chat/message-components.tsx +41 -0
  24. package/corpus/core/src/client/composer/TiptapComposer.tsx +45 -8
  25. package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +30 -11
  26. package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +270 -0
  27. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +177 -40
  28. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +478 -4
  29. package/corpus/core/src/client/resources/mcp-integration-logos.ts +108 -0
  30. package/corpus/core/src/client/sharing/ShareButton.tsx +30 -9
  31. package/corpus/core/src/client/use-agent-chat-home-handoff.ts +2 -2
  32. package/corpus/core/src/deploy/build.ts +32 -0
  33. package/corpus/core/src/extensions/html-shell.ts +33 -1
  34. package/corpus/core/src/ingestion/office.ts +1 -2
  35. package/corpus/core/src/ingestion/pptx.ts +2 -4
  36. package/corpus/core/src/localization/default-messages.ts +129 -1
  37. package/corpus/core/src/mcp/actions/call-mcp-tool.ts +1 -0
  38. package/corpus/core/src/secrets/register-framework-secrets.ts +28 -0
  39. package/corpus/core/src/server/agent-chat-plugin.ts +29 -1
  40. package/corpus/core/src/server/index.ts +4 -0
  41. package/corpus/core/src/server/org-admin.ts +28 -0
  42. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +9 -0
  43. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/references/api.md +31 -0
  44. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +9 -0
  45. package/corpus/core/src/vite/client.ts +24 -0
  46. package/corpus/templates/analytics/.agents/skills/creative-context/SKILL.md +64 -0
  47. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +29 -21
  48. package/corpus/templates/analytics/AGENTS.md +13 -0
  49. package/corpus/templates/analytics/actions/clone-creative-context-dashboard.ts +86 -0
  50. package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1 -1
  51. package/corpus/templates/analytics/actions/update-dashboard.ts +6 -2
  52. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +35 -7
  53. package/corpus/templates/analytics/app/components/layout/Layout.tsx +3 -3
  54. package/corpus/templates/analytics/app/i18n/zh-TW.ts +1 -0
  55. package/corpus/templates/analytics/app/i18n-data.ts +1 -0
  56. package/corpus/templates/analytics/app/pages/Ask.tsx +8 -4
  57. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +11 -1
  58. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/extension-slot.ts +11 -0
  59. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +86 -0
  60. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +6 -0
  61. package/corpus/templates/analytics/app/routes/agent.tsx +7 -1
  62. package/corpus/templates/analytics/changelog/2026-07-17-dashboard-extension-boxes.md +6 -0
  63. package/corpus/templates/analytics/changelog/2026-07-17-library-now-flags-published-dashboards-with-newer-versions-a.md +6 -0
  64. package/corpus/templates/analytics/changelog/2026-07-17-resources-can-be-added-to-creative-context-from-their-action.md +6 -0
  65. package/corpus/templates/analytics/changelog/2026-07-17-you-can-add-exact-approved-artifact-versions-to-governed-cre.md +6 -0
  66. package/corpus/templates/analytics/package.json +1 -0
  67. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +8 -0
  68. package/corpus/templates/analytics/server/lib/native-creative-context.ts +158 -0
  69. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
  70. package/corpus/templates/analytics/server/plugins/creative-context.ts +10 -0
  71. package/corpus/templates/assets/.agents/skills/creative-context/SKILL.md +12 -3
  72. package/corpus/templates/assets/AGENTS.md +5 -0
  73. package/corpus/templates/assets/actions/clone-creative-context-asset.ts +74 -0
  74. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +2 -1
  75. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +308 -178
  76. package/corpus/templates/assets/app/routes/library.tsx +5 -11
  77. package/corpus/templates/assets/changelog/2026-07-17-library-now-flags-published-assets-with-newer-versions-and-l.md +6 -0
  78. package/corpus/templates/assets/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  79. package/corpus/templates/assets/changelog/2026-07-17-you-can-add-exact-approved-artifact-versions-to-governed-cre.md +6 -0
  80. package/corpus/templates/assets/server/lib/native-creative-context.ts +198 -0
  81. package/corpus/templates/assets/server/plugins/creative-context.ts +4 -0
  82. package/corpus/templates/brain/actions/provider-api-request.ts +1 -0
  83. package/corpus/templates/brain/app/hooks/use-navigation-state.ts +6 -1
  84. package/corpus/templates/brain/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  85. package/corpus/templates/calendar/actions/provider-api-request.ts +1 -0
  86. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -1
  87. package/corpus/templates/calendar/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  88. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +4 -1
  89. package/corpus/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  90. package/corpus/templates/clips/actions/get-recording-insights.ts +7 -4
  91. package/corpus/templates/clips/actions/list-recordings.ts +48 -0
  92. package/corpus/templates/clips/actions/list-viewers.ts +2 -1
  93. package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +3 -1
  94. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  95. package/corpus/templates/clips/app/components/player/share-dialog.tsx +1 -3
  96. package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +11 -6
  97. package/corpus/templates/clips/app/hooks/use-view-tracking.ts +6 -1
  98. package/corpus/templates/clips/app/lib/ffmpeg-export.ts +4 -2
  99. package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -3
  100. package/corpus/templates/clips/changelog/2026-07-17-dictation-keeps-sentence-spacing-and-no-longer-crashes-when-.md +6 -0
  101. package/corpus/templates/clips/changelog/2026-07-17-shared-clips-now-preserve-editor-access-and-show-editor-insi.md +6 -0
  102. package/corpus/templates/clips/changelog/2026-07-17-stitching-clips-no-longer-fails-when-editor-media-metadata-i.md +6 -0
  103. package/corpus/templates/clips/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  104. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +14 -8
  105. package/corpus/templates/clips/shared/view-analytics.ts +4 -0
  106. package/corpus/templates/content/.agents/skills/creative-context/SKILL.md +12 -3
  107. package/corpus/templates/content/AGENTS.md +5 -0
  108. package/corpus/templates/content/actions/_content-space-access.ts +45 -2
  109. package/corpus/templates/content/actions/clone-creative-context-document.ts +61 -0
  110. package/corpus/templates/content/actions/create-content-database.ts +41 -7
  111. package/corpus/templates/content/actions/provider-api-request.ts +1 -0
  112. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +21 -0
  113. package/corpus/templates/content/app/components/layout/Layout.tsx +1 -1
  114. package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +29 -0
  115. package/corpus/templates/content/app/root.tsx +1 -10
  116. package/corpus/templates/content/changelog/2026-07-17-creating-a-database-now-completes-reliably-in-hosted-workspa.md +6 -0
  117. package/corpus/templates/content/changelog/2026-07-17-library-now-flags-published-documents-with-newer-versions-an.md +6 -0
  118. package/corpus/templates/content/changelog/2026-07-17-resources-can-be-added-to-creative-context-from-their-action.md +6 -0
  119. package/corpus/templates/content/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  120. package/corpus/templates/content/changelog/2026-07-17-you-can-add-exact-approved-artifact-versions-to-governed-cre.md +6 -0
  121. package/corpus/templates/content/parity/matrix.md +1 -1
  122. package/corpus/templates/content/parity/matrix.ts +1 -0
  123. package/corpus/templates/content/server/lib/native-creative-context.ts +191 -0
  124. package/corpus/templates/content/server/plugins/creative-context.ts +8 -1
  125. package/corpus/templates/design/.agents/skills/creative-context/SKILL.md +11 -3
  126. package/corpus/templates/design/AGENTS.md +5 -0
  127. package/corpus/templates/design/actions/clone-creative-context-design-native.ts +111 -0
  128. package/corpus/templates/design/actions/provider-api-request.ts +1 -0
  129. package/corpus/templates/design/app/pages/Index.tsx +44 -0
  130. package/corpus/templates/design/app/pages/design-editor/types.ts +1 -0
  131. package/corpus/templates/design/changelog/2026-07-17-library-now-flags-published-designs-with-newer-versions-and-.md +6 -0
  132. package/corpus/templates/design/changelog/2026-07-17-resources-can-be-added-to-creative-context-from-their-action.md +6 -0
  133. package/corpus/templates/design/changelog/2026-07-17-you-can-add-exact-approved-artifact-versions-to-governed-cre.md +6 -0
  134. package/corpus/templates/design/server/lib/native-creative-context.ts +265 -0
  135. package/corpus/templates/design/server/plugins/creative-context.ts +8 -1
  136. package/corpus/templates/dispatch/actions/provider-api-request.ts +1 -0
  137. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +4 -1
  138. package/corpus/templates/dispatch/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  139. package/corpus/templates/forms/app/components/layout/Layout.tsx +2 -4
  140. package/corpus/templates/forms/app/components/ui/popover.tsx +25 -1
  141. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +6 -1
  142. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +13 -10
  143. package/corpus/templates/forms/app/root.tsx +6 -1
  144. package/corpus/templates/forms/changelog/2026-07-17-form-builder-popovers-stay-within-the-viewport.md +6 -0
  145. package/corpus/templates/forms/changelog/2026-07-17-form-editor-loading-matches-current-sidebar-free-layout.md +6 -0
  146. package/corpus/templates/forms/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  147. package/corpus/templates/mail/actions/provider-api-request.ts +1 -0
  148. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +1 -1
  149. package/corpus/templates/mail/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  150. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +14 -3
  151. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +8 -1
  152. package/corpus/templates/plan/app/root.tsx +0 -2
  153. package/corpus/templates/plan/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  154. package/corpus/templates/slides/.agents/skills/creative-context/SKILL.md +11 -3
  155. package/corpus/templates/slides/AGENTS.md +5 -0
  156. package/corpus/templates/slides/actions/clone-creative-context-deck.ts +96 -0
  157. package/corpus/templates/slides/actions/extract-pdf.ts +3 -2
  158. package/corpus/templates/slides/actions/import-file.ts +3 -2
  159. package/corpus/templates/slides/actions/provider-api-request.ts +1 -0
  160. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +27 -0
  161. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +21 -0
  162. package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -1
  163. package/corpus/templates/slides/app/context/DeckContext.tsx +23 -23
  164. package/corpus/templates/slides/changelog/2026-07-17-duplicated-slides-now-stay-in-the-deck.md +6 -0
  165. package/corpus/templates/slides/changelog/2026-07-17-library-now-flags-published-decks-with-newer-versions-and-le.md +6 -0
  166. package/corpus/templates/slides/changelog/2026-07-17-pdf-and-powerpoint-imports-now-work-reliably-in-hosted-decks.md +6 -0
  167. package/corpus/templates/slides/changelog/2026-07-17-resources-can-be-added-to-creative-context-from-their-action.md +6 -0
  168. package/corpus/templates/slides/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  169. package/corpus/templates/slides/changelog/2026-07-17-you-can-add-exact-approved-artifact-versions-to-governed-cre.md +6 -0
  170. package/corpus/templates/slides/server/lib/native-creative-context.ts +288 -0
  171. package/corpus/templates/slides/server/plugins/creative-context.ts +4 -0
  172. package/corpus/templates/tasks/app/components/layout/Layout.tsx +2 -13
  173. package/corpus/templates/tasks/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it.md +6 -0
  174. package/dist/agent/production-agent.d.ts.map +1 -1
  175. package/dist/agent/production-agent.js +13 -1
  176. package/dist/agent/production-agent.js.map +1 -1
  177. package/dist/agent/run-store.d.ts +17 -0
  178. package/dist/agent/run-store.d.ts.map +1 -1
  179. package/dist/agent/run-store.js +84 -2
  180. package/dist/agent/run-store.js.map +1 -1
  181. package/dist/client/AssistantChat.d.ts.map +1 -1
  182. package/dist/client/AssistantChat.js +18 -3
  183. package/dist/client/AssistantChat.js.map +1 -1
  184. package/dist/client/CommandMenu.d.ts.map +1 -1
  185. package/dist/client/CommandMenu.js +4 -0
  186. package/dist/client/CommandMenu.js.map +1 -1
  187. package/dist/client/active-run-state.d.ts +7 -0
  188. package/dist/client/active-run-state.d.ts.map +1 -1
  189. package/dist/client/active-run-state.js +28 -0
  190. package/dist/client/active-run-state.js.map +1 -1
  191. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  192. package/dist/client/agent-chat-adapter.js +4 -1
  193. package/dist/client/agent-chat-adapter.js.map +1 -1
  194. package/dist/client/chat/message-components.d.ts.map +1 -1
  195. package/dist/client/chat/message-components.js +35 -1
  196. package/dist/client/chat/message-components.js.map +1 -1
  197. package/dist/client/composer/TiptapComposer.d.ts +7 -0
  198. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  199. package/dist/client/composer/TiptapComposer.js +37 -8
  200. package/dist/client/composer/TiptapComposer.js.map +1 -1
  201. package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
  202. package/dist/client/integrations/IntegrationsPanel.js +3 -2
  203. package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
  204. package/dist/client/resources/McpConnectionSuggestion.d.ts +9 -0
  205. package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -0
  206. package/dist/client/resources/McpConnectionSuggestion.js +134 -0
  207. package/dist/client/resources/McpConnectionSuggestion.js.map +1 -0
  208. package/dist/client/resources/McpIntegrationDialog.d.ts +2 -1
  209. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  210. package/dist/client/resources/McpIntegrationDialog.js +51 -21
  211. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  212. package/dist/client/resources/mcp-integration-catalog.d.ts +15 -0
  213. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  214. package/dist/client/resources/mcp-integration-catalog.js +420 -4
  215. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  216. package/dist/client/resources/mcp-integration-logos.d.ts +2 -0
  217. package/dist/client/resources/mcp-integration-logos.d.ts.map +1 -0
  218. package/dist/client/resources/mcp-integration-logos.js +109 -0
  219. package/dist/client/resources/mcp-integration-logos.js.map +1 -0
  220. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  221. package/dist/client/sharing/ShareButton.js +15 -12
  222. package/dist/client/sharing/ShareButton.js.map +1 -1
  223. package/dist/client/use-agent-chat-home-handoff.d.ts +1 -1
  224. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
  225. package/dist/client/use-agent-chat-home-handoff.js +1 -1
  226. package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
  227. package/dist/collab/routes.d.ts +1 -1
  228. package/dist/collab/struct-routes.d.ts +1 -1
  229. package/dist/deploy/build.d.ts.map +1 -1
  230. package/dist/deploy/build.js +23 -0
  231. package/dist/deploy/build.js.map +1 -1
  232. package/dist/extensions/html-shell.d.ts.map +1 -1
  233. package/dist/extensions/html-shell.js +33 -1
  234. package/dist/extensions/html-shell.js.map +1 -1
  235. package/dist/ingestion/office.d.ts.map +1 -1
  236. package/dist/ingestion/office.js +1 -2
  237. package/dist/ingestion/office.js.map +1 -1
  238. package/dist/ingestion/pptx.js +2 -4
  239. package/dist/ingestion/pptx.js.map +1 -1
  240. package/dist/localization/default-messages.d.ts +100 -0
  241. package/dist/localization/default-messages.d.ts.map +1 -1
  242. package/dist/localization/default-messages.js +101 -1
  243. package/dist/localization/default-messages.js.map +1 -1
  244. package/dist/mcp/actions/call-mcp-tool.js +1 -0
  245. package/dist/mcp/actions/call-mcp-tool.js.map +1 -1
  246. package/dist/notifications/routes.d.ts +1 -1
  247. package/dist/observability/routes.d.ts +5 -5
  248. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  249. package/dist/resources/handlers.d.ts +1 -1
  250. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  251. package/dist/secrets/register-framework-secrets.js +25 -0
  252. package/dist/secrets/register-framework-secrets.js.map +1 -1
  253. package/dist/secrets/routes.d.ts +9 -9
  254. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  255. package/dist/server/agent-chat-plugin.js +23 -1
  256. package/dist/server/agent-chat-plugin.js.map +1 -1
  257. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  258. package/dist/server/index.d.ts +1 -0
  259. package/dist/server/index.d.ts.map +1 -1
  260. package/dist/server/index.js +1 -0
  261. package/dist/server/index.js.map +1 -1
  262. package/dist/server/org-admin.d.ts +3 -0
  263. package/dist/server/org-admin.d.ts.map +1 -0
  264. package/dist/server/org-admin.js +24 -0
  265. package/dist/server/org-admin.js.map +1 -0
  266. package/dist/templates/chat/app/hooks/use-navigation-state.ts +4 -1
  267. package/dist/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  268. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +9 -0
  269. package/dist/templates/workspace-core/.agents/skills/extensions/references/api.md +31 -0
  270. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +9 -0
  271. package/dist/vite/client.d.ts.map +1 -1
  272. package/dist/vite/client.js +20 -0
  273. package/dist/vite/client.js.map +1 -1
  274. package/docs/content/integrations.mdx +597 -0
  275. package/docs/content/locales/ar-SA/mcp-clients.mdx +19 -1
  276. package/docs/content/locales/de-DE/mcp-clients.mdx +22 -1
  277. package/docs/content/locales/es-ES/mcp-clients.mdx +23 -1
  278. package/docs/content/locales/fr-FR/mcp-clients.mdx +23 -1
  279. package/docs/content/locales/hi-IN/mcp-clients.mdx +22 -1
  280. package/docs/content/locales/ja-JP/mcp-clients.mdx +21 -1
  281. package/docs/content/locales/ko-KR/mcp-clients.mdx +20 -1
  282. package/docs/content/locales/pt-BR/mcp-clients.mdx +22 -1
  283. package/docs/content/locales/zh-CN/mcp-clients.mdx +17 -1
  284. package/docs/content/locales/zh-TW/mcp-clients.mdx +17 -1
  285. package/docs/content/mcp-clients.mdx +51 -1
  286. package/docs/content/organizations-teams-permissions.mdx +413 -0
  287. package/package.json +1 -1
  288. package/src/templates/chat/app/hooks/use-navigation-state.ts +4 -1
  289. package/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +6 -0
  290. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +9 -0
  291. package/src/templates/workspace-core/.agents/skills/extensions/references/api.md +31 -0
  292. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +9 -0
@@ -38,7 +38,9 @@ import React, {
38
38
  import type { ReasoningEffort } from "../shared/reasoning-effort.js";
39
39
  import {
40
40
  ACTIVE_RUN_STATE_EVENT,
41
+ clearPendingTurnIfMatches,
41
42
  clearActiveRunIfMatches,
43
+ getPendingTurn,
42
44
  getActiveRunActivityTool,
43
45
  getActiveRun,
44
46
  resolveReconnectAfterSeq,
@@ -172,6 +174,7 @@ import {
172
174
  useGuidedQuestionFlow,
173
175
  } from "./guided-questions.js";
174
176
  import { useT } from "./i18n.js";
177
+ import { McpConnectionSuggestion } from "./resources/McpConnectionSuggestion.js";
175
178
  import {
176
179
  AgentAutoContinueSignal,
177
180
  type ContentPart,
@@ -2239,6 +2242,14 @@ const AssistantChatInner = forwardRef<
2239
2242
  // (unsupported format, size cap, body-size rejection, drop errors).
2240
2243
  // Cleared on the next message send.
2241
2244
  const [composerError, setComposerError] = useState<string | null>(null);
2245
+ const [composerText, setComposerText] = useState("");
2246
+ const handleComposerTextChange = useCallback(
2247
+ (text: string) => {
2248
+ setComposerText(text);
2249
+ onComposerTextChange?.(text);
2250
+ },
2251
+ [onComposerTextChange],
2252
+ );
2242
2253
  const dropDepthRef = useRef(0);
2243
2254
  const handleChatDragEnter = useCallback((e: React.DragEvent) => {
2244
2255
  if (!Array.from(e.dataTransfer?.types ?? []).includes("Files")) return;
@@ -4272,6 +4283,7 @@ const AssistantChatInner = forwardRef<
4272
4283
  }
4273
4284
  const activeRun = getActiveRun();
4274
4285
  const runIdToAbort = reconnectRunIdRef.current ?? activeRun?.runId;
4286
+ const pendingTurn = threadId ? getPendingTurn(threadId) : null;
4275
4287
  userStoppedRunRef.current = {
4276
4288
  at: Date.now(),
4277
4289
  ...(runIdToAbort ? { runId: runIdToAbort } : {}),
@@ -4283,6 +4295,16 @@ const AssistantChatInner = forwardRef<
4283
4295
  fetch(`${apiUrl}/runs/${encodeURIComponent(runIdToAbort)}/abort`, {
4284
4296
  method: "POST",
4285
4297
  }).catch(() => {});
4298
+ } else if (pendingTurn && threadId) {
4299
+ clearPendingTurnIfMatches(threadId, pendingTurn.turnId);
4300
+ fetch(
4301
+ `${apiUrl}/runs/turn/${encodeURIComponent(pendingTurn.turnId)}/abort`,
4302
+ {
4303
+ method: "POST",
4304
+ headers: { "Content-Type": "application/json" },
4305
+ body: JSON.stringify({ threadId }),
4306
+ },
4307
+ ).catch(() => {});
4286
4308
  }
4287
4309
  if (isReconnecting) {
4288
4310
  reconnectAbortRef.current?.abort();
@@ -5382,6 +5404,9 @@ const AssistantChatInner = forwardRef<
5382
5404
  </MessageScrollerProvider>
5383
5405
 
5384
5406
  {showComposerSlot ? composerSlot : null}
5407
+ {isActiveComposer && (
5408
+ <McpConnectionSuggestion text={composerText} />
5409
+ )}
5385
5410
  {showCenteredEmptyThreadFooterSlot ? (
5386
5411
  <div className="agent-thread-footer-slot agent-thread-footer-slot--centered-empty">
5387
5412
  {resolvedThreadFooterSlot}
@@ -5488,7 +5513,7 @@ const AssistantChatInner = forwardRef<
5488
5513
  focusRef={tiptapRef}
5489
5514
  onTextChange={
5490
5515
  isActiveComposer
5491
- ? onComposerTextChange
5516
+ ? handleComposerTextChange
5492
5517
  : undefined
5493
5518
  }
5494
5519
  disabled={isComposerDisabled}
@@ -72,6 +72,11 @@ export function openAgentSettings(
72
72
  const normalizedSection =
73
73
  typeof section === "string" ? section : section?.section;
74
74
 
75
+ const secretHash = normalizedSection?.replace(/^#/, "");
76
+ if (secretHash?.toLowerCase().startsWith("secrets:")) {
77
+ window.location.hash = `#${secretHash}`;
78
+ }
79
+
75
80
  openAgentSidebar();
76
81
  // Voice mode unmounts the chat surface while its dock is collapsed, so its
77
82
  // settings listener does not exist until opening the sidebar remounts it.
@@ -1,4 +1,5 @@
1
1
  const STORAGE_KEY = "agent-chat-active-run";
2
+ const PENDING_TURN_STORAGE_KEY = "agent-chat-pending-turn";
2
3
  export const ACTIVE_RUN_STATE_EVENT = "agent-chat:active-run-state-change";
3
4
 
4
5
  export interface ActiveRunState {
@@ -8,6 +9,11 @@ export interface ActiveRunState {
8
9
  activityTool?: string | null;
9
10
  }
10
11
 
12
+ export interface PendingTurnState {
13
+ threadId: string;
14
+ turnId: string;
15
+ }
16
+
11
17
  function notifyActiveRunStateChanged(state: ActiveRunState | null): void {
12
18
  if (
13
19
  typeof window === "undefined" ||
@@ -88,6 +94,34 @@ export function clearActiveRunIfMatches(threadId: string, runId: string): void {
88
94
  clearActiveRun();
89
95
  }
90
96
 
97
+ export function setPendingTurn(state: PendingTurnState): void {
98
+ try {
99
+ sessionStorage.setItem(PENDING_TURN_STORAGE_KEY, JSON.stringify(state));
100
+ } catch {}
101
+ }
102
+
103
+ export function getPendingTurn(threadId: string): PendingTurnState | null {
104
+ try {
105
+ const raw = sessionStorage.getItem(PENDING_TURN_STORAGE_KEY);
106
+ if (!raw) return null;
107
+ const state = JSON.parse(raw) as PendingTurnState;
108
+ return state.threadId === threadId && state.turnId ? state : null;
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+
114
+ export function clearPendingTurnIfMatches(
115
+ threadId: string,
116
+ turnId?: string,
117
+ ): void {
118
+ const state = getPendingTurn(threadId);
119
+ if (!state || (turnId && state.turnId !== turnId)) return;
120
+ try {
121
+ sessionStorage.removeItem(PENDING_TURN_STORAGE_KEY);
122
+ } catch {}
123
+ }
124
+
91
125
  /** Resume reconnect SSE after the last seen event (0 = replay from the start). */
92
126
  export function resolveReconnectAfterSeq(
93
127
  threadId: string,
@@ -11,9 +11,11 @@ import type {
11
11
  } from "../agent/types.js";
12
12
  import type { ReasoningEffort } from "../shared/reasoning-effort.js";
13
13
  import {
14
+ clearPendingTurnIfMatches,
14
15
  setActiveRun,
15
16
  updateActiveRunSeq,
16
17
  clearActiveRun,
18
+ setPendingTurn,
17
19
  } from "./active-run-state.js";
18
20
  import { captureError } from "./analytics.js";
19
21
  import { agentNativePath } from "./api-path.js";
@@ -1634,6 +1636,7 @@ export function createAgentChatAdapter(
1634
1636
  const content: ContentPart[] = [];
1635
1637
  const toolCallCounter = { value: 0 };
1636
1638
  const turnId = generateTurnId();
1639
+ if (threadId) setPendingTurn({ threadId, turnId });
1637
1640
  let runId: string | null = null;
1638
1641
  let lastSeq = -1;
1639
1642
  const seenRunSeqs = new Map<string, number>();
@@ -3279,6 +3282,7 @@ export function createAgentChatAdapter(
3279
3282
  attemptedRunIds.push(runId);
3280
3283
  }
3281
3284
  if (runId && threadId) {
3285
+ clearPendingTurnIfMatches(threadId, turnId);
3282
3286
  setActiveRun({ threadId, runId, lastSeq: -1 });
3283
3287
  }
3284
3288
 
@@ -62,6 +62,7 @@ import {
62
62
  import { isPastedTextAttachmentName } from "../composer/pasted-text.js";
63
63
  import { PastedTextChip } from "../composer/PastedTextChip.js";
64
64
  import { ThumbsFeedback } from "../observability/ThumbsFeedback.js";
65
+ import { McpConnectionSuggestion } from "../resources/McpConnectionSuggestion.js";
65
66
  import type { ContentPart } from "../sse-event-processor.js";
66
67
  import { cn } from "../utils.js";
67
68
  import {
@@ -819,6 +820,37 @@ function assistantMessageStatusIsTerminal(message: {
819
820
  return statusType === "complete" || statusType === "incomplete";
820
821
  }
821
822
 
823
+ function messageTextFromContent(content: unknown): string {
824
+ if (typeof content === "string") return content;
825
+ if (!Array.isArray(content)) return "";
826
+ return content
827
+ .flatMap((part) => {
828
+ if (!part || typeof part !== "object") return [];
829
+ const record = part as {
830
+ type?: unknown;
831
+ text?: unknown;
832
+ result?: unknown;
833
+ };
834
+ const values: string[] = [];
835
+ if (typeof record.text === "string") values.push(record.text);
836
+ if (record.type === "tool-call" && typeof record.result === "string") {
837
+ values.push(record.result);
838
+ }
839
+ return values;
840
+ })
841
+ .join("\n");
842
+ }
843
+
844
+ function latestUserMessageText(messages: readonly unknown[]): string {
845
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
846
+ const message = messages[index];
847
+ if (!message || typeof message !== "object") continue;
848
+ const record = message as { role?: unknown; content?: unknown };
849
+ if (record.role === "user") return messageTextFromContent(record.content);
850
+ }
851
+ return "";
852
+ }
853
+
822
854
  export function assistantMessageHasUnresolvedTool(content: unknown): boolean {
823
855
  if (!Array.isArray(content)) return false;
824
856
  return content.some((part): boolean => {
@@ -946,6 +978,8 @@ export function AssistantMessage() {
946
978
  thread.messages[thread.messages.length - 1].id === msg.id;
947
979
  const hasRenderableContent = assistantMessageHasRenderableContent(msg);
948
980
  const hasUnresolvedTool = assistantMessageHasUnresolvedTool(msg.content);
981
+ const responseConnectionText = messageTextFromContent(msg.content);
982
+ const responseConnectionContext = latestUserMessageText(thread.messages);
949
983
  const isComplete = shouldShowAssistantMessageFooter({
950
984
  isLast,
951
985
  chatRunning,
@@ -1104,6 +1138,13 @@ export function AssistantMessage() {
1104
1138
  {isComplete && hasCodeAgentTools && msgContent && (
1105
1139
  <FilesChangedSummary parts={msgContent} />
1106
1140
  )}
1141
+ {isComplete && isLast && (
1142
+ <McpConnectionSuggestion
1143
+ text={responseConnectionText}
1144
+ contextText={responseConnectionContext}
1145
+ variant="response"
1146
+ />
1147
+ )}
1107
1148
  {isLast && hasUnresolvedTool && !chatRunning && (
1108
1149
  <RunningActivityStatus label="Thinking" />
1109
1150
  )}
@@ -110,6 +110,28 @@ export function canSubmitComposerContent(options: {
110
110
  );
111
111
  }
112
112
 
113
+ const VOICE_TERMINAL_PUNCTUATION = /[.!?…。!?:;](?:["'”’»)\]}]*)$/;
114
+
115
+ export function formatVoiceTranscriptForComposer(text: string): string {
116
+ const trimmed = text.trim();
117
+ if (!trimmed) return "";
118
+ return `${trimmed}${VOICE_TERMINAL_PUNCTUATION.test(trimmed) ? "" : "."} `;
119
+ }
120
+
121
+ export function canRemoveVoicePreview(options: {
122
+ documentSize: number;
123
+ anchor: number;
124
+ previewText: string;
125
+ currentText: string;
126
+ }): boolean {
127
+ if (!options.previewText) return false;
128
+ if (options.anchor < 1) return false;
129
+ if (options.anchor + options.previewText.length > options.documentSize) {
130
+ return false;
131
+ }
132
+ return options.currentText === options.previewText;
133
+ }
134
+
113
135
  export function resolveComposerPrimaryAction(options: {
114
136
  canSubmit: boolean;
115
137
  hasStopButton: boolean;
@@ -2082,15 +2104,16 @@ export function TiptapComposer({
2082
2104
  (text: string) => {
2083
2105
  const ed = editor;
2084
2106
  if (!isComposerEditorUsable(ed)) return;
2107
+ const formattedText = formatVoiceTranscriptForComposer(text);
2085
2108
 
2086
2109
  const anchor = voiceAnchorRef.current;
2087
2110
  if (anchor != null) {
2088
2111
  const prevLen = prevVoiceInsertRef.current.length;
2089
- if (text) {
2112
+ if (formattedText) {
2090
2113
  ed.chain()
2091
2114
  .focus()
2092
2115
  .deleteRange({ from: anchor, to: anchor + prevLen })
2093
- .insertContentAt(anchor, text + " ")
2116
+ .insertContentAt(anchor, formattedText)
2094
2117
  .run();
2095
2118
  } else if (prevLen > 0) {
2096
2119
  ed.chain()
@@ -2099,14 +2122,14 @@ export function TiptapComposer({
2099
2122
  }
2100
2123
  voiceAnchorRef.current = null;
2101
2124
  prevVoiceInsertRef.current = "";
2102
- } else if (text) {
2125
+ } else if (formattedText) {
2103
2126
  const { from } = ed.state.selection;
2104
2127
  const prevChar =
2105
2128
  from > 1 ? ed.state.doc.textBetween(from - 1, from) : "";
2106
2129
  const needsLead = prevChar && !/\s/.test(prevChar);
2107
2130
  ed.chain()
2108
2131
  .focus()
2109
- .insertContent((needsLead ? " " : "") + text + " ")
2132
+ .insertContent((needsLead ? " " : "") + formattedText)
2110
2133
  .run();
2111
2134
  }
2112
2135
  },
@@ -2172,10 +2195,24 @@ export function TiptapComposer({
2172
2195
  const anchor = voiceAnchorRef.current;
2173
2196
  const prevLen = prevVoiceInsertRef.current.length;
2174
2197
  if (isComposerEditorUsable(editor) && prevLen > 0) {
2175
- editor
2176
- .chain()
2177
- .deleteRange({ from: anchor, to: anchor + prevLen })
2178
- .run();
2198
+ const documentSize = editor.state.doc.content.size;
2199
+ const currentText =
2200
+ anchor >= 1 && anchor + prevLen <= documentSize
2201
+ ? editor.state.doc.textBetween(anchor, anchor + prevLen, "", "\n")
2202
+ : "";
2203
+ if (
2204
+ canRemoveVoicePreview({
2205
+ documentSize,
2206
+ anchor,
2207
+ previewText: prevVoiceInsertRef.current,
2208
+ currentText,
2209
+ })
2210
+ ) {
2211
+ editor
2212
+ .chain()
2213
+ .deleteRange({ from: anchor, to: anchor + prevLen })
2214
+ .run();
2215
+ }
2179
2216
  }
2180
2217
  voiceAnchorRef.current = null;
2181
2218
  prevVoiceInsertRef.current = "";
@@ -14,6 +14,7 @@ import {
14
14
  } from "@tabler/icons-react";
15
15
  import React, { useState, useCallback, useEffect } from "react";
16
16
 
17
+ import { AgentAskPopover } from "../AgentAskPopover.js";
17
18
  import { agentNativePath } from "../api-path.js";
18
19
  import {
19
20
  Tooltip,
@@ -511,6 +512,14 @@ export function IntegrationsPanel() {
511
512
  <div className="text-[10px] font-medium text-muted-foreground mb-1.5">
512
513
  {t("integrations.addChatIntegration")}
513
514
  </div>
515
+ <AgentAskPopover
516
+ label={t("integrations.addSomething")}
517
+ title={t("integrations.addSomethingTitle")}
518
+ placeholder={t("integrations.addSomethingPlaceholder")}
519
+ prompt=""
520
+ context="The user wants to add a chat or workspace integration that is not in the current directory. Research the provider's official OAuth or MCP setup, explain any app registration or allowlist requirements, and add a reusable integration preset when it is supported. Never ask the user to paste credentials into a prompt."
521
+ className="mb-2 h-7 w-full justify-center border-dashed px-2 text-[10px]"
522
+ />
514
523
  <AddIntegrationPicker
515
524
  connectedIds={connectedIds}
516
525
  onSelect={(p) => {
@@ -533,17 +542,27 @@ export function IntegrationsPanel() {
533
542
  {t("integrations.chatIntegrationsDescription")}
534
543
  </div>
535
544
  </div>
536
- <Tooltip>
537
- <TooltipTrigger asChild>
538
- <button
539
- onClick={() => setShowPicker(true)}
540
- className="flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50"
541
- >
542
- <IconPlus size={12} />
543
- </button>
544
- </TooltipTrigger>
545
- <TooltipContent>{t("integrations.addIntegration")}</TooltipContent>
546
- </Tooltip>
545
+ <div className="flex items-center gap-1">
546
+ <Tooltip>
547
+ <TooltipTrigger asChild>
548
+ <button
549
+ onClick={() => setShowPicker(true)}
550
+ className="flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:bg-accent/50 hover:text-foreground"
551
+ >
552
+ <IconPlus size={12} />
553
+ </button>
554
+ </TooltipTrigger>
555
+ <TooltipContent>{t("integrations.addIntegration")}</TooltipContent>
556
+ </Tooltip>
557
+ <AgentAskPopover
558
+ label={t("integrations.addSomething")}
559
+ title={t("integrations.addSomethingTitle")}
560
+ placeholder={t("integrations.addSomethingPlaceholder")}
561
+ prompt=""
562
+ context="The user wants to add a chat or workspace integration that is not in the current directory. Research the provider's official OAuth or MCP setup, explain any app registration or allowlist requirements, and add a reusable integration preset when it is supported. Never ask the user to paste credentials into a prompt."
563
+ className="h-7 px-2 text-[10px]"
564
+ />
565
+ </div>
547
566
  </div>
548
567
 
549
568
  {loading ? (
@@ -0,0 +1,270 @@
1
+ import {
2
+ IconArrowUpRight,
3
+ IconLoader2,
4
+ IconPlugConnected,
5
+ IconX,
6
+ } from "@tabler/icons-react";
7
+ import { useEffect, useMemo, useState } from "react";
8
+
9
+ import { agentNativePath } from "../api-path.js";
10
+ import { openAgentSettings } from "../CommandMenu.js";
11
+ import { useT } from "../i18n.js";
12
+ import {
13
+ buildMcpOAuthStartUrl,
14
+ findMcpIntegrationForText,
15
+ getMcpIntegrationApiFallback,
16
+ getDefaultMcpIntegrations,
17
+ isMcpConnectionFailureText,
18
+ type DefaultMcpIntegration,
19
+ } from "./mcp-integration-catalog.js";
20
+ import { McpIntegrationDialog } from "./McpIntegrationDialog.js";
21
+ import {
22
+ useCreateMcpServer,
23
+ useMcpServers,
24
+ type McpServer,
25
+ } from "./use-mcp-servers.js";
26
+
27
+ export type McpConnectionSuggestionVariant = "composer" | "response";
28
+
29
+ interface McpConnectionSuggestionProps {
30
+ text: string;
31
+ contextText?: string;
32
+ variant?: McpConnectionSuggestionVariant;
33
+ }
34
+
35
+ function compareUrl(value: string): string {
36
+ try {
37
+ const url = new URL(value.trim());
38
+ url.hash = "";
39
+ return url.toString().replace(/\/+$/, "");
40
+ } catch {
41
+ return value.trim().replace(/\/+$/, "");
42
+ }
43
+ }
44
+
45
+ function isConnected(
46
+ integration: DefaultMcpIntegration,
47
+ servers: McpServer[],
48
+ ): boolean {
49
+ const targetUrl = compareUrl(integration.url);
50
+ return servers.some(
51
+ (server) =>
52
+ server.status.state === "connected" &&
53
+ compareUrl(server.url) === targetUrl,
54
+ );
55
+ }
56
+
57
+ function returnUrl(): string {
58
+ if (typeof window === "undefined") return "/";
59
+ return (
60
+ window.location.pathname + window.location.search + window.location.hash
61
+ );
62
+ }
63
+
64
+ function canStartOAuth(integration: DefaultMcpIntegration): boolean {
65
+ return (
66
+ integration.authMode === "oauth" &&
67
+ integration.connectionMode === "oauth" &&
68
+ integration.availability === "ready"
69
+ );
70
+ }
71
+
72
+ function hasApiFallback(
73
+ apiFallback: DefaultMcpIntegration["apiFallback"] | null,
74
+ ): boolean {
75
+ return Boolean(apiFallback);
76
+ }
77
+
78
+ export function McpConnectionSuggestion({
79
+ text,
80
+ contextText = "",
81
+ variant = "composer",
82
+ }: McpConnectionSuggestionProps) {
83
+ const t = useT();
84
+ const mcpServersQuery = useMcpServers();
85
+ const createMcpServer = useCreateMcpServer();
86
+ const [dialogOpen, setDialogOpen] = useState(false);
87
+ const [dismissedId, setDismissedId] = useState<string | null>(null);
88
+ const [connecting, setConnecting] = useState(false);
89
+ const [error, setError] = useState<string | null>(null);
90
+ const integrations = useMemo(() => getDefaultMcpIntegrations(), []);
91
+ const textIntegration = useMemo(
92
+ () => findMcpIntegrationForText(text, integrations),
93
+ [integrations, text],
94
+ );
95
+ const contextIntegration = useMemo(
96
+ () =>
97
+ contextText ? findMcpIntegrationForText(contextText, integrations) : null,
98
+ [contextText, integrations],
99
+ );
100
+ const integration =
101
+ variant === "response" &&
102
+ textIntegration &&
103
+ contextIntegration &&
104
+ textIntegration.id !== contextIntegration.id
105
+ ? null
106
+ : (textIntegration ?? contextIntegration);
107
+ const apiFallback = integration
108
+ ? getMcpIntegrationApiFallback(integration)
109
+ : null;
110
+ const servers = useMemo(
111
+ () => [
112
+ ...(mcpServersQuery.data?.user ?? []),
113
+ ...(mcpServersQuery.data?.org ?? []),
114
+ ],
115
+ [mcpServersQuery.data],
116
+ );
117
+ const connected = integration ? isConnected(integration, servers) : false;
118
+ const shouldSuggest =
119
+ mcpServersQuery.isSuccess &&
120
+ integration &&
121
+ !connected &&
122
+ dismissedId !== integration.id &&
123
+ (variant === "composer" || isMcpConnectionFailureText(text));
124
+
125
+ useEffect(() => {
126
+ setError(null);
127
+ setConnecting(false);
128
+ }, [integration?.id, variant]);
129
+
130
+ if (!shouldSuggest) return null;
131
+
132
+ const connect = async () => {
133
+ if (!integration || connecting) return;
134
+ setError(null);
135
+
136
+ if (apiFallback) {
137
+ openAgentSettings(`secrets:${apiFallback.secretKey}`);
138
+ return;
139
+ }
140
+
141
+ if (canStartOAuth(integration)) {
142
+ window.location.assign(
143
+ agentNativePath(
144
+ buildMcpOAuthStartUrl({
145
+ name: integration.name,
146
+ url: integration.url,
147
+ description: integration.description,
148
+ scope: "user",
149
+ returnUrl: returnUrl(),
150
+ }),
151
+ ),
152
+ );
153
+ return;
154
+ }
155
+
156
+ if (
157
+ integration.authMode === "none" &&
158
+ integration.connectionMode === "direct"
159
+ ) {
160
+ setConnecting(true);
161
+ try {
162
+ await createMcpServer.mutateAsync({
163
+ scope: "user",
164
+ name: integration.name,
165
+ url: integration.url,
166
+ description: integration.description,
167
+ });
168
+ setDismissedId(integration.id);
169
+ } catch (cause) {
170
+ setError(
171
+ cause instanceof Error ? cause.message : t("mcpIntegrations.failed"),
172
+ );
173
+ } finally {
174
+ setConnecting(false);
175
+ }
176
+ return;
177
+ }
178
+
179
+ setDialogOpen(true);
180
+ };
181
+
182
+ const actionLabel = hasApiFallback(apiFallback)
183
+ ? t("mcpIntegrations.useApiToken")
184
+ : canStartOAuth(integration)
185
+ ? t("mcpIntegrations.connectWithOAuth")
186
+ : integration.availability === "client-restricted" ||
187
+ integration.availability === "provider-setup"
188
+ ? t("mcpIntegrations.viewSetup")
189
+ : t("mcpIntegrations.connect");
190
+
191
+ return (
192
+ <>
193
+ <div
194
+ className={
195
+ variant === "response"
196
+ ? "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]"
197
+ : "mx-auto mb-2 flex w-[min(100%,680px)] items-center gap-2 rounded-lg border border-primary/20 bg-primary/5 px-3 py-2 text-[12px]"
198
+ }
199
+ data-mcp-connection-suggestion={integration.id}
200
+ >
201
+ <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">
202
+ <span aria-hidden="true">{integration.name.slice(0, 1)}</span>
203
+ {integration.logoUrl && (
204
+ <img
205
+ src={integration.logoUrl}
206
+ alt=""
207
+ className="absolute h-5 w-5 object-contain"
208
+ onError={(event) => {
209
+ event.currentTarget.hidden = true;
210
+ }}
211
+ />
212
+ )}
213
+ </div>
214
+ <span className="min-w-0 flex-1 leading-snug text-foreground">
215
+ {t(
216
+ hasApiFallback(apiFallback)
217
+ ? "mcpIntegrations.connectSuggestionWithApiToken"
218
+ : "mcpIntegrations.connectSuggestion",
219
+ { name: integration.name },
220
+ )}
221
+ </span>
222
+ <button
223
+ type="button"
224
+ onClick={() => void connect()}
225
+ disabled={connecting}
226
+ 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"
227
+ >
228
+ {connecting && <IconLoader2 className="h-3 w-3 animate-spin" />}
229
+ {!connecting &&
230
+ canStartOAuth(integration) &&
231
+ !hasApiFallback(apiFallback) && (
232
+ <IconPlugConnected className="h-3 w-3" />
233
+ )}
234
+ {!connecting && hasApiFallback(apiFallback) && (
235
+ <IconPlugConnected className="h-3 w-3" />
236
+ )}
237
+ {actionLabel}
238
+ {!connecting &&
239
+ !canStartOAuth(integration) &&
240
+ !hasApiFallback(apiFallback) && (
241
+ <IconArrowUpRight className="h-3 w-3" />
242
+ )}
243
+ </button>
244
+ <button
245
+ type="button"
246
+ onClick={() => setDismissedId(integration.id)}
247
+ className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-background hover:text-foreground"
248
+ aria-label={t("mcpIntegrations.dismissSuggestion")}
249
+ >
250
+ <IconX className="h-3.5 w-3.5" />
251
+ </button>
252
+ </div>
253
+ {error && (
254
+ <div className="mx-auto mb-2 w-[min(100%,680px)] text-[11px] text-destructive">
255
+ {error}
256
+ </div>
257
+ )}
258
+ <McpIntegrationDialog
259
+ open={dialogOpen}
260
+ onOpenChange={setDialogOpen}
261
+ initialIntegrationId={integration.id}
262
+ defaultScope="user"
263
+ canCreateOrgMcp={false}
264
+ hasOrg={Boolean(mcpServersQuery.data?.orgId)}
265
+ onCreateMcpServer={(args) => createMcpServer.mutateAsync(args)}
266
+ onCreated={() => setDismissedId(integration.id)}
267
+ />
268
+ </>
269
+ );
270
+ }