@agent-native/core 0.169.0 → 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 (496) 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/bigquery-table-info.ts +3 -2
  6. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  7. package/corpus/templates/analytics/actions/search-bigquery-schema.ts +130 -4
  8. package/corpus/templates/analytics/agent-native.config.ts +1 -0
  9. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +36 -23
  10. package/corpus/templates/analytics/app/i18n-data.ts +28 -0
  11. package/corpus/templates/analytics/app/lib/dashboard-visibility.ts +41 -0
  12. package/corpus/templates/analytics/app/pages/Agents.tsx +25 -1
  13. package/corpus/templates/analytics/app/pages/DashboardOverview.tsx +34 -9
  14. package/corpus/templates/analytics/app/routes/$.tsx +10 -0
  15. package/corpus/templates/analytics/app/routes.ts +3 -1
  16. package/corpus/templates/analytics/changelog/2026-08-21-dashboard-filters-keep-other-users-dashboards-out-of-mine.md +6 -0
  17. package/corpus/templates/analytics/changelog/2026-08-22-fixed-the-agent-native-templates-first-party-dashboard-panel.md +6 -0
  18. package/corpus/templates/analytics/changelog/2026-08-22-org-admin-panels-no-longer-report-a-database-error-as-a-per.md +9 -0
  19. package/corpus/templates/analytics/changelog/2026-08-22-slack-requests-report-invalid-inputs.md +6 -0
  20. package/corpus/templates/analytics/changelog/2026-08-22-unknown-analytics-links-now-return-a-real-not-found-status.md +6 -0
  21. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +2 -1
  22. package/corpus/templates/analytics/docs/schemas/tracked-events.md +2 -0
  23. package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +29 -7
  24. package/corpus/templates/analytics/server/handlers/slack.ts +59 -5
  25. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +11 -6
  26. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +132 -2
  27. package/corpus/templates/analytics/server/lib/real-data-actions.ts +14 -3
  28. package/corpus/templates/analytics/server/lib/slack.ts +4 -2
  29. package/corpus/templates/analytics/server/plugins/agent-chat.ts +33 -3
  30. package/corpus/templates/analytics/vitest.config.ts +6 -1
  31. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +11 -4
  32. package/corpus/templates/assets/app/routes/library.tsx +5 -3
  33. package/corpus/templates/assets/app/routes.ts +3 -1
  34. package/corpus/templates/assets/changelog/2026-08-22-library-page-loads-again-instead-of-crashing-on-open.md +6 -0
  35. package/corpus/templates/assets/vitest.config.ts +6 -1
  36. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +11 -4
  37. package/corpus/templates/brain/app/components/ui/pointer-lock.ts +1 -0
  38. package/corpus/templates/brain/app/routes/sources.tsx +8 -3
  39. package/corpus/templates/brain/changelog/2026-08-22-tuning-or-adding-a-source-no-longer-leaves-the-sources-page.md +6 -0
  40. package/corpus/templates/brain/server/lib/brain.ts +27 -2
  41. package/corpus/templates/brain/vitest.config.ts +1 -0
  42. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +11 -4
  43. package/corpus/templates/calendar/actions/list-booking-links.ts +83 -4
  44. package/corpus/templates/calendar/actions/update-booking-link.ts +4 -3
  45. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +11 -3
  46. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +1 -1
  47. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +103 -44
  48. package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +28 -24
  49. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +9 -2
  50. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +47 -58
  51. package/corpus/templates/calendar/app/hooks/use-booking-links.ts +5 -1
  52. package/corpus/templates/calendar/app/lib/event-layout.ts +52 -26
  53. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +126 -98
  54. package/corpus/templates/calendar/app/pages/CalendarView.tsx +1 -0
  55. package/corpus/templates/calendar/app/pages/Settings.tsx +88 -81
  56. package/corpus/templates/calendar/app/routes.ts +3 -1
  57. package/corpus/templates/calendar/changelog/2026-08-22-booking-link-visibility-respects-shared-access.md +6 -0
  58. package/corpus/templates/calendar/changelog/2026-08-22-clicking-an-out-of-office-event-s-marker-no-longer-creates-a.md +6 -0
  59. package/corpus/templates/calendar/changelog/2026-08-22-event-detail-views-now-show-your-calendar-timezone.md +6 -0
  60. package/corpus/templates/calendar/changelog/2026-08-22-google-calendar-can-now-connect-with-the-shared-google-oauth.md +6 -0
  61. package/corpus/templates/calendar/changelog/2026-08-22-overlapping-events-now-show-each-others-boundaries.md +6 -0
  62. package/corpus/templates/calendar/changelog/2026-08-22-public-booking-pages-now-offer-time-slots-from-the-host-s-we.md +6 -0
  63. package/corpus/templates/calendar/server/handlers/bookings.ts +5 -7
  64. package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
  65. package/corpus/templates/calendar/server/lib/google-calendar.ts +139 -14
  66. package/corpus/templates/calendar/server/onboarding.ts +85 -0
  67. package/corpus/templates/calendar/server/plugins/agent-chat.ts +2 -0
  68. package/corpus/templates/calendar/shared/api.ts +9 -1
  69. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  70. package/corpus/templates/chat/app/routes.ts +3 -1
  71. package/corpus/templates/chat/vitest.config.ts +8 -0
  72. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +11 -4
  73. package/corpus/templates/clips/actions/get-meeting.ts +9 -4
  74. package/corpus/templates/clips/actions/list-recordings.ts +16 -3
  75. package/corpus/templates/clips/actions/search-meetings.ts +1 -0
  76. package/corpus/templates/clips/actions/stop-meeting-recording.ts +87 -6
  77. package/corpus/templates/clips/actions/view-screen.ts +8 -1
  78. package/corpus/templates/clips/app/components/library/search-bar.tsx +1 -1
  79. package/corpus/templates/clips/app/components/meetings/meeting-history-row.tsx +32 -1
  80. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +1 -1
  81. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +29 -1
  82. package/corpus/templates/clips/app/i18n/en-US.ts +5 -0
  83. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +33 -4
  84. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -0
  85. package/corpus/templates/clips/app/routes/access-request.approve.tsx +16 -9
  86. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +17 -7
  87. package/corpus/templates/clips/app/routes/share.$shareId.tsx +17 -7
  88. package/corpus/templates/clips/changelog/2026-08-21-camera-bubble-black-circle.md +6 -0
  89. package/corpus/templates/clips/changelog/2026-08-22-screen-recordings-respect-the-microphone-toggle.md +6 -0
  90. package/corpus/templates/clips/changelog/2026-08-22-the-recordings-library-no-longer-fails-right-after-server-start.md +6 -0
  91. package/corpus/templates/clips/changelog/2026-08-23-the-agent-can-see-your-library-right-after-server-start.md +6 -0
  92. package/corpus/templates/clips/chrome-extension/src/background.ts +1 -2
  93. package/corpus/templates/clips/chrome-extension/src/native-transcription.ts +39 -7
  94. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +21 -25
  95. package/corpus/templates/clips/desktop/src/app.tsx +53 -24
  96. package/corpus/templates/clips/desktop/src/lib/bubble-playback.ts +68 -0
  97. package/corpus/templates/clips/desktop/src/lib/recorder.ts +3 -0
  98. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +72 -14
  99. package/corpus/templates/clips/desktop/src/lib/updater.ts +8 -3
  100. package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +162 -20
  101. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +43 -6
  102. package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +150 -13
  103. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
  104. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +28 -3
  105. package/corpus/templates/clips/server/lib/emails.ts +17 -33
  106. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +11 -4
  107. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +140 -15
  108. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +12 -14
  109. package/corpus/templates/content/app/components/ui/pointer-lock.ts +1 -0
  110. package/corpus/templates/content/app/hooks/use-content-database.ts +18 -2
  111. package/corpus/templates/content/app/hooks/use-local-storage.ts +38 -22
  112. package/corpus/templates/content/app/i18n-data.ts +25 -0
  113. package/corpus/templates/content/app/routes.ts +3 -1
  114. package/corpus/templates/content/changelog/2026-08-22-code-blocks-inserted-from-the-slash-menu-no-longer-get-stuck.md +6 -0
  115. package/corpus/templates/content/changelog/2026-08-22-the-sidebar-page-tree-no-longer-flashes-empty-after-creating-a-page.md +6 -0
  116. package/corpus/templates/content/docs/solutions/2026-08-21-content-mermaid-rendering-shape.md +233 -0
  117. package/corpus/templates/content/server/plugins/agent-chat.ts +9 -2
  118. package/corpus/templates/content/vitest.config.ts +7 -1
  119. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +11 -4
  120. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +11 -4
  121. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1386 -92
  122. package/corpus/templates/design/actions/generate-design.ts +98 -47
  123. package/corpus/templates/design/actions/get-design-system.ts +6 -1
  124. package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +146 -0
  125. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +70 -26
  126. package/corpus/templates/design/app/components/design/EditPanel.tsx +15 -47
  127. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +284 -136
  128. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +2060 -144
  129. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +6 -2
  130. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +4 -4
  131. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +10 -8
  132. package/corpus/templates/design/app/components/design/multi-screen/alt-hover-measurement.ts +19 -2
  133. package/corpus/templates/design/app/components/design/multi-screen/types.ts +9 -2
  134. package/corpus/templates/design/app/components/layout/Header.tsx +15 -0
  135. package/corpus/templates/design/app/components/layout/Layout.tsx +7 -2
  136. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +13 -8
  137. package/corpus/templates/design/app/i18n-data.ts +11 -10
  138. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +12 -0
  139. package/corpus/templates/design/app/lib/design-system-data.ts +68 -0
  140. package/corpus/templates/design/app/pages/DesignEditor.tsx +99 -57
  141. package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +39 -8
  142. package/corpus/templates/design/app/pages/DesignSystems.tsx +137 -43
  143. package/corpus/templates/design/app/pages/Index.tsx +3 -1
  144. package/corpus/templates/design/app/pages/Templates.tsx +0 -10
  145. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +10 -0
  146. package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +50 -0
  147. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +1 -1
  148. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +10 -8
  149. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +6 -6
  150. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +1 -1
  151. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +18 -7
  152. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +4 -90
  153. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +2 -1
  154. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +4 -3
  155. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +12 -2
  156. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +9 -2
  157. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +1 -1
  158. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +1 -1
  159. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +1 -1
  160. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +1 -1
  161. package/corpus/templates/design/app/pages/design-editor/editor-state.ts +11 -1
  162. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +11 -19
  163. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +6 -6
  164. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +1 -1
  165. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +12 -15
  166. package/corpus/templates/design/app/pages/design-editor/preview-navigation.ts +25 -0
  167. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +5 -59
  168. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +8 -0
  169. package/corpus/templates/design/app/pages/design-editor/types.ts +3 -3
  170. package/corpus/templates/design/app/routes.ts +3 -1
  171. package/corpus/templates/design/changelog/2026-08-20-canvas-edits-patch-the-frame-instead-of-rebuilding-it.md +6 -0
  172. package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +6 -0
  173. package/corpus/templates/design/changelog/2026-08-21-draw-mode-needs-shift-y.md +6 -0
  174. package/corpus/templates/design/changelog/2026-08-21-eyedropper-shortcut.md +6 -0
  175. package/corpus/templates/design/changelog/2026-08-21-figma-style-alignment-guides-and-snapping.md +6 -0
  176. package/corpus/templates/design/changelog/2026-08-21-group-transforms-keep-the-selection.md +6 -0
  177. package/corpus/templates/design/changelog/2026-08-21-inspector-fields-keep-focus-on-enter.md +6 -0
  178. package/corpus/templates/design/changelog/2026-08-21-pen-alt-keeps-the-incoming-handle.md +6 -0
  179. package/corpus/templates/design/changelog/2026-08-21-pen-on-the-board-creates-one-vector.md +6 -0
  180. package/corpus/templates/design/changelog/2026-08-21-scale-a-multi-selection-from-the-group-handles.md +6 -0
  181. package/corpus/templates/design/changelog/2026-08-21-scale-resizes-text-with-the-object.md +6 -0
  182. package/corpus/templates/design/changelog/2026-08-21-selecting-another-object-keeps-the-scale-tool-armed.md +6 -0
  183. package/corpus/templates/design/changelog/2026-08-21-the-shape-tool-remembers-the-shape-you-picked.md +6 -0
  184. package/corpus/templates/design/changelog/2026-08-21-vectors-drawn-in-a-frame-land-where-you-drew-them.md +6 -0
  185. package/corpus/templates/design/changelog/2026-08-22-multi-screen-generation-no-longer-loses-a-saved-screens-layo.md +6 -0
  186. package/corpus/templates/design/changelog/2026-08-22-rename-and-search-fields-are-labeled-for-screen-readers.md +6 -0
  187. package/corpus/templates/design/package.json +2 -0
  188. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +311 -0
  189. package/corpus/templates/design/shared/canvas-math.ts +612 -206
  190. package/corpus/templates/design/shared/pen-path.ts +37 -0
  191. package/corpus/templates/design/vitest.config.ts +7 -1
  192. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +11 -4
  193. package/corpus/templates/dispatch/actions/list-workspace-connections.ts +34 -3
  194. package/corpus/templates/dispatch/app/routes/integrations.tsx +55 -21
  195. package/corpus/templates/dispatch/app/routes.ts +3 -1
  196. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +11 -4
  197. package/corpus/templates/factory/.env.example +2 -7
  198. package/corpus/templates/factory/AGENTS.md +3 -0
  199. package/corpus/templates/factory/README.md +5 -3
  200. package/corpus/templates/factory/actions/create-factory.ts +16 -3
  201. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +2 -0
  202. package/corpus/templates/factory/actions/get-triage-item.ts +2 -0
  203. package/corpus/templates/factory/actions/list-factory-audit.ts +116 -36
  204. package/corpus/templates/factory/actions/list-factory-automations.ts +2 -1
  205. package/corpus/templates/factory/actions/list-triage-items.ts +22 -19
  206. package/corpus/templates/factory/actions/run-factory-automation.ts +7 -3
  207. package/corpus/templates/factory/actions/save-factory-automation.ts +5 -2
  208. package/corpus/templates/factory/actions/save-triage-config.ts +2 -8
  209. package/corpus/templates/factory/actions/start-builder-for-item.ts +21 -0
  210. package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +229 -297
  211. package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +397 -247
  212. package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +33 -0
  213. package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +202 -162
  214. package/corpus/templates/factory/app/i18n/en-US.ts +32 -4
  215. package/corpus/templates/factory/app/routes/factory.tsx +84 -11
  216. package/corpus/templates/factory/app/routes.ts +3 -1
  217. package/corpus/templates/factory/changelog/2026-08-21-activity-runs-use-automation-display-names.md +6 -0
  218. package/corpus/templates/factory/changelog/2026-08-21-create-and-settings-source-cards.md +6 -0
  219. package/corpus/templates/factory/changelog/2026-08-21-keep-automations-visible-while-running.md +6 -0
  220. package/corpus/templates/factory/changelog/2026-08-21-nested-factory-automations-can-poll.md +6 -0
  221. package/corpus/templates/factory/changelog/2026-08-21-settings-sticky-unsaved-bar.md +6 -0
  222. package/corpus/templates/factory/server/connectors/credentials.ts +10 -5
  223. package/corpus/templates/factory/server/lib/factory-audit-report.ts +412 -0
  224. package/corpus/templates/factory/server/lib/factory-config-reconcile.ts +321 -0
  225. package/corpus/templates/factory/server/lib/factory-scope.ts +25 -2
  226. package/corpus/templates/factory/server/lib/require-factory-automation.ts +13 -4
  227. package/corpus/templates/factory/server/plugins/factory-migrations.ts +148 -4
  228. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +4 -6
  229. package/corpus/templates/factory/vitest.config.ts +17 -2
  230. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +11 -4
  231. package/corpus/templates/forms/app/routes/_app.settings.tsx +4 -1
  232. package/corpus/templates/forms/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  233. package/corpus/templates/forms/server/lib/public-form-ssr.ts +11 -1
  234. package/corpus/templates/forms/vitest.config.ts +1 -0
  235. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +11 -4
  236. package/corpus/templates/macros/app/routes.ts +3 -1
  237. package/corpus/templates/macros/vitest.config.ts +6 -1
  238. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +11 -4
  239. package/corpus/templates/mail/actions/manage-gmail-filters.ts +10 -2
  240. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +100 -37
  241. package/corpus/templates/mail/app/components/email/IntegrationsSidebar.tsx +14 -2
  242. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +66 -36
  243. package/corpus/templates/mail/app/hooks/use-emails.ts +13 -3
  244. package/corpus/templates/mail/app/hooks/use-google-auth.ts +2 -0
  245. package/corpus/templates/mail/app/lib/google-oauth-setup.ts +17 -0
  246. package/corpus/templates/mail/app/pages/InboxPage.tsx +69 -9
  247. package/corpus/templates/mail/app/routes/$.tsx +9 -0
  248. package/corpus/templates/mail/app/routes/$view.$threadId.tsx +23 -1
  249. package/corpus/templates/mail/app/routes/$view.tsx +47 -1
  250. package/corpus/templates/mail/app/routes.ts +3 -1
  251. package/corpus/templates/mail/changelog/2026-08-22-gmail-can-now-connect-with-the-shared-google-oauth.md +6 -0
  252. package/corpus/templates/mail/changelog/2026-08-22-gmail-filters-now-shows-the-real-error.md +6 -0
  253. package/corpus/templates/mail/changelog/2026-08-22-unknown-mail-urls-now-show-the-404-page.md +6 -0
  254. package/corpus/templates/mail/server/handlers/google-auth.ts +11 -2
  255. package/corpus/templates/mail/server/lib/google-auth.ts +92 -12
  256. package/corpus/templates/mail/server/onboarding.ts +66 -18
  257. package/corpus/templates/mail/vitest.config.ts +6 -1
  258. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +11 -4
  259. package/corpus/templates/plan/app/routes/settings.tsx +4 -1
  260. package/corpus/templates/plan/app/routes.ts +3 -1
  261. package/corpus/templates/plan/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  262. package/corpus/templates/plan/netlify.toml +1 -1
  263. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +11 -4
  264. package/corpus/templates/slides/actions/patch-deck.ts +79 -10
  265. package/corpus/templates/slides/actions/update-slide.ts +11 -1
  266. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +14 -4
  267. package/corpus/templates/slides/app/components/editor/ExportMenu.tsx +10 -52
  268. package/corpus/templates/slides/app/components/editor/GoogleDocImportHint.tsx +8 -53
  269. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +9 -75
  270. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +8 -60
  271. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +10 -2
  272. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +19 -7
  273. package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +49 -36
  274. package/corpus/templates/slides/app/routes/access-request.approve.tsx +16 -9
  275. package/corpus/templates/slides/app/routes.ts +3 -1
  276. package/corpus/templates/slides/changelog/2026-08-22-already-uploaded-chat-images-are-no-longer-dropped.md +6 -0
  277. package/corpus/templates/slides/changelog/2026-08-22-google-drive-and-slides-can-now-connect-with-the-shared-google-oauth.md +6 -0
  278. package/corpus/templates/slides/changelog/2026-08-22-multi-slide-repairs-now-report-slides-that-still-overflow.md +6 -0
  279. package/corpus/templates/slides/changelog/2026-08-22-update-slide-now-reports-which-batched-edit-was-skipped.md +6 -0
  280. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +52 -1
  281. package/corpus/templates/slides/server/lib/chat-attachments.ts +29 -3
  282. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +66 -16
  283. package/corpus/templates/slides/server/lib/slide-content-patch.ts +13 -2
  284. package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -2
  285. package/corpus/templates/slides/tsconfig.json +5 -0
  286. package/corpus/templates/slides/vitest.config.ts +6 -1
  287. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +11 -4
  288. package/corpus/templates/tasks/app/routes/settings.tsx +4 -1
  289. package/corpus/templates/tasks/app/routes.ts +3 -1
  290. package/corpus/templates/tasks/changelog/2026-08-22-the-extensions-link-now-opens-the-extensions-tab-instead-o.md +6 -0
  291. package/corpus/templates/tasks/vitest.config.ts +7 -1
  292. package/dist/action.d.ts +91 -0
  293. package/dist/action.js +50 -0
  294. package/dist/agent/abort-reasons.d.ts +38 -0
  295. package/dist/agent/abort-reasons.js +49 -0
  296. package/dist/agent/engine/ai-sdk-engine.js +8 -5
  297. package/dist/agent/engine/anthropic-engine.js +7 -5
  298. package/dist/agent/engine/credential-errors.d.ts +1 -1
  299. package/dist/agent/engine/credential-errors.js +2 -2
  300. package/dist/agent/engine/first-event-timeout.d.ts +42 -17
  301. package/dist/agent/engine/first-event-timeout.js +67 -25
  302. package/dist/agent/production-agent.d.ts +23 -0
  303. package/dist/agent/production-agent.js +107 -102
  304. package/dist/agent/run-loop-with-resume.d.ts +2 -28
  305. package/dist/agent/run-loop-with-resume.js +25 -40
  306. package/dist/agent/run-manager.js +5 -4
  307. package/dist/agent/run-store.d.ts +55 -0
  308. package/dist/agent/run-store.js +124 -1
  309. package/dist/agent/tool-search.js +2 -1
  310. package/dist/agent/types.d.ts +9 -4
  311. package/dist/app-config/configuration-error.d.ts +11 -0
  312. package/dist/app-config/configuration-error.js +14 -0
  313. package/dist/app-config/index.d.ts +1 -0
  314. package/dist/app-config/index.js +1 -0
  315. package/dist/app-config/integrations.d.ts +1 -0
  316. package/dist/app-config/integrations.js +10 -0
  317. package/dist/app-config/plugins.d.ts +34 -0
  318. package/dist/app-config/plugins.js +39 -0
  319. package/dist/app-config/run-lifecycle-invariants.d.ts +18 -9
  320. package/dist/app-config/run-lifecycle-invariants.js +18 -25
  321. package/dist/app-config/schema.d.ts +16 -0
  322. package/dist/app-config/schema.js +2 -0
  323. package/dist/chat-threads/schema-migrations.js +20 -0
  324. package/dist/chat-threads/store.js +21 -4
  325. package/dist/cli/native-dependencies.d.ts +4 -0
  326. package/dist/cli/native-dependencies.js +15 -0
  327. package/dist/client/AssistantChat.js +47 -15
  328. package/dist/client/ConnectBuilderCard.d.ts +3 -1
  329. package/dist/client/ConnectBuilderCard.js +6 -3
  330. package/dist/client/EnvironmentBadge.d.ts +1 -1
  331. package/dist/client/EnvironmentBadge.js +40 -5
  332. package/dist/client/MultiTabAssistantChat.d.ts +1 -1
  333. package/dist/client/MultiTabAssistantChat.js +35 -14
  334. package/dist/client/agent-chat/index.d.ts +1 -1
  335. package/dist/client/agent-chat/index.js +1 -1
  336. package/dist/client/agent-page/use-jobs.d.ts +2 -1
  337. package/dist/client/agent-page/use-jobs.js +3 -5
  338. package/dist/client/agent-sidebar-state.js +3 -1
  339. package/dist/client/blocks/library/code-tabs.js +5 -0
  340. package/dist/client/blocks/library/code.js +1 -0
  341. package/dist/client/chat/message-components.d.ts +7 -0
  342. package/dist/client/chat/message-components.js +1 -1
  343. package/dist/client/chat/run-recovery.js +5 -2
  344. package/dist/client/chat/tool-call-display.js +9 -3
  345. package/dist/client/chat-first/apps-rail.js +2 -2
  346. package/dist/client/chat-model-groups.d.ts +12 -0
  347. package/dist/client/chat-model-groups.js +3 -2
  348. package/dist/client/error-format.js +12 -0
  349. package/dist/client/integrations/GoogleProductLogo.d.ts +5 -0
  350. package/dist/client/integrations/GoogleProductLogo.js +45 -0
  351. package/dist/client/integrations/index.d.ts +2 -0
  352. package/dist/client/integrations/index.js +2 -0
  353. package/dist/client/integrations/workspace-provider-oauth.d.ts +8 -0
  354. package/dist/client/integrations/workspace-provider-oauth.js +13 -0
  355. package/dist/client/navigation/index.d.ts +1 -0
  356. package/dist/client/navigation/index.js +1 -0
  357. package/dist/client/resources/mcp-integration-catalog.js +0 -29
  358. package/dist/client/route-state.js +6 -0
  359. package/dist/client/settings/SettingsTabsPage.js +10 -6
  360. package/dist/client/sharing/ShareButton.js +11 -2
  361. package/dist/client/use-chat-models.d.ts +6 -0
  362. package/dist/client/use-chat-models.js +10 -0
  363. package/dist/client/use-db-sync.js +27 -9
  364. package/dist/client/workspace-app-navigation.d.ts +10 -0
  365. package/dist/client/workspace-app-navigation.js +38 -0
  366. package/dist/collab/struct-routes.d.ts +1 -1
  367. package/dist/connections/catalog.d.ts +111 -9
  368. package/dist/connections/catalog.js +86 -30
  369. package/dist/db/create-get-db.js +18 -0
  370. package/dist/db/ddl-guard.d.ts +0 -4
  371. package/dist/db/ddl-guard.js +46 -0
  372. package/dist/deploy/build.d.ts +32 -0
  373. package/dist/deploy/build.js +241 -16
  374. package/dist/deploy/function-bundle.d.ts +45 -0
  375. package/dist/deploy/function-bundle.js +337 -0
  376. package/dist/deploy/workspace-deploy.js +19 -1
  377. package/dist/eject/workspace-connections.js +4 -0
  378. package/dist/email-catalog/registry.d.ts +4 -0
  379. package/dist/email-catalog/registry.js +79 -14
  380. package/dist/extensions/content-patch.js +14 -2
  381. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  382. package/dist/integrations/plugin.d.ts +10 -0
  383. package/dist/integrations/plugin.js +40 -6
  384. package/dist/jobs/actions/run-automation-now.d.ts +2 -1
  385. package/dist/jobs/actions/run-automation-now.js +11 -5
  386. package/dist/jobs/frontmatter.js +53 -2
  387. package/dist/jobs/run-now.d.ts +11 -1
  388. package/dist/jobs/run-now.js +42 -7
  389. package/dist/jobs/scheduler.d.ts +1 -0
  390. package/dist/jobs/scheduler.js +2 -1
  391. package/dist/localization/core-messages/ar-SA.js +4 -1
  392. package/dist/localization/core-messages/de-DE.js +4 -1
  393. package/dist/localization/core-messages/en-US.d.ts +4 -1
  394. package/dist/localization/core-messages/en-US.js +4 -1
  395. package/dist/localization/core-messages/es-ES.js +4 -1
  396. package/dist/localization/core-messages/fr-FR.js +4 -1
  397. package/dist/localization/core-messages/hi-IN.js +4 -1
  398. package/dist/localization/core-messages/ja-JP.js +4 -1
  399. package/dist/localization/core-messages/ko-KR.js +4 -1
  400. package/dist/localization/core-messages/pt-BR.js +4 -1
  401. package/dist/localization/core-messages/zh-CN.js +4 -1
  402. package/dist/localization/core-messages/zh-TW.js +4 -1
  403. package/dist/localization/core-messages.d.ts +4 -1
  404. package/dist/localization/default-messages.d.ts +2 -5
  405. package/dist/localization/default-messages.js +2 -5
  406. package/dist/mcp/build-server.d.ts +9 -0
  407. package/dist/mcp/build-server.js +37 -8
  408. package/dist/mcp-client/oauth-client.d.ts +7 -0
  409. package/dist/mcp-client/oauth-client.js +12 -1
  410. package/dist/notifications/routes.d.ts +1 -1
  411. package/dist/oauth-tokens/index.d.ts +1 -1
  412. package/dist/oauth-tokens/index.js +1 -1
  413. package/dist/oauth-tokens/lifecycle.d.ts +11 -0
  414. package/dist/oauth-tokens/lifecycle.js +17 -0
  415. package/dist/oauth-tokens/store.js +7 -0
  416. package/dist/observability/posthog-ai.d.ts +15 -1
  417. package/dist/observability/posthog-ai.js +24 -12
  418. package/dist/observability/traces.js +158 -28
  419. package/dist/onboarding/app-profile.js +2 -2
  420. package/dist/onboarding/plugin.js +10 -2
  421. package/dist/onboarding/types.d.ts +2 -0
  422. package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
  423. package/dist/provider-api/actions/provider-api.d.ts +11 -11
  424. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  425. package/dist/provider-api/index.js +2 -0
  426. package/dist/resources/handlers.d.ts +1 -1
  427. package/dist/resources/store.js +13 -4
  428. package/dist/scripts/agent-engines/list-agent-engines.js +29 -3
  429. package/dist/scripts/db/check-scoping.js +9 -6
  430. package/dist/secrets/register-framework-secrets.js +1 -1
  431. package/dist/secrets/routes.d.ts +6 -6
  432. package/dist/server/action-discovery.js +5 -0
  433. package/dist/server/agent-chat/action-filters-a2a.d.ts +27 -3
  434. package/dist/server/agent-chat/action-filters-a2a.js +48 -9
  435. package/dist/server/agent-chat-plugin.js +36 -9
  436. package/dist/server/agent-discovery.js +43 -20
  437. package/dist/server/auth.js +18 -16
  438. package/dist/server/beta-opt-out-html.js +45 -4
  439. package/dist/server/better-auth-instance.d.ts +2 -1
  440. package/dist/server/better-auth-instance.js +23 -7
  441. package/dist/server/builder-browser.d.ts +4 -0
  442. package/dist/server/builder-browser.js +23 -1
  443. package/dist/server/builder-design-systems.d.ts +4 -1
  444. package/dist/server/builder-design-systems.js +87 -6
  445. package/dist/server/builder-oauth.d.ts +1 -7
  446. package/dist/server/builder-oauth.js +80 -163
  447. package/dist/server/core-routes-plugin.d.ts +29 -0
  448. package/dist/server/core-routes-plugin.js +113 -21
  449. package/dist/server/default-plugins.d.ts +18 -0
  450. package/dist/server/default-plugins.js +22 -0
  451. package/dist/server/edge.d.ts +1 -0
  452. package/dist/server/edge.js +1 -0
  453. package/dist/server/framework-request-handler.js +31 -3
  454. package/dist/server/google-oauth.d.ts +3 -0
  455. package/dist/server/google-oauth.js +3 -0
  456. package/dist/server/index.d.ts +4 -4
  457. package/dist/server/index.js +3 -3
  458. package/dist/server/onboarding-html.js +37 -3
  459. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  460. package/dist/server/workspace-provider-oauth.js +72 -20
  461. package/dist/shared/agent-sidebar-url.d.ts +1 -0
  462. package/dist/shared/agent-sidebar-url.js +1 -0
  463. package/dist/shared/environment-lanes.d.ts +2 -0
  464. package/dist/shared/environment-lanes.js +3 -1
  465. package/dist/shared/index.d.ts +3 -1
  466. package/dist/shared/index.js +3 -1
  467. package/dist/shared/surface-visibility.d.ts +31 -0
  468. package/dist/shared/surface-visibility.js +57 -0
  469. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  470. package/dist/templates/chat/app/routes.ts +3 -1
  471. package/dist/templates/chat/vitest.config.ts +8 -0
  472. package/dist/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  473. package/dist/templates/default/app/routes.ts +3 -1
  474. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  475. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
  476. package/dist/tracking/registry.d.ts +11 -0
  477. package/dist/tracking/registry.js +5 -2
  478. package/dist/triggers/actions.js +10 -3
  479. package/dist/usage/store.js +23 -3
  480. package/dist/user-profile/actions/get-auth-methods.js +18 -5
  481. package/dist/vite/client.js +24 -5
  482. package/docs/content/actions-access-control.mdx +43 -4
  483. package/docs/content/actions-defining.mdx +16 -0
  484. package/docs/content/template-clips-capture-everywhere.mdx +29 -30
  485. package/docs/content/template-clips-developers.mdx +4 -4
  486. package/docs/content/template-clips.mdx +3 -1
  487. package/package.json +3 -3
  488. package/src/eject/workspace-connections.ts +4 -0
  489. package/src/templates/chat/.agents/skills/secrets/SKILL.md +11 -4
  490. package/src/templates/chat/app/routes.ts +3 -1
  491. package/src/templates/chat/vitest.config.ts +8 -0
  492. package/src/templates/default/.agents/skills/secrets/SKILL.md +11 -4
  493. package/src/templates/default/app/routes.ts +3 -1
  494. package/src/templates/headless/.agents/skills/secrets/SKILL.md +11 -4
  495. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +11 -4
  496. /package/corpus/templates/dispatch/app/routes/{apps.$appId.tsx → apps.$appId.$.tsx} +0 -0
