@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
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Button } from "@agent-native/toolkit/ui/button";
3
3
  import { Popover, PopoverContent, PopoverTrigger, } from "@agent-native/toolkit/ui/popover";
4
- import { useEffect, useMemo, useRef } from "react";
5
- import { BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, buildEnvironmentOptOutUrl, buildEnvironmentUrl, resolveEnvironmentTargets, } from "../shared/environment-lanes.js";
4
+ import { useEffect, useMemo, useRef, useState } from "react";
5
+ import { BETA_FORCE_QUERY_PARAM, BETA_FORCE_SESSION_STORAGE_KEY, BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, buildEnvironmentOptOutUrl, buildEnvironmentUrl, resolveEnvironmentTargets, } from "../shared/environment-lanes.js";
6
6
  import { trackEvent } from "./analytics.js";
7
7
  import { injectedAgentNativeConfig } from "./app-config.js";
8
8
  import { useSession } from "./use-session.js";
9
9
  import { cn } from "./utils.js";
10
- export { BETA_OPT_OUT_DURATION_MS, BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, buildEnvironmentOptOutUrl, buildEnvironmentUrl, resolveEnvironmentTargets, } from "../shared/environment-lanes.js";
10
+ export { BETA_FORCE_QUERY_PARAM, BETA_FORCE_SESSION_STORAGE_KEY, BETA_OPT_OUT_DURATION_MS, BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, buildEnvironmentOptOutUrl, buildEnvironmentUrl, resolveEnvironmentTargets, } from "../shared/environment-lanes.js";
11
11
  export function isBuilderIoEmployee(email) {
12
12
  return email?.trim().toLowerCase().endsWith("@builder.io") ?? false;
13
13
  }
@@ -50,6 +50,29 @@ function readBetaOptOutUntil(now = Date.now()) {
50
50
  }
51
51
  return null;
52
52
  }
53
+ function rememberForcedProductionSession(sourceHref) {
54
+ let forcedByQuery = false;
55
+ try {
56
+ forcedByQuery =
57
+ new URL(sourceHref).searchParams.get(BETA_FORCE_QUERY_PARAM) === "true";
58
+ }
59
+ catch {
60
+ // coercion-ok: the browser supplied an invalid location.
61
+ }
62
+ if (typeof window === "undefined")
63
+ return forcedByQuery;
64
+ try {
65
+ if (forcedByQuery) {
66
+ window.sessionStorage.setItem(BETA_FORCE_SESSION_STORAGE_KEY, "1");
67
+ }
68
+ return (forcedByQuery ||
69
+ window.sessionStorage.getItem(BETA_FORCE_SESSION_STORAGE_KEY) === "1");
70
+ }
71
+ catch {
72
+ // coercion-ok: session storage is optional; the current URL remains authoritative.
73
+ return forcedByQuery;
74
+ }
75
+ }
53
76
  function consumeBetaOptOutQueryParam(sourceHref, now = Date.now()) {
54
77
  let target;
55
78
  try {
@@ -81,8 +104,11 @@ function EnvironmentLink({ label, href }) {
81
104
  return (_jsx(Button, { asChild: true, className: "w-full justify-center", size: "sm", variant: "outline", children: _jsx("a", { href: href, children: label }) }));
82
105
  }
83
106
  function EnvironmentBadgeContent({ environment, targets, }) {
107
+ const [isHidden, setIsHidden] = useState(false);
84
108
  if (typeof window === "undefined")
85
109
  return null;
110
+ if (isHidden)
111
+ return null;
86
112
  const currentHref = window.location.href;
87
113
  const betaHref = buildEnvironmentUrl(currentHref, targets.betaHost);
88
114
  const productionHref = buildEnvironmentOptOutUrl(currentHref, targets.productionHost);
@@ -94,7 +120,7 @@ function EnvironmentBadgeContent({ environment, targets, }) {
94
120
  : "You're on Agent Native Production";
95
121
  return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { "aria-label": `Open ${title.toLowerCase()} switcher`, className: cn(environmentBadgePlacementClasses, environment === "beta"
96
122
  ? "border-primary/80"
97
- : "border-border/80 bg-background/95 text-foreground"), size: "sm", variant: environment === "beta" ? "default" : "outline", children: label }) }), _jsxs(PopoverContent, { align: "start", className: "w-[280px] p-5", side: "top", sideOffset: 8, children: [_jsx("div", { className: "mb-1 text-sm font-semibold leading-5", children: title }), _jsx("div", { className: "mb-4 text-sm text-muted-foreground", children: "Choose where you want to continue." }), _jsx("div", { className: "grid gap-2", children: environment === "beta" ? (_jsx(EnvironmentLink, { href: productionHref, label: "Switch to production" })) : (_jsx(EnvironmentLink, { href: betaHref, label: "Go to beta" })) })] })] }));
123
+ : "border-border/80 bg-background/95 text-foreground"), size: "sm", variant: environment === "beta" ? "default" : "outline", children: label }) }), _jsxs(PopoverContent, { align: "start", className: "w-[280px] p-5", side: "top", sideOffset: 8, children: [_jsx("div", { className: "mb-1 text-sm font-semibold leading-5", children: title }), _jsx("div", { className: "mb-4 text-sm text-muted-foreground", children: "Choose where you want to continue." }), _jsxs("div", { className: "grid gap-2", children: [environment === "beta" ? (_jsx(EnvironmentLink, { href: productionHref, label: "Switch to production" })) : (_jsx(EnvironmentLink, { href: betaHref, label: "Go to beta" })), _jsx(Button, { className: "mt-2 -mb-2 w-full justify-center text-muted-foreground", onClick: () => setIsHidden(true), size: "sm", type: "button", variant: "ghost", children: "Hide badge" })] })] })] }));
98
124
  }
