@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
@@ -56,6 +56,10 @@ import {
56
56
  SelectValue,
57
57
  } from "@/components/ui/select";
58
58
  import { Skeleton } from "@/components/ui/skeleton";
59
+ import {
60
+ isDashboardMine,
61
+ type DashboardVisibility,
62
+ } from "@/lib/dashboard-visibility";
59
63
  import { dashboardCacheScope } from "@/lib/prefetch-keys";
60
64
 
61
65
  import { NewDashboardDialog } from "../components/layout/NewDashboardDialog";
@@ -65,7 +69,8 @@ type Dashboard = {
65
69
  id: string;
66
70
  name?: string;
67
71
  title?: string;
68
- visibility?: string;
72
+ visibility?: DashboardVisibility;
73
+ ownerEmail?: string | null;
69
74
  folderId?: string | null;
70
75
  };
71
76
  type Folder = {
@@ -125,10 +130,15 @@ export default function DashboardOverview() {
125
130
  ) {
126
131
  continue;
127
132
  }
133
+ const ownerEmail =
134
+ typeof dashboard.ownerEmail === "string"
135
+ ? dashboard.ownerEmail
136
+ : undefined;
128
137
  validDashboards.push({
129
138
  id: dashboard.id,
130
139
  name: dashboard.name,
131
140
  visibility: dashboard.visibility,
141
+ ...(ownerEmail ? { ownerEmail } : {}),
132
142
  folderId: dashboard.folderId ?? null,
133
143
  });
134
144
  }
@@ -394,6 +404,7 @@ export default function DashboardOverview() {
394
404
  folders={folders}
395
405
  grouped={grouped}
396
406
  onMove={moveDashboard}
407
+ currentUserEmail={auth?.email}
397
408
  t={t}
398
409
  />
399
410
  ))}