@@ -40,7 +40,6 @@
40
40
  "common-room",
41
41
  "exa",
42
42
  "gong",
43
- "google-workspace",
44
43
  "grafana",
45
44
  "intercom",
46
45
  "monday",
@@ -70,7 +69,11 @@
70
69
  "figma",
71
70
  "notion",
72
71
  "gmail",
72
+ "google_calendar",
73
+ "google_docs",
73
74
  "google_drive",
75
+ "google_sheets",
76
+ "google_slides",
74
77
  "hubspot",
75
78
  "salesforce",
76
79
  "jira",
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { spawn } from "node:child_process";
4
4
  import { existsSync, statSync } from "node:fs";
5
+ import { createRequire } from "node:module";
5
6
  import { dirname, join } from "node:path";
6
7
  import { fileURLToPath, pathToFileURL } from "node:url";
7
8
 
@@ -62,14 +63,31 @@ if (!useSourceFallback) {
62
63
 
63
64
  await import(pathToFileURL(distEntry).href);
64
65
  } else {
65
- const child = spawn("tsx", [sourceEntry, ...process.argv.slice(2)], {
66
- stdio: "inherit",
67
- env: process.env,
68
- });
66
+ // Resolve tsx from this package instead of trusting PATH: the fallback is
67
+ // also reached through `node packages/core/bin/agent-native.js`, which runs
68
+ // without node_modules/.bin on PATH.
69
+ let tsxCli;
70
+ try {
71
+ tsxCli = createRequire(import.meta.url).resolve("tsx/cli");
72
+ } catch (error) {
73
+ console.error(
74
+ `agent-native CLI source fallback could not resolve tsx (${error.message}). Run \`pnpm --filter @agent-native/core build\` and try again.`,
75
+ );
76
+ process.exit(1);
77
+ }
78
+
79
+ const child = spawn(
80
+ process.execPath,
81
+ [tsxCli, sourceEntry, ...process.argv.slice(2)],
82
+ {
83
+ stdio: "inherit",
84
+ env: process.env,
85
+ },
86
+ );
69
87
 
70
88
  child.on("error", (error) => {
71
89
  console.error(
72
- `agent-native CLI build output is missing and the source fallback failed: ${error.message}`,
90
+ `agent-native CLI source fallback failed: ${error.message}. Run \`pnpm --filter @agent-native/core build\` and try again.`,
73
91
  );
74
92
  process.exit(1);
75
93
  });
package/corpus/README.md CHANGED
@@ -31,4 +31,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
31
31
 
32
32
  ## Generated Counts
33
33
 
34
- - template files: 8522
34
+ - template files: 8585
@@ -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
 
@@ -9,12 +9,12 @@ Use these sources of truth instead:
9
9
 
10
10
  - \`list-data-dictionary\` for approved metric, table, column, join, and caveat definitions configured by this organization.
11
11
  - \`data-source-status --key bigquery\` to confirm whether BigQuery credentials and a project are configured.
12
- - \`search-bigquery-schema\` to list configured datasets/tables or inspect exact table columns before writing SQL.
12
+ - \`search-bigquery-schema\` to search the configured project by dataset, table, or column term, or inspect exact table columns before writing SQL.
13
13
  - The configured warehouse's \`INFORMATION_SCHEMA.COLUMNS\` tables when you need to discover actual datasets, tables, and columns.
14
14
  - \`@app_events\` as an optional placeholder for a default application events table in query-metrics examples. It defaults to \`<BIGQUERY_PROJECT_ID>.analytics.events_partitioned\` and can be overridden with \`ANALYTICS_BIGQUERY_EVENTS_TABLE\`; it is not the BigQuery connection status or a table catalog.
15
15
  - \`@project\` as the configured BigQuery project placeholder for fully-qualified table references.
16
16
 
17
- If no data-dictionary entry exists and schema discovery is unavailable, ask the user for the source table or metric definition before writing SQL. Never invent table names, column names, joins, or numbers.
17
+ If no data-dictionary entry exists, search the configured project before asking about business meaning. Ask the user for a metric definition only after the configured schema and query actions prove that the source or metric is unavailable. Never ask the user to provide internal dataset, table, or column names that the schema action can discover, and never invent table names, column names, joins, or numbers.
18
18
 
19
19
  Preferred schema discovery:
20
20
 
@@ -22,6 +22,7 @@ Preferred schema discovery:
22
22
  pnpm action search-bigquery-schema
23
23
  pnpm action search-bigquery-schema --dataset=<dataset>
24
24
  pnpm action search-bigquery-schema --table=<dataset.table>
25
+ pnpm action search-bigquery-schema --search=<metric-or-column-term>
25
26
  \`\`\`
26
27
 
27
28
  Example schema discovery query:
@@ -48,7 +48,7 @@ function toDataTableResult(result: {
48
48
 
49
49
  export default defineAction({
50
50
  description:
51
- "Query the built-in first-party Analytics source: events recorded through this app's analytics collector endpoint (/track), compact daily rollups updated transactionally with new ingest, identifiable user-day rollups, and session replay summaries recorded through /api/analytics/replay. This source does not require an external provider connection. Use it for questions about app/site traffic, product events, template/app usage, conversions, session recordings, LLM/agent observability, model cost, token volume, latency, and other first-party data collected by this analytics app. Use source-specific actions such as BigQuery, GA4, Mixpanel, PostHog, or Amplitude when the user asks for those sources or the relevant data lives there. SQL may read analytics_events, analytics_event_daily_rollups, analytics_user_days, and session_recordings; session_replay_chunks is intentionally unavailable, and reads are automatically scoped to the current user/org. Prefer analytics_event_daily_rollups for event counts and analytics_user_days for active-user or retention questions. On the Builder.io production organization after the explicit BigQuery cutover, event and rollup reads use partitioned BigQuery tables/views while session_recordings remains in the SQL store; cross-backend joins are not supported. Before a large or historical query, call get-first-party-analytics-health and use a configured external backend when it recommends one: BigQuery supports warehouse SQL and historical analysis, while Amplitude supports product analytics, funnels, and retention. Connecting a backend does not automatically reroute /track events or copy existing Neon events; the migration action performs that explicit prepare, backfill, and cutover sequence. Aggregate, project only needed columns, use bounded recent drill-downs, and add a LIMIT for raw or high-cardinality reads; do not issue an unbounded raw-event scan or paginate a large cohort. An explicit all-time or lifetime request remains all-time, so do not invent a default lower time bound. Safe scoped results are cached for up to five minutes for this agent action. analytics_events columns include event_name, timestamp, event_date, user_id, anonymous_id, user_key, session_id, app, template, signed_in, url, path, hostname, referrer, properties, and context. analytics_event_daily_rollups columns include tenant_key, owner_email, org_id, event_date, event_name, app, template, and event_count. analytics_user_days columns include tenant_key, owner_email, org_id, event_date, and user_key. LLM observability events use event_name = '$ai_generation'; useful properties include $ai_trace_id/run_id, $ai_session_id/thread_id, $ai_model/model, $ai_provider/provider, $ai_input_tokens/input_tokens, $ai_output_tokens/output_tokens, cache_read_tokens, cache_write_tokens, cost_cents_x100, $ai_total_cost_usd/cost_usd, duration_ms/$ai_latency, status, tool_calls, successful_tools, failed_tools, tools, tools_truncated, delegated, delegation_protocol, caller_app, delegation_task_id, a2a_task_id, parent_run_id, parent_turn_id, and error_message/$ai_error. Agent Teams child runs use delegation_protocol = 'agent-team' and retain their own run_id while linking to the launching run through parent_run_id. The bounded tools array contains names, relative start times, durations, statuses, and coarse error classes only, never args or results; failed runs and interrupted tools remain queryable. session_recordings columns include id, session_id, user_id, anonymous_id, user_key, started_at, ended_at, duration_ms, chunk_count, event_count, page_count, error_count, rage_click_count, app, template, status, first_url, last_url, path, hostname, referrer, and metadata.",
51
+ "Query the built-in first-party Analytics source: events recorded through this app's analytics collector endpoint (/track), compact daily rollups updated transactionally with new ingest, identifiable user-day rollups, and session replay summaries recorded through /api/analytics/replay. This source does not require an external provider connection. Use it for questions about app/site traffic, product events, template/app usage, conversions, session recordings, LLM/agent observability, model cost, token volume, latency, and other first-party data collected by this analytics app. Use source-specific actions such as BigQuery, GA4, Mixpanel, PostHog, or Amplitude when the user asks for those sources or the relevant data lives there. SQL may read analytics_events, analytics_event_daily_rollups, analytics_user_days, and session_recordings; session_replay_chunks is intentionally unavailable, and reads are automatically scoped to the current user/org. Prefer analytics_event_daily_rollups for event counts and analytics_user_days for active-user or retention questions. On the Builder.io production organization after the explicit BigQuery cutover, event and rollup reads use partitioned BigQuery tables/views while session_recordings remains in the SQL store; cross-backend joins are not supported. Before a large or historical query, call get-first-party-analytics-health and use a configured external backend when it recommends one: BigQuery supports warehouse SQL and historical analysis, while Amplitude supports product analytics, funnels, and retention. Connecting a backend does not automatically reroute /track events or copy existing Neon events; the migration action performs that explicit prepare, backfill, and cutover sequence. Aggregate, project only needed columns, use bounded recent drill-downs, and add a LIMIT for raw or high-cardinality reads; do not issue an unbounded raw-event scan or paginate a large cohort. An explicit all-time or lifetime request remains all-time, so do not invent a default lower time bound. Safe scoped results are cached for up to five minutes for this agent action. analytics_events columns include event_name, timestamp, event_date, user_id, anonymous_id, user_key, session_id, app, template, signed_in, url, path, hostname, referrer, properties, and context. analytics_event_daily_rollups columns include tenant_key, owner_email, org_id, event_date, event_name, app, template, and event_count. analytics_user_days columns include tenant_key, owner_email, org_id, event_date, and user_key. LLM observability events use event_name = '$ai_generation'; useful properties include $ai_trace_id/run_id, $ai_session_id/thread_id, $ai_model/model, $ai_provider/provider, $ai_input_tokens/input_tokens, $ai_output_tokens/output_tokens, cache_read_tokens, cache_write_tokens, cost_cents_x100, $ai_total_cost_usd/cost_usd, duration_ms (full run, milliseconds), $ai_latency (model time in seconds, run minus tool time), status, tool_calls, successful_tools, failed_tools, tools, tools_truncated, delegated, delegation_protocol, caller_app, delegation_task_id, a2a_task_id, parent_run_id, parent_turn_id, and error_message/$ai_error. Agent Teams child runs use delegation_protocol = 'agent-team' and retain their own run_id while linking to the launching run through parent_run_id. The bounded tools array contains names, relative start times, durations, statuses, and coarse error classes only, never args or results; failed runs and interrupted tools remain queryable. session_recordings columns include id, session_id, user_id, anonymous_id, user_key, started_at, ended_at, duration_ms, chunk_count, event_count, page_count, error_count, rage_click_count, app, template, status, first_url, last_url, path, hostname, referrer, and metadata.",
52
52
  schema: z.object({
53
53
  sql: z
54
54
  .string()
@@ -35,6 +35,15 @@ interface TableListResponse {
35
35
  }>;
36
36
  }
37
37
 
38
+ interface BigQueryTableSummary {
39
+ projectId?: string;
40
+ datasetId?: string;
41
+ tableId?: string;
42
+ type?: string;
43
+ friendlyName?: string;
44
+ labels?: Record<string, string>;
45
+ }
46
+
38
47
  interface TableMetadata {
39
48
  tableReference?: {
40
49
  projectId?: string;
@@ -54,6 +63,9 @@ interface TableMetadata {
54
63
 
55
64
  const PROJECT_RE = /^[A-Za-z][A-Za-z0-9-]{4,61}[A-Za-z0-9]$/;
56
65
  const ID_RE = /^[A-Za-z0-9_]+$/;
66
+ const GLOBAL_SEARCH_DATASET_LIMIT = 100;
67
+ const GLOBAL_SEARCH_TABLE_LIMIT = 250;
68
+ const GLOBAL_SEARCH_METADATA_BATCH_SIZE = 20;
57
69
 
58
70
  function assertIdentifier(
59
71
  label: string,
@@ -183,7 +195,12 @@ function compactTable(meta: TableMetadata, includeColumns: boolean) {
183
195
  }
184
196
 
185
197
  function matchesSearch(meta: TableMetadata, search: string): boolean {
186
- const q = search.toLowerCase();
198
+ const terms = search
199
+ .toLowerCase()
200
+ .replace(/[._-]+/g, " ")
201
+ .split(/\s+/)
202
+ .filter(Boolean);
203
+ if (!terms.length) return true;
187
204
  const ref = meta.tableReference ?? {};
188
205
  const haystack = [
189
206
  ref.projectId,
@@ -199,8 +216,9 @@ function matchesSearch(meta: TableMetadata, search: string): boolean {
199
216
  ]
200
217
  .filter(Boolean)
201
218
  .join(" ")
202
- .toLowerCase();
203
- return haystack.includes(q);
219
+ .toLowerCase()
220
+ .replace(/[._-]+/g, " ");
221
+ return terms.every((term) => haystack.includes(term));
204
222
  }
205
223
 
206
224
  async function listDatasets(projectId: string, limit: number, search: string) {
@@ -245,6 +263,111 @@ async function listTables(projectId: string, datasetId: string, limit: number) {
245
263
  }));
246
264
  }
247
265
 
266
+ async function searchAcrossDatasets(
267
+ projectId: string,
268
+ search: string,
269
+ limit: number,
270
+ ) {
271
+ const datasets = await listDatasets(
272
+ projectId,
273
+ GLOBAL_SEARCH_DATASET_LIMIT + 1,
274
+ "",
275
+ );
276
+ const scannableDatasets = datasets.slice(0, GLOBAL_SEARCH_DATASET_LIMIT);
277
+ const tables: BigQueryTableSummary[] = [];
278
+ const datasetCount = scannableDatasets.filter(
279
+ (dataset) => typeof dataset.datasetId === "string" && dataset.datasetId,
280
+ ).length;
281
+ let datasetsScanned = 0;
282
+ let truncated = datasets.length > GLOBAL_SEARCH_DATASET_LIMIT;
283
+
284
+ for (const dataset of scannableDatasets) {
285
+ const datasetId = dataset.datasetId;
286
+ if (!datasetId) continue;
287
+ if (tables.length >= GLOBAL_SEARCH_TABLE_LIMIT) {
288
+ truncated = true;
289
+ break;
290
+ }
291
+
292
+ datasetsScanned += 1;
293
+ const remaining = GLOBAL_SEARCH_TABLE_LIMIT - tables.length;
294
+ const listed = await listTables(
295
+ projectId,
296
+ datasetId,
297
+ Math.min(remaining, GLOBAL_SEARCH_TABLE_LIMIT),
298
+ );
299
+ tables.push(...listed);
300
+ }
301
+
302
+ if (datasetsScanned < datasetCount) truncated = true;
303
+
304
+ // Inspect table metadata in bounded batches so a search can match columns,
305
+ // not only table names, without issuing an unbounded burst of requests.
306
+ const matches: ReturnType<typeof compactTable>[] = [];
307
+ const errors: Array<{
308
+ projectId?: string;
309
+ datasetId?: string;
310
+ tableId?: string;
311
+ error: string;
312
+ }> = [];
313
+
314
+ for (
315
+ let offset = 0;
316
+ offset < tables.length;
317
+ offset += GLOBAL_SEARCH_METADATA_BATCH_SIZE
318
+ ) {
319
+ const batch = tables.slice(
320
+ offset,
321
+ offset + GLOBAL_SEARCH_METADATA_BATCH_SIZE,
322
+ );
323
+ const settled = await Promise.allSettled(
324
+ batch.map(async (table) => {
325
+ if (!table.datasetId || !table.tableId) return null;
326
+ const metadata = await getTableMetadata(
327
+ projectId,
328
+ table.datasetId,
329
+ table.tableId,
330
+ );
331
+ return matchesSearch(metadata, search)
332
+ ? compactTable(metadata, true)
333
+ : null;
334
+ }),
335
+ );
336
+
337
+ settled.forEach((result, index) => {
338
+ const table = batch[index];
339
+ if (result.status === "fulfilled") {
340
+ if (result.value) matches.push(result.value);
341
+ return;
342
+ }
343
+ errors.push({
344
+ projectId: table?.projectId ?? projectId,
345
+ datasetId: table?.datasetId,
346
+ tableId: table?.tableId,
347
+ error:
348
+ result.reason instanceof Error
349
+ ? result.reason.message
350
+ : String(result.reason),
351
+ });
352
+ });
353
+ }
354
+
355
+ return {
356
+ mode: "table-search",
357
+ projectId,
358
+ search,
359
+ datasetsScanned,
360
+ tablesScanned: tables.length,
361
+ truncated,
362
+ tables: matches.slice(0, limit),
363
+ ...(errors.length
364
+ ? { errors: errors.slice(0, 12), errorCount: errors.length }
365
+ : {}),
366
+ nextStep:
367
+ "Use table=dataset.table for full metadata. Global search is bounded; pass a returned dataset/table reference for a complete inspection.",
368
+ };
369
+ }
370
+
248
371
  async function getTableMetadata(
249
372
  projectId: string,
250
373
  datasetId: string,
@@ -256,7 +379,7 @@ async function getTableMetadata(
256
379
 
257
380
  export default defineAction({
258
381
  description:
259
- "Search or describe BigQuery metadata for the configured warehouse. Use before writing SQL when the data dictionary does not already name the dataset, table, and columns. With no args, lists datasets. With dataset, lists tables. With dataset + table or a dataset.table value, returns columns for that table.",
382
+ "Search or describe BigQuery metadata for the configured warehouse. Use before writing SQL when the data dictionary does not already name the dataset, table, and columns. With no args, lists datasets. With search and no dataset, searches accessible tables and columns across the configured project so the user does not need to provide internal table names. With dataset, lists tables. With dataset + table or a dataset.table value, returns columns for that table.",
260
383
  schema: z.object({
261
384
  dataset: z
262
385
  .string()
@@ -307,6 +430,9 @@ export default defineAction({
307
430
  }
308
431
 
309
432
  if (!args.dataset) {
433
+ if (search) {
434
+ return searchAcrossDatasets(configuredProjectId, search, limit);
435
+ }
310
436
  return {
311
437
  mode: "datasets",
312
438
  projectId: configuredProjectId,
@@ -1,5 +1,6 @@
1
1
  import { defineAgentNativeConfig } from "@agent-native/core/config";
2
2
 
3
3
  export default defineAgentNativeConfig({
4
+ changelog: { enabled: true },
4
5
  harness: true,
5
6
  });
@@ -46,6 +46,11 @@ import { toast } from "sonner";
46
46
 
47
47
  import { useAuth } from "@/components/auth/AuthProvider";
48
48
  import { ANALYTICS_CHAT_STORAGE_KEY } from "@/lib/chat-handoff";
49
+ import {
50
+ matchesDashboardVisibilityFilter,
51
+ type DashboardVisibility,
52
+ type DashboardVisibilityFilter,
53
+ } from "@/lib/dashboard-visibility";
49
54
  import { cn, shortcutModifierLabel } from "@/lib/utils";
50
55
  import {
51
56
  dashboards,
@@ -63,6 +68,7 @@ type SidebarDashboard = {
63
68
  source: "static" | "sql" | "analysis";
64
69
  resourceId?: string;
65
70
  visibility?: Visibility;
71
+ ownerEmail?: string | null;
66
72
  /** Id of the dashboard this one nests under in the sidebar, if any. */
67
73
  parentId?: string;
68
74
  };
@@ -162,7 +168,7 @@ const SIDEBAR_SKELETON_CLASS =
162
168
  "bg-sidebar-foreground/12 dark:bg-sidebar-foreground/10";
163
169
 
164
170
  type SidebarSortMode = "most-used" | "alphabetical" | "manual";
165
- type SidebarVisibilityFilter = "all" | "private" | "shared";
171
+ type SidebarVisibilityFilter = DashboardVisibilityFilter;
166
172
 
167
173
  import {
168
174
  DndContext,
@@ -258,14 +264,11 @@ function isVisibility(value: unknown): value is Visibility {
258
264
  }
259
265
 
260
266
  export function matchesVisibilityFilter(
261
- item: { visibility?: Visibility },
267
+ item: { visibility?: Visibility; ownerEmail?: string | null },
262
268
  filter: SidebarVisibilityFilter,
269
+ currentUserEmail?: string | null,
263
270
  ): boolean {
264
- if (filter === "all") return true;
265
- if (filter === "private") {
266
- return item.visibility !== "org" && item.visibility !== "public";
267
- }
268
- return item.visibility === "org" || item.visibility === "public";
271
+ return matchesDashboardVisibilityFilter(item, filter, currentUserEmail);
269
272
  }
270
273
 
271
274
  export function threadMatchesVisibilityFilter(
@@ -447,7 +450,7 @@ function SidebarSectionSettingsPopover({
447
450
 
448
451
  // --- Visibility types and helpers ---
449
452
 
450
- type Visibility = "private" | "org" | "public";
453
+ type Visibility = DashboardVisibility;
451
454
 
452
455
  // --- Shared sortable row (used by both dashboards and analyses) ---
453
456
 
@@ -1143,6 +1146,7 @@ type SqlDashboardListItem = {
1143
1146
  id: string;
1144
1147
  name: string;
1145
1148
  visibility?: Visibility;
1149
+ ownerEmail?: string | null;
1146
1150
  parentId?: string;
1147
1151
  };
1148
1152
 
@@ -1160,18 +1164,25 @@ async function fetchSqlDashboards(
1160
1164
  d.visibility === "org" ||
1161
1165
  d.visibility === "public"),
1162
1166
  )
1163
- .map((d: any) => ({
1164
- id: d.id,
1165
- name:
1166
- typeof d.name === "string" && d.name.trim().length > 0
1167
- ? d.name
1168
- : t("sidebar.untitledDashboard"),
1169
- visibility: d.visibility as Visibility,
1170
- parentId:
1171
- typeof d.parentId === "string" && d.parentId.trim().length > 0
1172
- ? d.parentId
1173
- : undefined,
1174
- }));
1167
+ .map((d: any) => {
1168
+ const ownerEmail =
1169
+ typeof d.ownerEmail === "string" && d.ownerEmail.trim().length > 0
1170
+ ? d.ownerEmail
1171
+ : undefined;
1172
+ return {
1173
+ id: d.id,
1174
+ name:
1175
+ typeof d.name === "string" && d.name.trim().length > 0
1176
+ ? d.name
1177
+ : t("sidebar.untitledDashboard"),
1178
+ visibility: d.visibility as Visibility,
1179
+ ...(ownerEmail ? { ownerEmail } : {}),
1180
+ parentId:
1181
+ typeof d.parentId === "string" && d.parentId.trim().length > 0
1182
+ ? d.parentId
1183
+ : undefined,
1184
+ };
1185
+ });
1175
1186
  }
1176
1187
 
1177
1188
  async function fetchSidebarAnalyses(t: (key: string) => string): Promise<
@@ -1525,7 +1536,8 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1525
1536
  activeDashboardId !== null,
1526
1537
  );
1527
1538
  const [dashShowAll, setDashShowAll] = useState(false);
1528
- const [dashFilter, setDashFilter] = useState<SidebarVisibilityFilter>("all");
1539
+ const [dashFilter, setDashFilter] =
1540
+ useState<SidebarVisibilityFilter>("private");
1529
1541
  const [dashboardSortMode, setDashboardSortModeState] =
1530
1542
  useState<SidebarSortMode>(() => getStoredSortMode(DASHBOARD_SORT_MODE_KEY));
1531
1543
  const { data: popularity, isReady: popularityReady } = usePopularity();
@@ -1749,6 +1761,7 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1749
1761
  name: d.name,
1750
1762
  source: "sql",
1751
1763
  visibility: d.visibility,
1764
+ ownerEmail: d.ownerEmail,
1752
1765
  parentId: d.parentId,
1753
1766
  }));
1754
1767
  const analysisItems: SidebarDashboard[] = analysesList.map((a) => ({
@@ -1802,9 +1815,9 @@ export function Sidebar({ mobile }: { mobile?: boolean } = {}) {
1802
1815
  const filteredDashboards = useMemo(
1803
1816
  () =>
1804
1817
  visibleDashboards.filter((dashboard) =>
1805
- matchesVisibilityFilter(dashboard, dashFilter),
1818
+ matchesVisibilityFilter(dashboard, dashFilter, auth?.email),
1806
1819
  ),
1807
- [visibleDashboards, dashFilter],
1820
+ [auth?.email, visibleDashboards, dashFilter],
1808
1821
  );
1809
1822
 
1810
1823
  // Group dashboards that declare a parentId beneath their parent. Nesting is
@@ -468,6 +468,9 @@ const enUS = {
468
468
  adminOnlyTitle: "Admin access required",
469
469
  adminOnlyDescription:
470
470
  "Only organization owners and admins can open Analytics admin tools.",
471
+ roleUnavailableTitle: "Couldn't verify your access",
472
+ roleUnavailableDescription:
473
+ "We couldn't check your organization role: {{message}}",
471
474
  notTracked: "Not tracked",
472
475
  visibilityprivate: "Private",
473
476
  visibilityorg: "Shared with org",
@@ -13018,6 +13021,8 @@ const translatedDashboardAdminTranslations = {
13018
13021
  adminOnlyTitle: "需要管理员权限",
13019
13022
  adminOnlyDescription:
13020
13023
  "只有组织所有者和管理员可以打开 Analytics 管理工具。",
13024
+ roleUnavailableTitle: "无法验证你的访问权限",
13025
+ roleUnavailableDescription: "无法检查你的组织角色:{{message}}",
13021
13026
  notTracked: "未跟踪",
13022
13027
  visibilityprivate: "私有",
13023
13028
  visibilityorg: "与组织共享",
@@ -13066,6 +13071,9 @@ const translatedDashboardAdminTranslations = {
13066
13071
  adminOnlyTitle: "Se requiere acceso de administrador",
13067
13072
  adminOnlyDescription:
13068
13073
  "Solo los propietarios y administradores de la organización pueden abrir las herramientas de administración de Analytics.",
13074
+ roleUnavailableTitle: "No se pudo verificar tu acceso",
13075
+ roleUnavailableDescription:
13076
+ "No pudimos comprobar tu rol en la organización: {{message}}",
13069
13077
  notTracked: "No registrado",
13070
13078
  visibilityprivate: "Privado",
13071
13079
  visibilityorg: "Compartido con la organización",
@@ -13114,6 +13122,9 @@ const translatedDashboardAdminTranslations = {
13114
13122
  adminOnlyTitle: "Accès administrateur requis",
13115
13123
  adminOnlyDescription:
13116
13124
  "Seuls les propriétaires et administrateurs de l'organisation peuvent ouvrir les outils d'administration Analytics.",
13125
+ roleUnavailableTitle: "Impossible de vérifier votre accès",
13126
+ roleUnavailableDescription:
13127
+ "Nous n'avons pas pu vérifier votre rôle dans l'organisation : {{message}}",
13117
13128
  notTracked: "Non suivi",
13118
13129
  visibilityprivate: "Privé",
13119
13130
  visibilityorg: "Partagé avec l'organisation",
@@ -13162,6 +13173,9 @@ const translatedDashboardAdminTranslations = {
13162
13173
  adminOnlyTitle: "Adminzugriff erforderlich",
13163
13174
  adminOnlyDescription:
13164
13175
  "Nur Organisationsinhaber und Administratoren können Analytics-Admin-Tools öffnen.",
13176
+ roleUnavailableTitle: "Zugriff konnte nicht überprüft werden",
13177
+ roleUnavailableDescription:
13178
+ "Deine Organisationsrolle konnte nicht überprüft werden: {{message}}",
13165
13179
  notTracked: "Nicht erfasst",
13166
13180
  visibilityprivate: "Privat",
13167
13181
  visibilityorg: "Mit Organisation geteilt",
@@ -13210,6 +13224,9 @@ const translatedDashboardAdminTranslations = {
13210
13224
  adminOnlyTitle: "管理者アクセスが必要です",
13211
13225
  adminOnlyDescription:
13212
13226
  "組織の所有者と管理者のみが Analytics 管理ツールを開けます。",
13227
+ roleUnavailableTitle: "アクセス権を確認できませんでした",
13228
+ roleUnavailableDescription:
13229
+ "組織内のロールを確認できませんでした: {{message}}",
13213
13230
  notTracked: "未追跡",
13214
13231
  visibilityprivate: "非公開",
13215
13232
  visibilityorg: "組織と共有",
@@ -13257,6 +13274,9 @@ const translatedDashboardAdminTranslations = {
13257
13274
  adminOnlyTitle: "관리자 권한 필요",
13258
13275
  adminOnlyDescription:
13259
13276
  "조직 소유자와 관리자만 Analytics 관리 도구를 열 수 있습니다.",
13277
+ roleUnavailableTitle: "접근 권한을 확인할 수 없습니다",
13278
+ roleUnavailableDescription:
13279
+ "조직 역할을 확인하지 못했습니다: {{message}}",
13260
13280
  notTracked: "추적 안 됨",
13261
13281
  visibilityprivate: "비공개",
13262
13282
  visibilityorg: "조직과 공유됨",
@@ -13305,6 +13325,9 @@ const translatedDashboardAdminTranslations = {
13305
13325
  adminOnlyTitle: "Acesso de administrador necessário",
13306
13326
  adminOnlyDescription:
13307
13327
  "Somente proprietários e administradores da organização podem abrir as ferramentas administrativas do Analytics.",
13328
+ roleUnavailableTitle: "Não foi possível verificar seu acesso",
13329
+ roleUnavailableDescription:
13330
+ "Não conseguimos verificar sua função na organização: {{message}}",
13308
13331
  notTracked: "Não rastreado",
13309
13332
  visibilityprivate: "Privado",
13310
13333
  visibilityorg: "Compartilhado com a organização",
@@ -13352,6 +13375,9 @@ const translatedDashboardAdminTranslations = {
13352
13375
  adminOnlyTitle: "एडमिन access आवश्यक है",
13353
13376
  adminOnlyDescription:
13354
13377
  "केवल organization owners और admins Analytics admin tools खोल सकते हैं।",
13378
+ roleUnavailableTitle: "आपका access सत्यापित नहीं किया जा सका",
13379
+ roleUnavailableDescription:
13380
+ "हम आपकी organization role जांच नहीं सके: {{message}}",
13355
13381
  notTracked: "ट्रैक नहीं किया गया",
13356
13382
  visibilityprivate: "निजी",
13357
13383
  visibilityorg: "संगठन के साथ साझा",
@@ -13400,6 +13426,8 @@ const translatedDashboardAdminTranslations = {
13400
13426
  adminOnlyTitle: "مطلوب وصول مسؤول",
13401
13427
  adminOnlyDescription:
13402
13428
  "يمكن لمالكي المؤسسة والمسؤولين فقط فتح أدوات إدارة Analytics.",
13429
+ roleUnavailableTitle: "تعذر التحقق من وصولك",
13430
+ roleUnavailableDescription: "تعذر التحقق من دورك في المؤسسة: {{message}}",
13403
13431
  notTracked: "غير متتبع",
13404
13432
  visibilityprivate: "خاص",
13405
13433
  visibilityorg: "مشترك مع المؤسسة",
@@ -0,0 +1,41 @@
1
+ export type DashboardVisibility = "private" | "org" | "public";
2
+ export type DashboardVisibilityFilter = "all" | "private" | "shared";
3
+
4
+ export type DashboardVisibilityItem = {
5
+ visibility?: DashboardVisibility;
6
+ ownerEmail?: string | null;
7
+ };
8
+
9
+ function normalizeEmail(email: string | null | undefined): string | null {
10
+ const normalized = email?.trim().toLowerCase();
11
+ return normalized ? normalized : null;
12
+ }
13
+
14
+ export function isDashboardMine(
15
+ item: DashboardVisibilityItem,
16
+ currentUserEmail?: string | null,
17
+ ): boolean {
18
+ if (item.visibility === "org" || item.visibility === "public") {
19
+ return false;
20
+ }
21
+
22
+ if ("ownerEmail" in item) {
23
+ const ownerEmail = normalizeEmail(item.ownerEmail);
24
+ const viewerEmail = normalizeEmail(currentUserEmail);
25
+ return Boolean(ownerEmail && viewerEmail && ownerEmail === viewerEmail);
26
+ }
27
+
28
+ // Older dashboard-shaped items do not always carry ownership metadata.
29
+ return true;
30
+ }
31
+
32
+ export function matchesDashboardVisibilityFilter(
33
+ item: DashboardVisibilityItem,
34
+ filter: DashboardVisibilityFilter,
35
+ currentUserEmail?: string | null,
36
+ ): boolean {
37
+ if (filter === "all") return true;
38
+ return filter === "private"
39
+ ? isDashboardMine(item, currentUserEmail)
40
+ : !isDashboardMine(item, currentUserEmail);
41
+ }
@@ -428,7 +428,11 @@ function UsageStatCard({
428
428
 
429
429
  export default function AgentsPage() {
430
430
  const t = useT();
431
- const { canManageOrg, isLoading: orgRoleLoading } = useOrgRole();
431
+ const {
432
+ canManageOrg,
433
+ isLoading: orgRoleLoading,
434
+ error: orgRoleError,
435
+ } = useOrgRole();
432
436
  const [searchParams, setSearchParams] = useSearchParams();
433
437
  const view = parseView(searchParams.get("view"));
434
438
  const selectedConnectionId = searchParams.get("db");
@@ -461,6 +465,26 @@ export default function AgentsPage() {
461
465
  );
462
466
  }
463
467
 
468
+ if (orgRoleError && isAdminView) {
469
+ return (
470
+ <div className="mx-auto flex h-full w-full max-w-7xl items-center justify-center px-4 py-5 lg:px-6">
471
+ <div className="max-w-sm rounded-lg border bg-background p-6 text-center">
472
+ <div className="mx-auto mb-3 flex h-10 w-10 items-center justify-center rounded-full bg-muted">
473
+ <IconAlertTriangle className="h-5 w-5 text-muted-foreground" />
474
+ </div>
475
+ <h1 className="text-sm font-semibold">
476
+ {t("agents.roleUnavailableTitle")}
477
+ </h1>
478
+ <p className="mt-1.5 text-sm leading-6 text-muted-foreground">
479
+ {t("agents.roleUnavailableDescription", {
480
+ message: orgRoleError.message,
481
+ })}
482
+ </p>
483
+ </div>
484
+ </div>
485
+ );
486
+ }
487
+
464
488
  if (!canManageOrg && isAdminView) {
465
489
  return (
466
490
  <div className="mx-auto flex h-full w-full max-w-7xl items-center justify-center px-4 py-5 lg:px-6">