@agent-native/core 0.141.6 → 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 (501) hide show
  1. package/agent-native.eject.json +9 -0
  2. package/corpus/README.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +3 -14
  4. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +11 -6
  5. package/corpus/templates/analytics/.agents/skills/prometheus/SKILL.md +5 -5
  6. package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +19 -0
  7. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +296 -0
  8. package/corpus/templates/analytics/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  9. package/corpus/templates/analytics/.agents/skills/turn-into-skill/SKILL.md +112 -0
  10. package/corpus/templates/analytics/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  11. package/corpus/templates/analytics/AGENTS.md +37 -40
  12. package/corpus/templates/analytics/actions/compose-dashboard.ts +1 -1
  13. package/corpus/templates/analytics/actions/ensure-native-v2-dashboards.ts +1 -1
  14. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +17 -22
  15. package/corpus/templates/analytics/actions/migrate-first-party-analytics-to-bigquery.ts +135 -0
  16. package/corpus/templates/analytics/actions/navigate.ts +5 -6
  17. package/corpus/templates/analytics/actions/provider-api-register.ts +50 -0
  18. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +46 -13
  19. package/corpus/templates/analytics/actions/test-custom-api-connection.ts +106 -0
  20. package/corpus/templates/analytics/actions/update-dashboard.ts +0 -1
  21. package/corpus/templates/analytics/actions/view-screen.ts +0 -20
  22. package/corpus/templates/analytics/app/components/CustomApiCard.tsx +430 -0
  23. package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
  24. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +5 -5
  25. package/corpus/templates/analytics/app/i18n-data.ts +682 -90
  26. package/corpus/templates/analytics/app/lib/native-mcp-exclusions.ts +6 -0
  27. package/corpus/templates/analytics/app/lib/sql-query.ts +33 -6
  28. package/corpus/templates/analytics/app/pages/Agents.tsx +0 -3
  29. package/corpus/templates/analytics/app/pages/DataSources.tsx +4 -0
  30. package/corpus/templates/analytics/app/pages/Settings.tsx +22 -43
  31. package/corpus/templates/analytics/app/pages/settings/settings-search.ts +23 -20
  32. package/corpus/templates/analytics/app/routes/extensions._index.tsx +1 -1
  33. package/corpus/templates/analytics/app/routes/settings.$.tsx +1 -0
  34. package/corpus/templates/analytics/app/routes/team.tsx +1 -1
  35. package/corpus/templates/analytics/changelog/2026-08-05-settings-no-longer-includes-an-unnecessary-about-section.md +6 -0
  36. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-load-reliably-during-background-data-sw.md +6 -0
  37. package/corpus/templates/analytics/changelog/2026-08-06-analytics-dashboards-remain-responsive-while-historical-data.md +6 -0
  38. package/corpus/templates/analytics/changelog/2026-08-06-analytics-query-results-now-render-as-a-table-with-csv-downl.md +6 -0
  39. package/corpus/templates/analytics/changelog/2026-08-06-connect-public-https-custom-apis-and-hand-tested-endpoints-t.md +6 -0
  40. package/corpus/templates/analytics/changelog/2026-08-06-durable-agent-worker-memory.md +6 -0
  41. package/corpus/templates/analytics/changelog/2026-08-06-live-dashboard-panels-use-the-shared-query-timeout.md +6 -0
  42. package/corpus/templates/analytics/changelog/2026-08-06-on-demand-billing-is-available-as-a-native-dashboard-with-ta.md +6 -0
  43. package/corpus/templates/analytics/changelog/2026-08-06-visible-dashboard-names-are-unique.md +6 -0
  44. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +1 -1
  45. package/corpus/templates/analytics/netlify.toml +7 -0
  46. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +4 -0
  47. package/corpus/templates/analytics/scripts/first-party-analytics-bigquery.sql +104 -0
  48. package/corpus/templates/analytics/server/db/index.ts +27 -0
  49. package/corpus/templates/analytics/server/db/schema.ts +10 -0
  50. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -2
  51. package/corpus/templates/analytics/server/lib/dashboards-store.ts +227 -60
  52. package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +1147 -0
  53. package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +34 -15
  54. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +57 -4
  55. package/corpus/templates/analytics/server/lib/native-v2-dashboards.ts +227 -1
  56. package/corpus/templates/analytics/server/lib/real-data-actions.ts +1 -3
  57. package/corpus/templates/analytics/server/plugins/agent-chat.ts +7 -4
  58. package/corpus/templates/analytics/server/plugins/analytics-rollup-backfill-jobs.ts +1 -0
  59. package/corpus/templates/analytics/server/plugins/db.ts +52 -18
  60. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +36 -8
  61. package/corpus/templates/assets/.agents/skills/image-generation/SKILL.md +16 -1
  62. package/corpus/templates/assets/.agents/skills/library-management/SKILL.md +16 -1
  63. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +296 -0
  64. package/corpus/templates/assets/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  65. package/corpus/templates/assets/.agents/skills/turn-into-skill/SKILL.md +112 -0
  66. package/corpus/templates/assets/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  67. package/corpus/templates/assets/AGENTS.md +1 -0
  68. package/corpus/templates/assets/actions/_helpers.ts +12 -0
  69. package/corpus/templates/assets/actions/generate-image.ts +9 -3
  70. package/corpus/templates/assets/actions/import-style-from-url.ts +115 -0
  71. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +3 -1
  72. package/corpus/templates/assets/app/routes/extensions._index.tsx +1 -1
  73. package/corpus/templates/assets/app/routes/settings.$.tsx +1 -0
  74. package/corpus/templates/assets/app/routes/settings.tsx +5 -0
  75. package/corpus/templates/assets/app/routes/team.tsx +1 -1
  76. package/corpus/templates/assets/changelog/2026-08-05-brand-kits-can-import-a-website-s-hydrated-visual-language-a.md +6 -0
  77. package/corpus/templates/assets/changelog/2026-08-05-generated-images-now-hand-off-embeddable-previews-to-other-w.md +6 -0
  78. package/corpus/templates/assets/server/lib/generation.ts +58 -0
  79. package/corpus/templates/assets/shared/api.ts +12 -0
  80. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +296 -0
  81. package/corpus/templates/brain/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  82. package/corpus/templates/brain/.agents/skills/turn-into-skill/SKILL.md +112 -0
  83. package/corpus/templates/brain/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  84. package/corpus/templates/brain/actions/list-connection-providers.ts +24 -3
  85. package/corpus/templates/brain/app/lib/dispatch-links.ts +44 -0
  86. package/corpus/templates/brain/app/routes/extensions._index.tsx +1 -1
  87. package/corpus/templates/brain/app/routes/sources.tsx +15 -7
  88. package/corpus/templates/brain/app/routes/team.tsx +1 -1
  89. package/corpus/templates/brain/app/routes.ts +1 -1
  90. package/corpus/templates/brain/changelog/2026-08-06-brain-provider-setup-links-open-dispatch-correctly-in-standa.md +6 -0
  91. package/corpus/templates/brain/server/plugins/agent-chat.ts +1 -0
  92. package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +26 -0
  93. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +296 -0
  94. package/corpus/templates/calendar/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  95. package/corpus/templates/calendar/.agents/skills/turn-into-skill/SKILL.md +112 -0
  96. package/corpus/templates/calendar/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  97. package/corpus/templates/calendar/AGENTS.md +11 -32
  98. package/corpus/templates/calendar/actions/update-event.ts +107 -1
  99. package/corpus/templates/calendar/app/components/calendar/EventCalendarSelect.tsx +83 -0
  100. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +57 -0
  101. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +59 -73
  102. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +3 -1
  103. package/corpus/templates/calendar/app/hooks/use-events.ts +4 -1
  104. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  105. package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +1 -1
  106. package/corpus/templates/calendar/app/routes/_app.settings.$.tsx +1 -0
  107. package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
  108. package/corpus/templates/calendar/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  109. package/corpus/templates/calendar/changelog/2026-08-06-existing-events-can-move-between-connected-google-account-ca.md +6 -0
  110. package/corpus/templates/calendar/server/lib/google-calendar.ts +101 -0
  111. package/corpus/templates/calendar/server/plugins/agent-chat.ts +7 -1
  112. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  113. package/corpus/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  114. package/corpus/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  115. package/corpus/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  116. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -1
  117. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  118. package/corpus/templates/chat/app/root.tsx +1 -1
  119. package/corpus/templates/chat/app/routes/agent.tsx +7 -7
  120. package/corpus/templates/chat/app/routes/extensions._index.tsx +1 -1
  121. package/corpus/templates/chat/app/routes/settings.$.tsx +1 -0
  122. package/corpus/templates/chat/app/routes/team.tsx +1 -1
  123. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +296 -0
  124. package/corpus/templates/clips/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  125. package/corpus/templates/clips/.agents/skills/turn-into-skill/SKILL.md +112 -0
  126. package/corpus/templates/clips/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  127. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +9 -24
  128. package/corpus/templates/clips/app/components/editor/timeline-geometry.ts +15 -0
  129. package/corpus/templates/clips/app/components/editor/waveform.tsx +4 -17
  130. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  131. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +14 -3
  132. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +1 -1
  133. package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +1 -1
  134. package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +1 -1
  135. package/corpus/templates/clips/app/routes/_app.settings.$.tsx +1 -0
  136. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +28 -38
  137. package/corpus/templates/clips/app/routes/share.$shareId.tsx +21 -27
  138. package/corpus/templates/clips/changelog/2026-08-06-clips-recovers-from-stalled-recording-setup-without-requirin.md +6 -0
  139. package/corpus/templates/clips/changelog/2026-08-06-clips-starts-faster-after-a-deploy-or-idle-period-startup-no.md +6 -0
  140. package/corpus/templates/clips/changelog/2026-08-06-deleting-a-recording-returns-cleanly-to-the-library-and-fit-.md +6 -0
  141. package/corpus/templates/clips/changelog/2026-08-06-hide-clip-insights-from-viewers-without-analytics-access.md +6 -0
  142. package/corpus/templates/clips/desktop/src/app.tsx +48 -20
  143. package/corpus/templates/clips/desktop/src/lib/recorder.ts +275 -74
  144. package/corpus/templates/clips/desktop/src/lib/recording-start-guard.ts +84 -0
  145. package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +14 -4
  146. package/corpus/templates/clips/server/plugins/db.ts +214 -26
  147. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +296 -0
  148. package/corpus/templates/content/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  149. package/corpus/templates/content/.agents/skills/turn-into-skill/SKILL.md +112 -0
  150. package/corpus/templates/content/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  151. package/corpus/templates/content/app/routes/_app.extensions._index.tsx +1 -1
  152. package/corpus/templates/content/app/routes/_app.settings.$.tsx +1 -0
  153. package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
  154. package/corpus/templates/content/e2e/global-setup.ts +1 -1
  155. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +296 -0
  156. package/corpus/templates/crm/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  157. package/corpus/templates/crm/.agents/skills/turn-into-skill/SKILL.md +112 -0
  158. package/corpus/templates/crm/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  159. package/corpus/templates/crm/changelog/2026-08-06-crm-starts-faster-after-a-deploy-or-idle-period-one-time-dat.md +6 -0
  160. package/corpus/templates/crm/server/plugins/db.ts +11 -8
  161. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +36 -1
  162. package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +6 -1
  163. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +296 -0
  164. package/corpus/templates/design/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  165. package/corpus/templates/design/.agents/skills/turn-into-skill/SKILL.md +112 -0
  166. package/corpus/templates/design/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  167. package/corpus/templates/design/actions/analyze-brand-assets.ts +7 -7
  168. package/corpus/templates/design/actions/import-from-url.ts +6 -5
  169. package/corpus/templates/design/app/components/design/LayersPanel.tsx +27 -18
  170. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +2 -2
  171. package/corpus/templates/design/app/pages/Index.tsx +6 -2
  172. package/corpus/templates/design/app/routes/extensions._index.tsx +1 -1
  173. package/corpus/templates/design/app/routes/settings.$.tsx +1 -0
  174. package/corpus/templates/design/app/routes/team.tsx +1 -1
  175. package/corpus/templates/design/changelog/2026-08-05-deleting-a-design-from-the-home-page-no-longer-leaves-the-ap.md +6 -0
  176. package/corpus/templates/design/changelog/2026-08-05-renaming-a-layer-now-focuses-its-name-field-automatically.md +6 -0
  177. package/corpus/templates/design/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-de.md +6 -0
  178. package/corpus/templates/design/e2e/global-setup.ts +1 -1
  179. package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
  180. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +296 -0
  181. package/corpus/templates/dispatch/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  182. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/SKILL.md +112 -0
  183. package/corpus/templates/dispatch/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  184. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
  185. package/corpus/templates/dispatch/app/routes/settings.$.tsx +1 -0
  186. package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
  187. package/corpus/templates/dispatch/changelog/2026-08-06-ready-workspace-apps-stay-one-click-away-in-a-compact-dispat.md +6 -0
  188. package/corpus/templates/dispatch/changelog/2026-08-06-shared-vault-values-and-management-are-now-restricted-to-wor.md +6 -0
  189. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +296 -0
  190. package/corpus/templates/factory/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  191. package/corpus/templates/factory/.agents/skills/turn-into-skill/SKILL.md +112 -0
  192. package/corpus/templates/factory/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  193. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +1 -1
  194. package/corpus/templates/factory/app/routes/extensions._index.tsx +1 -1
  195. package/corpus/templates/factory/app/routes/settings.$.tsx +1 -0
  196. package/corpus/templates/factory/app/routes/team.tsx +1 -1
  197. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +296 -0
  198. package/corpus/templates/forms/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  199. package/corpus/templates/forms/.agents/skills/turn-into-skill/SKILL.md +112 -0
  200. package/corpus/templates/forms/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  201. package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +1 -1
  202. package/corpus/templates/forms/app/routes/_app.settings.$.tsx +1 -0
  203. package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
  204. package/corpus/templates/forms/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  205. package/corpus/templates/forms/server/plugins/agent-chat.ts +4 -0
  206. package/corpus/templates/forms/shared/navigation.ts +1 -1
  207. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +296 -0
  208. package/corpus/templates/macros/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  209. package/corpus/templates/macros/.agents/skills/turn-into-skill/SKILL.md +112 -0
  210. package/corpus/templates/macros/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  211. package/corpus/templates/macros/app/routes/extensions._index.tsx +1 -1
  212. package/corpus/templates/macros/app/routes/settings.$.tsx +1 -0
  213. package/corpus/templates/macros/app/routes/team.tsx +1 -1
  214. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +296 -0
  215. package/corpus/templates/mail/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  216. package/corpus/templates/mail/.agents/skills/turn-into-skill/SKILL.md +112 -0
  217. package/corpus/templates/mail/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  218. package/corpus/templates/mail/app/routes/extensions._index.tsx +1 -1
  219. package/corpus/templates/mail/app/routes/settings.$.tsx +1 -0
  220. package/corpus/templates/mail/changelog/2026-08-06-delegated-requests-continue-in-the-background.md +6 -0
  221. package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
  222. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +296 -0
  223. package/corpus/templates/plan/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  224. package/corpus/templates/plan/.agents/skills/turn-into-skill/SKILL.md +112 -0
  225. package/corpus/templates/plan/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  226. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
  227. package/corpus/templates/plan/app/routes/extensions._index.tsx +1 -1
  228. package/corpus/templates/plan/app/routes/settings.$.tsx +1 -0
  229. package/corpus/templates/plan/app/routes/team.tsx +1 -1
  230. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +48 -5
  231. package/corpus/templates/slides/.agents/skills/design-systems/SKILL.md +40 -2
  232. package/corpus/templates/slides/.agents/skills/image-generation-via-a2a/SKILL.md +6 -0
  233. package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +15 -2
  234. package/corpus/templates/slides/.agents/skills/slide-images/SKILL.md +29 -24
  235. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +296 -0
  236. package/corpus/templates/slides/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  237. package/corpus/templates/slides/.agents/skills/turn-into-skill/SKILL.md +112 -0
  238. package/corpus/templates/slides/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  239. package/corpus/templates/slides/AGENTS.md +7 -9
  240. package/corpus/templates/slides/_gitignore +1 -0
  241. package/corpus/templates/slides/actions/analyze-brand-assets.ts +7 -7
  242. package/corpus/templates/slides/actions/export-pptx.ts +402 -36
  243. package/corpus/templates/slides/actions/import-file.ts +46 -85
  244. package/corpus/templates/slides/actions/import-from-url.ts +6 -6
  245. package/corpus/templates/slides/actions/import-google-slides-reference.ts +271 -12
  246. package/corpus/templates/slides/actions/import-pptx.ts +85 -60
  247. package/corpus/templates/slides/app/components/deck/DeckCard.tsx +10 -13
  248. package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
  249. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +5 -1
  250. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +25 -12
  251. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +112 -57
  252. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +202 -0
  253. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +26 -14
  254. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +176 -0
  255. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +182 -141
  256. package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +1 -0
  257. package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +18 -0
  258. package/corpus/templates/slides/app/components/editor/slide-text-targets.ts +85 -0
  259. package/corpus/templates/slides/app/components/layout/Layout.tsx +3 -0
  260. package/corpus/templates/slides/app/components/onboarding/FirstDeckOnboardingFlow.tsx +13 -3
  261. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +27 -1
  262. package/corpus/templates/slides/app/context/DeckContext.tsx +71 -20
  263. package/corpus/templates/slides/app/global.css +6 -0
  264. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  265. package/corpus/templates/slides/app/lib/create-deck-generation.ts +10 -6
  266. package/corpus/templates/slides/app/lib/deck-preview-frame.ts +15 -0
  267. package/corpus/templates/slides/app/lib/deck-share-links.ts +9 -0
  268. package/corpus/templates/slides/app/lib/export-pptx-client.ts +89 -0
  269. package/corpus/templates/slides/app/lib/slide-animation-elements.ts +3 -0
  270. package/corpus/templates/slides/app/pages/DeckEditor.tsx +17 -0
  271. package/corpus/templates/slides/app/pages/Index.tsx +107 -6
  272. package/corpus/templates/slides/app/routes/extensions._index.tsx +1 -1
  273. package/corpus/templates/slides/app/routes/settings.$.tsx +1 -0
  274. package/corpus/templates/slides/app/routes/team.tsx +1 -1
  275. package/corpus/templates/slides/changelog/2026-08-05-failed-deck-creation-and-reference-uploads-now-recover-clean.md +6 -0
  276. package/corpus/templates/slides/changelog/2026-08-05-slides-recover-completed-generation-results-after-a-sync-hic.md +6 -0
  277. package/corpus/templates/slides/changelog/2026-08-05-website-url-imports-now-capture-hydrated-browser-computed-st.md +6 -0
  278. package/corpus/templates/slides/changelog/2026-08-06-clicking-the-gray-canvas-around-a-slide-clears-its-selection.md +6 -0
  279. package/corpus/templates/slides/changelog/2026-08-06-deck-thumbnails-keep-a-consistent-listing-frame-across-aspec.md +6 -0
  280. package/corpus/templates/slides/changelog/2026-08-06-deep-linked-decks-open-directly-instead-of-being-interrupted.md +6 -0
  281. package/corpus/templates/slides/changelog/2026-08-06-google-slides-exports-now-show-clear-import-steps-when-direc.md +6 -0
  282. package/corpus/templates/slides/changelog/2026-08-06-import-pdf-google-slides-and-powerpoint-decks-directly-from-.md +6 -0
  283. package/corpus/templates/slides/changelog/2026-08-06-imported-powerpoint-exports-keep-text-and-images-editable-an.md +6 -0
  284. package/corpus/templates/slides/changelog/2026-08-06-presentation-prompts-continue-adding-rendered-slides-until-t.md +6 -0
  285. package/corpus/templates/slides/changelog/2026-08-06-public-decks-now-share-read-only-presentation-links-by-defau.md +6 -0
  286. package/corpus/templates/slides/changelog/2026-08-06-slides-offers-a-direct-connect-google-button-when-a-drive-co.md +6 -0
  287. package/corpus/templates/slides/changelog/2026-08-06-slides-preserve-uploaded-pdf-layouts-accept-larger-reference.md +6 -0
  288. package/corpus/templates/slides/changelog/2026-08-06-styled-words-stay-part-of-their-text-box-instead-of-becoming.md +6 -0
  289. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +7 -20
  290. package/corpus/templates/slides/server/handlers/import/html-converter.ts +236 -13
  291. package/corpus/templates/slides/server/handlers/import/pptx-assets.ts +67 -0
  292. package/corpus/templates/slides/server/handlers/import/pptx-parser.ts +2 -0
  293. package/corpus/templates/slides/server/handlers/uploads.ts +7 -3
  294. package/corpus/templates/slides/server/lib/chat-attachments.ts +6 -3
  295. package/corpus/templates/slides/server/lib/emails.ts +7 -2
  296. package/corpus/templates/slides/server/lib/google-docs-error.ts +50 -0
  297. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +1 -0
  298. package/corpus/templates/slides/server/lib/import-asset-storage.ts +127 -0
  299. package/corpus/templates/slides/server/plugins/agent-chat.ts +4 -3
  300. package/corpus/templates/slides/server/routes/api/import-assets/[token].get.ts +70 -0
  301. package/corpus/templates/slides/shared/upload-types.ts +3 -0
  302. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +296 -0
  303. package/corpus/templates/tasks/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  304. package/corpus/templates/tasks/.agents/skills/turn-into-skill/SKILL.md +112 -0
  305. package/corpus/templates/tasks/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  306. package/corpus/templates/tasks/app/components/layout/Header.tsx +3 -1
  307. package/corpus/templates/tasks/app/routes/extensions._index.tsx +1 -1
  308. package/corpus/templates/tasks/app/routes/settings.$.tsx +1 -0
  309. package/dist/agent/engine/ai-sdk-engine.js +49 -3
  310. package/dist/agent/production-agent.d.ts +18 -0
  311. package/dist/agent/production-agent.js +80 -1
  312. package/dist/agent/types.d.ts +7 -0
  313. package/dist/cli/agent-plugin.d.ts +112 -0
  314. package/dist/cli/agent-plugin.js +1081 -0
  315. package/dist/cli/app-skill.js +39 -1
  316. package/dist/cli/code-agent-executor.d.ts +3 -0
  317. package/dist/cli/code-agent-executor.js +51 -13
  318. package/dist/cli/index.js +13 -0
  319. package/dist/cli/templates-meta.js +1 -1
  320. package/dist/client/AgentPanel.d.ts +3 -1
  321. package/dist/client/AgentPanel.js +9 -2
  322. package/dist/client/AssistantChat.d.ts +8 -0
  323. package/dist/client/AssistantChat.js +23 -8
  324. package/dist/client/NewWorkspaceAppFlow.js +1 -0
  325. package/dist/client/agent-chat-adapter.d.ts +1 -1
  326. package/dist/client/agent-chat-adapter.js +153 -7
  327. package/dist/client/agent-page/AgentWorkspaceContent.d.ts +1 -1
  328. package/dist/client/agent-page/AgentWorkspaceContent.js +13 -13
  329. package/dist/client/assistant-ui-recovery.d.ts +2 -1
  330. package/dist/client/assistant-ui-recovery.js +7 -3
  331. package/dist/client/chat/run-recovery.js +5 -1
  332. package/dist/client/embed-auth.js +6 -2
  333. package/dist/client/error-format.js +12 -0
  334. package/dist/client/integrations/IntegrationsPanel.js +40 -6
  335. package/dist/client/onboarding/FirstRunOnboarding.js +11 -4
  336. package/dist/client/org/OrgSwitcher.js +2 -2
  337. package/dist/client/org/TeamPage.js +92 -72
  338. package/dist/client/require-session.d.ts +1 -1
  339. package/dist/client/require-session.js +4 -4
  340. package/dist/client/resources/McpConnectionSuggestion.d.ts +1 -0
  341. package/dist/client/resources/McpConnectionSuggestion.js +27 -10
  342. package/dist/client/resources/McpIntegrationDialog.js +77 -45
  343. package/dist/client/resources/mcp-integration-catalog.d.ts +13 -1
  344. package/dist/client/resources/mcp-integration-catalog.js +255 -2
  345. package/dist/client/resources/mcp-integration-logos.js +18 -2
  346. package/dist/client/resources/use-mcp-servers.d.ts +5 -0
  347. package/dist/client/resources/use-mcp-servers.js +36 -0
  348. package/dist/client/settings/AccountSettingsCard.js +42 -36
  349. package/dist/client/settings/AutomationsSection.js +1 -1
  350. package/dist/client/settings/DemoModeSection.d.ts +3 -1
  351. package/dist/client/settings/DemoModeSection.js +4 -1
  352. package/dist/client/settings/ExtensionsSettingsContent.js +1 -1
  353. package/dist/client/settings/SchedulingTimezoneField.d.ts +3 -1
  354. package/dist/client/settings/SchedulingTimezoneField.js +9 -5
  355. package/dist/client/settings/SettingsPanel.d.ts +4 -1
  356. package/dist/client/settings/SettingsPanel.js +21 -21
  357. package/dist/client/settings/SettingsTabsPage.d.ts +2 -2
  358. package/dist/client/settings/SettingsTabsPage.js +98 -45
  359. package/dist/client/settings/VoiceTranscriptionSection.js +6 -1
  360. package/dist/client/settings/useSettingsPanelController.js +47 -8
  361. package/dist/collab/routes.d.ts +1 -1
  362. package/dist/db/client.d.ts +9 -0
  363. package/dist/db/client.js +51 -16
  364. package/dist/db/create-get-db.js +2 -2
  365. package/dist/db/ddl-guard.d.ts +11 -10
  366. package/dist/db/ddl-guard.js +40 -12
  367. package/dist/deploy/build.d.ts +2 -0
  368. package/dist/deploy/build.js +97 -4
  369. package/dist/deploy/workspace-deploy.js +0 -2
  370. package/dist/guards/no-env-credentials.js +9 -0
  371. package/dist/ingestion/index.d.ts +1 -1
  372. package/dist/ingestion/pptx.d.ts +68 -0
  373. package/dist/ingestion/pptx.js +660 -213
  374. package/dist/ingestion/website.d.ts +30 -0
  375. package/dist/integrations/plugin.js +9 -6
  376. package/dist/localization/default-messages.d.ts +59 -0
  377. package/dist/localization/default-messages.js +62 -2
  378. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  379. package/dist/mcp-client/oauth-routes.d.ts +2 -0
  380. package/dist/mcp-client/oauth-routes.js +74 -7
  381. package/dist/mcp-client/routes.d.ts +1 -0
  382. package/dist/mcp-client/routes.js +49 -0
  383. package/dist/navigation/index.js +16 -5
  384. package/dist/notifications/routes.d.ts +1 -1
  385. package/dist/observability/routes.d.ts +3 -3
  386. package/dist/onboarding/app-profile.js +11 -0
  387. package/dist/progress/routes.d.ts +1 -1
  388. package/dist/provider-api/actions/custom-provider-registration.d.ts +13 -13
  389. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  390. package/dist/resources/store.js +15 -1
  391. package/dist/scripts/call-agent.js +45 -4
  392. package/dist/secrets/routes.d.ts +6 -6
  393. package/dist/server/agent-chat/action-filters-a2a.d.ts +1 -1
  394. package/dist/server/agent-chat/action-filters-a2a.js +36 -1
  395. package/dist/server/agent-chat-plugin.js +29 -8
  396. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  397. package/dist/server/auth.js +55 -17
  398. package/dist/server/better-auth-instance.js +5 -3
  399. package/dist/server/core-routes-plugin.d.ts +8 -1
  400. package/dist/server/core-routes-plugin.js +28 -3
  401. package/dist/server/credential-provider.d.ts +3 -3
  402. package/dist/server/credential-provider.js +90 -4
  403. package/dist/server/identity-sso.js +2 -1
  404. package/dist/server/onboarding-html.d.ts +2 -0
  405. package/dist/server/onboarding-html.js +171 -62
  406. package/dist/server/realtime-token.d.ts +1 -1
  407. package/dist/server/self-dispatch.d.ts +5 -4
  408. package/dist/server/self-dispatch.js +25 -14
  409. package/dist/server/ssr-handler.d.ts +1 -1
  410. package/dist/server/ssr-handler.js +1 -1
  411. package/dist/server/workspace-provider-oauth.js +1 -1
  412. package/dist/setup-connections/onboarding.js +1 -1
  413. package/dist/shared/cache-control.d.ts +26 -2
  414. package/dist/shared/cache-control.js +43 -2
  415. package/dist/shared/index.d.ts +1 -1
  416. package/dist/shared/index.js +1 -1
  417. package/dist/shared/password-policy.d.ts +3 -0
  418. package/dist/shared/password-policy.js +3 -0
  419. package/dist/shared/sign-in-journey.d.ts +5 -2
  420. package/dist/shared/sign-in-journey.js +10 -4
  421. package/dist/sharing/actions/set-resource-visibility.js +16 -4
  422. package/dist/sharing/registry.d.ts +14 -0
  423. package/dist/styles/agent-native.css +6 -0
  424. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  425. package/dist/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  426. package/dist/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  427. package/dist/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  428. package/dist/templates/chat/app/components/layout/Layout.tsx +1 -1
  429. package/dist/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  430. package/dist/templates/chat/app/root.tsx +1 -1
  431. package/dist/templates/chat/app/routes/agent.tsx +7 -7
  432. package/dist/templates/chat/app/routes/extensions._index.tsx +1 -1
  433. package/dist/templates/chat/app/routes/settings.$.tsx +1 -0
  434. package/dist/templates/chat/app/routes/team.tsx +1 -1
  435. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  436. package/dist/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  437. package/dist/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  438. package/dist/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  439. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  440. package/dist/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  441. package/dist/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  442. package/dist/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  443. package/dist/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  444. package/dist/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
  445. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
  446. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  447. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  448. package/dist/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  449. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  450. package/dist/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  451. package/dist/templates/workspace-root/AGENTS.md +7 -0
  452. package/dist/user-profile/actions/change-password.js +8 -3
  453. package/dist/user-profile/actions/set-password.js +5 -1
  454. package/dist/vite/action-types-plugin.js +59 -0
  455. package/docs/content/authentication.mdx +4 -5
  456. package/docs/content/skills-guide.mdx +13 -0
  457. package/docs/content/template-analytics-developers.mdx +1 -1
  458. package/docs/content/template-calendar-developers.mdx +1 -1
  459. package/docs/content/template-chat-developers.mdx +2 -2
  460. package/docs/content/template-content-developers.mdx +1 -1
  461. package/docs/content/template-mail-developers.mdx +1 -1
  462. package/docs/content/template-plan-developers.mdx +1 -1
  463. package/docs/content/toolkit-command-navigation.mdx +6 -6
  464. package/docs/content/toolkit-org-team.mdx +1 -1
  465. package/docs/content/toolkit-settings.mdx +8 -8
  466. package/docs/content/toolkit-setup-connections.mdx +1 -1
  467. package/package.json +6 -2
  468. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +296 -0
  469. package/src/templates/chat/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  470. package/src/templates/chat/.agents/skills/turn-into-skill/SKILL.md +112 -0
  471. package/src/templates/chat/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  472. package/src/templates/chat/app/components/layout/Layout.tsx +1 -1
  473. package/src/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  474. package/src/templates/chat/app/root.tsx +1 -1
  475. package/src/templates/chat/app/routes/agent.tsx +7 -7
  476. package/src/templates/chat/app/routes/extensions._index.tsx +1 -1
  477. package/src/templates/chat/app/routes/settings.$.tsx +1 -0
  478. package/src/templates/chat/app/routes/team.tsx +1 -1
  479. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +296 -0
  480. package/src/templates/default/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  481. package/src/templates/default/.agents/skills/turn-into-skill/SKILL.md +112 -0
  482. package/src/templates/default/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  483. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +296 -0
  484. package/src/templates/headless/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  485. package/src/templates/headless/.agents/skills/turn-into-skill/SKILL.md +112 -0
  486. package/src/templates/headless/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  487. package/src/templates/workspace-core/.agents/skills/adding-workspace-apps/SKILL.md +6 -0
  488. package/src/templates/workspace-core/.agents/skills/address-feedback/SKILL.md +37 -6
  489. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +4 -2
  490. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +51 -0
  491. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +296 -0
  492. package/src/templates/workspace-core/.agents/skills/turn-into-app/agents/openai.yaml +4 -0
  493. package/src/templates/workspace-core/.agents/skills/turn-into-skill/SKILL.md +112 -0
  494. package/src/templates/workspace-core/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
  495. package/src/templates/workspace-root/AGENTS.md +7 -0
  496. package/corpus/templates/analytics/.agents/skills/dashboard-management/references/template-catalog-and-demo.md +0 -62
  497. package/corpus/templates/analytics/actions/install-dashboard-template.ts +0 -369
  498. package/corpus/templates/analytics/actions/list-dashboard-templates.ts +0 -47
  499. package/corpus/templates/analytics/actions/list-native-v2-dashboard-templates.ts +0 -34
  500. package/corpus/templates/analytics/app/routes/catalog.tsx +0 -240
  501. package/src/templates/default/actions/navigate.spec.ts +0 -53
