@agent-native/core 0.169.1 → 0.170.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 (459) hide show
  1. package/agent-native.eject.json +4 -1
  2. package/bin/agent-native.js +23 -5
  3. package/corpus/README.md +1 -1
  4. package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +11 -4
  5. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  6. package/corpus/templates/analytics/app/i18n-data.ts +28 -0
  7. package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
  8. package/corpus/templates/analytics/app/routes/$.tsx +10 -0
  9. package/corpus/templates/analytics/app/routes.ts +3 -1
  10. package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
  11. package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
  12. package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
  13. package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
  14. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
  15. package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
  16. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
  17. package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
  18. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
  19. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
  20. package/corpus/templates/analytics/server/lib/slack.ts +4 -2
  21. package/corpus/templates/analytics/vitest.config.ts +6 -1
  22. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
  23. package/corpus/templates/assets/app/routes/library.tsx +5 -3
  24. package/corpus/templates/assets/app/routes.ts +3 -1
  25. package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
  26. package/corpus/templates/assets/vitest.config.ts +6 -1
  27. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
  28. package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
  29. package/corpus/templates/brain/app/routes/sources.tsx +8 -3
  30. package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
  31. package/corpus/templates/brain/vitest.config.ts +1 -0
  32. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
  33. package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
  34. package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
  35. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
  36. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
  37. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
  38. package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
  39. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
  40. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
  41. package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
  42. package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
  43. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
  44. package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
  45. package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
  46. package/corpus/templates/calendar/app/routes.ts +3 -1
  47. package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
  48. package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
  49. package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
  50. package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
  51. package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
  52. package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
  53. package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
  54. package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
  55. package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
  56. package/corpus/templates/calendar/server/onboarding.ts +85 -0
  57. package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
  58. package/corpus/templates/calendar/shared/api.ts +9 -1
  59. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  60. package/corpus/templates/chat/app/routes.ts +3 -1
  61. package/corpus/templates/chat/vitest.config.ts +8 -0
  62. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
  63. package/corpus/templates/clips/actions/get-meeting.ts +9 -4
  64. package/corpus/templates/clips/actions/list-recordings.ts +16 -3
  65. package/corpus/templates/clips/actions/search-meetings.ts +1 -0
  66. package/corpus/templates/clips/actions/view-screen.ts +8 -1
  67. package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
  68. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
  69. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
  70. package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
  71. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
  72. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
  73. package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
  74. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
  75. package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
  76. package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
  77. package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
  78. package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
  80. package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
  81. package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
  82. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
  83. package/corpus/templates/clips/desktop/src/app.tsx +53 -24
  84. package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
  85. package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
  86. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
  87. package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
  88. package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
  89. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
  90. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
  91. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
  92. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
  93. package/corpus/templates/clips/server/lib/emails.ts +17 -33
  94. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
  95. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
  96. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
  97. package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
  98. package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
  99. package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
  100. package/corpus/templates/content/app/i18n-data.ts +25 -0
  101. package/corpus/templates/content/app/routes.ts +3 -1
  102. package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
  103. package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
  104. package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
  105. package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
  106. package/corpus/templates/content/vitest.config.ts +7 -1
  107. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
  108. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
  109. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1383 -88
  110. package/corpus/templates/design/actions/generate-design.ts +98 -47
  111. package/corpus/templates/design/actions/get-design-system.ts +6 -1
  112. package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
  113. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
  114. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
  115. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2057 -141
  116. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
  117. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
  118. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -1
  119. package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
  120. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
  121. package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
  122. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
  123. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +11 -4
  124. package/corpus/templates/design/app/i18n-data.ts +1 -0
  125. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
  126. package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
  127. package/corpus/templates/design/app/pages/DesignEditor.tsx +77 -35
  128. package/corpus/templates/design/app/pages/DesignSystems.tsx +136 -42
  129. package/corpus/templates/design/app/pages/Index.tsx +2 -0
  130. package/corpus/templates/design/app/pages/Templates.tsx +0 -10
  131. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
  132. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
  133. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
  134. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
  135. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
  136. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
  137. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
  138. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
  139. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
  140. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
  141. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
  142. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
  143. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
  144. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
  145. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
  146. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
  147. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
  148. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
  149. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
  150. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
  151. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
  152. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
  153. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
  154. package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
  155. package/corpus/templates/design/app/routes.ts +3 -1
  156. package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
  157. package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
  158. package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
  159. package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
  160. package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
  161. package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
  162. package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
  163. package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
  164. package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
  165. package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
  166. package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
  167. package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
  168. package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
  169. package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
  170. package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
  171. package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
  172. package/corpus/templates/design/package.json +2 -0
  173. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
  174. package/corpus/templates/design/shared/canvas-math.ts +612 -206
  175. package/corpus/templates/design/shared/pen-path.ts +37 -0
  176. package/corpus/templates/design/vitest.config.ts +7 -1
  177. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
  178. package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
  179. package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
  180. package/corpus/templates/dispatch/app/routes.ts +3 -1
  181. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
  182. package/corpus/templates/factory/.env.example +2 -7
  183. package/corpus/templates/factory/AGENTS.md +3 -0
  184. package/corpus/templates/factory/README.md +5 -3
  185. package/corpus/templates/factory/actions/create-factory.ts +16 -3
  186. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
  187. package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
  188. package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
  189. package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
  190. package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
  191. package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
  192. package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
  193. package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
  194. package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
  195. package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
  196. package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
  197. package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
  198. package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
  199. package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
  200. package/corpus/templates/factory/app/routes/factory.tsx +84 -11
  201. package/corpus/templates/factory/app/routes.ts +3 -1
  202. package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
  203. package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
  204. package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
  205. package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
  206. package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
  207. package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
  208. package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
  209. package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
  210. package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
  211. package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
  212. package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
  213. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
  214. package/corpus/templates/factory/vitest.config.ts +17 -2
  215. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
  216. package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
  217. package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  218. package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
  219. package/corpus/templates/forms/vitest.config.ts +1 -0
  220. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
  221. package/corpus/templates/macros/app/routes.ts +3 -1
  222. package/corpus/templates/macros/vitest.config.ts +6 -1
  223. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
  224. package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
  225. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
  226. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
  227. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
  228. package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
  229. package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
  230. package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
  231. package/corpus/templates/mail/app/routes/$.tsx +9 -0
  232. package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
  233. package/corpus/templates/mail/app/routes/$view.tsx +47 -1
  234. package/corpus/templates/mail/app/routes.ts +3 -1
  235. package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
  236. package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
  237. package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
  238. package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
  239. package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
  240. package/corpus/templates/mail/server/onboarding.ts +66 -18
  241. package/corpus/templates/mail/vitest.config.ts +6 -1
  242. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
  243. package/corpus/templates/plan/app/routes/settings.tsx +4 -1
  244. package/corpus/templates/plan/app/routes.ts +3 -1
  245. package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  246. package/corpus/templates/plan/netlify.toml +1 -1
  247. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
  248. package/corpus/templates/slides/actions/patch-deck.ts +79 -10
  249. package/corpus/templates/slides/actions/update-slide.ts +11 -1
  250. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
  251. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
  252. package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
  253. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
  254. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
  255. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
  256. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
  257. package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
  258. package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
  259. package/corpus/templates/slides/app/routes.ts +3 -1
  260. package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
  261. package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
  262. package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
  263. package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
  264. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
  265. package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
  266. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
  267. package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
  268. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
  269. package/corpus/templates/slides/tsconfig.json +5 -0
  270. package/corpus/templates/slides/vitest.config.ts +6 -1
  271. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
  272. package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
  273. package/corpus/templates/tasks/app/routes.ts +3 -1
  274. package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  275. package/corpus/templates/tasks/vitest.config.ts +7 -1
  276. package/dist/action.d.ts +91 -0
  277. package/dist/action.js +50 -0
  278. package/dist/agent/abort-reasons.d.ts +38 -0
  279. package/dist/agent/abort-reasons.js +49 -0
  280. package/dist/agent/engine/ai-sdk-engine.js +8 -5
  281. package/dist/agent/engine/anthropic-engine.js +7 -5
  282. package/dist/agent/engine/first-event-timeout.d.ts +42 -17
  283. package/dist/agent/engine/first-event-timeout.js +67 -25
  284. package/dist/agent/production-agent.d.ts +23 -0
  285. package/dist/agent/production-agent.js +107 -102
  286. package/dist/agent/run-loop-with-resume.d.ts +2 -28
  287. package/dist/agent/run-loop-with-resume.js +25 -40
  288. package/dist/agent/run-manager.js +5 -4
  289. package/dist/agent/run-store.d.ts +55 -0
  290. package/dist/agent/run-store.js +124 -1
  291. package/dist/agent/tool-search.js +2 -1
  292. package/dist/agent/types.d.ts +9 -4
  293. package/dist/app-config/configuration-error.d.ts +11 -0
  294. package/dist/app-config/configuration-error.js +14 -0
  295. package/dist/app-config/index.d.ts +1 -0
  296. package/dist/app-config/index.js +1 -0
  297. package/dist/app-config/integrations.d.ts +1 -0
  298. package/dist/app-config/integrations.js +10 -0
  299. package/dist/app-config/plugins.d.ts +34 -0
  300. package/dist/app-config/plugins.js +39 -0
  301. package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
  302. package/dist/app-config/run-lifecycle-invariants.js +18 -25
  303. package/dist/app-config/schema.d.ts +16 -0
  304. package/dist/app-config/schema.js +2 -0
  305. package/dist/chat-threads/schema-migrations.js +20 -0
  306. package/dist/chat-threads/store.js +21 -4
  307. package/dist/cli/native-dependencies.d.ts +4 -0
  308. package/dist/cli/native-dependencies.js +15 -0
  309. package/dist/client/EnvironmentBadge.d.ts +1 -1
  310. package/dist/client/EnvironmentBadge.js +40 -5
  311. package/dist/client/MultiTabAssistantChat.d.ts +1 -1
  312. package/dist/client/MultiTabAssistantChat.js +35 -14
  313. package/dist/client/agent-chat/index.d.ts +1 -1
  314. package/dist/client/agent-chat/index.js +1 -1
  315. package/dist/client/agent-page/use-jobs.d.ts +2 -1
  316. package/dist/client/agent-page/use-jobs.js +3 -5
  317. package/dist/client/agent-sidebar-state.js +3 -1
  318. package/dist/client/blocks/library/code-tabs.js +5 -0
  319. package/dist/client/blocks/library/code.js +1 -0
  320. package/dist/client/chat-first/apps-rail.js +2 -2
  321. package/dist/client/chat-model-groups.d.ts +12 -0
  322. package/dist/client/chat-model-groups.js +3 -2
  323. package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
  324. package/dist/client/integrations/GoogleProductLogo.js +45 -0
  325. package/dist/client/integrations/index.d.ts +2 -0
  326. package/dist/client/integrations/index.js +2 -0
  327. package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
  328. package/dist/client/integrations/workspace-provider-oauth.js +13 -0
  329. package/dist/client/resources/mcp-integration-catalog.js +0 -29
  330. package/dist/client/settings/SettingsTabsPage.js +10 -6
  331. package/dist/client/sharing/ShareButton.js +11 -2
  332. package/dist/client/use-chat-models.d.ts +6 -0
  333. package/dist/client/use-chat-models.js +10 -0
  334. package/dist/client/use-db-sync.js +27 -9
  335. package/dist/connections/catalog.d.ts +111 -9
  336. package/dist/connections/catalog.js +86 -30
  337. package/dist/db/create-get-db.js +18 -0
  338. package/dist/db/ddl-guard.d.ts +0 -4
  339. package/dist/db/ddl-guard.js +46 -0
  340. package/dist/deploy/build.d.ts +19 -0
  341. package/dist/deploy/build.js +190 -16
  342. package/dist/deploy/function-bundle.d.ts +45 -0
  343. package/dist/deploy/function-bundle.js +337 -0
  344. package/dist/deploy/workspace-deploy.js +19 -1
  345. package/dist/eject/workspace-connections.js +4 -0
  346. package/dist/email-catalog/registry.d.ts +4 -0
  347. package/dist/email-catalog/registry.js +79 -14
  348. package/dist/extensions/content-patch.js +14 -2
  349. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  350. package/dist/integrations/plugin.d.ts +10 -0
  351. package/dist/integrations/plugin.js +40 -6
  352. package/dist/jobs/actions/run-automation-now.d.ts +2 -1
  353. package/dist/jobs/actions/run-automation-now.js +11 -5
  354. package/dist/jobs/frontmatter.js +53 -2
  355. package/dist/jobs/run-now.d.ts +11 -1
  356. package/dist/jobs/run-now.js +42 -7
  357. package/dist/jobs/scheduler.d.ts +1 -0
  358. package/dist/jobs/scheduler.js +2 -1
  359. package/dist/localization/core-messages/ar-SA.js +3 -0
  360. package/dist/localization/core-messages/de-DE.js +3 -0
  361. package/dist/localization/core-messages/en-US.d.ts +3 -0
  362. package/dist/localization/core-messages/en-US.js +3 -0
  363. package/dist/localization/core-messages/es-ES.js +3 -0
  364. package/dist/localization/core-messages/fr-FR.js +3 -0
  365. package/dist/localization/core-messages/hi-IN.js +3 -0
  366. package/dist/localization/core-messages/ja-JP.js +3 -0
  367. package/dist/localization/core-messages/ko-KR.js +3 -0
  368. package/dist/localization/core-messages/pt-BR.js +3 -0
  369. package/dist/localization/core-messages/zh-CN.js +3 -0
  370. package/dist/localization/core-messages/zh-TW.js +3 -0
  371. package/dist/localization/core-messages.d.ts +3 -0
  372. package/dist/localization/default-messages.d.ts +2 -5
  373. package/dist/localization/default-messages.js +2 -5
  374. package/dist/mcp/build-server.d.ts +9 -0
  375. package/dist/mcp/build-server.js +37 -8
  376. package/dist/mcp-client/oauth-client.d.ts +7 -0
  377. package/dist/mcp-client/oauth-client.js +12 -1
  378. package/dist/oauth-tokens/index.d.ts +1 -1
  379. package/dist/oauth-tokens/index.js +1 -1
  380. package/dist/oauth-tokens/lifecycle.d.ts +11 -0
  381. package/dist/oauth-tokens/lifecycle.js +17 -0
  382. package/dist/oauth-tokens/store.js +7 -0
  383. package/dist/observability/posthog-ai.d.ts +15 -1
  384. package/dist/observability/posthog-ai.js +24 -12
  385. package/dist/observability/routes.d.ts +3 -3
  386. package/dist/observability/traces.js +158 -28
  387. package/dist/onboarding/app-profile.js +2 -2
  388. package/dist/onboarding/plugin.js +10 -2
  389. package/dist/onboarding/types.d.ts +2 -0
  390. package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
  391. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  392. package/dist/provider-api/index.js +2 -0
  393. package/dist/resources/store.js +13 -4
  394. package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
  395. package/dist/secrets/register-framework-secrets.js +1 -1
  396. package/dist/server/action-discovery.js +5 -0
  397. package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
  398. package/dist/server/agent-chat/action-filters-a2a.js +48 -9
  399. package/dist/server/agent-chat-plugin.js +36 -9
  400. package/dist/server/agent-discovery.js +43 -20
  401. package/dist/server/auth.js +18 -16
  402. package/dist/server/beta-opt-out-html.js +45 -4
  403. package/dist/server/better-auth-instance.d.ts +2 -1
  404. package/dist/server/better-auth-instance.js +23 -7
  405. package/dist/server/builder-design-systems.d.ts +4 -1
  406. package/dist/server/builder-design-systems.js +87 -6
  407. package/dist/server/builder-oauth.d.ts +1 -7
  408. package/dist/server/builder-oauth.js +80 -163
  409. package/dist/server/core-routes-plugin.d.ts +29 -0
  410. package/dist/server/core-routes-plugin.js +100 -20
  411. package/dist/server/default-plugins.d.ts +18 -0
  412. package/dist/server/default-plugins.js +22 -0
  413. package/dist/server/edge.d.ts +1 -0
  414. package/dist/server/edge.js +1 -0
  415. package/dist/server/framework-request-handler.js +31 -3
  416. package/dist/server/google-oauth.d.ts +3 -0
  417. package/dist/server/google-oauth.js +3 -0
  418. package/dist/server/index.d.ts +4 -4
  419. package/dist/server/index.js +3 -3
  420. package/dist/server/onboarding-html.js +37 -3
  421. package/dist/server/realtime-token.d.ts +1 -1
  422. package/dist/server/transcribe-voice.d.ts +1 -1
  423. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  424. package/dist/server/workspace-provider-oauth.js +72 -20
  425. package/dist/shared/agent-sidebar-url.d.ts +1 -0
  426. package/dist/shared/agent-sidebar-url.js +1 -0
  427. package/dist/shared/environment-lanes.d.ts +2 -0
  428. package/dist/shared/environment-lanes.js +3 -1
  429. package/dist/shared/index.d.ts +3 -1
  430. package/dist/shared/index.js +3 -1
  431. package/dist/shared/surface-visibility.d.ts +31 -0
  432. package/dist/shared/surface-visibility.js +57 -0
  433. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  434. package/dist/templates/chat/app/routes.ts +3 -1
  435. package/dist/templates/chat/vitest.config.ts +8 -0
  436. package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  437. package/dist/templates/default/app/routes.ts +3 -1
  438. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  439. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
  440. package/dist/tracking/registry.d.ts +11 -0
  441. package/dist/tracking/registry.js +5 -2
  442. package/dist/triggers/actions.js +10 -3
  443. package/dist/usage/store.js +23 -3
  444. package/dist/user-profile/actions/get-auth-methods.js +18 -5
  445. package/dist/vite/client.js +24 -5
  446. package/docs/content/actions-access-control.mdx +43 -4
  447. package/docs/content/actions-defining.mdx +16 -0
  448. package/docs/content/template-clips-capture-everywhere.mdx +29 -30
  449. package/docs/content/template-clips-developers.mdx +4 -4
  450. package/docs/content/template-clips.mdx +3 -1
  451. package/package.json +2 -2
  452. package/src/eject/workspace-connections.ts +4 -0
  453. package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  454. package/src/templates/chat/app/routes.ts +3 -1
  455. package/src/templates/chat/vitest.config.ts +8 -0
  456. package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  457. package/src/templates/default/app/routes.ts +3 -1
  458. package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  459. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