99
125
  function LocalEnvironmentBadge() {
100
126
  return (_jsx("div", { "aria-label": "Local development environment", className: cn(environmentBadgePlacementClasses, "inline-flex items-center justify-center border border-border/80 bg-background/95 text-foreground"), role: "status", children: "dev" }));
@@ -107,6 +133,10 @@ function ProductionEnvironmentBadge({ targets, }) {
107
133
  isBuilderIoEmployee(session?.email);
108
134
  const didAutoRedirect = useRef(false);
109
135
  useEffect(() => {
136
+ if (typeof window === "undefined")
137
+ return;
138
+ if (rememberForcedProductionSession(window.location.href))
139
+ return;
110
140
  if (!isEligible || didAutoRedirect.current) {
111
141
  return;
112
142
  }
@@ -140,11 +170,16 @@ function ProductionEnvironmentBadge({ targets, }) {
140
170
  * lane for authenticated staff.
141
171
  */
142
172
  export function EnvironmentBadge({ showProduction = true, } = {}) {
173
+ const [hydrated, setHydrated] = useState(false);
143
174
  const config = useMemo(injectedAgentNativeConfig, []);
144
175
  const hostname = typeof window === "undefined" ? undefined : window.location.hostname;
145
176
  const environment = resolveEnvironmentChannel(config, hostname);
146
177
  const targets = resolveEnvironmentTargets(hostname);
147
- if (typeof window === "undefined" ||
178
+ useEffect(() => {
179
+ setHydrated(true);
180
+ }, []);
181
+ if (!hydrated ||
182
+ typeof window === "undefined" ||
148
183
  window.parent !== window ||
149
184
  !environment) {
150
185
  return null;
@@ -71,4 +71,4 @@ export type MultiTabAssistantChatProps = Omit<AssistantChatProps, "tabId" | "thr
71
71
  /** Cadence for hydrating agent-team sub-agent tab status. Default: 3000. */
72
72
  agentTeamPollMs?: number;
73
73
  };
74
- export declare function MultiTabAssistantChat({ showTabBar, renderHeader, renderOverlay, contentHidden, apiUrl, storageKey, restoreActiveThread, browserTabId, threadUrlSync, scope, isolateHistoryByScope, agentTeamPollMs, ...props }: MultiTabAssistantChatProps): React.JSX.Element;
74
+ export declare function MultiTabAssistantChat({ showTabBar, renderHeader, renderOverlay, contentHidden, apiUrl, storageKey, restoreActiveThread, browserTabId, threadUrlSync, scope, isolateHistoryByScope, agentTeamPollMs, availableModels: hostAvailableModels, modelListLoading: hostModelListLoading, onModelChange: hostOnModelChange, ...props }: MultiTabAssistantChatProps): React.JSX.Element;
@@ -17,7 +17,7 @@ import { DEFAULT_LOCALE, useOptionalLocale, useT } from "./i18n.js";
17
17
  import { RunStuckBanner } from "./RunStuckBanner.js";
18
18
  import { callAction } from "./use-action.js";
19
19
  import { useChangeVersion } from "./use-change-version.js";
20
- import { CHAT_MODEL_SELECTION_CHANGED_EVENT } from "./use-chat-models.js";
20
+ import { CHAT_MODEL_SELECTION_CHANGED_EVENT, chatModelSelectionStorageKey, } from "./use-chat-models.js";
21
21
  import { useChatThreads, } from "./use-chat-threads.js";
22
22
  import { usePollLoop } from "./use-poll-loop.js";
23
23
  import { cn } from "./utils.js";
@@ -43,7 +43,6 @@ function deliverPendingSend(ref, send) {
43
43
  ref.sendMessage(send.message, send.images);
44
44
  }
45
45
  }
46
- const MODEL_SELECTION_STORAGE_KEY = "agent-native:chat-models:selection";
47
46
  function readStoredModelSelection(key) {
48
47
  if (typeof window === "undefined")
49
48
  return undefined;
@@ -402,7 +401,7 @@ function runToAgentTeamTabInfo(run) {
402
401
  status: run.status ?? "unknown",
403
402
  };
404
403
  }
405
- export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderOverlay, contentHidden = false, apiUrl = agentNativePath("/_agent-native/agent-chat"), storageKey, restoreActiveThread = true, browserTabId, threadUrlSync = false, scope = null, isolateHistoryByScope = false, agentTeamPollMs = DEFAULT_AGENT_TEAM_POLL_MS, ...props }) {
404
+ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderOverlay, contentHidden = false, apiUrl = agentNativePath("/_agent-native/agent-chat"), storageKey, restoreActiveThread = true, browserTabId, threadUrlSync = false, scope = null, isolateHistoryByScope = false, agentTeamPollMs = DEFAULT_AGENT_TEAM_POLL_MS, availableModels: hostAvailableModels, modelListLoading: hostModelListLoading, onModelChange: hostOnModelChange, ...props }) {
406
405
  const translate = useT();
407
406
  const contextNamespace = scope
408
407
  ? scope.contextKey?.trim() || `scope:${scope.type}:${scope.id}`
@@ -528,7 +527,7 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
528
527
  }, [switchThreadState, writeThreadUrl]);
529
528
  // Namespace all localStorage keys by storageKey when provided (for per-app isolation in frame)
530
529
  const keyPrefix = storageKey ? `:${storageKey}` : "";
531
- const modelSelectionKey = `${MODEL_SELECTION_STORAGE_KEY}${keyPrefix}`;
530
+ const modelSelectionKey = chatModelSelectionStorageKey(storageKey);
532
531
  // Track which tabs have been focused at least once (lazy mount for sub-agent tabs)
533
532
  const mountedTabsRef = useRef(new Set());
534
533
  const activeThreadIdRef = useRef(activeThreadId);
@@ -557,8 +556,16 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
557
556
  setPageOverlayScrolled(target.scrollTop > 1);
558
557
  }, [renderOverlay]);
559
558
  // ─── Model state ─────────────────────────────────────────────────────────
560
- const [availableModels, setAvailableModels] = useState([]);
561
- const [modelListLoading, setModelListLoading] = useState(true);
559
+ // A host that supplies its own catalog owns the whole picker: the server
560
+ // catalog must not be discovered or merged, or a host with no engine of its
561
+ // own silently gets this app's models instead.
562
+ const hostManagedModels = hostAvailableModels !== undefined;
563
+ const [discoveredModels, setDiscoveredModels] = useState([]);
564
+ const availableModels = hostAvailableModels ?? discoveredModels;
565
+ const [discoveredModelsLoading, setModelListLoading] = useState(true);
566
+ const modelListLoading = hostManagedModels
567
+ ? (hostModelListLoading ?? false)
568
+ : discoveredModelsLoading;
562
569
  const [defaultModel, setDefaultModel] = useState(DEFAULT_MODEL);