@@ -131,8 +131,30 @@ export const BACKGROUND_FOLLOW_IDLE_TIMEOUT_MS = 210_000;
131
131
  // every poll tick and the follow loop never exits (prod: 26 chained runs over
132
132
  // 22 minutes, all error:stale_run, user watching a spinner). These bound the
133
133
  // whole turn instead, and an identical repeated failure counts as no progress.
134
- export const MAX_FOLLOWED_BACKGROUND_RUNS = 6;
135
- export const MAX_BACKGROUND_FOLLOW_WALL_TIME_MS = 10 * 60_000;
134
+ //
135
+ // CLIENT-ABOVE-SERVER INVARIANT (asserted in agent-chat-adapter.spec.ts).
136
+ // These are a backstop for a server that has gone silent in a way the idle
137
+ // timeout misses — NOT the primary limit. They must stay ABOVE the server's
138
+ // own ceilings so the server, which can actually tell progress from looping,
139
+ // always terminates a turn first and writes a truthful terminal reason:
140
+ // BACKGROUND_SOFT_TIMEOUT_CEILING_MS (13 min, run-manager.ts) — one chunk
141
+ // MAX_TURN_WALL_CLOCK_MS (90 min, production-agent.ts) — one turn
142
+ // MAX_BACKGROUND_RUN_CONTINUATIONS (20, production-agent.ts)
143
+ //
144
+ // They were originally set to 10 min / 6 runs, which put the whole-turn client
145
+ // budget BELOW the 13-minute ceiling of a single legal chunk. Any turn needing
146
+ // a second full-length chunk was killed by the client while the server was
147
+ // healthy and had 80 minutes left — measured in prod as turns dying at 11-25
148
+ // minutes with `last_progress_at` tracking the abort, i.e. still streaming
149
+ // tokens and completing tools when the client gave up. That is the top
150
+ // non-auth cause of "the chat just stopped" reports.
151
+ //
152
+ // Killing a turn that is NOT progressing is already covered twice over, by
153
+ // mechanisms that read progress rather than a clock: the 210s idle timeout
154
+ // above, and MAX_REPEATED_BACKGROUND_TERMINAL_REASONS below. Do not re-tighten
155
+ // these two to catch a stuck turn — fix the progress signal instead.
156
+ export const MAX_FOLLOWED_BACKGROUND_RUNS = 24;
157
+ export const MAX_BACKGROUND_FOLLOW_WALL_TIME_MS = 95 * 60_000;
136
158
  const MAX_REPEATED_BACKGROUND_TERMINAL_REASONS = 3;