@@ -5,6 +5,7 @@ import {
5
5
  AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT,
6
6
  AGENT_NATIVE_SOCIAL_IMAGE_TYPE,
7
7
  AGENT_NATIVE_SOCIAL_IMAGE_WIDTH,
8
+ SSR_QUERY_CACHE_KEY_HEADER,
8
9
  withAgentNativeSocialImageCacheBuster,
9
10
  } from "@agent-native/core/shared";
10
11
  import { eq } from "drizzle-orm";
@@ -321,6 +322,7 @@ export async function renderPublicForm(event: H3Event) {
321
322
  // short-fresh/long-SWR policy as React Router SSR. Keep all cache headers
322
323
  // here; relying on provider config would make templates perform differently.
323
324
  Object.assign(headers, resolveSsrCacheHeaders());
325
+ headers[SSR_QUERY_CACHE_KEY_HEADER] = "query";
324
326
  }
325
327
  return new Response(getMethod(event) === "HEAD" ? null : html, {
326
328
  status,
@@ -472,7 +474,15 @@ function renderFormPage(
472
474
 
473
475
  function revalidateFormVersion() {
474
476
  fetch(PUBLIC_FORM_API, { cache: "no-store" })
475
- .then(function(response) { return response.ok ? response.json() : null; })
477
+ .then(function(response) {
478
+ if (response.status === 404) {
479
+ var currentUrl = new URL(window.location.href);
480
+ currentUrl.searchParams.set("v", String(Date.now()));
481
+ window.location.replace(currentUrl.toString());
482
+ return null;
483
+ }
484
+ return response.ok ? response.json() : null;
485
+ })
476
486
  .then(function(latest) {
477
487
  if (!latest || typeof latest.updatedAt !== "string" || !latest.updatedAt || latest.updatedAt === FORM_VERSION) return;
478
488
  var currentUrl = new URL(window.location.href);
@@ -22,6 +22,7 @@ export default mergeConfig(
22
22
  "**/node_modules/**",
23
23
  "**/.git/**",
24
24
  "**/dist/**",
25
+ "**/.react-router/**",
25
26
  "shared/types.public-settings.spec.ts",
26
27
  "server/lib/submission-validation.spec.ts",
27
28
  ],
@@ -19,10 +19,17 @@ data, and generated extension/app content may mention credential **names** such
19
19
  as `OPENAI_API_KEY`, but must not contain real API keys, tokens, webhook URLs,
20
20
  signing secrets, OAuth refresh tokens, or private Builder/customer data.
21
21
 
22
- Secret values are supplied at runtime through deployment configuration, the
23
- encrypted `app_secrets` vault, `saveCredential` / `resolveCredential`, OAuth, or
24
- `${keys.NAME}` substitution. Examples must use obvious placeholders such as
25
- `<OPENAI_API_KEY>` or `${keys.SLACK_WEBHOOK}`, not real-looking copied values.
22
+ Provider secret values are supplied at runtime through the encrypted
23
+ `app_secrets` vault, `saveCredential` / `resolveCredential`, OAuth, or
24
+ `${keys.NAME}` substitution. Deployment configuration is reserved for
25
+ deploy-level secrets and non-provider configuration. Examples must use obvious
26
+ placeholders such as `<OPENAI_API_KEY>` or `${keys.SLACK_WEBHOOK}`, not
27
+ real-looking copied values.
28
+
29
+ Provider credentials and provider account identifiers are workspace data. Use
30
+ standard workspace connections and org/workspace vault scopes; never put them
31
+ in `.env` or deployment environment variables, and never add a provider-specific
32
+ action or startup bootstrap just to write a credential for one organization.
26
33
 
27
34
  ## Credential Modeling Preflight
28
35
 
@@ -1,3 +1,5 @@
1
1
  import type { RouteConfig } from "@react-router/dev/routes";
2
2
  import { flatRoutes } from "@react-router/fs-routes";
3
- export default flatRoutes() satisfies RouteConfig;
3
+ export default flatRoutes({
4
+ ignoredRouteFiles: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"],
5
+ }) satisfies RouteConfig;
@@ -14,7 +14,12 @@ export default mergeConfig(
14
14
  },
15
15
  test: {
16
16
  include: ["**/*.{test,spec}.?(c|m)[jt]s?(x)"],
17
- exclude: ["**/node_modules/**", "**/.git/**", "**/dist/**"],
17
+ exclude: [
18
+ "**/node_modules/**",
19
+ "**/.git/**",
20
+ "**/dist/**",
21
+ "**/.react-router/**",
22
+ ],
18
23
  },
19
24
  }),
20
25
  );
@@ -19,10 +19,17 @@ data, and generated extension/app content may mention credential **names** such
19
19
  as `OPENAI_API_KEY`, but must not contain real API keys, tokens, webhook URLs,
20
20
  signing secrets, OAuth refresh tokens, or private Builder/customer data.
21
21
 
22
- Secret values are supplied at runtime through deployment configuration, the
23
- encrypted `app_secrets` vault, `saveCredential` / `resolveCredential`, OAuth, or
24
- `${keys.NAME}` substitution. Examples must use obvious placeholders such as
25
- `<OPENAI_API_KEY>` or `${keys.SLACK_WEBHOOK}`, not real-looking copied values.
22
+ Provider secret values are supplied at runtime through the encrypted
23
+ `app_secrets` vault, `saveCredential` / `resolveCredential`, OAuth, or
24
+ `${keys.NAME}` substitution. Deployment configuration is reserved for
25
+ deploy-level secrets and non-provider configuration. Examples must use obvious
26
+ placeholders such as `<OPENAI_API_KEY>` or `${keys.SLACK_WEBHOOK}`, not
27
+ real-looking copied values.
28
+
29
+ Provider credentials and provider account identifiers are workspace data. Use
30
+ standard workspace connections and org/workspace vault scopes; never put them
31
+ in `.env` or deployment environment variables, and never add a provider-specific
32
+ action or startup bootstrap just to write a credential for one organization.
26
33
 
27
34
  ## Credential Modeling Preflight
28
35
 
@@ -1,4 +1,4 @@
1
- import { defineAction } from "@agent-native/core";
1
+ import { ActionContractError, defineAction } from "@agent-native/core";
2
2
  import { writeAppState } from "@agent-native/core/application-state";
3
3
  import { z } from "zod";
4
4
 
@@ -499,7 +499,15 @@ function accountLabel(account: ConnectedAccount) {
499
499
  async function allAccounts(): Promise<ConnectedAccount[]> {
500
500
  const accounts = await getAccessTokens();
501
501
  if (accounts.length === 0) {
502
- throw new Error("No Google account connected. Connect Gmail first.");
502
+ // A plain Error has no statusCode, so action-routes.ts can't tell this
503
+ // deterministic, caller-correctable precondition apart from a real server
504
+ // fault — it collapses to a 500 and the specific message never reaches
505
+ // the UI. ActionContractError carries an explicit sub-500 statusCode the
506
+ // route treats as user-facing and echoes as-is.
507
+ throw new ActionContractError(
508
+ "No Google account connected. Connect Gmail first.",
509
+ { errorCode: "GOOGLE_ACCOUNT_NOT_CONNECTED", statusCode: 400 },
510
+ );
503
511
  }
504
512
  return accounts;
505
513
  }
@@ -4,6 +4,7 @@ import {
4
4
  oauthRedirectUri,
5
5
  } from "@agent-native/core/client/host";
6
6
  import { useT } from "@agent-native/core/client/i18n";
7
+ import { startWorkspaceProviderOAuth } from "@agent-native/core/client/integrations";
7
8
  import {
8
9
  IconMail,
9
10
  IconX,
@@ -25,6 +26,7 @@ import {
25
26
  useGoogleAddAccountUrl,
26
27
  useDisconnectGoogle,
27
28
  } from "@/hooks/use-google-auth";
29
+ import { shouldOfferGoogleOAuthSetup } from "@/lib/google-oauth-setup";
28
30
 
29
31
  interface EnvKeyStatus {
30
32
  key: string;
@@ -76,6 +78,15 @@ const ADD_ACCOUNT_POLL_ABORT_MS = Math.max(
76
78
  ADD_ACCOUNT_POLL_INTERVAL_MS * 4,
77
79
  );
78
80
 
81
+ function startManagedGoogleOAuth(): void {
82
+ const returnPath = `${window.location.pathname}${window.location.search}`;
83
+ startWorkspaceProviderOAuth("gmail", {
84
+ appId: "mail",
85
+ returnPath,
86
+ scope: "user",
87
+ });
88
+ }
89
+
79
90
  function newDesktopOAuthVerifier(): string | null {
80
91
  const cryptoApi = globalThis.crypto;
81
92
  const randomUuid = cryptoApi?.randomUUID;
@@ -125,6 +136,8 @@ export function GoogleConnectBanner({
125
136
 
126
137
  const accounts = googleStatus.data?.accounts ?? [];
127
138
  const hasAccounts = accounts.length > 0;
139
+ const googleConfigured = googleStatus.data?.configured === true;
140
+ const canOfferOAuthSetup = useMemo(() => shouldOfferGoogleOAuthSetup(), []);
128
141
 
129
142
  const isBuilderFrame = useMemo(() => isInBuilderFrame(), []);
130
143
  const useDesktopAuth = useMemo(
@@ -336,13 +349,15 @@ export function GoogleConnectBanner({
336
349
  useEffect(() => {
337
350
  if (authUrl.error) {
338
351
  setWantAuthUrl(false);
339
- setShowWizard(true);
340
- fetchStatus();
352
+ if (canOfferOAuthSetup) {
353
+ setShowWizard(true);
354
+ fetchStatus();
355
+ }
341
356
  setAuthError(
342
357
  (authUrl.error as any)?.message || t("mail.error.failedToConnect"),
343
358
  );
344
359
  }
345
- }, [authUrl.error, fetchStatus]);
360
+ }, [authUrl.error, canOfferOAuthSetup, fetchStatus]);
346
361
 
347
362
  const allConfigured =
348
363
  envStatus.length > 0 && envStatus.every((k) => k.configured);
@@ -419,20 +434,22 @@ export function GoogleConnectBanner({
419
434
  }, [wantAddAccount, addAccountUrl.data, isBuilderFrame]);
420
435
 
421
436
  function handleConnect() {
437
+ if (!googleConfigured && !canOfferOAuthSetup) return;
422
438
  setDesktopAuthIssue(null);
423
439
  if (useDesktopAuth) {
424
440
  signInViaDesktopBrowser();
425
441
  return;
426
442
  }
427
- setWantAuthUrl(true);
443
+ startManagedGoogleOAuth();
428
444
  }
429
445
 
430
446
  function handleAddAccount() {
447
+ if (!googleConfigured && !canOfferOAuthSetup) return;
431
448
  if (useDesktopAuth) {
432
449
  signInViaDesktopBrowser(true);
433
450
  return;
434
451
  }
435
- setWantAddAccount(true);
452
+ startManagedGoogleOAuth();
436
453
  }
437
454
 
438
455
  async function handleJsonUpload(file: File) {
@@ -489,6 +506,15 @@ export function GoogleConnectBanner({
489
506
  }
490
507
 
491
508
  if (dismissed) return null;
509
+ if (!googleStatus.data && !canOfferOAuthSetup && !googleStatus.isError)
510
+ return null;
511
+ if (
512
+ !googleConfigured &&
513
+ !canOfferOAuthSetup &&
514
+ !hasAccounts &&
515
+ !googleStatus.isError
516
+ )
517
+ return null;
492
518
 
493
519
  // Full-page hero for setup / reconnection
494
520
  if (variant === "hero") {
@@ -503,22 +529,34 @@ export function GoogleConnectBanner({
503
529
  <p className="mt-2 max-w-sm text-sm text-muted-foreground leading-relaxed">
504
530
  {t("mail.googleConnect.heroDescription")}
505
531
  </p>
506
- <Button
507
- size="sm"
508
- className="mt-8 gap-2 px-5 h-9 text-sm font-medium bg-white text-black hover:bg-white/90"
509
- onClick={() => {
510
- setAuthError(null);
511
- handleConnect();
512
- }}
513
- disabled={authUrl.isLoading || authUrl.isFetching}
514
- >
515
- <GoogleIcon className="h-4 w-4" />
516
- {authUrl.isLoading
517
- ? t("mail.accounts.connecting")
518
- : allConfigured
519
- ? t("mail.accounts.signInWithGoogle")
520
- : t("mail.accounts.connectGoogle")}
521
- </Button>
532
+ {googleStatus.isError ? (
533
+ <Button
534
+ size="sm"
535
+ variant="outline"
536
+ className="mt-8 gap-2 px-5 h-9 text-sm font-medium"
537
+ onClick={() => void googleStatus.refetch()}
538
+ disabled={googleStatus.isFetching}
539
+ >
540
+ {t("mail.error.tryAgain")}
541
+ </Button>
542
+ ) : googleConfigured || canOfferOAuthSetup ? (
543
+ <Button
544
+ size="sm"
545
+ className="mt-8 gap-2 px-5 h-9 text-sm font-medium bg-primary text-primary-foreground hover:bg-primary/90"
546
+ onClick={() => {
547
+ setAuthError(null);
548
+ handleConnect();
549
+ }}
550
+ disabled={authUrl.isLoading || authUrl.isFetching}
551
+ >
552
+ <GoogleIcon className="h-4 w-4" />
553
+ {authUrl.isLoading
554
+ ? t("mail.accounts.connecting")
555
+ : allConfigured
556
+ ? t("mail.accounts.signInWithGoogle")
557
+ : t("mail.accounts.connectGoogle")}
558
+ </Button>
559
+ ) : null}
522
560
 
523
561
  <GoogleAuthIssuePanel
524
562
  issue={desktopAuthIssue}
@@ -531,7 +569,7 @@ export function GoogleConnectBanner({
531
569
  <p className="mt-3 text-xs text-red-400">{authError}</p>
532
570
  )}
533
571
 
534
- {showWizard && !allConfigured && (
572
+ {showWizard && !allConfigured && canOfferOAuthSetup && (
535
573
  <div className="mt-10 w-full max-w-lg text-start">
536
574
  <p className="text-xs text-muted-foreground mb-3">
537
575
  {t("mail.googleConnect.setupIntro")}
@@ -711,21 +749,25 @@ export function GoogleConnectBanner({
711
749
  className="group flex items-center gap-1.5 text-xs text-foreground/60"
712
750
  >
713
751
  <span className="truncate">{account.email}</span>
714
- <button
715
- onClick={() => disconnectGoogle.mutate(account.email)}
716
- className="opacity-0 group-hover:opacity-100 transition-opacity text-foreground/30 hover:text-foreground/60"
717
- >
718
- <IconX className="h-3 w-3" />
719
- </button>
752
+ {!account.shared && (
753
+ <button
754
+ onClick={() => disconnectGoogle.mutate(account.email)}
755
+ className="opacity-0 group-hover:opacity-100 transition-opacity text-foreground/30 hover:text-foreground/60"
756
+ >
757
+ <IconX className="h-3 w-3" />
758
+ </button>
759
+ )}
720
760
  </div>
721
761
  ))}
722
- <button
723
- onClick={handleAddAccount}
724
- disabled={addAccountUrl.isLoading || addAccountUrl.isFetching}
725
- className="text-xs text-foreground/40 hover:text-foreground/60 transition-colors whitespace-nowrap"
726
- >
727
- + {t("mail.accounts.addAccount")}
728
- </button>
762
+ {(googleConfigured || canOfferOAuthSetup) && (
763
+ <button
764
+ onClick={handleAddAccount}
765
+ disabled={addAccountUrl.isLoading || addAccountUrl.isFetching}
766
+ className="text-xs text-foreground/40 hover:text-foreground/60 transition-colors whitespace-nowrap"
767
+ >
768
+ + {t("mail.accounts.addAccount")}
769
+ </button>
770
+ )}
729
771
  </div>
730
772
  <Button
731
773
  variant="ghost"
@@ -742,6 +784,17 @@ export function GoogleConnectBanner({
742
784
  onDismiss={() => setDesktopAuthIssue(null)}
743
785
  className="mx-4 mb-3"
744
786
  />
787
+ {googleStatus.isError && (
788
+ <Button
789
+ variant="ghost"
790
+ size="sm"
791
+ className="mx-4 mb-2"
792
+ onClick={() => void googleStatus.refetch()}
793
+ disabled={googleStatus.isFetching}
794
+ >
795
+ {t("mail.error.tryAgain")}
796
+ </Button>
797
+ )}
745
798
  </div>
746
799
  );
747
800
  }
@@ -763,7 +816,17 @@ export function GoogleConnectBanner({
763
816
  </div>
764
817
 
765
818
  <div className="flex items-center gap-1.5 shrink-0">
766
- {showWizard && !allConfigured ? (
819
+ {googleStatus.isError ? (
820
+ <Button
821
+ size="sm"
822
+ variant="outline"
823
+ className="gap-1.5 text-xs h-7 font-medium"
824
+ onClick={() => void googleStatus.refetch()}
825
+ disabled={googleStatus.isFetching}
826
+ >
827
+ {t("mail.error.tryAgain")}
828
+ </Button>
829
+ ) : showWizard && !allConfigured && canOfferOAuthSetup ? (
767
830
  <Button
768
831
  size="sm"
769
832
  variant="outline"
@@ -817,7 +880,7 @@ export function GoogleConnectBanner({
817
880
  />
818
881
 
819
882
  {/* Inline setup wizard */}
820
- {showWizard && !allConfigured && (
883
+ {showWizard && !allConfigured && canOfferOAuthSetup && (
821
884
  <div className="px-4 pb-4 pt-1 max-w-2xl">
822
885
  <p className="text-xs text-muted-foreground mb-3">
823
886
  {t("mail.googleConnect.setupIntro")}
@@ -187,15 +187,18 @@ export function IntegrationsSidebar({
187
187
  email,
188
188
  displayName,
189
189
  recentEmails,
190
+ recentEmailsError,
190
191
  threadId,
191
192
  focusedEmailId,
192
193
  }: {
193
194
  email: string;
194
195
  displayName: string;
195
196
  recentEmails: { id: string; subject: string }[];
197
+ recentEmailsError?: boolean;
196
198
  threadId?: string;
197
199
  focusedEmailId?: string;
198
200
  }) {
201
+ const t = useT();
199
202
  const statuses = useAllIntegrations();
200
203
  const anyConnected =
201
204
  statuses.apollo || statuses.hubspot || statuses.gong || statuses.pylon;
@@ -226,7 +229,16 @@ export function IntegrationsSidebar({
226
229
  )}
227
230
 
228
231
  {/* Recent emails */}
229
- {recentEmails.length > 0 && (
232
+ {recentEmailsError ? (
233
+ <div
234
+ className="mx-4 border-t border-border/30 px-0 py-3"
235
+ aria-live="polite"
236
+ >
237
+ <p className="text-[11px] text-muted-foreground/70">
238
+ {t("mail.error.loadTitle")}
239
+ </p>
240
+ </div>
241
+ ) : recentEmails.length > 0 ? (
230
242
  <>
231
243
  <div className="h-px bg-border/30 mx-4" />
232
244
  <div className="px-4 py-3">
@@ -245,7 +257,7 @@ export function IntegrationsSidebar({
245
257
  ))}
246
258
  </div>
247
259
  </>
248
- )}
260
+ ) : null}
249
261
 
250
262
  {/* Tool extension-point slot — user-installed widgets render here */}
251
263
  <ExtensionSlot
@@ -7,6 +7,7 @@ import { appApiPath } from "@agent-native/core/client/api-path";
7
7
  import { DevDatabaseLink } from "@agent-native/core/client/db-admin";
8
8
  import { usePerAppChatOpen } from "@agent-native/core/client/hooks";
9
9
  import { useT } from "@agent-native/core/client/i18n";
10
+ import { startWorkspaceProviderOAuth } from "@agent-native/core/client/integrations";
10
11
  import { openCommandMenu } from "@agent-native/core/client/navigation";
11
12
  import { InvitationBanner, OrgSwitcher } from "@agent-native/core/client/org";
12
13
  import { FeedbackButton } from "@agent-native/core/client/ui";
@@ -82,6 +83,7 @@ import {
82
83
  } from "@/hooks/use-keyboard-shortcuts";
83
84
  import { useIsMobile } from "@/hooks/use-mobile";
84
85
  import { runUndo } from "@/hooks/use-undo";
86
+ import { shouldOfferGoogleOAuthSetup } from "@/lib/google-oauth-setup";
85
87
  import {
86
88
  OTHER_INBOX_TAB_ID,
87
89
  OTHER_INBOX_TAB_PARAM,
@@ -91,6 +93,7 @@ import {
91
93
  } from "@/lib/inbox-tabs";
92
94
  import { isMcpEmbedSurface } from "@/lib/mcp-embed";
93
95
  import { cn } from "@/lib/utils";
96
+ import { isKnownMailView } from "@/routes/$view";
94
97
 
95
98
  import { CommandPalette } from "./CommandPalette";
96
99
  import { useHeaderTitle, useHeaderActions } from "./HeaderActions";
@@ -328,6 +331,11 @@ function AppLayoutInner({ children }: AppLayoutProps) {
328
331
  const googleStatus = useGoogleAuthStatus();
329
332
  const accounts = googleStatus.data?.accounts ?? [];
330
333
  const hasAccounts = accounts.length > 0;
334
+ const googleConfigured = googleStatus.data?.configured === true;
335
+ const canOfferGoogleOAuthSetup = useMemo(
336
+ () => shouldOfferGoogleOAuthSetup(),
337
+ [],
338
+ );
331
339
  const googleStatusReady = !googleStatus.isLoading && !googleStatus.isError;
332
340
  const [accountPopoverOpen, setAccountPopoverOpen] = useState(false);
333
341
  // Account filter: which accounts' emails to show. Empty set = all accounts.
@@ -1063,18 +1071,18 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1063
1071
  const localCountsForKind = (kind: CountKind) =>
1064
1072
  kind === "total" ? labelThreadCounts.total : labelThreadCounts.unread;
1065
1073
 
1066
- // Take the larger of the server-reported count and the count we compute
1067
- // locally from loaded inbox emails. Either side can be stale (Gmail label
1068
- // totals can lag; loaded emails may be a partial window).
1074
+ // Prefer the complete server count when Gmail provides one. Falling back to
1075
+ // loaded rows is useful for local/demo mail, but merging the two with
1076
+ // Math.max makes badges grow as more pages happen to be loaded.
1069
1077
  const getInboxCount = (kind: CountKind) => {
1070
1078
  const inboxLabel = resolveLabelForCount("inbox");
1071
1079
  const countField = countFieldForKind(kind);
1072
1080
  const localCounts = localCountsForKind(kind);
1073
- const serverCount = useServerLabelCounts
1074
- ? (inboxLabel?.[countField] ?? 0)
1075
- : 0;
1081
+ const serverCount = inboxLabel?.[countField];
1076
1082
  const localCount = localCounts["__inboxTotal"] ?? 0;
1077
- return Math.max(serverCount, localCount);
1083
+ return typeof serverCount === "number" && useServerLabelCounts
1084
+ ? serverCount
1085
+ : localCount;
1078
1086
  };
1079
1087
 
1080
1088
  const getOtherCount = (kind: CountKind) => {
@@ -1096,12 +1104,11 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1096
1104
  const localCounts = localCountsForKind(kind);
1097
1105
  const localCount =
1098
1106
  localCounts[viewId] ?? (label ? (localCounts[label.id] ?? 0) : 0);
1099
- const serverCount =
1100
- useServerLabelCounts && viewId !== "note-to-self"
1101
- ? (label?.[countField] ?? 0)
1102
- : 0;
1103
1107
  if (inboxPartitionTabIds.has(viewId)) return localCount;
1104
- return Math.max(serverCount, localCount);
1108
+ const serverCount = label?.[countField];
1109
+ return typeof serverCount === "number" && useServerLabelCounts
1110
+ ? serverCount
1111
+ : localCount;
1105
1112
  };
1106
1113
  const getTopBarCount = (viewId: string) => getTabCount(viewId, "total");
1107
1114
  const getUnreadCount = (viewId: string) => getTabCount(viewId, "unread");
@@ -1494,6 +1501,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1494
1501
  >
1495
1502
  <AccountPopover
1496
1503
  accounts={accounts}
1504
+ canAddAccount={googleConfigured || canOfferGoogleOAuthSetup}
1497
1505
  activeAccounts={activeAccounts}
1498
1506
  onToggleAccount={(email) => {
1499
1507
  setActiveAccounts((prev) => {
@@ -1899,13 +1907,17 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1899
1907
  </div>
1900
1908
  )}
1901
1909
 
1902
- {/* Show full-page takeover when no accounts connected (except on settings page) */}
1910
+ {/* Show full-page takeover when no accounts connected (except on
1911
+ settings page, or on an unknown route — an unmatched path must
1912
+ still reach the routed NotFound content, not this gate). */}
1903
1913
  {!googleStatus.isLoading &&
1904
1914
  !googleStatus.isError &&
1905
1915
  !hasAccounts &&
1906
1916
  !hasLocalMailboxData &&
1907
1917
  view !== "settings" &&
1908
- view !== "draft-queue" ? (
1918
+ view !== "draft-queue" &&
1919
+ isKnownMailView(view) &&
1920
+ (googleConfigured || canOfferGoogleOAuthSetup) ? (
1909
1921
  <GoogleConnectBanner variant="hero" />
1910
1922
  ) : (
1911
1923
  <main className="agent-native-app-main flex flex-1 overflow-hidden">
@@ -2561,11 +2573,18 @@ function TabSettingsPopover({
2561
2573
 
2562
2574
  function AccountPopover({
2563
2575
  accounts,
2576
+ canAddAccount,
2564
2577
  activeAccounts,
2565
2578
  onToggleAccount,
2566
2579
  onRemoveAccount,
2567
2580
  }: {
2568
- accounts: Array<{ email: string; displayName?: string; photoUrl?: string }>;
2581
+ accounts: Array<{
2582
+ email: string;
2583
+ displayName?: string;
2584
+ photoUrl?: string;
2585
+ shared?: boolean;
2586
+ }>;
2587
+ canAddAccount: boolean;
2569
2588
  activeAccounts: Set<string>;
2570
2589
  onToggleAccount: (email: string) => void;
2571
2590
  onRemoveAccount: (email: string) => void;
@@ -2668,32 +2687,43 @@ function AccountPopover({
2668
2687
  </span>
2669
2688
  )}
2670
2689
  </span>
2671
- <button
2672
- onClick={() => {
2673
- onRemoveAccount(account.email);
2674
- disconnectGoogle.mutate(account.email);
2675
- }}
2676
- className="opacity-0 group-hover:opacity-100 text-[11px] text-muted-foreground hover:text-red-400 transition-all"
2677
- >
2678
- {t("mail.accounts.remove")}
2679
- </button>
2690
+ {!account.shared && (
2691
+ <button
2692
+ onClick={() => {
2693
+ onRemoveAccount(account.email);
2694
+ disconnectGoogle.mutate(account.email);
2695
+ }}
2696
+ className="opacity-0 group-hover:opacity-100 text-[11px] text-muted-foreground hover:text-destructive transition-all"
2697
+ >
2698
+ {t("mail.accounts.remove")}
2699
+ </button>
2700
+ )}
2680
2701
  </div>
2681
2702
  );
2682
2703
  })}
2683
2704
  </div>
2684
2705
 
2685
- <div className="border-t border-border/30 px-3 py-2">
2686
- <button
2687
- onClick={() => setWantAuthUrl(true)}
2688
- disabled={authUrl.isLoading || authUrl.isFetching}
2689
- className="flex items-center gap-2 w-full text-[13px] text-muted-foreground hover:text-foreground transition-colors py-1"
2690
- >
2691
- <IconPlus className="h-3.5 w-3.5" />
2692
- {authUrl.isFetching
2693
- ? t("mail.accounts.connecting")
2694
- : t("mail.accounts.addAccount")}
2695
- </button>
2696
- </div>
2706
+ {canAddAccount ? (
2707
+ <div className="border-t border-border/30 px-3 py-2">
2708
+ <button
2709
+ onClick={() => {
2710
+ const returnPath = `${window.location.pathname}${window.location.search}`;
2711
+ startWorkspaceProviderOAuth("gmail", {
2712
+ appId: "mail",
2713
+ returnPath,
2714
+ scope: "user",
2715
+ });
2716
+ }}
2717
+ disabled={authUrl.isLoading || authUrl.isFetching}
2718
+ className="flex items-center gap-2 w-full text-[13px] text-muted-foreground hover:text-foreground transition-colors py-1"
2719
+ >
2720
+ <IconPlus className="h-3.5 w-3.5" />
2721
+ {authUrl.isFetching
2722
+ ? t("mail.accounts.connecting")
2723
+ : t("mail.accounts.addAccount")}
2724
+ </button>
2725
+ </div>
2726
+ ) : null}
2697
2727
  </>
2698
2728
  );
2699
2729
  }
@@ -8,9 +8,11 @@ export interface GoogleAuthAccount {
8
8
  displayName?: string;
9
9
  expiresAt?: string;
10
10
  photoUrl?: string;
11
+ shared?: boolean;
11
12
  }
12
13
 
13
14
  export interface GoogleAuthStatus {
15
+ configured?: boolean;
14
16
  connected: boolean;
15
17
  accounts: GoogleAuthAccount[];
16
18
  }
@@ -0,0 +1,17 @@
1
+ function localHostname(hostname: string): boolean {
2
+ return (
3
+ hostname === "localhost" ||
4
+ hostname === "127.0.0.1" ||
5
+ hostname === "::1" ||
6
+ hostname.endsWith(".localhost") ||
7
+ hostname.endsWith(".local")
8
+ );
9
+ }
10
+
11
+ export function shouldOfferGoogleOAuthSetup(): boolean {
12
+ const env = (import.meta.env ?? {}) as Record<string, unknown>;
13
+ if (env.DEV === true) return true;
14
+ if (env.VITE_ENABLE_GOOGLE_OAUTH_SETUP === "true") return true;
15
+ if (typeof window === "undefined") return false;
16
+ return localHostname(window.location.hostname.toLowerCase());
17
+ }