563
570
  const threadModelRef = useRef(new Map());
564
571
  const [persistedModelSelection, setPersistedModelSelection] = useState(() => readStoredModelSelection(modelSelectionKey));
@@ -666,6 +673,14 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
666
673
  persistModelSelection,
667
674
  props.selectedAgent,
668
675
  ]);
676
+ // A host that owns the model list still needs the internal selection updated:
677
+ // `selectedModel`/`selectedEngine` render from it and submitted turns read it,
678
+ // so routing a pick only to the host snaps the picker back to the previous
679
+ // model and sends that one.
680
+ const handleModelChangeWithHost = useCallback((model, engine) => {
681
+ handleModelChange(model, engine);
682
+ hostOnModelChange?.(model, engine);
683
+ }, [handleModelChange, hostOnModelChange]);
669
684
  const handleEffortChange = useCallback((effort) => {
670
685
  const threadId = activeThreadIdRef.current;
671
686
  if (!threadId)
@@ -689,15 +704,19 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
689
704
  resolveThreadModelSelection,
690
705
  ]);
691
706
  useEffect(() => {
692
- const preferredAgentModel = props.selectedAgent
693
- ? resolvePreferredAgentModel(props.selectedAgent, availableModels)
694
- : undefined;
695
- if (!preferredAgentModel)
696
- return;
697
707
  const threadId = activeThreadIdRef.current;
698
708
  const current = threadId
699
709
  ? resolveThreadModelSelection(threadId)
700
710
  : persistedModelSelection;
711
+ // Only correct a selection the agent cannot run. This effect re-runs on
712
+ // every selection change, so an unconditional rewrite pins the picker and
713
+ // each later user pick snaps straight back.
714
+ const preferredAgentModel = isClaudeCodeAgentId(props.selectedAgent) &&
715
+ isLunaModel(current?.model ?? "")
716
+ ? resolvePreferredAgentModel(props.selectedAgent, availableModels)
717
+ : undefined;
718
+ if (!preferredAgentModel)
719
+ return;
701
720
  if (current?.model === preferredAgentModel.model &&
702
721
  current.engine === preferredAgentModel.engine) {
703
722
  return;
@@ -721,6 +740,8 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
721
740
  resolveThreadModelSelection,
722
741
  ]);
723
742
  const refreshEngines = useCallback(() => {
743
+ if (hostManagedModels)
744
+ return;
724
745
  setModelListLoading(true);
725
746
  Promise.all([
726
747
  callAction("manage-agent-engine", { action: "list" }).catch(() => null),
@@ -751,12 +772,12 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
751
772
  currentEngineName,
752
773
  currentModel,
753
774
  });
754
- setAvailableModels(groups);
775
+ setDiscoveredModels(groups);
755
776
  setDefaultModel(currentModel ?? DEFAULT_MODEL);
756
777
  })
757
778
  .catch(() => { })
758
779
  .finally(() => setModelListLoading(false));
759
- }, []);
780
+ }, [hostManagedModels]);
760
781
  useEffect(() => {
761
782
  refreshEngines();
762
783
  window.addEventListener("agent-engine:configured-changed", refreshEngines);
@@ -1976,7 +1997,7 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1976
1997
  ? clearActiveTab
1977
1998
  : undefined, isThreadStateLoading: isLoading, onMessageCountChange: (count) => setMessageCounts((prev) => prev[tabId] === count
1978
1999
  ? prev
1979
- : { ...prev, [tabId]: count }), onSaveThread: handleSaveThread, onGenerateTitle: handleGenerateTitle, onSlashCommand: handleSlashCommand, selectedModel: modelSelection?.model, selectedEngine: modelSelection?.engine, selectedEffort: modelSelection?.effort ?? DEFAULT_REASONING_EFFORT, composerSlot: props.composerSlot, defaultModel: defaultModel, availableModels: availableModels, modelListLoading: modelListLoading, onModelChange: handleModelChange, onEffortChange: handleEffortChange, onForkChat: () => handleForkChat(tabId),
2000
+ : { ...prev, [tabId]: count }), onSaveThread: handleSaveThread, onGenerateTitle: handleGenerateTitle, onSlashCommand: handleSlashCommand, selectedModel: modelSelection?.model, selectedEngine: modelSelection?.engine, selectedEffort: modelSelection?.effort ?? DEFAULT_REASONING_EFFORT, composerSlot: props.composerSlot, defaultModel: defaultModel, availableModels: availableModels, modelListLoading: modelListLoading, onModelChange: handleModelChangeWithHost, onEffortChange: handleEffortChange, onForkChat: () => handleForkChat(tabId),
1980
2001
  // Sub-agent tabs are read-only: sending a new message from the
1981
2002
  // sub-agent tab would start a fresh run on that thread and kill
1982
2003
  // the in-flight team chunk. Disable the composer and show a
@@ -11,7 +11,7 @@ export { buildRepositoryFromCodeAgentTranscript, type BuildRepositoryFromCodeAge
11
11
  export { compareCodeAgentTranscriptEvents, getCodeAgentTranscriptSeq, isCodeAgentRunActive, mergeCodeAgentTranscriptEvents, type CodeAgentRunStateLike, type CodeAgentTranscriptOrderEvent, } from "../../code-agents/transcript-order.js";
12
12
  export { CREDENTIAL_GAP_SIGNAL, isCredentialGapCodeAgentEvent, } from "../../code-agents/transcript-normalizer.js";
13
13
  export { useSendToAgentChat } from "../use-send-to-agent-chat.js";
14
- export { useChatModels, type UseChatModelsResult, type EngineModelGroup, } from "../use-chat-models.js";
14
+ export { chatModelSelectionStorageKey, useChatModels, type UseChatModelsResult, type EngineModelGroup, } from "../use-chat-models.js";
15
15
  export { CodeRequiredDialog, type CodeRequiredDialogProps, } from "../components/CodeRequiredDialog.js";
16
16
  export { ChatFirstAgentActivityPanel, type ChatFirstAgentActivityPanelProps, } from "../chat-first-agent-activity.js";
17
17
  export { ChatFirstSurfacePanelToggle } from "../chat-first-surface-panel-toggle.js";
@@ -11,7 +11,7 @@ export { buildRepositoryFromCodeAgentTranscript, } from "../../agent/thread-data
11
11
  export { compareCodeAgentTranscriptEvents, getCodeAgentTranscriptSeq, isCodeAgentRunActive, mergeCodeAgentTranscriptEvents, } from "../../code-agents/transcript-order.js";
12
12
  export { CREDENTIAL_GAP_SIGNAL, isCredentialGapCodeAgentEvent, } from "../../code-agents/transcript-normalizer.js";
13
13
  export { useSendToAgentChat } from "../use-send-to-agent-chat.js";
14
- export { useChatModels, } from "../use-chat-models.js";
14
+ export { chatModelSelectionStorageKey, useChatModels, } from "../use-chat-models.js";
15
15
  export { CodeRequiredDialog, } from "../components/CodeRequiredDialog.js";
16
16
  export { ChatFirstAgentActivityPanel, } from "../chat-first-agent-activity.js";
17
17
  export { ChatFirstSurfacePanelToggle } from "../chat-first-surface-panel-toggle.js";
@@ -57,7 +57,8 @@ export type ManageJobInput = {
57
57
  };
58
58
  export type ManageAutomationInput = ManageJobInput;
59
59
  export interface RunAutomationNowInput {
60
- name: string;
60
+ name?: string;
61
+ path?: string;
61
62
  scope: "personal" | "organization";
62
63
  }
63
64
  export interface RunAutomationNowResult {
@@ -87,12 +87,10 @@ export function useRunAutomationNow() {
87
87
  return useActionMutation("run-automation-now", {
88
88
  onSuccess: (_result, variables) => {
89
89
  const scope = variables.scope === "organization" ? "organization" : "personal";
90
+ const name = variables.name ??
91
+ variables.path?.replace(/^jobs\//, "").replace(/\.md$/, "");
90
92
  queryClient.invalidateQueries({
91
- queryKey: [
92
- "action",
93
- "list-automation-runs",
94
- { scope, name: variables.name },
95
- ],
93
+ queryKey: ["action", "list-automation-runs", { scope, name }],
96
94
  });
97
95
  queryClient.invalidateQueries({
98
96
  queryKey: ["action", "list-automations", { scope }],
@@ -1,4 +1,4 @@
1
- import { AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, } from "../shared/agent-sidebar-url.js";
1
+ import { AGENT_SIDEBAR_QUERY_PARAM, AGENT_SIDEBAR_QUERY_VALUE_CLOSED, AGENT_SIDEBAR_QUERY_VALUE_OPEN, } from "../shared/agent-sidebar-url.js";
2
2
  import { hasChatThreadDeepLink } from "./chat-thread-url.js";
3
3
  export { hasChatThreadDeepLink } from "./chat-thread-url.js";
4
4
  export const SIDEBAR_OPEN_KEY = "agent-native-sidebar-open";
@@ -62,6 +62,8 @@ export function getAgentSidebarUrlOpenOverride() {
62
62
  const value = url.searchParams.get(AGENT_SIDEBAR_QUERY_PARAM);
63
63
  if (value === AGENT_SIDEBAR_QUERY_VALUE_CLOSED)
64
64
  return false;
65
+ if (value === AGENT_SIDEBAR_QUERY_VALUE_OPEN)
66
+ return true;
65
67
  }
66
68
  catch { }
67
69
  return null;
@@ -273,4 +273,9 @@ export const codeTabsBlock = defineBlock({
273
273
  label: "Code tabs",
274
274
  icon: IconCode,
275
275
  description: "A vertical file tab rail of syntax-highlighted code snippets, one tab per file with an optional language and caption.",
276
+ // `tabs` has schema min(1), so a fresh insert needs one starter tab — same
277
+ // shape `addTab` mints for a second tab.
278
+ empty: () => ({
279
+ tabs: [{ id: newCodeTabId(), label: "file-1.ts", code: "" }],
280
+ }),
276
281
  });
@@ -131,4 +131,5 @@ export const codeBlock = defineBlock({
131
131
  label: "Code",
132
132
  icon: IconCode,
133
133
  description: "A single syntax-highlighted code snippet, Notion-style: one border, a hover language switcher + copy, and collapse-to-N lines. Put several in a `tabs` block for a file rail.",
134
+ empty: () => ({ code: "" }),
134
135
  });
@@ -44,7 +44,7 @@ function AppRows({ apps, defaultAppIds, activeAppId, layout, onDragStart, onDrop
44
44
  const pinned = layout.pinnedIds.includes(app.id);
45
45
  const index = orderedApps.indexOf(app);
46
46
  return (_jsxs(ContextMenu, { children: [_jsx(ContextMenuTrigger, { asChild: true, children: _jsxs("li", { draggable: true, "data-chat-first-app": true, "data-app-id": app.id, className: cn("group flex h-8 w-full min-w-0 items-center gap-1 rounded-md px-0 text-sm", active
47
- ? "font-medium text-sidebar-foreground"
47
+ ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
48
48
  : "text-sidebar-foreground/75 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), onDragStart: (event) => {
49
49
  event.dataTransfer.effectAllowed = "move";
50
50
  onDragStart(app.id);
@@ -136,7 +136,7 @@ export const ChatFirstAppsRail = memo(function ChatFirstAppsRail({ apps, default
136
136
  return (_jsx(TooltipProvider, { children: _jsxs("section", { "data-chat-first-apps-rail": true, className: "flex flex-col items-center gap-1 px-1.5 pt-2", "aria-label": copy("workspaceApps"), children: [loading && apps.length === 0
137
137
  ? [0, 1, 2].map((index) => (_jsx(Skeleton, { className: "size-9 rounded-md" }, index)))
138
138
  : visibleApps.map((app) => (_jsxs(Tooltip, { delayDuration: 0, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "data-chat-first-app": true, "data-app-id": app.id, className: cn("flex size-9 items-center justify-center rounded-md", activeAppId === app.id
139
- ? "text-sidebar-foreground"
139
+ ? "bg-sidebar-accent text-sidebar-accent-foreground"
140
140
  : "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), onClick: () => onOpenApp(app), "aria-label": copy("openApp", { name: app.name }), children: _jsx(ChatFirstRailAppIcon, { app: app, activeAppId: activeAppId, renderIcon: renderIcon }) }) }), _jsx(TooltipContent, { side: "right", children: app.name })] }, app.id))), onOpenAllApps ? (_jsxs(Tooltip, { delayDuration: 0, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "data-chat-first-all-apps": true, className: "flex size-9 items-center justify-center rounded-md text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", onClick: onOpenAllApps, "aria-label": copy("allApps"), children: _jsx(IconApps, { size: 16, "aria-hidden": "true" }) }) }), _jsx(TooltipContent, { side: "right", children: copy("allApps") })] })) : null, error ? (_jsx("span", { className: "size-1.5 rounded-full bg-destructive", title: error, "aria-label": error })) : null] }) }));
141
141
  }
142
142
  return (_jsxs("section", { "data-chat-first-apps-rail": true, className: "mt-3 px-2 pb-2 pt-2", "aria-label": copy("workspaceApps"), children: [_jsxs("div", { className: "mb-1 flex items-center gap-1.5 px-2 text-[11px] font-medium text-sidebar-foreground/50", children: [_jsx("span", { children: copy("workspaceApps") }), _jsx("span", { className: "ml-auto", children: createTrigger })] }), loading && apps.length === 0 ? (_jsx("div", { className: "space-y-0.5 px-2", children: [0, 1, 2].map((index) => (_jsx(Skeleton, { className: "h-8 w-full rounded-md" }, index))) })) : apps.length === 0 ? (_jsxs("div", { className: "px-2", children: [_jsx("p", { className: "text-xs text-sidebar-foreground/55", children: copy("noWorkspaceApps") }), createAppTrigger ? (createTrigger) : onCreateApp ? (_jsxs("button", { type: "button", className: "mt-1 inline-flex h-6 items-center gap-1.5 rounded-md border border-sidebar-border px-2 text-xs text-sidebar-foreground/75 hover:bg-sidebar-accent hover:text-sidebar-foreground", onClick: onCreateApp, children: [_jsx(IconPlus, { size: 13, "aria-hidden": "true" }), copy("createApp")] })) : (createTrigger)] })) : (_jsx(AppRows, { apps: visibleApps, defaultAppIds: defaultAppIds, activeAppId: activeAppId, layout: layout, onDragStart: setDraggedAppId, onDrop: reorderApps, onDragEnd: () => setDraggedAppId(null), onOpenApp: onOpenApp, onRemoveApp: onRemoveApp, onTogglePinned: togglePinned, onMove: moveApp, renderIcon: renderIcon, copy: copy })), hasMoreApps || showAllApps ? (_jsxs("button", { type: "button", className: "mt-0.5 flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs text-sidebar-foreground/50 hover:bg-sidebar-accent hover:text-sidebar-foreground", onClick: () => setShowAllApps((value) => !value), children: [showAllApps ? (_jsx(IconChevronUp, { size: 14, "aria-hidden": "true" })) : (_jsx(IconChevronDown, { size: 14, "aria-hidden": "true" })), showAllApps ? copy("showLess") : copy("showMore")] })) : null, onOpenAllApps ? (_jsx("div", { className: "mt-1 border-t border-sidebar-border/60 pt-1", children: _jsxs("button", { type: "button", "data-chat-first-all-apps": true, className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-xs text-sidebar-foreground/55 hover:bg-sidebar-accent hover:text-sidebar-foreground", onClick: onOpenAllApps, children: [_jsx(IconApps, { size: 14, "aria-hidden": "true" }), _jsx("span", { children: copy("allApps") })] }) })) : null, error ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "mt-1 flex items-center gap-1 px-2 text-[10px] text-destructive/80", onClick: onRetry, "aria-label": error, children: [_jsx("span", { className: "size-1.5 rounded-full bg-destructive" }), onRetry ? copy("retry") : copy("appsLoadError")] }) }), _jsx(TooltipContent, { side: "right", children: error })] })) : null] }));
@@ -10,6 +10,18 @@ export interface ChatModelEngineEntry {
10
10
  supportedModels?: readonly string[];
11
11
  requiredEnvVars?: readonly string[];
12
12
  packageInstalled?: boolean;
13
+ /**
14
+ * Server-resolved readiness. The env-key fallback below cannot see
15
+ * vault-stored credentials or the deploy-injected Builder gateway lane, so
16
+ * an engine running on either is reported unconfigured without this.
17
+ *
18
+ * Undefined means the server could not resolve it — including a credential
19
+ * read that threw, reported in `configuredError`. That deliberately falls
20
+ * through to the env heuristic rather than reading as "needs an API key".
21
+ */
22
+ configured?: boolean;
23
+ /** Why readiness is unknown, when the server's lookup failed. */
24
+ configuredError?: string;
13
25
  }
14
26
  export interface BuildChatModelGroupsOptions {
15
27
  engines: readonly ChatModelEngineEntry[];
@@ -143,8 +143,9 @@ export function buildChatModelGroups({ engines, configuredKeys, builderConnected
143
143
  engine: engine.name,
144
144
  label: engine.label,
145
145
  models: sortModelsByCost(addCurrentModel(engine.supportedModels ?? [], engine.name, currentEngineName, currentModel)),
146
- configured: requiredEnvVars.length === 0 ||
147
- requiredEnvVars.some((key) => configured.has(key)),
146
+ configured: engine.configured ??
147
+ (requiredEnvVars.length === 0 ||
148
+ requiredEnvVars.some((key) => configured.has(key))),
148
149
  };
149
150
  })
150
151
  .filter((group) => group.models.length > 0);
@@ -0,0 +1,5 @@
1
+ import type { SVGProps } from "react";
2
+ export type GoogleProduct = "calendar" | "docs" | "drive" | "gmail" | "sheets" | "slides";
3
+ export declare function GoogleProductLogo({ product, className, ...props }: {
4
+ product: GoogleProduct;
5
+ } & Omit<SVGProps<SVGSVGElement>, "children">): import("react").JSX.Element;
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const GOOGLE_MARK_COLORS = {
3
+ // guard:allow-raw-color - official Google product mark color
4
+ blue: "#4285F4",
5
+ // guard:allow-raw-color - official Google product mark color
6
+ blueDark: "#1A73E8",
7
+ // guard:allow-raw-color - official Google product mark color
8
+ blueLight: "#8AB4F8",
9
+ // guard:allow-raw-color - official Google product mark color
10
+ border: "#DADCE0",
11
+ // guard:allow-raw-color - official Google product mark color
12
+ green: "#34A853",
13
+ // guard:allow-raw-color - official Google product mark color
14
+ greenDark: "#188038",
15
+ // guard:allow-raw-color - official Google product mark color
16
+ red: "#EA4335",
17
+ // guard:allow-raw-color - official Google product mark color
18
+ yellow: "#FBBC04",
19
+ // guard:allow-raw-color - official Google product mark color
20
+ yellowDark: "#F9AB00",
21
+ };
22
+ const commonProps = {
23
+ viewBox: "0 0 24 24",
24
+ fill: "none",
25
+ xmlns: "http://www.w3.org/2000/svg",
26
+ "aria-hidden": true,
27
+ focusable: false,
28
+ };
29
+ export function GoogleProductLogo({ product, className, ...props }) {
30
+ const svgProps = { ...commonProps, className, ...props };
31
+ switch (product) {
32
+ case "gmail":
33
+ return (_jsxs("svg", { ...svgProps, children: [_jsx("path", { d: "M3.5 5.25h17A1.5 1.5 0 0 1 22 6.75v10.5a1.5 1.5 0 0 1-1.5 1.5h-17A1.5 1.5 0 0 1 2 17.25V6.75a1.5 1.5 0 0 1 1.5-1.5Z", fill: "white", stroke: GOOGLE_MARK_COLORS.border }), _jsx("path", { d: "m3 7 9 6.75L21 7", stroke: GOOGLE_MARK_COLORS.red, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("path", { d: "M3 17.75V7m18 10.75V7", stroke: GOOGLE_MARK_COLORS.blue, strokeWidth: "2", strokeLinecap: "round" }), _jsx("path", { d: "m3 7 4.25 3.2", stroke: GOOGLE_MARK_COLORS.yellow, strokeWidth: "2", strokeLinecap: "round" }), _jsx("path", { d: "m21 7-4.25 3.2", stroke: GOOGLE_MARK_COLORS.green, strokeWidth: "2", strokeLinecap: "round" })] }));
34
+ case "calendar":
35
+ return (_jsxs("svg", { ...svgProps, children: [_jsx("rect", { x: "3", y: "4", width: "18", height: "17", rx: "2.5", fill: GOOGLE_MARK_COLORS.blue }), _jsx("path", { d: "M3 9h18", stroke: "white", strokeWidth: "2" }), _jsx("path", { d: "M7 3v3M17 3v3", stroke: GOOGLE_MARK_COLORS.blueDark, strokeWidth: "2", strokeLinecap: "round" }), _jsx("text", { x: "12", y: "17", textAnchor: "middle", fill: "white", fontFamily: "Arial, sans-serif", fontSize: "8", fontWeight: "700", children: "31" })] }));
36
+ case "drive":
37
+ return (_jsxs("svg", { ...svgProps, children: [_jsx("path", { d: "M8.1 3.5h4.65l8.45 14.65h-4.65L8.1 3.5Z", fill: GOOGLE_MARK_COLORS.yellow }), _jsx("path", { d: "M8.1 3.5 3.2 12l4.65 8.05 4.9-8.5L8.1 3.5Z", fill: GOOGLE_MARK_COLORS.green }), _jsx("path", { d: "M3.2 12h9.55l3.8 6.15H6.75L3.2 12Z", fill: GOOGLE_MARK_COLORS.blue })] }));
38
+ case "docs":
39
+ return (_jsxs("svg", { ...svgProps, children: [_jsx("path", { d: "M6 2.5h8l4 4v15H6a2 2 0 0 1-2-2v-15a2 2 0 0 1 2-2Z", fill: GOOGLE_MARK_COLORS.blue }), _jsx("path", { d: "M14 2.5v4h4", fill: GOOGLE_MARK_COLORS.blueLight }), _jsx("path", { d: "M8 11h8M8 14.5h8M8 18h5", stroke: "white", strokeWidth: "1.4", strokeLinecap: "round" })] }));
40
+ case "sheets":
41
+ return (_jsxs("svg", { ...svgProps, children: [_jsx("path", { d: "M6 2.5h8l4 4v15H6a2 2 0 0 1-2-2v-15a2 2 0 0 1 2-2Z", fill: GOOGLE_MARK_COLORS.green }), _jsx("path", { d: "M14 2.5v4h4", fill: GOOGLE_MARK_COLORS.greenDark }), _jsx("path", { d: "M8 10h8v8H8v-8Zm0 2.7h8M8 15.3h8M10.7 10v8", stroke: "white", strokeWidth: "1.2" })] }));
42
+ case "slides":
43
+ return (_jsxs("svg", { ...svgProps, children: [_jsx("path", { d: "M6 2.5h8l4 4v15H6a2 2 0 0 1-2-2v-15a2 2 0 0 1 2-2Z", fill: GOOGLE_MARK_COLORS.yellowDark }), _jsx("path", { d: "M14 2.5v4h4", fill: GOOGLE_MARK_COLORS.yellow }), _jsx("path", { d: "M8 17V11m3 6v-3m3 3v-7", stroke: "white", strokeWidth: "1.7", strokeLinecap: "round" })] }));
44
+ }
45
+ }
@@ -1,6 +1,8 @@
1
1
  export { IntegrationsPanel, McpIntegrationsLanding, McpIntegrationsSection, type McpIntegrationsLandingProps, type McpIntegrationsSectionProps, } from "./IntegrationsPanel.js";
2
2
  export { IntegrationGrid, type IntegrationGridItem, type IntegrationGridProps, } from "./IntegrationGrid.js";
3
3
  export { IntegrationConnectionChoice, type IntegrationConnectionChoiceProps, } from "./IntegrationConnectionChoice.js";
4
+ export { GoogleProductLogo, type GoogleProduct } from "./GoogleProductLogo.js";
5
+ export { startWorkspaceProviderOAuth, workspaceProviderOAuthUrl, type WorkspaceProviderOAuthOptions, type WorkspaceProviderOAuthScope, } from "./workspace-provider-oauth.js";
4
6
  export { useIntegrationStatus } from "./useIntegrationStatus.js";
5
7
  export type { IntegrationStatus } from "./useIntegrationStatus.js";
6
8
  export { listIntegrationEnvStatuses, listIntegrationStatuses, saveIntegrationEnvVars, setIntegrationEnabled, setupIntegration, disconnectManagedIntegrationInstallation, listManagedIntegrationInstallations, managedIntegrationOAuthUrl, managedSlackAgentManifestUrl, listManagedIntegrationScopes, saveManagedIntegrationScope, listManagedIntegrationBudgets, listManagedIntegrationMemory, forgetManagedIntegrationMemory, saveManagedIntegrationBudget, testManagedIntegrationInstallation, IntegrationClientError, type ClientIntegrationInstallation, type ClientIntegrationScope, type ClientIntegrationUsageBudget, type ClientIntegrationMemory, type ClientIntegrationStatus, type IntegrationEnvStatus, type SavedEnvVarsResult, } from "./api.js";
@@ -1,5 +1,7 @@
1
1
  export { IntegrationsPanel, McpIntegrationsLanding, McpIntegrationsSection, } from "./IntegrationsPanel.js";
2
2
  export { IntegrationGrid, } from "./IntegrationGrid.js";
3
3
  export { IntegrationConnectionChoice, } from "./IntegrationConnectionChoice.js";
4
+ export { GoogleProductLogo } from "./GoogleProductLogo.js";
5
+ export { startWorkspaceProviderOAuth, workspaceProviderOAuthUrl, } from "./workspace-provider-oauth.js";
4
6
  export { useIntegrationStatus } from "./useIntegrationStatus.js";
5
7
  export { listIntegrationEnvStatuses, listIntegrationStatuses, saveIntegrationEnvVars, setIntegrationEnabled, setupIntegration, disconnectManagedIntegrationInstallation, listManagedIntegrationInstallations, managedIntegrationOAuthUrl, managedSlackAgentManifestUrl, listManagedIntegrationScopes, saveManagedIntegrationScope, listManagedIntegrationBudgets, listManagedIntegrationMemory, forgetManagedIntegrationMemory, saveManagedIntegrationBudget, testManagedIntegrationInstallation, IntegrationClientError, } from "./api.js";
@@ -0,0 +1,8 @@
1
+ export type WorkspaceProviderOAuthScope = "user" | "organization" | "app";
2
+ export interface WorkspaceProviderOAuthOptions {
3
+ appId: string;
4
+ returnPath?: string;
5
+ scope?: WorkspaceProviderOAuthScope;
6
+ }
7
+ export declare function workspaceProviderOAuthUrl(provider: string, options: WorkspaceProviderOAuthOptions): string;
8
+ export declare function startWorkspaceProviderOAuth(provider: string, options: WorkspaceProviderOAuthOptions): void;
@@ -0,0 +1,13 @@
1
+ import { agentNativePath } from "../api-path.js";
2
+ export function workspaceProviderOAuthUrl(provider, options) {
3
+ const params = new URLSearchParams({
4
+ appId: options.appId,
5
+ scope: options.scope ?? "user",
6
+ });
7
+ if (options.returnPath)
8
+ params.set("return", options.returnPath);
9
+ return agentNativePath(`/_agent-native/connections/oauth/${provider}/start?${params.toString()}`);
10
+ }
11
+ export function startWorkspaceProviderOAuth(provider, options) {
12
+ window.location.assign(workspaceProviderOAuthUrl(provider, options));
13
+ }
@@ -383,34 +383,6 @@ export const DEFAULT_MCP_INTEGRATIONS = [
383
383
  "Grafana Cloud",
384
384
  ],
385
385
  },
386
- {
387
- id: "google-workspace",
388
- name: "Google Workspace",
389
- provider: "google-workspace",
390
- description: "Search Google Workspace data through its remote MCP server.",
391
- descriptionKey: "mcpIntegrations.catalog.googleWorkspace.description",
392
- useCase: "Workspace search across Gmail, Drive, Calendar, Chat, Docs, Sheets, Slides",
393
- useCaseKey: "mcpIntegrations.catalog.googleWorkspace.useCase",
394
- url: "https://workspacemcp.googleapis.com/mcp/v1",
395
- authMode: "oauth",
396
- connectionMode: "manual",
397
- availability: "beta",
398
- verification: "restricted",
399
- logoUrl: mcpIntegrationLogo("google-workspace"),
400
- docsUrl: "https://developers.google.com/workspace/guides/configure-mcp-servers",
401
- setupNoteKey: "mcpIntegrations.catalog.googleWorkspace.setupNote",
402
- brandAliases: ["Google", "Gmail", "Google Drive", "Google Calendar"],
403
- keywords: [
404
- "email",
405
- "gmail",
406
- "drive",
407
- "calendar",
408
- "chat",
409
- "docs",
410
- "sheets",
411
- "slides",
412
- ],
413
- },
414
386
  {
415
387
  id: "gitlab",
416
388
  name: "GitLab",
@@ -900,7 +872,6 @@ const MCP_LINK_HOSTS = {
900
872
  sentry: ["sentry.io", "sentry.dev"],
901
873
  gong: ["gong.io"],
902
874
  grafana: ["grafana.com", "grafana.net"],
903
- "google-workspace": ["google.com", "googleapis.com"],
904
875
  "builder-cms": ["builder.io"],
905
876
  notion: ["notion.so", "notion.site"],
906
877
  granola: ["granola.ai"],
@@ -200,18 +200,22 @@ export function SettingsTabsPage({ general, account, team, whatsNew, extraTabs =
200
200
  ? defaultTab
201
201
  : (tabs[0]?.id ?? "general");
202
202
  const tabGroups = useMemo(() => {
203
- const groups = [];
203
+ // Keyed by group id so tabs sharing a group merge into one section even
204
+ // when another group's tabs sit between them in `tabs` — adjacency-only
205
+ // merging left same-id groups duplicated (and rendered with duplicate
206
+ // React keys) whenever the tab list interleaved groups.
207
+ const groupsById = new Map();
204
208
  for (const tab of tabs) {
205
209
  const groupId = tab.group ?? "app";
206
- const previousGroup = groups.at(-1);
207
- if (previousGroup?.id === groupId) {
208
- previousGroup.tabs.push(tab);
210
+ const group = groupsById.get(groupId);
211
+ if (group) {
212
+ group.tabs.push(tab);
209
213
  }
210
214
  else {
211
- groups.push({ id: groupId, tabs: [tab] });
215
+ groupsById.set(groupId, { id: groupId, tabs: [tab] });
212
216
  }
213
217
  }
214
- return groups;
218
+ return Array.from(groupsById.values());
215
219
  }, [tabs]);
216
220
  const tabGroupLabels = {
217
221
  app: "Personal",
@@ -133,7 +133,14 @@ function SharePanel(props) {
133
133
  const { controller } = props;
134
134
  const { inviteEmail, setInviteEmail: onInviteEmailChange, activeShareTab, handleShareTabChange, data, policy, visibility, canManage, role, setRole, notifyPeople, setNotifyPeople, shareMessage, setShareMessage, messageOpen, setMessageOpen, shareError, setShareError, suggestionsOpen, setSuggestionsOpen, inFlight, memberSearch, memberSuggestions, groupSuggestions, selectGroup, knownMembers, shares, handleVisibility, handleHideInSearch, handleAdd, handleChangeRole, handleRemove, } = controller;
135
135
  const hasInviteEmail = inviteEmail.trim().length > 0;
136
- const isLoading = data === undefined;
136
+ // `data` stays undefined after a failed read, so a stuck skeleton is
137
+ // indistinguishable from loading unless the error comes off the query itself.
138
+ // `isError` alone is not that signal: it is also true when a refetch fails
139
+ // while React Query still holds usable data, and this panel refetches on open
140
+ // and after every mutation — blocking on that would swap a working panel for
141
+ // a retry screen on one transient failure.
142
+ const loadFailed = controller.sharesQuery.isError && data === undefined;
143
+ const isLoading = !loadFailed && data === undefined;
137
144
  const meta = visibilityMeta(visibility, t, props.visibilityCopy);
138
145
  const peopleAccessLabel = props.peopleAccessLabel ??
139
146
  t("agentChat.share.peopleWithAccess", {
@@ -151,7 +158,9 @@ function SharePanel(props) {
151
158
  const hasTabs = extraTabs.length > 0;
152
159
  const shareTabLabel = props.shareTabs?.shareLabel ??
153
160
  t("agentChat.share.shareLink", { defaultValue: "Share link" });
154
- const sharePanel = isLoading ? (_jsxs("div", { children: [showShareLinks ? (_jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" })) : null, _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsx("div", { className: "mb-4 h-7 rounded-md bg-muted animate-pulse" })] })) : (_jsxs("div", { children: [showShareLinks && shareUrlPlacement === "top" ? shareLinks : null, _jsxs("div", { className: "mb-4", children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(meta.Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { value: visibility, onChange: handleVisibility, disabled: !canManage, visibilityCopy: props.visibilityCopy, allowPublic: policy.allowPublic }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [_jsx("span", { className: "sr-only", children: meta.description }), visibility === "org" && props.hideInSearchControl ? (_jsx(AdvancedAccessPopover, { control: props.hideInSearchControl, canManage: canManage, onToggle: handleHideInSearch })) : null] })] })] })] }), _jsxs("div", { className: "mb-4 space-y-4", children: [_jsx("div", { className: "text-sm font-semibold", children: peopleAccessLabel }), canManage ? (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx(MemberAutocomplete, { value: inviteEmail, open: suggestionsOpen, onOpenChange: setSuggestionsOpen, onValueChange: (next) => {
161
+ const sharePanel = loadFailed ? (_jsxs("div", { children: [showShareLinks && shareUrlPlacement === "top" ? shareLinks : null, _jsxs("div", { role: "alert", className: "flex items-center justify-between gap-2 rounded-md border border-border bg-muted/30 px-3 py-2", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: t("agentChat.share.loadFailed", {
162
+ defaultValue: "Couldn't load sharing settings.",
163
+ }) }), _jsx("button", { type: "button", onClick: () => controller.sharesQuery.refetch(), disabled: controller.sharesQuery.isFetching, className: cn(BUTTON_BASE, "h-7 px-2 text-xs text-muted-foreground hover:bg-accent hover:text-accent-foreground"), children: t("agentChat.common.retry") })] }), showShareLinks && shareUrlPlacement === "bottom" ? shareLinks : null] })) : isLoading ? (_jsxs("div", { children: [showShareLinks ? (_jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" })) : null, _jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsx("div", { className: "mb-4 h-9 rounded-md bg-muted animate-pulse" }), _jsx("div", { className: "mb-2 text-sm font-semibold", children: peopleAccessLabel }), _jsx("div", { className: "mb-4 h-7 rounded-md bg-muted animate-pulse" })] })) : (_jsxs("div", { children: [showShareLinks && shareUrlPlacement === "top" ? shareLinks : null, _jsxs("div", { className: "mb-4", children: [_jsx("div", { className: "mb-2 text-sm font-semibold", children: generalAccessLabel }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(meta.Icon, { size: 16, strokeWidth: 1.75 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(VisibilitySelect, { value: visibility, onChange: handleVisibility, disabled: !canManage, visibilityCopy: props.visibilityCopy, allowPublic: policy.allowPublic }), _jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted-foreground", children: [_jsx("span", { className: "sr-only", children: meta.description }), visibility === "org" && props.hideInSearchControl ? (_jsx(AdvancedAccessPopover, { control: props.hideInSearchControl, canManage: canManage, onToggle: handleHideInSearch })) : null] })] })] })] }), _jsxs("div", { className: "mb-4 space-y-4", children: [_jsx("div", { className: "text-sm font-semibold", children: peopleAccessLabel }), canManage ? (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-stretch gap-2", children: [_jsx(MemberAutocomplete, { value: inviteEmail, open: suggestionsOpen, onOpenChange: setSuggestionsOpen, onValueChange: (next) => {
155
164
  onInviteEmailChange(next);
156
165
  if (shareError)
157
166
  setShareError(null);
@@ -24,6 +24,12 @@ interface Options {
24
24
  */
25
25
  enabled?: boolean;
26
26
  }
27
+ /**
28
+ * `useChatModels` takes the raw localStorage key while `MultiTabAssistantChat`
29
+ * takes only the namespace suffix — a surface that hand-writes either one stops
30
+ * sharing the selection with the chat it sits next to.
31
+ */
32
+ export declare function chatModelSelectionStorageKey(namespace?: string | null): string;
27
33
  export declare const CHAT_MODEL_SELECTION_CHANGED_EVENT = "agent-native:chat-model-selection-changed";
28
34
  /**
29
35
  * Fetches available engines/models from the agent server and exposes the same