137
159
  // A re-observed terminal run whose outcome would be an ERROR (never a
138
160
  // genuine "done" success) gets a short extra grace window before the follow
@@ -958,6 +980,65 @@ class AgentStartupTimeoutError extends Error {
958
980
  this.timeoutMs = timeoutMs;
959
981
  }
960
982
  }
983
+ /**
984
+ * Keep the server's error contract intact across the fetch boundary. In
985
+ * particular, a POST response with `retryable: false` must not be fed into the
986
+ * generic reconnect/continuation path: replaying a mutation after the server
987
+ * has started processing it can duplicate work. The previous code discarded
988
+ * this metadata and exposed the raw JSON body to the user instead.
989
+ */
990
+ class AgentChatHttpError extends Error {
991
+ errorCode;
992
+ details;
993
+ retryable;
994
+ upgradeUrl;
995
+ constructor(error) {
996
+ super(error.message);
997
+ this.name = "AgentChatHttpError";
998
+ this.errorCode = error.errorCode;
999
+ this.details = error.details;
1000
+ this.retryable = error.retryable;
1001
+ this.upgradeUrl = error.upgradeUrl;
1002
+ }
1003
+ }
1004
+ function parseStructuredAgentChatError(body) {
1005
+ if (!body.trim())
1006
+ return null;
1007
+ try {
1008
+ const parsed = JSON.parse(body);
1009
+ if (!parsed || typeof parsed !== "object")
1010
+ return null;
1011
+ const message = typeof parsed.error === "string"
1012
+ ? parsed.error
1013
+ : typeof parsed.message === "string"
1014
+ ? parsed.message
1015
+ : "";
1016
+ if (!message)
1017
+ return null;
1018
+ return {
1019
+ message,
1020
+ ...(typeof parsed.code === "string"
1021
+ ? { errorCode: parsed.code }
1022
+ : typeof parsed.errorCode === "string"
1023
+ ? { errorCode: parsed.errorCode }
1024
+ : {}),
1025
+ ...(typeof parsed.details === "string"
1026
+ ? { details: parsed.details }
1027
+ : {}),
1028
+ ...(typeof parsed.retryable === "boolean"
1029
+ ? { retryable: parsed.retryable }
1030
+ : {}),
1031
+ ...(typeof parsed.upgradeUrl === "string"
1032
+ ? { upgradeUrl: parsed.upgradeUrl }
1033
+ : {}),
1034
+ };
1035
+ }
1036
+ catch (error) {
1037
+ if (error instanceof SyntaxError)
1038
+ return null;
1039
+ throw error;
1040
+ }
1041
+ }
961
1042
  async function fetchWithStartupTimeout(input, init, timeoutMs, abortSignal) {
962
1043
  if (abortSignal.aborted) {
963
1044
  throw new DOMException("The operation was aborted.", "AbortError");
@@ -2185,7 +2266,12 @@ export function createAgentChatAdapter(options) {
2185
2266
  if (Date.now() - followStartedAt >=
2186
2267
  MAX_BACKGROUND_FOLLOW_WALL_TIME_MS) {
2187
2268
  yield* stopBackgroundTurnBeforeReporting({
2188
- message: `The agent kept restarting this step for ${Math.round(MAX_BACKGROUND_FOLLOW_WALL_TIME_MS / 60_000)} minutes without finishing it. It was stopped so you can retry from the preserved chat context — a smaller request usually gets through.`,
2269
+ // Says only what this backstop actually knows. It fires on a
2270
+ // clock, so it cannot tell a looping turn from one that was
2271
+ // still working — the old copy asserted "kept restarting
2272
+ // without finishing", which prod runs contradicted: they were
2273
+ // streaming tokens right up to the abort.
2274
+ message: `This turn ran for ${Math.round(MAX_BACKGROUND_FOLLOW_WALL_TIME_MS / 60_000)} minutes without finishing, so it was stopped. Your chat context is preserved — retrying, or splitting this into smaller requests, usually gets through.`,
2189
2275
  errorCode: "background_follow_time_budget_exhausted",
2190
2276
  details: `followed_runs: ${followedRunIds.size}`,
2191
2277
  });
@@ -2716,7 +2802,7 @@ export function createAgentChatAdapter(options) {
2716
2802
  const body = await res.text();
2717
2803
  const parsed = JSON.parse(body);
2718
2804
  if (parsed.error) {
2719
- throw new Error(parsed.error);
2805
+ throw new Error(String(parsed.error));
2720
2806
  }
2721
2807
  }
2722
2808
  catch (e) {
@@ -2850,6 +2936,7 @@ export function createAgentChatAdapter(options) {
2850
2936
  let errorText = `Server error: ${res.status}`;
2851
2937
  try {
2852
2938
  const body = await res.text();
2939
+ const structuredError = parseStructuredAgentChatError(body);
2853
2940
  if (isAuthErrorMessage(body)) {
2854
2941
  if (await tryRecoverAuthOnce()) {
2855
2942
  continue;
@@ -2893,11 +2980,25 @@ export function createAgentChatAdapter(options) {
2893
2980
  "Agent chat endpoint not found. Make sure the agent-chat plugin is loaded in server/plugins/.";
2894
2981
  }
2895
2982
  else if (body) {
2896
- errorText =
2897
- body.length > 200 ? body.slice(0, 200) + "..." : body;
2983
+ // A non-retryable structured response is a terminal server
2984
+ // outcome. Preserve its code and stop before the generic
2985
+ // connection recovery below can POST the same turn again.
2986
+ if (structuredError &&
2987
+ (structuredError.retryable === false ||
2988
+ structuredError.errorCode === "database_unavailable")) {
2989
+ throw new AgentChatHttpError(structuredError);
2990
+ }
2991
+ errorText = structuredError
2992
+ ? structuredError.message
2993
+ : body.length > 200
2994
+ ? body.slice(0, 200) + "..."
2995
+ : body;
2898
2996
  }
2899
2997
  }
2900
- catch { }
2998
+ catch (error) {
2999
+ if (error instanceof AgentChatHttpError)
3000
+ throw error;
3001
+ }
2901
3002
  throw new Error(errorText);
2902
3003
  }
2903
3004
  if (!res.body) {
@@ -3068,6 +3169,51 @@ export function createAgentChatAdapter(options) {
3068
3169
  return;
3069
3170
  continue;
3070
3171
  }
3172
+ if (err instanceof AgentChatHttpError) {
3173
+ const normalized = normalizeChatError(err.message, err.errorCode);
3174
+ const details = [err.details, normalized.details]
3175
+ .filter(Boolean)
3176
+ .join("\n\n");
3177
+ const runError = {
3178
+ message: normalized.message,
3179
+ ...(details ? { details } : {}),
3180
+ ...(err.errorCode ? { errorCode: err.errorCode } : {}),
3181
+ recoverable: err.retryable === true,
3182
+ ...(runId ? { runId } : {}),
3183
+ };
3184
+ captureChatClientError(err, "server-error", {
3185
+ ...(err.errorCode ? { errorCode: err.errorCode } : {}),
3186
+ retryable: err.retryable ?? false,
3187
+ });
3188
+ if (typeof window !== "undefined") {
3189
+ window.dispatchEvent(new CustomEvent("agent-chat:run-error", {
3190
+ detail: {
3191
+ ...runError,
3192
+ ...(err.upgradeUrl ? { upgradeUrl: err.upgradeUrl } : {}),
3193
+ tabId,
3194
+ },
3195
+ }));
3196
+ }
3197
+ settleInterruptedToolCalls(content, undefined, {
3198
+ includeActivity: true,
3199
+ });
3200
+ content.push({
3201
+ type: "text",
3202
+ text: `Something went wrong: ${normalized.message}`,
3203
+ });
3204
+ yield {
3205
+ content: [...content],
3206
+ status: {
3207
+ type: "incomplete",
3208
+ reason: "error",
3209
+ },
3210
+ metadata: {
3211
+ custom: { ...(runId ? { runId } : {}), runError },
3212
+ },
3213
+ };
3214
+ clearActiveRun();
3215
+ return;
3216
+ }
3071
3217
  const errMsg = err instanceof Error ? err.message : "Something went wrong.";
3072
3218
  const isAuthError = isAuthErrorMessage(errMsg);
3073
3219
  // Don't try to reconnect for auth/client errors — show error directly
@@ -1,5 +1,5 @@
1
1
  import { type ReactNode } from "react";
2
- export type AgentWorkspaceTab = "overview" | "resources" | "automations" | "agents" | "access";
2
+ export type AgentWorkspaceTab = "overview" | "resources" | "automations" | "agents";
3
3
  export declare function AgentWorkspaceContent({ overview, className, activeTab, }: {
4
4
  overview: ReactNode;
5
5
  activeTab: AgentWorkspaceTab;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconBook2, IconBolt, IconChecklist, IconFolder, IconHierarchy2, IconHistory, IconNotes, IconShieldLock, IconTopologyRing2, } from "@tabler/icons-react";
2
+ import { IconBook2, IconBolt, IconChecklist, IconFolder, IconHierarchy2, IconHistory, IconNotes, IconTopologyRing2, } from "@tabler/icons-react";
3
3
  import { lazy, Suspense, useEffect, useState } from "react";
4
4
  import { AgentsSection } from "../settings/AgentsSection.js";
5
5
  import { cn } from "../utils.js";
@@ -21,7 +21,6 @@ const HUB_TABS = [
21
21
  { id: "resources", label: "Resources", icon: IconFolder },
22
22
  { id: "automations", label: "Automations", icon: IconBolt },
23
23
  { id: "agents", label: "Connected agents", icon: IconTopologyRing2 },
24
- { id: "access", label: "Access", icon: IconShieldLock },
25
24
  ];
26
25
  const RESOURCE_IDS = new Set(RESOURCE_TABS.map((tab) => tab.id));
27
26
  function normalizeHash(value) {
@@ -31,9 +30,15 @@ function initialHubState() {
31
30
  if (typeof window === "undefined") {
32
31
  return { tab: "overview", resource: "files" };
33
32
  }
33
+ const pathParts = window.location.pathname.split("/").filter(Boolean);
34
+ const settingsIndex = pathParts.indexOf("settings");
35
+ const settingsPath = settingsIndex === -1 ? [] : pathParts.slice(settingsIndex + 1);
36
+ const routeParts = settingsPath[0] === "agent" ? settingsPath : ["agent", ...settingsPath];
34
37
  const hash = normalizeHash(window.location.hash);
35
- const parts = hash.split(":");
36
- const scoped = parts[0] === "agent";
38
+ const hashParts = hash.split(":");
39
+ const pathScoped = settingsPath[0] === "agent";
40
+ const scoped = pathScoped || hashParts[0] === "agent";
41
+ const parts = pathScoped ? routeParts : hashParts;
37
42
  const requested = scoped ? parts[1] : hash;
38
43
  const resource = scoped && RESOURCE_IDS.has(parts[2])
39
44
  ? parts[2]
@@ -54,8 +59,6 @@ function initialHubState() {
54
59
  requested === "remote-agents") {
55
60
  return { tab: "agents", resource };
56
61
  }
57
- if (requested === "access")
58
- return { tab: "access", resource };
59
62
  return { tab: "overview", resource };
60
63
  }
61
64
  function ResourceContent({ resource }) {
@@ -65,8 +68,8 @@ function ResourceContent({ resource }) {
65
68
  const selected = tab.id === resource;
66
69
  return (_jsxs("button", { type: "button", onClick: () => {
67
70
  if (typeof window !== "undefined") {
68
- window.history.pushState(null, "", `${window.location.pathname}${window.location.search}#agent:resources:${tab.id}`);
69
- window.dispatchEvent(new Event("hashchange"));
71
+ window.history.pushState(null, "", `/settings/agent/resources/${tab.id}${window.location.search}`);
72
+ window.dispatchEvent(new Event("popstate"));
70
73
  }
71
74
  }, className: cn("inline-flex shrink-0 items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors", selected
72
75
  ? "bg-accent text-foreground"
@@ -75,9 +78,6 @@ function ResourceContent({ resource }) {
75
78
  ? "Add context the agent can use across conversations."
76
79
  : "Manage the resources that shape how the agent works." })] }), _jsx(Suspense, { fallback: _jsx("div", { className: "h-48 animate-pulse rounded-xl border border-border bg-muted/20" }), children: _jsx(ResourcesPanel, { showMcpServers: false, resourceFilter: resource, resourceTreeVariant: "collection", scope: "personal" }, resource) })] }));
77
80
  }
78
- function AccessContent() {
79
- return (_jsx("div", { children: _jsx("div", { className: "rounded-xl border border-border/70 bg-card text-card-foreground", children: _jsx("div", { className: "px-5 py-5 sm:px-6", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-lg border border-border bg-background text-muted-foreground", children: _jsx(IconShieldLock, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: "Agent access" }), _jsx("p", { className: "mt-1 text-sm leading-5 text-muted-foreground", children: "Use the agent card and MCP endpoints from connected clients." })] })] }) }) }) }));
80
- }
81
81
  export function AgentWorkspaceContent({ overview, className, activeTab, }) {
82
82
  const [{ resource }, setState] = useState(initialHubState);
83
83
  useEffect(() => {
@@ -98,8 +98,8 @@ export function AgentWorkspaceContent({ overview, className, activeTab, }) {
98
98
  ? "Schedule and manage agent tasks."
99
99
  : activeTab === "agents"
100
100
  ? "Connect agents to delegate work from chat."
101
- : "Control how other apps and agents access this agent.";
102
- return (_jsxs("div", { className: cn("w-full space-y-6", className), children: [_jsxs("header", { className: "space-y-1", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight text-foreground", children: activeTab === "overview" ? "Agent" : page?.label }), _jsx("p", { className: "text-sm leading-5 text-muted-foreground", children: pageDescription })] }), activeTab === "overview" && overview, activeTab === "resources" && _jsx(ResourceContent, { resource: resource }), activeTab === "automations" && (_jsx(Suspense, { fallback: _jsx("div", { className: "h-48 animate-pulse rounded-xl border border-border bg-muted/20" }), children: _jsx(AgentJobsTab, { scope: "user", canManageOrg: true, hideHeader: true }) })), activeTab === "agents" && _jsx(AgentsSection, {}), activeTab === "access" && _jsx(AccessContent, {})] }));
101
+ : "Configure how your agent works, what it knows, and what it can do.";
102
+ return (_jsxs("div", { className: cn("w-full space-y-6", className), children: [_jsxs("header", { className: "space-y-1", children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight text-foreground", children: activeTab === "overview" ? "Agent" : page?.label }), _jsx("p", { className: "text-sm leading-5 text-muted-foreground", children: pageDescription })] }), activeTab === "overview" && overview, activeTab === "resources" && _jsx(ResourceContent, { resource: resource }), activeTab === "automations" && (_jsx(Suspense, { fallback: _jsx("div", { className: "h-48 animate-pulse rounded-xl border border-border bg-muted/20" }), children: _jsx(AgentJobsTab, { scope: "user", canManageOrg: true, hideHeader: true }) })), activeTab === "agents" && _jsx(AgentsSection, {})] }));
103
103
  }
104
104
  export function agentWorkspaceTabHash(tab) {
105
105
  return `agent:${tab}`;
@@ -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
  }
@@ -227,7 +227,11 @@ export function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDism
227
227
  const canRecover = info.recoverable === true;
228
228
  const shouldShowBuilderReconnect = isBuilderReconnectRunError(info);
229
229
  const isProviderAuthError = isProviderAuthenticationError([info.message, info.details].filter(Boolean).join("\n"), info.errorCode);
230
- const canRetry = canRecover || isProviderAuthError;
230
+ // Blocked on something the reader goes and fixes elsewhere, then comes back
231
+ // to. Without a retry the card is a dead end and its own copy ("then retry")
232
+ // points at a button that isn't there.
233
+ const isUnblockableExternally = info.errorCode === "email_verification_required";
234
+ const canRetry = canRecover || isProviderAuthError || isUnblockableExternally;
231
235
  const builderReconnectResolved = shouldShowBuilderReconnect &&
232
236
  builderReconnect.hasFetchedStatus &&
233
237
  builderReconnect.configured;
@@ -1,4 +1,5 @@
1
1
  import { EMBED_MODE_QUERY_PARAM, EMBED_START_PATH, EMBED_TARGET_HEADER, EMBED_TARGET_QUERY_PARAM, EMBED_TOKEN_QUERY_PARAM, MCP_APP_CHAT_BRIDGE_QUERY_PARAM, } from "../shared/embed-auth.js";
2
+ import { SIGN_IN_ENTRY_PATH, SIGN_IN_LEGACY_ENTRY_PATH, } from "../shared/sign-in-journey.js";
2
3
  let installed = false;
3
4
  let memoryToken = null;
4
5
  let mcpChatBridgeActive = false;
@@ -322,9 +323,12 @@ function shouldGuardAuthFailure(method, url) {
322
323
  if (url.pathname === EMBED_START_PATH)
323
324
  return false;
324
325
  // Suffix, not equality: an app mounted under a base path serves
325
- // `/<app>/_agent-native/sign-in`, which the old exact match never matched.
326
- if (url.pathname.endsWith("/_agent-native/sign-in"))
326
+ // `/<app>/sign-in` (or the legacy framework path), which an exact match
327
+ // would miss.
328
+ if (url.pathname.endsWith(SIGN_IN_ENTRY_PATH) ||
329
+ url.pathname.endsWith(SIGN_IN_LEGACY_ENTRY_PATH)) {
327
330
  return false;
331
+ }
328
332
  return true;
329
333
  }
330
334
  function activeAuthFailure(record) {
@@ -100,6 +100,18 @@ export function normalizeChatError(errorMessage, errorCode) {
100
100
  details: text,
101
101
  };
102
102
  }
103
+ // Reaches us as a bare gateway 403 with no upgradeUrl, so before this case
104
+ // it fell all the way through to the raw upstream sentence under a generic
105
+ // "The agent hit an error" headline, with no retry and no action — a dead
106
+ // end. It was the single largest cause of turns ending without an answer in
107
+ // one app, and reads to the user as the chat being broken rather than as
108
+ // something one person can fix in a minute.
109
+ if (code === "email_verification_required") {
110
+ return {
111
+ message: "AI is paused until an email address in this workspace is verified. Check the inbox for the verification link, then retry.",
112
+ details: text,
113
+ };
114
+ }
103
115
  // A model/parameter combination this provider will never accept. Retrying is
104
116
  // pointless and the raw sentence names an API surface the reader has no way
105
117
  // to act on, so say what they can actually change.
@@ -1,12 +1,12 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { IconPlus, IconBrandSlack, IconBrandTelegram, IconBrandWhatsapp, IconBrandGoogleDrive, IconTerminal2, IconBuildingSkyscraper, IconCopy, IconCheck, IconChevronLeft, IconChevronRight, IconExternalLink, IconCircleCheck, IconInfoCircle, IconSearch, IconServer, } from "@tabler/icons-react";
2
+ import { IconPlus, IconBrandSlack, IconBrandTelegram, IconBrandWhatsapp, IconBrandGoogleDrive, IconTerminal2, IconBuildingSkyscraper, IconCopy, IconCheck, IconChevronLeft, IconChevronRight, IconExternalLink, IconCircleCheck, IconInfoCircle, IconSearch, IconServer, IconLoader2, IconRefresh, } from "@tabler/icons-react";
3
3
  import { useState, useCallback, useEffect, useMemo } from "react";
4
4
  import { agentNativePath } from "../api-path.js";
5
5
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
6
6
  import { useT } from "../i18n.js";
7
7
  import { getDefaultMcpIntegrations, } from "../resources/mcp-integration-catalog.js";
8
8
  import { McpIntegrationDialog } from "../resources/McpIntegrationDialog.js";
9
- import { useCreateMcpServer, useDeleteMcpServer, useMcpServers, } from "../resources/use-mcp-servers.js";
9
+ import { useCreateMcpServer, useDeleteMcpServer, useMcpServers, useReconnectMcpServer, } from "../resources/use-mcp-servers.js";
10
10
  import { useIntegrationStatus, } from "./useIntegrationStatus.js";
11
11
  import { isNonPublicWebhookUrl } from "./webhook-url.js";
12
12
  const PLATFORMS = [
@@ -257,12 +257,19 @@ function McpLogo({ integration }) {
257
257
  const [failed, setFailed] = useState(false);
258
258
  return (_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg border border-border/70 bg-background text-xs font-semibold text-muted-foreground", children: failed ? (integration.name.slice(0, 1)) : (_jsx("img", { src: integration.logoUrl, alt: "", loading: "lazy", decoding: "async", className: "size-7 object-contain", onError: () => setFailed(true) })) }));
259
259
  }
260
- function McpServerStatus({ server }) {
260
+ function McpServerStatus({ server, onReconnect, reconnecting = false, reconnectError, }) {
261
+ const t = useT();
261
262
  if (server.status.state === "connected") {
262
263
  return (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-emerald-600 dark:text-emerald-400", children: [_jsx("span", { className: "size-1.5 rounded-full bg-emerald-500" }), "Connected \u00B7 ", server.status.toolCount, " tool", server.status.toolCount === 1 ? "" : "s"] }));
263
264
  }
264
265
  if (server.status.state === "error") {
265
- return (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-destructive", children: [_jsx("span", { className: "size-1.5 rounded-full bg-destructive" }), "Connection error"] }));
266
+ return (_jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-2 sm:flex-row sm:items-start sm:justify-between", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "inline-flex items-center gap-1.5 text-xs text-destructive", children: [_jsx("span", { className: "size-1.5 rounded-full bg-destructive" }), t("mcpIntegrations.connectionError")] }), _jsx("p", { className: "mt-1 max-w-3xl break-words text-xs leading-5 text-destructive/85", children: t("mcpIntegrations.connectionErrorReason", {
267
+ reason: server.status.error,
268
+ }) }), reconnectError && (_jsx("p", { className: "mt-1 break-words text-xs leading-5 text-destructive", children: t("mcpIntegrations.reconnectFailed", {
269
+ error: reconnectError,
270
+ }) }))] }), onReconnect && (_jsxs("button", { type: "button", onClick: onReconnect, disabled: reconnecting, className: "inline-flex shrink-0 items-center gap-1.5 rounded-md border border-border bg-background px-2.5 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-wait disabled:opacity-60", children: [reconnecting ? (_jsx(IconLoader2, { className: "size-3.5 animate-spin" })) : (_jsx(IconRefresh, { className: "size-3.5" })), reconnecting
271
+ ? t("mcpIntegrations.reconnecting")
272
+ : t("mcpIntegrations.reconnect")] }))] }));
266
273
  }
267
274
  return (_jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs text-muted-foreground", children: [_jsx("span", { className: "size-1.5 rounded-full bg-muted-foreground/50" }), "Status unknown"] }));
268
275
  }
@@ -273,10 +280,13 @@ function McpIntegrationsSection({ query }) {
273
280
  const serversQuery = useMcpServers();
274
281
  const createServer = useCreateMcpServer();
275
282
  const deleteServer = useDeleteMcpServer();
283
+ const reconnectServer = useReconnectMcpServer();
276
284
  const [dialogOpen, setDialogOpen] = useState(false);
277
285
  const [initialIntegrationId, setInitialIntegrationId] = useState(null);
278
286
  const [deleteTarget, setDeleteTarget] = useState(null);
279
287
  const [deleteError, setDeleteError] = useState(null);
288
+ const [reconnectingKey, setReconnectingKey] = useState(null);
289
+ const [reconnectError, setReconnectError] = useState(null);
280
290
  const catalog = useMemo(() => getDefaultMcpIntegrations(), []);
281
291
  const normalizedQuery = query.trim().toLowerCase();
282
292
  const filteredCatalog = useMemo(() => {
@@ -318,14 +328,38 @@ function McpIntegrationsSection({ query }) {
318
328
  : "Could not remove agent integration.");
319
329
  }
320
330
  }, [deleteServer, deleteTarget]);
331
+ const reconnect = useCallback(async (server) => {
332
+ const key = `${server.scope}:${server.id}`;
333
+ setReconnectingKey(key);
334
+ setReconnectError(null);
335
+ try {
336
+ await reconnectServer.mutateAsync({
337
+ id: server.id,
338
+ scope: server.scope,
339
+ });
340
+ }
341
+ catch (error) {
342
+ setReconnectError({
343
+ key,
344
+ message: error instanceof Error ? error.message : String(error),
345
+ });
346
+ }
347
+ finally {
348
+ setReconnectingKey(null);
349
+ }
350
+ }, [reconnectServer]);
321
351
  return (_jsxs("section", { "data-testid": "mcp-integrations", className: "space-y-5", children: [_jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(IconServer, { className: "size-4 text-muted-foreground" }), _jsx("h2", { className: "text-sm font-semibold text-foreground", children: "Agent integrations" })] }), _jsx("p", { className: "mt-1 text-xs leading-5 text-muted-foreground", children: "Give your agent tools and context from the services you use." })] }), _jsxs("button", { type: "button", onClick: () => openCatalog(), className: "inline-flex w-fit items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground transition-colors hover:bg-primary/90", children: [_jsx(IconPlus, { className: "size-3.5" }), "Add integration"] })] }), deleteError && (_jsx("p", { className: "border-y border-destructive/20 bg-destructive/5 py-3 text-xs text-destructive", children: deleteError })), serversQuery.isError ? (_jsx("p", { className: "border-y border-destructive/20 bg-destructive/5 py-3 text-xs text-destructive", children: "Could not load connected agent integrations. The catalog is still available." })) : serversQuery.isLoading ? (_jsxs("div", { className: "space-y-3 rounded-xl border border-border/70 bg-card px-4 py-4", children: [_jsx("div", { className: "h-5 w-1/2 animate-pulse rounded bg-muted" }), _jsx("div", { className: "h-5 w-3/4 animate-pulse rounded bg-muted" })] })) : servers.length > 0 && !normalizedQuery ? (_jsxs("section", { className: "space-y-2", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Installed" }), _jsx("div", { className: "overflow-hidden rounded-xl border border-border/70 bg-card text-card-foreground", children: _jsx("div", { className: "divide-y divide-border/60 px-4", children: servers.map((server) => {
322
352
  const key = `${server.scope}:${server.id}`;
323
353
  const canRemove = server.scope === "user" ||
324
354
  serversQuery.data?.role === "owner" ||
325
355
  serversQuery.data?.role === "admin";
326
- return (_jsxs("div", { className: "flex items-center gap-3 py-3.5", children: [_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-lg border border-border/70 bg-background text-muted-foreground", children: _jsx(IconServer, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "truncate text-sm font-medium text-foreground", children: server.name }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: server.scope === "user"
356
+ return (_jsxs("div", { className: "flex items-start gap-3 py-3.5", children: [_jsx("span", { className: "mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-lg border border-border/70 bg-background text-muted-foreground", children: _jsx(IconServer, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "truncate text-sm font-medium text-foreground", children: server.name }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: server.scope === "user"
327
357
  ? "Personal"
328
- : "Organization" })] }), _jsx(McpServerStatus, { server: server })] }), canRemove && (_jsx("button", { type: "button", onClick: () => void removeServer(server), disabled: deleteServer.isPending, className: "shrink-0 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:opacity-50", children: deleteTarget === key ? "Confirm" : "Remove" }))] }, key));
358
+ : "Organization" })] }), _jsx(McpServerStatus, { server: server, onReconnect: server.status.state === "error"
359
+ ? () => void reconnect(server)
360
+ : undefined, reconnecting: reconnectingKey === key, reconnectError: reconnectError?.key === key
361
+ ? reconnectError.message
362
+ : undefined })] }), canRemove && (_jsx("button", { type: "button", onClick: () => void removeServer(server), disabled: deleteServer.isPending, className: "shrink-0 rounded-md border border-border px-2.5 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:opacity-50", children: deleteTarget === key ? "Confirm" : "Remove" }))] }, key));
329
363
  }) }) })] })) : null, filteredCatalog.length > 0 && (_jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between gap-3", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: "Available integrations" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: [filteredCatalog.length, " integrations"] })] }), _jsx("div", { className: "grid gap-x-8 overflow-hidden rounded-xl border border-border/70 bg-card px-4 sm:grid-cols-2", children: filteredCatalog.map((integration) => (_jsx(McpCatalogItem, { integration: integration, connected: connectedUrls.has(compareMcpUrl(integration.url)), onConnect: openCatalog }, integration.id))) })] })), filteredCatalog.length === 0 && normalizedQuery && (_jsxs("p", { className: "border-y border-border/60 py-4 text-xs text-muted-foreground", children: ["No agent integrations match \u201C", query, "\u201D."] })), _jsx(McpIntegrationDialog, { open: dialogOpen, onOpenChange: setDialogOpen, initialIntegrationId: initialIntegrationId, defaultScope: "user", canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrg, onCreateMcpServer: (args) => createServer.mutateAsync(args) })] }));
330
364
  }
331
365
  export function IntegrationsPanel() {
@@ -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";
@@ -30,8 +30,8 @@ const SECTION_LABEL_CLASS = "px-2.5 pt-1 pb-0.5 text-[10px] uppercase tracking-w
30
30
  const APP_SUBMENU_CONTENT_CLASS = "z-50 w-72 rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2";
31
31
  const SWITCHER_BUTTON_CLASS = "flex w-full items-center gap-2 rounded-md border-0 bg-accent/50 px-2.5 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent/70 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60 cursor-pointer";
32
32
  const COMPACT_SWITCHER_BUTTON_CLASS = "flex items-center justify-center rounded-md border-0 bg-accent/50 p-1.5 text-muted-foreground hover:bg-accent/70 hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-60 cursor-pointer";
33
- const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings#organization";
34
- const DEFAULT_PROFILE_PATH = "/settings#account";
33
+ const DEFAULT_ORGANIZATION_SETTINGS_PATH = "/settings/organization";
34
+ const DEFAULT_PROFILE_PATH = "/settings/account";
35
35
  const DEFAULT_AGENT_PATH = "/agent";
36
36
  const APP_ICON_MAP = {
37
37
  Mail: IconMail,