@@ -428,6 +439,7 @@ function DashboardScopeSection({
428
439
  folders,
429
440
  grouped,
430
441
  onMove,
442
+ currentUserEmail,
431
443
  t,
432
444
  }: {
433
445
  scope: Scope;
@@ -435,11 +447,12 @@ function DashboardScopeSection({
435
447
  folders: Folder[];
436
448
  grouped: Map<string, Dashboard[]>;
437
449
  onMove: (dashboard: Dashboard, folderId: string | null) => void;
450
+ currentUserEmail?: string | null;
438
451
  t: ReturnType<typeof useT>;
439
452
  }) {
440
453
  const scopeFolders = folders.filter((folder) => folder.scope === scope);
441
454
  const scopeDashboards = dashboards.filter((dashboard) =>
442
- isDashboardInScope(dashboard, scope),
455
+ isDashboardInScope(dashboard, scope, currentUserEmail),
443
456
  );
444
457
  const Icon = scope === "personal" ? IconLock : IconUsers;
445
458
 
@@ -476,6 +489,7 @@ function DashboardScopeSection({
476
489
  folders={folders}
477
490
  scope={scope}
478
491
  onMove={onMove}
492
+ currentUserEmail={currentUserEmail}
479
493
  t={t}
480
494
  />
481
495
  ))}
@@ -485,6 +499,7 @@ function DashboardScopeSection({
485
499
  folders={folders}
486
500
  scope={scope}
487
501
  onMove={onMove}
502
+ currentUserEmail={currentUserEmail}
488
503
  t={t}
489
504
  hideWhenEmpty
490
505
  />
@@ -500,6 +515,7 @@ function FolderSection({
500
515
  folders,
501
516
  scope,
502
517
  onMove,
518
+ currentUserEmail,
503
519
  t,
504
520
  hideWhenEmpty = false,
505
521
  }: {
@@ -508,11 +524,12 @@ function FolderSection({
508
524
  folders: Folder[];
509
525
  scope: Scope;
510
526
  onMove: (dashboard: Dashboard, folderId: string | null) => void;
527
+ currentUserEmail?: string | null;
511
528
  t: ReturnType<typeof useT>;
512
529
  hideWhenEmpty?: boolean;
513
530
  }) {
514
531
  const scopedDashboards = dashboards.filter((dashboard) =>
515
- isDashboardInScope(dashboard, scope),
532
+ isDashboardInScope(dashboard, scope, currentUserEmail),
516
533
  );
517
534
  if (hideWhenEmpty && scopedDashboards.length === 0) return null;
518
535
 
@@ -540,6 +557,7 @@ function FolderSection({
540
557
  folders={folders}
541
558
  currentFolderId={folder?.id ?? null}
542
559
  onMove={onMove}
560
+ currentUserEmail={currentUserEmail}
543
561
  t={t}
544
562
  />
545
563
  ))}
@@ -554,23 +572,26 @@ function DashboardRow({
554
572
  folders,
555
573
  currentFolderId,
556
574
  onMove,
575
+ currentUserEmail,
557
576
  t,
558
577
  }: {
559
578
  dashboard: Dashboard;
560
579
  folders: Folder[];
561
580
  currentFolderId: string | null;
562
581
  onMove: (dashboard: Dashboard, folderId: string | null) => void;
582
+ currentUserEmail?: string | null;
563
583
  t: ReturnType<typeof useT>;
564
584
  }) {
565
585
  const name =
566
586
  dashboard.name || dashboard.title || t("sidebar.untitledDashboard");
587
+ const mine = isDashboardMine(dashboard, currentUserEmail);
567
588
  const candidateFolders = folders.filter((folder) => {
568
- if (dashboard.visibility === "private") {
589
+ if (mine) {
569
590
  return folder.scope === "personal";
570
591
  }
571
592
  return dashboard.visibility === "org" && folder.scope === "shared";
572
593
  });
573
- const canOrganize = dashboard.visibility !== "public";
594
+ const canOrganize = mine || dashboard.visibility === "org";
574
595
 
575
596
  return (
576
597
  <div className="group flex items-center gap-3 px-4 py-3 transition-colors hover:bg-muted/30">
@@ -586,7 +607,7 @@ function DashboardRow({
586
607
  {name}
587
608
  </p>
588
609
  <p className="truncate text-xs text-muted-foreground">
589
- {dashboard.visibility === "private"
610
+ {mine
590
611
  ? t("dashboardOverview.personal")
591
612
  : t("dashboardOverview.shared")}
592
613
  </p>
@@ -635,8 +656,12 @@ function DashboardRow({
635
656
  );
636
657
  }
637
658
 
638
- function isDashboardInScope(dashboard: Dashboard, scope: Scope): boolean {
659
+ function isDashboardInScope(
660
+ dashboard: Dashboard,
661
+ scope: Scope,
662
+ currentUserEmail?: string | null,
663
+ ): boolean {
639
664
  return scope === "personal"
640
- ? dashboard.visibility === "private"
641
- : dashboard.visibility === "org" || dashboard.visibility === "public";
665
+ ? isDashboardMine(dashboard, currentUserEmail)
666
+ : !isDashboardMine(dashboard, currentUserEmail);
642
667
  }
@@ -1,3 +1,5 @@
1
+ import { data } from "react-router";
2
+
1
3
  import { messagesByLocale } from "@/i18n-data";
2
4
  import NotFound from "@/pages/NotFound";
3
5
 
@@ -5,6 +7,14 @@ export function meta() {
5
7
  return [{ title: messagesByLocale["en-US"].routeTitles.notFound }];
6
8
  }
7
9
 
10
+ // The splat route matches every unmatched path, so React Router's "no routes
11
+ // matched" 404 branch never fires here and the response defaults to 200. Set
12
+ // the status explicitly so the shell is served (and CDN-cached) as the
13
+ // not-found page it actually is.
14
+ export function loader() {
15
+ return data(null, { status: 404 });
16
+ }
17
+
8
18
  export default function CatchAllRoute() {
9
19
  return <NotFound />;
10
20
  }
@@ -1,4 +1,6 @@
1
1
  import { type RouteConfig } from "@react-router/dev/routes";
2
2
  import { flatRoutes } from "@react-router/fs-routes";
3
3
 
4
- export default flatRoutes() satisfies RouteConfig;
4
+ export default flatRoutes({
5
+ ignoredRouteFiles: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"],
6
+ }) satisfies RouteConfig;
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-21
4
+ ---
5
+
6
+ Dashboard filters keep other users' dashboards out of Mine
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-22
4
+ ---
5
+
6
+ Fixed the Agent Native Templates (First-party) dashboard panels failing to load on a local SQLite database
@@ -0,0 +1,9 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-22
4
+ ---
5
+
6
+ Org admin panels no longer report a database error as a permission denial. A failed
7
+ organization-role lookup now surfaces as a retryable error instead of silently reading
8
+ as "you are not an owner or admin", which had been 403-ing the usage stats panel for
9
+ real admins whenever the database was briefly unreachable.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-22
4
+ ---
5
+
6
+ Slack analytics requests now reject invalid workspaces and cursors with actionable errors instead of using the wrong workspace or returning a server failure.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-22
4
+ ---
5
+
6
+ Visiting a broken or mistyped Analytics link now returns a real not-found response instead of a silent success.
@@ -128,7 +128,8 @@ Useful query fields live in `properties`:
128
128
  | `cache_read_tokens`, `cache_write_tokens` | Prompt-cache token counts |
129
129
  | `$ai_total_cost_usd`, `cost_usd` | Estimated run cost in USD |
130
130
  | `cost_cents_x100` | Estimated run cost in centicents |
131
- | `$ai_latency`, `duration_ms` | Run duration in seconds / milliseconds |
131
+ | `duration_ms` | Run duration in milliseconds |
132
+ | `$ai_latency` | Model time in seconds (run duration minus tool time), on `$ai_generation` |
132
133
  | `tool_calls`, `successful_tools`, `failed_tools` | Complete tool-call counts |
133
134
  | `tools`, `tools_truncated` | First 50 tool names, offsets, durations, statuses, and error classes, including interrupted calls |
134
135
  | `delegated`, `delegation_protocol`, `caller_app` | Delegated-run attribution |
@@ -29,6 +29,8 @@ Events tracked by application instrumentation and stored in the configured appli
29
29
  `$ai_model`, `$ai_provider`, `$ai_input_tokens`, `$ai_output_tokens`,
30
30
  `$ai_latency`, `$ai_total_cost_usd`, `run_id`, `thread_id`,
31
31
  `cost_cents_x100`, `duration_ms`, `tool_calls`, `status`, and error fields.
32
+ `$ai_latency` is model time in seconds; `duration_ms` is the full run in
33
+ milliseconds, and the two differ by the time spent in tools.
32
34
  A bounded `tools` array records only tool names, relative start times,
33
35
  durations, statuses, and coarse error classes; interrupted tools and failed
34
36
  runs remain visible, and `tools_truncated` marks runs above the 50-entry cap.
@@ -5,7 +5,29 @@ import { existsSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import { fileURLToPath, pathToFileURL } from "node:url";
7
7
 
8
- import { cloneServerBundleForFunction } from "@agent-native/core/deploy/function-bundle";
8
+ import {
9
+ cloneServerBundleForFunction,
10
+ pruneBrowserRuntimeFromNonAgentClone,
11
+ pruneSsrIslandFromRewritingClone,
12
+ } from "@agent-native/core/deploy/function-bundle";
13
+
14
+ /**
15
+ * Each sweep worker is a full clone of the server bundle, but its entry rewrites
16
+ * the pathname to one scheduled route. It can reach neither the SSR pages nor an
17
+ * agent turn, yet it shipped both the page island and the 79MB browser runtime —
18
+ * six times over, and Netlify zips every function separately.
19
+ */
20
+ function writeWorkerEntry(dest: string, name: string, source: string): void {
21
+ writeFileSync(path.join(dest, `${name}.mjs`), source);
22
+ const freed =
23
+ pruneSsrIslandFromRewritingClone(dest, source) +
24
+ pruneBrowserRuntimeFromNonAgentClone(dest, source);
25
+ if (freed > 0) {
26
+ console.log(
27
+ `[deploy] Pruned ${(freed / 1024 / 1024).toFixed(1)}MB of unreachable modules from ${name}.`,
28
+ );
29
+ }
30
+ }
9
31
 
10
32
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
11
33
  const FUNCTIONS_DIR = path.join(ROOT, ".netlify", "functions-internal");
@@ -164,7 +186,7 @@ export const config = {
164
186
  };
165
187
  `;
166
188
 
167
- writeFileSync(path.join(dest, `${WORKER_NAME}.mjs`), source);
189
+ writeWorkerEntry(dest, WORKER_NAME, source);
168
190
  }
169
191
 
170
192
  function emitAlertScheduledTrigger(token: string) {
@@ -282,7 +304,7 @@ export const config = {
282
304
  };
283
305
  `;
284
306
 
285
- writeFileSync(path.join(dest, `${ALERT_WORKER_NAME}.mjs`), source);
307
+ writeWorkerEntry(dest, ALERT_WORKER_NAME, source);
286
308
  }
287
309
 
288
310
  function emitUptimeScheduledTrigger(token: string) {
@@ -400,7 +422,7 @@ export const config = {
400
422
  };
401
423
  `;
402
424
 
403
- writeFileSync(path.join(dest, `${UPTIME_WORKER_NAME}.mjs`), source);
425
+ writeWorkerEntry(dest, UPTIME_WORKER_NAME, source);
404
426
  }
405
427
 
406
428
  function emitRollupScheduledTrigger(token: string) {
@@ -500,7 +522,7 @@ export const config = {
500
522
  };
501
523
  `;
502
524
 
503
- writeFileSync(path.join(dest, `${ROLLUP_WORKER_NAME}.mjs`), source);
525
+ writeWorkerEntry(dest, ROLLUP_WORKER_NAME, source);
504
526
  }
505
527
 
506
528
  function emitBigQueryScheduledTrigger(token: string) {
@@ -600,7 +622,7 @@ export const config = {
600
622
  };
601
623
  `;
602
624
 
603
- writeFileSync(path.join(dest, `${BIGQUERY_WORKER_NAME}.mjs`), source);
625
+ writeWorkerEntry(dest, BIGQUERY_WORKER_NAME, source);
604
626
  }
605
627
 
606
628
  function emitRetentionScheduledTrigger(token: string) {
@@ -702,7 +724,7 @@ export const config = {
702
724
  };
703
725
  `;
704
726
 
705
- writeFileSync(path.join(dest, `${RETENTION_WORKER_NAME}.mjs`), source);
727
+ writeWorkerEntry(dest, RETENTION_WORKER_NAME, source);
706
728
  }
707
729
 
708
730
  function isDirectRun(): boolean {
@@ -19,8 +19,57 @@ import {
19
19
  type SlackMessage,
20
20
  } from "../lib/slack";
21
21
 
22
- function parseWorkspace(raw?: string): Workspace {
23
- return raw === "secondary" ? "secondary" : "primary";
22
+ export function parseWorkspace(raw?: unknown): Workspace | null {
23
+ if (raw === undefined || raw === null || raw === "" || raw === "primary") {
24
+ return "primary";
25
+ }
26
+ if (raw === "secondary") return "secondary";
27
+ return null;
28
+ }
29
+
30
+ function invalidWorkspace(event: H3Event) {
31
+ setResponseStatus(event, 400);
32
+ return { error: "workspace must be primary or secondary" };
33
+ }
34
+
35
+ export function parseCursorMap(
36
+ raw?: unknown,
37
+ ): { ok: true; value: Record<string, string> } | { ok: false } {
38
+ if (raw === undefined || raw === null || raw === "") {
39
+ return { ok: true, value: {} };
40
+ }
41
+
42
+ try {
43
+ const parsed: unknown = JSON.parse(String(raw));
44
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
45
+ return { ok: false };
46
+ }
47
+ const entries = Object.entries(parsed);
48
+ if (
49
+ entries.some(
50
+ ([, value]) =>
51
+ typeof value !== "string" ||
52
+ !/^\d+(?:\.\d{1,6})?$/.test(value.trim()),
53
+ )
54
+ ) {
55
+ return { ok: false };
56
+ }
57
+ return {
58
+ ok: true,
59
+ value: Object.fromEntries(
60
+ entries.map(([channelId, value]) => [channelId, value.trim()]),
61
+ ),
62
+ };
63
+ } catch {
64
+ return { ok: false };
65
+ }
66
+ }
67
+
68
+ function invalidCursors(event: H3Event) {
69
+ setResponseStatus(event, 400);
70
+ return {
71
+ error: "cursors must be a JSON object of channel IDs to timestamps",
72
+ };
24
73
  }
25
74
 
26
75
  async function requireSlackCredential(event: H3Event, workspace: Workspace) {
@@ -34,6 +83,7 @@ export const handleSlackTeam = defineEventHandler((event) =>
34
83
  try {
35
84
  const { workspace: workspaceParam } = getQuery(event);
36
85
  const workspace = parseWorkspace(workspaceParam as string);
86
+ if (!workspace) return invalidWorkspace(event);
37
87
  const missing = await requireSlackCredential(event, workspace);
38
88
  if (missing) return missing;
39
89
  const team = await getTeamInfo(workspace);
@@ -51,6 +101,7 @@ export const handleSlackChannels = defineEventHandler((event) =>
51
101
  try {
52
102
  const { workspace: workspaceParam, cursor } = getQuery(event);
53
103
  const workspace = parseWorkspace(workspaceParam as string);
104
+ if (!workspace) return invalidWorkspace(event);
54
105
  const missing = await requireSlackCredential(event, workspace);
55
106
  if (missing) return missing;
56
107
  const result = await listChannelsWithCoverage(
@@ -102,6 +153,7 @@ export const handleSlackHistory = defineEventHandler((event) =>
102
153
  cursor,
103
154
  } = getQuery(event);
104
155
  const workspace = parseWorkspace(workspaceParam as string);
156
+ if (!workspace) return invalidWorkspace(event);
105
157
  const missing = await requireSlackCredential(event, workspace);
106
158
  if (missing) return missing;
107
159
  const limit = parseInt((limitParam as string) || "50", 10);
@@ -174,6 +226,7 @@ export const handleSlackMultiHistory = defineEventHandler((event) =>
174
226
  cursors: cursorsParam,
175
227
  } = getQuery(event);
176
228
  const workspace = parseWorkspace(workspaceParam as string);
229
+ if (!workspace) return invalidWorkspace(event);
177
230
  const missing = await requireSlackCredential(event, workspace);
178
231
  if (missing) return missing;
179
232
  // cursors is a JSON-encoded object: { channelId: timestamp }
@@ -188,9 +241,9 @@ export const handleSlackMultiHistory = defineEventHandler((event) =>
188
241
  const channelNamesList = namesParam
189
242
  ? (namesParam as string).split(",")
190
243
  : channelIds;
191
- const cursors: Record<string, string> = cursorsParam
192
- ? JSON.parse(cursorsParam as string)
193
- : {};
244
+ const parsedCursors = parseCursorMap(cursorsParam);
245
+ if (!parsedCursors.ok) return invalidCursors(event);
246
+ const cursors = parsedCursors.value;
194
247
 
195
248
  // Fetch pageSize messages from each channel in parallel while preserving
196
249
  // partial results when the bot is not invited to one of the channels.
@@ -358,6 +411,7 @@ export const handleSlackSearch = defineEventHandler((event) =>
358
411
  try {
359
412
  const { workspace: workspaceParam, query } = getQuery(event);
360
413
  const workspace = parseWorkspace(workspaceParam as string);
414
+ if (!workspace) return invalidWorkspace(event);
361
415
  const missing = await requireSlackCredential(event, workspace);
362
416
  if (missing) return missing;
363
417
 
@@ -69,15 +69,20 @@ async function resolveOrgRole(
69
69
  userEmail: string,
70
70
  orgId: string,
71
71
  ): Promise<string | null> {
72
- try {
73
- const { rows } = await getDbExec().execute({
72
+ // A failed lookup must never collapse into "no role": that reads downstream as
73
+ // a denial and 403s org owners whenever the database is briefly unreachable.
74
+ const { rows } = await getDbExec()
75
+ .execute({
74
76
  sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,
75
77
  args: [orgId, userEmail.toLowerCase()],
78
+ })
79
+ .catch((error: unknown) => {
80
+ throw new DbAdminConnectionError(
81
+ 503,
82
+ `Couldn't verify your organization role: ${redactDbAdminError(error)}`,
83
+ );
76
84
  });
77
- return readString((rows[0] ?? {}) as Record<string, unknown>, "role");
78
- } catch {
79
- return null;
80
- }
85
+ return readString((rows[0] ?? {}) as Record<string, unknown>, "role");
81
86
  }
82
87
 
83
88
  export async function requireAnalyticsAdminContext(input?: {
@@ -1,4 +1,4 @@
1
- import { getDbExec } from "@agent-native/core/db";
1
+ import { getDbExec, isPostgres } from "@agent-native/core/db";
2
2
  import { runWithRequestContext } from "@agent-native/core/server";
3
3
  import { and, eq, isNull, lt, or } from "drizzle-orm";
4
4
 
@@ -1072,6 +1072,130 @@ export function scopedAnalyticsSql(
1072
1072
  return { sql: rewritten, args };
1073
1073
  }
1074
1074
 
1075
+ /**
1076
+ * Dashboard panel SQL (seeded and agent/user-authored) is written against
1077
+ * PostgreSQL date/JSON syntax — `to_char`/`INTERVAL`/`::date`/`::jsonb ->>` —
1078
+ * because that's the dialect this app runs against in production. A local
1079
+ * SQLite dev database doesn't understand any of that and throws a syntax
1080
+ * error before a row is ever read. Rather than hand-rewrite every seeded
1081
+ * panel's SQL (this app also lets the agent/UI author new first-party SQL
1082
+ * panels through this exact same execution path), translate the handful of
1083
+ * Postgres-only shapes this query surface actually produces into SQLite
1084
+ * equivalents right here at the execution boundary. PostgreSQL SQL is never
1085
+ * touched: this only runs when the active database is not Postgres.
1086
+ */
1087
+ export function toSqliteCompatibleFirstPartySql(sql: string): string {
1088
+ let out = sql;
1089
+
1090
+ // properties::jsonb ->> 'key' -> json_extract(properties, '$."key"')
1091
+ // (a quoted JSON path member tolerates keys like "$ai_model" that start
1092
+ // with a character SQLite's unquoted path syntax can't lead with).
1093
+ out = out.replace(
1094
+ /([A-Za-z_][A-Za-z0-9_.]*)::jsonb\s*->>\s*'([^']*)'/g,
1095
+ (_match, column: string, key: string) =>
1096
+ `json_extract(${column}, '$."${key}"')`,
1097
+ );
1098
+
1099
+ // Postgres chr(N) -> SQLite char(N).
1100
+ out = out.replace(/\bchr\(/g, "char(");
1101
+
1102
+ // Any other Postgres type cast (::date, ::float, ::timestamptz, ...) is a
1103
+ // no-op on SQLite's dynamically-typed columns.
1104
+ out = out.replace(/::[A-Za-z_][A-Za-z0-9_]*/g, "");
1105
+
1106
+ // to_char(date_trunc('week', X), 'YYYY-MM-DD') -> Monday of X's week.
1107
+ // ('weekday 0' finds the next Sunday, '-6 days' steps back to that week's
1108
+ // Monday, matching Postgres's ISO week truncation.)
1109
+ out = out.replace(
1110
+ /to_char\(\s*date_trunc\(\s*'week'\s*,\s*([^()]+?)\s*\)\s*,\s*'YYYY-MM-DD'\s*\)/g,
1111
+ (_match, expr: string) => `date(${expr}, 'weekday 0', '-6 days')`,
1112
+ );
1113
+
1114
+ // <dateish-expr> (+|-) INTERVAL 'N days' -> the same day count applied
1115
+ // through SQLite's julian-day arithmetic, immediately reformatted back to
1116
+ // 'YYYY-MM-DD' text. Re-wrapping right away (instead of leaving a bare
1117
+ // julian-day number) matters: this expression sometimes appears outside
1118
+ // any to_char() call, compared directly against a text date column, and
1119
+ // SQLite treats any numeric value as less than any text value — a bare
1120
+ // number here would make that comparison silently always-true.
1121
+ out = out.replace(
1122
+ /([A-Za-z_][A-Za-z0-9_.]*|CURRENT_DATE)\s*(\+|-)\s*INTERVAL\s*'(\d+)\s*days?'/g,
1123
+ (_match, base: string, op: string, days: string) => {
1124
+ const juliandayBase = base === "CURRENT_DATE" ? "'now'" : base;
1125
+ return `date(julianday(${juliandayBase}) ${op} ${days})`;
1126
+ },
1127
+ );
1128
+
1129
+ // <dateish-expr ending in "date"> (+|-) <identifier> (no INTERVAL
1130
+ // keyword) — e.g. `bounds.start_date + offsets.n` in a generated date
1131
+ // series. Scoped to identifiers ending in "date" so unrelated integer
1132
+ // arithmetic (e.g. building the offsets themselves) is left alone.
1133
+ out = out.replace(
1134
+ /([A-Za-z_][A-Za-z0-9_.]*date)\s*(\+|-)\s*([A-Za-z_][A-Za-z0-9_.]*)/g,
1135
+ (_match, base: string, op: string, rhs: string) =>
1136
+ `date(julianday(${base}) ${op} ${rhs})`,
1137
+ );
1138
+
1139
+ // Every surviving to_char(expr, 'YYYY-MM-DD') now wraps an expr that
1140
+ // already evaluates to 'YYYY-MM-DD' text (a bare CURRENT_DATE, or one of
1141
+ // the date(...) forms produced above) — unwrap the call instead of
1142
+ // re-wrapping it. A regex can't balance the arbitrarily nested parens
1143
+ // `date(julianday(...) ...)` can produce, so walk the string instead.
1144
+ out = unwrapPostgresToChar(out);
1145
+
1146
+ return out;
1147
+ }
1148
+
1149
+ /**
1150
+ * Finds each top-level `to_char(expr, 'YYYY-MM-DD')` call and replaces it
1151
+ * with `expr` alone. Balances parens by hand rather than by regex so nested
1152
+ * calls (`date(julianday(...) - 7)`) unwrap correctly regardless of depth.
1153
+ */
1154
+ function unwrapPostgresToChar(sql: string): string {
1155
+ const marker = "to_char(";
1156
+ let out = "";
1157
+ let i = 0;
1158
+ while (i < sql.length) {
1159
+ const idx = sql.indexOf(marker, i);
1160
+ if (idx === -1) {
1161
+ out += sql.slice(i);
1162
+ break;
1163
+ }
1164
+ out += sql.slice(i, idx);
1165
+ const openParen = idx + marker.length - 1;
1166
+ let depth = 0;
1167
+ let closeParen = openParen;
1168
+ for (; closeParen < sql.length; closeParen++) {
1169
+ if (sql[closeParen] === "(") depth++;
1170
+ else if (sql[closeParen] === ")") {
1171
+ depth--;
1172
+ if (depth === 0) break;
1173
+ }
1174
+ }
1175
+ const inner = sql.slice(openParen + 1, closeParen);
1176
+ let innerDepth = 0;
1177
+ let topLevelCommaIdx = -1;
1178
+ for (let k = 0; k < inner.length; k++) {
1179
+ if (inner[k] === "(") innerDepth++;
1180
+ else if (inner[k] === ")") innerDepth--;
1181
+ else if (inner[k] === "," && innerDepth === 0) topLevelCommaIdx = k;
1182
+ }
1183
+ const expr =
1184
+ topLevelCommaIdx === -1 ? inner : inner.slice(0, topLevelCommaIdx);
1185
+ const format =
1186
+ topLevelCommaIdx === -1 ? "" : inner.slice(topLevelCommaIdx + 1).trim();
1187
+ if (format === "'YYYY-MM-DD'") {
1188
+ out += expr.trim();
1189
+ } else {
1190
+ // Not the to_char(expr, 'YYYY-MM-DD') shape this app's SQL uses;
1191
+ // leave it untouched rather than guess at unfamiliar formats.
1192
+ out += sql.slice(idx, closeParen + 1);
1193
+ }
1194
+ i = closeParen + 1;
1195
+ }
1196
+ return out;
1197
+ }
1198
+
1075
1199
  function valueType(value: unknown): string {
1076
1200
  if (typeof value === "number") return "number";
1077
1201
  if (typeof value === "boolean") return "boolean";
@@ -1141,7 +1265,13 @@ export async function queryFirstPartyAnalytics(
1141
1265
  return queryFirstPartyAnalyticsInBigQuery(scoped.sql, scoped.args, table);
1142
1266
  }
1143
1267
  const scoped = scopedAnalyticsSql(sql, scope);
1144
- const wrappedSql = `SELECT * FROM (${scoped.sql}) AS first_party_analytics_query LIMIT ${MAX_QUERY_ROWS}`;
1268
+ // Dashboard SQL is authored against Postgres date/JSON syntax; translate
1269
+ // it for a non-Postgres sql-store (local SQLite dev) at the last possible
1270
+ // moment so Postgres itself never sees a rewritten query.
1271
+ const dialectSql = isPostgres()
1272
+ ? scoped.sql
1273
+ : toSqliteCompatibleFirstPartySql(scoped.sql);
1274
+ const wrappedSql = `SELECT * FROM (${dialectSql}) AS first_party_analytics_query LIMIT ${MAX_QUERY_ROWS}`;
1145
1275
  const timeoutMs = Math.max(
1146
1276
  1,
1147
1277
  options.timeoutMs ?? FIRST_PARTY_ANALYTICS_QUERY_TIMEOUT_MS,
@@ -286,10 +286,13 @@ function looksLikeWorkflowOrAutomationRequest(lower: string): boolean {
286
286
  }
287
287
 
288
288
  const ANALYTICS_RESULT_TERMS =
289
- /\b(conversion|conversions|funnel|revenue|payment|payments|traffic|pageviews?|signups?|events?|active users?|sessions?|retention|churn|pipeline|deals?|calls?|transcripts?|sentiment|themes?|objections?|cohorts?|segments?|accounts?|customers?|tickets?|issues?|leads?|opportunities|mrr|arr|ctr|cvr|cac|ltv)\b/;
289
+ /\b(conversion|conversions|funnel|revenue|payment|payments|traffic|pageviews?|signups?|events?|active users?|sessions?|retention|churn|pipeline|deals?|calls?|transcripts?|sentiment|themes?|objections?|cohorts?|segments?|accounts?|customers?|tickets?|issues?|leads?|opportunities|usage|adoption|ai credits?|credit consumption|credits? consumed|allowance|quota|mrr|arr|ctr|cvr|cac|ltv)\b/;
290
+
291
+ const ANALYTICS_DOMAIN_ENTITY_TERMS =
292
+ /\b(?:branch(?:es)?|branch creation|created by|creator identity)\b/;
290
293
 
291
294
  const ANALYTICS_INTENT_TERMS =
292
- /\b(analy[sz]e|measure|calculate|query|report|summari[sz]e|break ?down|compare|rank|segment|forecast|trend|count|total|average|median|percent(?:age)?|rate|top|bottom|highest|lowest|how many|how much|what (?:is|are|was|were)|which|why)\b/;
295
+ /\b(analy[sz]e|measure|calculate|query|report|summari[sz]e|break ?down|compare|rank|segment|forecast|trend|count|total|average|median|percent(?:age)?|rate|top|bottom|highest|lowest|pull|fetch|retrieve|export|show|how many|how much|what (?:is|are|was|were)|which|why)\b/;
293
296
 
294
297
  const SOURCE_SEARCH_INTENT_TERMS =
295
298
  /\b(find|surface|search|scan|grep|review|inspect|check|look through|go find)\b/;
@@ -308,7 +311,7 @@ const ARTIFACT_DATA_INTENT =
308
311
  // a live provider data call. They should be answered from the data dictionary,
309
312
  // schema introspection tools, or the agent's knowledge of configured sources.
310
313
  const METADATA_ONLY_TERMS =
311
- /\b(what (?:tables?|columns?|fields?|sources?|datasets?|metrics?|schema) (?:are|is|exist|available|do (?:we|you|i) have)|which (?:sources?|tables?|providers?|integrations?) (?:are|is) (?:connected|configured|available|set up)|list (?:the )?(?:tables?|columns?|fields?|sources?|datasets?|schemas?)|show (?:me )?(?:available|the) (?:sources?|tables?|schemas?)|what does .+ (?:mean|measure|represent|track)|how is .+ (?:defined|calculated|computed|measured)|definition of|describe (?:the )?(?:\w+\s+)?(?:table|column|schema|metric|field)|list (?:the )?columns?\s+in|what (?:is|are) (?:the )?(?:data (?:dictionary|schema)|available (?:sources?|tables?))|what (?:source|provider|table) (?:has|stores|contains))\b/;
314
+ /\b(what (?:tables?|columns?|fields?|sources?|datasets?|metrics?|schema) (?:are|is|exist|available|do (?:we|you|i) have)|which (?:sources?|tables?|providers?|integrations?) (?:are|is) (?:connected|configured|available|set up)|list (?:the )?(?:tables?|columns?|fields?|sources?|datasets?|schemas?)|show (?:me )?(?:available|the) (?:data )?(?:sources?|tables?|schemas?)|what does .+ (?:mean|measure|represent|track)|how is .+ (?:defined|calculated|computed|measured)|definition of|describe (?:the )?(?:\w+\s+)?(?:table|column|schema|metric|field)|list (?:the )?columns?\s+in|what (?:is|are) (?:the )?(?:data (?:dictionary|schema)|available (?:data )?(?:sources?|tables?))|what (?:source|provider|table) (?:has|stores|contains))\b/;
312
315
 
313
316
  export function looksLikeAnalyticsDataRequest(text: string): boolean {
314
317
  const requestText = stripInjectedAnalyticsGuardContext(text);
@@ -350,6 +353,14 @@ export function looksLikeAnalyticsDataRequest(text: string): boolean {
350
353
  if (METADATA_ONLY_TERMS.test(lower)) return false;
351
354
 
352
355
  if (ANALYTICS_RESULT_TERMS.test(lower)) return true;
356
+ if (
357
+ ANALYTICS_DOMAIN_ENTITY_TERMS.test(lower) &&
358
+ (ANALYTICS_INTENT_TERMS.test(lower) ||
359
+ SOURCE_SEARCH_INTENT_TERMS.test(lower) ||
360
+ /\bdata\b/.test(lower))
361
+ ) {
362
+ return true;
363
+ }
353
364
  if (
354
365
  ANALYTICS_INTENT_TERMS.test(lower) &&
355
366
  /\b(data|source|table|sql)\b/.test(lower)