@agent-native/core 0.92.0 → 0.92.2

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 (375) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +20 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/application-state/store.ts +12 -1
  5. package/corpus/core/src/cli/sync-builder-starter-manifest.ts +29 -1
  6. package/corpus/core/src/client/AssistantChat.tsx +27 -14
  7. package/corpus/core/src/client/PoweredByBadge.tsx +1 -8
  8. package/corpus/core/src/client/agent-chat-adapter.ts +37 -10
  9. package/corpus/core/src/client/chat/widgets/DataTableWidget.tsx +52 -1
  10. package/corpus/core/src/client/db-admin/TableEditor.tsx +49 -0
  11. package/corpus/core/src/client/db-admin/export-utils.ts +13 -4
  12. package/corpus/core/src/client/db-admin/useAgentSync.ts +72 -0
  13. package/corpus/core/src/client/error-capture.ts +69 -7
  14. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +5 -1
  15. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +53 -8
  16. package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +5 -1
  17. package/corpus/core/src/client/extensions/portable-extension.ts +1 -0
  18. package/corpus/core/src/client/org/OrgSwitcher.tsx +12 -9
  19. package/corpus/core/src/client/org/TeamPage.tsx +77 -71
  20. package/corpus/core/src/client/settings/SettingsPanel.tsx +205 -52
  21. package/corpus/core/src/client/settings/SettingsSection.tsx +8 -1
  22. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +25 -9
  23. package/corpus/core/src/db-admin/agent-tools.ts +8 -2
  24. package/corpus/core/src/db-admin/operations.ts +116 -4
  25. package/corpus/core/src/db-admin/routes.ts +1 -0
  26. package/corpus/core/src/db-admin/types.ts +4 -0
  27. package/corpus/core/src/extensions/html-shell.ts +5 -4
  28. package/corpus/core/src/extensions/routes.ts +10 -0
  29. package/corpus/core/src/navigation/index.ts +1 -1
  30. package/corpus/core/src/notifications/channels.ts +1 -22
  31. package/corpus/core/src/resources/handlers.ts +10 -8
  32. package/corpus/core/src/server/poll.ts +293 -8
  33. package/corpus/core/src/styles/agent-native.css +27 -0
  34. package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
  35. package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  36. package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  37. package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +7 -0
  38. package/corpus/core/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
  39. package/corpus/core/src/templates/default/AGENTS.md +4 -2
  40. package/corpus/core/src/templates/headless/AGENTS.md +4 -0
  41. package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
  42. package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  43. package/corpus/core/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
  44. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
  45. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
  46. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  47. package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
  48. package/corpus/core/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
  49. package/corpus/core/src/templates/workspace-core/AGENTS.md +7 -1
  50. package/corpus/core/src/templates/workspace-root/AGENTS.md +7 -1
  51. package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +5 -0
  52. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
  53. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
  54. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +7 -0
  55. package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +5 -1
  56. package/corpus/templates/analytics/AGENTS.md +33 -14
  57. package/corpus/templates/analytics/actions/capture-test-error.ts +4 -0
  58. package/corpus/templates/analytics/actions/get-analytics-alert-rule-defaults.ts +23 -0
  59. package/corpus/templates/analytics/actions/get-error-issue.ts +1 -1
  60. package/corpus/templates/analytics/actions/list-analysis-revisions.ts +40 -0
  61. package/corpus/templates/analytics/actions/list-dashboard-revisions.ts +40 -0
  62. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +299 -0
  63. package/corpus/templates/analytics/actions/navigate.ts +4 -2
  64. package/corpus/templates/analytics/actions/restore-analysis-revision.ts +43 -0
  65. package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +68 -0
  66. package/corpus/templates/analytics/actions/save-analytics-alert-rule.ts +14 -0
  67. package/corpus/templates/analytics/actions/save-monitor.ts +1 -1
  68. package/corpus/templates/analytics/actions/view-screen.ts +24 -0
  69. package/corpus/templates/analytics/app/components/analysis/AnalysisHistoryPanel.tsx +181 -0
  70. package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +184 -0
  71. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +22 -16
  72. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
  73. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +27 -21
  74. package/corpus/templates/analytics/app/hooks/use-analysis-revisions.ts +43 -0
  75. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +110 -0
  76. package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +43 -0
  77. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +8 -3
  78. package/corpus/templates/analytics/app/i18n/zh-TW.ts +64 -2
  79. package/corpus/templates/analytics/app/i18n-data.ts +783 -3
  80. package/corpus/templates/analytics/app/pages/Agents.tsx +359 -19
  81. package/corpus/templates/analytics/app/pages/Settings.tsx +3 -2
  82. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +34 -1
  83. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +28 -0
  84. package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +18 -1
  85. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +7 -10
  86. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +479 -23
  87. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +0 -9
  88. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +11 -0
  89. package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +9 -1
  90. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +6 -3
  91. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +26 -30
  92. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +9 -99
  93. package/corpus/templates/analytics/app/pages/settings/AlertRulesSettingsCard.tsx +262 -104
  94. package/corpus/templates/analytics/app/routes/team.tsx +1 -1
  95. package/corpus/templates/analytics/changelog/2026-07-08-admins-can-audit-dashboard-usage-ownership-and-cleanup-signa.md +6 -0
  96. package/corpus/templates/analytics/changelog/2026-07-08-agent-monitoring-stays-available-to-non-admins.md +6 -0
  97. package/corpus/templates/analytics/changelog/2026-07-08-alert-emails-now-show-the-message-without-raw-metadata-json.md +6 -0
  98. package/corpus/templates/analytics/changelog/2026-07-08-alert-rules-are-easier-to-scan-expand-and-edit-from-settings.md +6 -0
  99. package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-forms-remember-last-email-recipients.md +6 -0
  100. package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-rules-can-now-use-per-rule-slack-and-webhook.md +6 -0
  101. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +5 -0
  102. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-usage-now-counts-explorer-dashboard-traffic.md +6 -0
  103. package/corpus/templates/analytics/changelog/2026-07-08-demo-mode-session-emails-are-filtered-and-anonymized.md +6 -0
  104. package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-adds-stack-traces-and-frequency-bars.md +6 -0
  105. package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-now-shows-the-latest-occurrence-message-a.md +6 -0
  106. package/corpus/templates/analytics/changelog/2026-07-08-monitoring-errors-only-show-test-action-when-empty.md +6 -0
  107. package/corpus/templates/analytics/changelog/2026-07-08-production-session-replay-now-requires-private-blob-storage-.md +6 -0
  108. package/corpus/templates/analytics/changelog/2026-07-08-shared-extension-links-now-show-a-clear-message-when-you-do-.md +6 -0
  109. package/corpus/templates/analytics/changelog/2026-07-08-team-settings-show-access-controls-next-to-member-lists.md +6 -0
  110. package/corpus/templates/analytics/changelog/2026-07-08-uptime-checks-no-longer-count-ssrf-setup-time-against-the-re.md +6 -0
  111. package/corpus/templates/analytics/changelog/2026-07-08-uptime-checks-reuse-one-keep-alive-connection-so-recorded-la.md +6 -0
  112. package/corpus/templates/analytics/changelog/2026-07-08-uptime-monitors-now-confirm-transient-timeout-failures-befor.md +6 -0
  113. package/corpus/templates/analytics/changelog/2026-07-08-uptime-monitors-now-use-a-10-second-request-timeout-by-defau.md +6 -0
  114. package/corpus/templates/analytics/docs/uptime-monitoring.md +30 -18
  115. package/corpus/templates/analytics/server/db/schema-monitoring.ts +1 -1
  116. package/corpus/templates/analytics/server/db/schema.ts +56 -0
  117. package/corpus/templates/analytics/server/lib/analytics-alerts.ts +92 -0
  118. package/corpus/templates/analytics/server/lib/dashboards-store.ts +334 -5
  119. package/corpus/templates/analytics/server/lib/error-capture.ts +231 -36
  120. package/corpus/templates/analytics/server/lib/session-replay.ts +114 -8
  121. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +244 -33
  122. package/corpus/templates/analytics/server/plugins/db.ts +112 -2
  123. package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +1 -0
  124. package/corpus/templates/assets/.agents/skills/actions/SKILL.md +5 -0
  125. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
  126. package/corpus/templates/assets/.agents/skills/security/SKILL.md +7 -0
  127. package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +5 -1
  128. package/corpus/templates/assets/AGENTS.md +4 -0
  129. package/corpus/templates/assets/app/routes/settings.tsx +1 -1
  130. package/corpus/templates/assets/app/routes/team.tsx +1 -1
  131. package/corpus/templates/brain/.agents/skills/actions/SKILL.md +5 -0
  132. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +5 -0
  133. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
  134. package/corpus/templates/brain/.agents/skills/security/SKILL.md +7 -0
  135. package/corpus/templates/brain/AGENTS.md +4 -0
  136. package/corpus/templates/brain/app/routes/team.tsx +1 -1
  137. package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +5 -0
  138. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
  139. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +7 -0
  140. package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +5 -1
  141. package/corpus/templates/calendar/AGENTS.md +4 -0
  142. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +11 -2
  143. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +21 -8
  144. package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +7 -1
  145. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -2
  146. package/corpus/templates/calendar/app/lib/popover-click-guard.ts +48 -4
  147. package/corpus/templates/calendar/app/pages/Settings.tsx +1 -1
  148. package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
  149. package/corpus/templates/calendar/changelog/2026-07-08-clicking-empty-calendar-space-closes-an-open-event-popover-b.md +6 -0
  150. package/corpus/templates/chat/.agents/skills/actions/SKILL.md +5 -0
  151. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +5 -0
  152. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  153. package/corpus/templates/chat/.agents/skills/security/SKILL.md +7 -0
  154. package/corpus/templates/chat/AGENTS.md +4 -0
  155. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  156. package/corpus/templates/chat/app/routes/settings.tsx +2 -2
  157. package/corpus/templates/chat/app/routes/team.tsx +1 -1
  158. package/corpus/templates/clips/.agents/skills/actions/SKILL.md +5 -0
  159. package/corpus/templates/clips/.agents/skills/security/SKILL.md +7 -0
  160. package/corpus/templates/clips/AGENTS.md +4 -0
  161. package/corpus/templates/clips/actions/finalize-recording.ts +9 -3
  162. package/corpus/templates/clips/actions/set-thumbnail.ts +11 -2
  163. package/corpus/templates/clips/app/components/meetings/canvas-editor.tsx +1 -7
  164. package/corpus/templates/clips/app/components/player/player-controls.tsx +21 -13
  165. package/corpus/templates/clips/app/components/player/video-player.tsx +30 -75
  166. package/corpus/templates/clips/app/i18n/ar-SA.ts +6 -5
  167. package/corpus/templates/clips/app/i18n/de-DE.ts +6 -6
  168. package/corpus/templates/clips/app/i18n/en-US.ts +6 -5
  169. package/corpus/templates/clips/app/i18n/es-ES.ts +6 -5
  170. package/corpus/templates/clips/app/i18n/fr-FR.ts +6 -6
  171. package/corpus/templates/clips/app/i18n/hi-IN.ts +6 -5
  172. package/corpus/templates/clips/app/i18n/ja-JP.ts +6 -5
  173. package/corpus/templates/clips/app/i18n/ko-KR.ts +6 -5
  174. package/corpus/templates/clips/app/i18n/pt-BR.ts +6 -5
  175. package/corpus/templates/clips/app/i18n/zh-CN.ts +6 -5
  176. package/corpus/templates/clips/app/i18n/zh-TW.ts +6 -5
  177. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +51 -118
  178. package/corpus/templates/clips/changelog/2026-07-08-hosted-clip-uploads-now-clear-failed-buffered-chunks.md +6 -0
  179. package/corpus/templates/clips/changelog/2026-07-08-hosted-recording-uploads-now-avoid-sql-chunk-storage.md +6 -0
  180. package/corpus/templates/clips/changelog/2026-07-08-meeting-recaps-now-keep-summaries-action-items-and-transcrip.md +6 -0
  181. package/corpus/templates/clips/changelog/2026-07-08-video-playback-controls-now-match-loom-style-5-second-skips-.md +6 -0
  182. package/corpus/templates/clips/server/lib/recording-upload-state.ts +63 -0
  183. package/corpus/templates/clips/server/lib/video-storage.ts +4 -0
  184. package/corpus/templates/clips/server/routes/api/recordings/[recordingId]/thumbnail.post.ts +19 -13
  185. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +40 -1
  186. package/corpus/templates/content/.agents/skills/actions/SKILL.md +5 -0
  187. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
  188. package/corpus/templates/content/.agents/skills/security/SKILL.md +7 -0
  189. package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +5 -1
  190. package/corpus/templates/content/AGENTS.md +4 -0
  191. package/corpus/templates/content/app/routes/_app.settings.tsx +2 -2
  192. package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
  193. package/corpus/templates/design/.agents/skills/actions/SKILL.md +5 -0
  194. package/corpus/templates/design/.agents/skills/security/SKILL.md +7 -0
  195. package/corpus/templates/design/AGENTS.md +4 -0
  196. package/corpus/templates/design/actions/take-design-screenshot.ts +12 -9
  197. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +57 -13
  198. package/corpus/templates/design/app/routes/team.tsx +1 -1
  199. package/corpus/templates/design/changelog/2026-07-08-local-images-added-to-designs-now-upload-to-file-storage-ins.md +6 -0
  200. package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +5 -0
  201. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +7 -0
  202. package/corpus/templates/dispatch/AGENTS.md +4 -0
  203. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
  204. package/corpus/templates/dispatch/app/routes/settings.tsx +2 -2
  205. package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
  206. package/corpus/templates/forms/.agents/skills/actions/SKILL.md +5 -0
  207. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
  208. package/corpus/templates/forms/.agents/skills/security/SKILL.md +7 -0
  209. package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +5 -1
  210. package/corpus/templates/forms/AGENTS.md +4 -0
  211. package/corpus/templates/forms/app/routes/_app.settings.tsx +2 -2
  212. package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
  213. package/corpus/templates/forms/shared/navigation.ts +1 -1
  214. package/corpus/templates/macros/.agents/skills/security/SKILL.md +7 -0
  215. package/corpus/templates/macros/AGENTS.md +4 -0
  216. package/corpus/templates/macros/app/routes/settings.tsx +2 -2
  217. package/corpus/templates/macros/app/routes/team.tsx +1 -1
  218. package/corpus/templates/mail/.agents/skills/actions/SKILL.md +5 -0
  219. package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +1 -1
  220. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
  221. package/corpus/templates/mail/.agents/skills/security/SKILL.md +7 -0
  222. package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +5 -1
  223. package/corpus/templates/mail/AGENTS.md +4 -0
  224. package/corpus/templates/mail/changelog/2026-07-08-mail-attachments-in-hosted-environments-now-require-file-sto.md +6 -0
  225. package/corpus/templates/mail/server/handlers/media.ts +26 -1
  226. package/corpus/templates/mail/server/lib/outgoing-email.ts +24 -1
  227. package/corpus/templates/mail/server/lib/upload-store.ts +2 -1
  228. package/corpus/templates/plan/.agents/skills/actions/SKILL.md +5 -0
  229. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +5 -0
  230. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
  231. package/corpus/templates/plan/.agents/skills/security/SKILL.md +7 -0
  232. package/corpus/templates/plan/AGENTS.md +4 -0
  233. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
  234. package/corpus/templates/plan/app/routes/settings.tsx +2 -2
  235. package/corpus/templates/plan/app/routes/team.tsx +1 -1
  236. package/corpus/templates/plan/changelog/2026-07-08-hosted-plan-images-now-require-connected-storage.md +6 -0
  237. package/corpus/templates/plan/server/lib/plan-assets.ts +33 -4
  238. package/corpus/templates/slides/.agents/skills/actions/SKILL.md +5 -0
  239. package/corpus/templates/slides/.agents/skills/security/SKILL.md +7 -0
  240. package/corpus/templates/slides/AGENTS.md +4 -0
  241. package/corpus/templates/slides/actions/generate-image-api.ts +15 -3
  242. package/corpus/templates/slides/app/routes/settings.tsx +2 -2
  243. package/corpus/templates/slides/app/routes/team.tsx +1 -1
  244. package/corpus/templates/slides/changelog/2026-07-08-generated-slide-images-now-return-hosted-file-storage-urls-i.md +6 -0
  245. package/corpus/templates/slides/shared/api.ts +1 -1
  246. package/dist/application-state/store.d.ts.map +1 -1
  247. package/dist/application-state/store.js +8 -2
  248. package/dist/application-state/store.js.map +1 -1
  249. package/dist/cli/sync-builder-starter-manifest.d.ts.map +1 -1
  250. package/dist/cli/sync-builder-starter-manifest.js +24 -1
  251. package/dist/cli/sync-builder-starter-manifest.js.map +1 -1
  252. package/dist/client/AssistantChat.d.ts.map +1 -1
  253. package/dist/client/AssistantChat.js +24 -13
  254. package/dist/client/AssistantChat.js.map +1 -1
  255. package/dist/client/PoweredByBadge.d.ts +1 -1
  256. package/dist/client/PoweredByBadge.d.ts.map +1 -1
  257. package/dist/client/PoweredByBadge.js +3 -9
  258. package/dist/client/PoweredByBadge.js.map +1 -1
  259. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  260. package/dist/client/agent-chat-adapter.js +28 -9
  261. package/dist/client/agent-chat-adapter.js.map +1 -1
  262. package/dist/client/chat/widgets/DataTableWidget.d.ts.map +1 -1
  263. package/dist/client/chat/widgets/DataTableWidget.js +19 -2
  264. package/dist/client/chat/widgets/DataTableWidget.js.map +1 -1
  265. package/dist/client/db-admin/TableEditor.d.ts.map +1 -1
  266. package/dist/client/db-admin/TableEditor.js +19 -2
  267. package/dist/client/db-admin/TableEditor.js.map +1 -1
  268. package/dist/client/db-admin/export-utils.d.ts +2 -0
  269. package/dist/client/db-admin/export-utils.d.ts.map +1 -1
  270. package/dist/client/db-admin/export-utils.js +11 -3
  271. package/dist/client/db-admin/export-utils.js.map +1 -1
  272. package/dist/client/db-admin/useAgentSync.d.ts.map +1 -1
  273. package/dist/client/db-admin/useAgentSync.js +63 -0
  274. package/dist/client/db-admin/useAgentSync.js.map +1 -1
  275. package/dist/client/error-capture.d.ts.map +1 -1
  276. package/dist/client/error-capture.js +41 -7
  277. package/dist/client/error-capture.js.map +1 -1
  278. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  279. package/dist/client/extensions/EmbeddedExtension.js +3 -1
  280. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  281. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  282. package/dist/client/extensions/ExtensionViewer.js +32 -5
  283. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  284. package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
  285. package/dist/client/extensions/InlineExtensionFrame.js +3 -1
  286. package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
  287. package/dist/client/extensions/portable-extension.d.ts.map +1 -1
  288. package/dist/client/extensions/portable-extension.js +1 -0
  289. package/dist/client/extensions/portable-extension.js.map +1 -1
  290. package/dist/client/org/OrgSwitcher.d.ts +1 -1
  291. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  292. package/dist/client/org/OrgSwitcher.js +11 -6
  293. package/dist/client/org/OrgSwitcher.js.map +1 -1
  294. package/dist/client/org/TeamPage.d.ts.map +1 -1
  295. package/dist/client/org/TeamPage.js +5 -5
  296. package/dist/client/org/TeamPage.js.map +1 -1
  297. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  298. package/dist/client/settings/SettingsPanel.js +37 -14
  299. package/dist/client/settings/SettingsPanel.js.map +1 -1
  300. package/dist/client/settings/SettingsSection.js +1 -1
  301. package/dist/client/settings/SettingsSection.js.map +1 -1
  302. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  303. package/dist/client/settings/SettingsTabsPage.js +21 -10
  304. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  305. package/dist/collab/routes.d.ts +1 -1
  306. package/dist/db-admin/agent-tools.d.ts.map +1 -1
  307. package/dist/db-admin/agent-tools.js +7 -2
  308. package/dist/db-admin/agent-tools.js.map +1 -1
  309. package/dist/db-admin/operations.d.ts.map +1 -1
  310. package/dist/db-admin/operations.js +90 -4
  311. package/dist/db-admin/operations.js.map +1 -1
  312. package/dist/db-admin/routes.d.ts.map +1 -1
  313. package/dist/db-admin/routes.js +1 -0
  314. package/dist/db-admin/routes.js.map +1 -1
  315. package/dist/db-admin/types.d.ts +4 -0
  316. package/dist/db-admin/types.d.ts.map +1 -1
  317. package/dist/db-admin/types.js.map +1 -1
  318. package/dist/extensions/html-shell.d.ts +5 -4
  319. package/dist/extensions/html-shell.d.ts.map +1 -1
  320. package/dist/extensions/html-shell.js.map +1 -1
  321. package/dist/extensions/routes.d.ts.map +1 -1
  322. package/dist/extensions/routes.js +8 -0
  323. package/dist/extensions/routes.js.map +1 -1
  324. package/dist/navigation/index.d.ts +1 -1
  325. package/dist/navigation/index.d.ts.map +1 -1
  326. package/dist/navigation/index.js +1 -1
  327. package/dist/navigation/index.js.map +1 -1
  328. package/dist/notifications/channels.js +1 -17
  329. package/dist/notifications/channels.js.map +1 -1
  330. package/dist/notifications/routes.d.ts +1 -1
  331. package/dist/resources/handlers.d.ts +5 -0
  332. package/dist/resources/handlers.d.ts.map +1 -1
  333. package/dist/resources/handlers.js +9 -8
  334. package/dist/resources/handlers.js.map +1 -1
  335. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  336. package/dist/server/poll.d.ts +12 -4
  337. package/dist/server/poll.d.ts.map +1 -1
  338. package/dist/server/poll.js +236 -9
  339. package/dist/server/poll.js.map +1 -1
  340. package/dist/styles/agent-native.css +27 -0
  341. package/dist/templates/default/.agents/skills/actions/SKILL.md +5 -0
  342. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  343. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  344. package/dist/templates/default/.agents/skills/security/SKILL.md +7 -0
  345. package/dist/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
  346. package/dist/templates/default/AGENTS.md +4 -2
  347. package/dist/templates/headless/AGENTS.md +4 -0
  348. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
  349. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  350. package/dist/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
  351. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
  352. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
  353. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  354. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
  355. package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
  356. package/dist/templates/workspace-core/AGENTS.md +7 -1
  357. package/dist/templates/workspace-root/AGENTS.md +7 -1
  358. package/package.json +1 -1
  359. package/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
  360. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  361. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  362. package/src/templates/default/.agents/skills/security/SKILL.md +7 -0
  363. package/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
  364. package/src/templates/default/AGENTS.md +4 -2
  365. package/src/templates/headless/AGENTS.md +4 -0
  366. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
  367. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  368. package/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
  369. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
  370. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
  371. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  372. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
  373. package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
  374. package/src/templates/workspace-core/AGENTS.md +7 -1
  375. package/src/templates/workspace-root/AGENTS.md +7 -1
@@ -0,0 +1,299 @@
1
+ import { defineAction } from "@agent-native/core/action";
2
+ import { buildDeepLink } from "@agent-native/core/server";
3
+ import { and, eq, like, or, sql } from "drizzle-orm";
4
+ import { z } from "zod";
5
+
6
+ import { getDb, schema } from "../server/db/index.js";
7
+ import { requireDbAdminContextFromRequest } from "../server/lib/db-admin-connections";
8
+
9
+ type DashboardUsageStats = {
10
+ id: string;
11
+ name: string;
12
+ kind: "explorer" | "sql";
13
+ ownerEmail: string | null;
14
+ visibility: "private" | "org" | "public";
15
+ createdAt: string;
16
+ updatedAt: string;
17
+ updatedBy: string | null;
18
+ archivedAt: string | null;
19
+ hiddenAt: string | null;
20
+ hiddenBy: string | null;
21
+ viewCount: number;
22
+ engagementCount: number;
23
+ eventEngagementCount: number;
24
+ savedViewCount: number;
25
+ uniqueUserCount: number;
26
+ lastViewedAt: string | null;
27
+ lastSavedViewAt: string | null;
28
+ panelCount: number | null;
29
+ url: string;
30
+ };
31
+
32
+ function toNumber(value: unknown): number {
33
+ if (typeof value === "number" && Number.isFinite(value)) return value;
34
+ if (typeof value === "bigint") return Number(value);
35
+ if (typeof value === "string" && value.trim()) {
36
+ const parsed = Number(value);
37
+ return Number.isFinite(parsed) ? parsed : 0;
38
+ }
39
+ return 0;
40
+ }
41
+
42
+ function parseConfig(value: unknown): Record<string, unknown> {
43
+ if (value && typeof value === "object" && !Array.isArray(value)) {
44
+ return value as Record<string, unknown>;
45
+ }
46
+ if (typeof value !== "string") return {};
47
+ try {
48
+ const parsed = JSON.parse(value);
49
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
50
+ ? parsed
51
+ : {};
52
+ } catch {
53
+ return {};
54
+ }
55
+ }
56
+
57
+ function dashboardName(row: { title: string; config: unknown }): string {
58
+ const config = parseConfig(row.config);
59
+ const configName = config.name;
60
+ if (typeof configName === "string" && configName.trim()) {
61
+ return configName.trim();
62
+ }
63
+ return row.title || "Untitled";
64
+ }
65
+
66
+ function dashboardPanelCount(row: {
67
+ kind: string;
68
+ config: unknown;
69
+ }): number | null {
70
+ if (row.kind !== "sql") return null;
71
+ const panels = parseConfig(row.config).panels;
72
+ return Array.isArray(panels) ? panels.length : 0;
73
+ }
74
+
75
+ export function dashboardIdFromPath(path: string | null): string | null {
76
+ const pathname = path ?? "";
77
+ const match = pathname.match(/(?:^|\/)(?:dashboards|adhoc)\/([^/?#]+)/);
78
+ if (!match) return null;
79
+ if (match[1] === "explorer-dashboard") {
80
+ return null;
81
+ }
82
+ try {
83
+ return decodeURIComponent(match[1]);
84
+ } catch {
85
+ return match[1];
86
+ }
87
+ }
88
+
89
+ export function dashboardIdFromEventLocation(
90
+ path: string | null,
91
+ url: string | null,
92
+ ): string | null {
93
+ const direct = dashboardIdFromPath(path);
94
+ if (direct) return direct;
95
+ const raw = url || path;
96
+ if (!raw) return null;
97
+ try {
98
+ const parsed = new URL(raw, "https://analytics.local");
99
+ if (
100
+ /(?:^|\/)(?:dashboards|adhoc)\/explorer-dashboard$/.test(parsed.pathname)
101
+ ) {
102
+ const id = parsed.searchParams.get("id");
103
+ return id && id.trim() ? id : null;
104
+ }
105
+ } catch {
106
+ // Fall through to regex below for malformed relative strings.
107
+ }
108
+ const match = raw.match(
109
+ /(?:^|\/)(?:dashboards|adhoc)\/explorer-dashboard(?:\?[^#]*)?[?&]id=([^&#]+)/,
110
+ );
111
+ if (!match) return null;
112
+ try {
113
+ return decodeURIComponent(match[1].replace(/\+/g, " "));
114
+ } catch {
115
+ return match[1];
116
+ }
117
+ }
118
+
119
+ function dashboardUrl(row: { id: string; kind: string }): string {
120
+ return row.kind === "explorer"
121
+ ? `/dashboards/explorer-dashboard?id=${encodeURIComponent(row.id)}`
122
+ : `/dashboards/${encodeURIComponent(row.id)}`;
123
+ }
124
+
125
+ export default defineAction({
126
+ description:
127
+ "List admin-only dashboard usage and cleanup stats for every dashboard in the active organization. Includes lifecycle metadata, owner, last tracked modifier, pageviews, engagement events, unique viewers, saved view counts, archive/hidden state, and dashboard links. Requires active organization owner/admin role.",
128
+ schema: z.object({}),
129
+ http: { method: "GET" },
130
+ readOnly: true,
131
+ link: () => ({
132
+ url: buildDeepLink({
133
+ app: "analytics",
134
+ view: "agents",
135
+ params: { agentsView: "dashboards" },
136
+ }),
137
+ label: "Open dashboard usage admin",
138
+ view: "agents",
139
+ }),
140
+ run: async (_args, ctx) => {
141
+ const admin = await requireDbAdminContextFromRequest(ctx);
142
+ const db = getDb() as any;
143
+
144
+ // guard:allow-unscoped — org owner/admin audit intentionally spans all
145
+ // dashboard rows in the active org after requireDbAdminContextFromRequest.
146
+ const dashboardRows = await db
147
+ .select()
148
+ .from(schema.dashboards)
149
+ .where(eq(schema.dashboards.orgId, admin.orgId));
150
+
151
+ const dashboardIds = new Set<string>(
152
+ dashboardRows.map((row: { id: string }) => row.id),
153
+ );
154
+
155
+ const savedViewRows = await db
156
+ .select({
157
+ dashboardId: schema.dashboardViews.dashboardId,
158
+ count: sql<number>`count(*)`,
159
+ lastSavedViewAt: sql<
160
+ string | null
161
+ >`max(${schema.dashboardViews.createdAt})`,
162
+ })
163
+ .from(schema.dashboardViews)
164
+ .groupBy(schema.dashboardViews.dashboardId);
165
+
166
+ const savedViewsByDashboard = new Map<
167
+ string,
168
+ { count: number; lastSavedViewAt: string | null }
169
+ >();
170
+ for (const row of savedViewRows as Array<{
171
+ dashboardId: string;
172
+ count: unknown;
173
+ lastSavedViewAt: string | null;
174
+ }>) {
175
+ if (!dashboardIds.has(row.dashboardId)) continue;
176
+ savedViewsByDashboard.set(row.dashboardId, {
177
+ count: toNumber(row.count),
178
+ lastSavedViewAt: row.lastSavedViewAt ?? null,
179
+ });
180
+ }
181
+
182
+ const analyticsUserIdentity = sql<
183
+ string | null
184
+ >`coalesce(nullif(${schema.analyticsEvents.userKey}, ''), nullif(${schema.analyticsEvents.userId}, ''), nullif(${schema.analyticsEvents.anonymousId}, ''), nullif(${schema.analyticsEvents.sessionId}, ''))`;
185
+ const eventRows = await db
186
+ .select({
187
+ path: schema.analyticsEvents.path,
188
+ url: schema.analyticsEvents.url,
189
+ eventName: schema.analyticsEvents.eventName,
190
+ count: sql<number>`count(*)`,
191
+ userIdentity: analyticsUserIdentity,
192
+ lastSeenAt: sql<
193
+ string | null
194
+ >`max(${schema.analyticsEvents.receivedAt})`,
195
+ })
196
+ .from(schema.analyticsEvents)
197
+ .where(
198
+ and(
199
+ eq(schema.analyticsEvents.orgId, admin.orgId),
200
+ or(
201
+ like(schema.analyticsEvents.path, "%/dashboards/%"),
202
+ like(schema.analyticsEvents.path, "%/adhoc/%"),
203
+ like(schema.analyticsEvents.url, "%/dashboards/%"),
204
+ like(schema.analyticsEvents.url, "%/adhoc/%"),
205
+ ),
206
+ ),
207
+ )
208
+ .groupBy(
209
+ schema.analyticsEvents.path,
210
+ schema.analyticsEvents.url,
211
+ schema.analyticsEvents.eventName,
212
+ analyticsUserIdentity,
213
+ );
214
+
215
+ const eventsByDashboard = new Map<
216
+ string,
217
+ {
218
+ viewCount: number;
219
+ eventEngagementCount: number;
220
+ uniqueUsers: Set<string>;
221
+ lastViewedAt: string | null;
222
+ }
223
+ >();
224
+ for (const row of eventRows as Array<{
225
+ path: string | null;
226
+ url: string | null;
227
+ eventName: string;
228
+ count: unknown;
229
+ userIdentity: string | null;
230
+ lastSeenAt: string | null;
231
+ }>) {
232
+ const dashboardId = dashboardIdFromEventLocation(row.path, row.url);
233
+ if (!dashboardId || !dashboardIds.has(dashboardId)) continue;
234
+ const current = eventsByDashboard.get(dashboardId) ?? {
235
+ viewCount: 0,
236
+ eventEngagementCount: 0,
237
+ uniqueUsers: new Set<string>(),
238
+ lastViewedAt: null,
239
+ };
240
+ const count = toNumber(row.count);
241
+ if (row.eventName === "pageview") {
242
+ current.viewCount += count;
243
+ current.lastViewedAt =
244
+ !current.lastViewedAt ||
245
+ (row.lastSeenAt && row.lastSeenAt > current.lastViewedAt)
246
+ ? (row.lastSeenAt ?? current.lastViewedAt)
247
+ : current.lastViewedAt;
248
+ } else {
249
+ current.eventEngagementCount += count;
250
+ }
251
+ if (row.userIdentity) current.uniqueUsers.add(row.userIdentity);
252
+ eventsByDashboard.set(dashboardId, current);
253
+ }
254
+
255
+ return (dashboardRows as Array<any>)
256
+ .map((row): DashboardUsageStats => {
257
+ const savedViews = savedViewsByDashboard.get(row.id) ?? {
258
+ count: 0,
259
+ lastSavedViewAt: null,
260
+ };
261
+ const events = eventsByDashboard.get(row.id) ?? {
262
+ viewCount: 0,
263
+ eventEngagementCount: 0,
264
+ uniqueUsers: new Set<string>(),
265
+ lastViewedAt: null,
266
+ };
267
+ return {
268
+ id: row.id,
269
+ name: dashboardName(row),
270
+ kind: row.kind === "explorer" ? "explorer" : "sql",
271
+ ownerEmail: row.ownerEmail ?? null,
272
+ visibility:
273
+ row.visibility === "org" || row.visibility === "public"
274
+ ? row.visibility
275
+ : "private",
276
+ createdAt: row.createdAt,
277
+ updatedAt: row.updatedAt,
278
+ updatedBy: row.updatedBy ?? null,
279
+ archivedAt: row.archivedAt ?? null,
280
+ hiddenAt: row.hiddenAt ?? null,
281
+ hiddenBy: row.hiddenBy ?? null,
282
+ viewCount: events.viewCount,
283
+ eventEngagementCount: events.eventEngagementCount,
284
+ savedViewCount: savedViews.count,
285
+ engagementCount: events.eventEngagementCount + savedViews.count,
286
+ uniqueUserCount: events.uniqueUsers.size,
287
+ lastViewedAt: events.lastViewedAt,
288
+ lastSavedViewAt: savedViews.lastSavedViewAt,
289
+ panelCount: dashboardPanelCount(row),
290
+ url: dashboardUrl(row),
291
+ };
292
+ })
293
+ .sort((a, b) => {
294
+ const views = b.viewCount - a.viewCount;
295
+ if (views !== 0) return views;
296
+ return b.updatedAt.localeCompare(a.updatedAt);
297
+ });
298
+ },
299
+ });
@@ -29,9 +29,11 @@ export default defineAction({
29
29
  .optional()
30
30
  .describe("Session recording id to open (used with view=sessions)"),
31
31
  agentsView: z
32
- .enum(["monitoring", "database"])
32
+ .enum(["monitoring", "dashboards", "database"])
33
33
  .optional()
34
- .describe("Agents subview to open (monitoring or app databases)"),
34
+ .describe(
35
+ "Admin subview to open (monitoring, dashboard usage, or app databases)",
36
+ ),
35
37
  dbAdminConnectionId: z
36
38
  .string()
37
39
  .optional()
@@ -0,0 +1,43 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import {
3
+ getRequestOrgId,
4
+ getRequestUserEmail,
5
+ } from "@agent-native/core/server";
6
+ import { z } from "zod";
7
+
8
+ import { restoreAnalysisRevision } from "../server/lib/dashboards-store";
9
+
10
+ function resolveScope() {
11
+ const orgId = getRequestOrgId() || null;
12
+ const email = getRequestUserEmail();
13
+ if (!email) throw new Error("no authenticated user");
14
+ return { orgId, email };
15
+ }
16
+
17
+ export default defineAction({
18
+ description:
19
+ "Restore an ad-hoc analysis to a saved history revision, snapshotting the current analysis first.",
20
+ schema: z.object({
21
+ analysisId: z.string().describe("Analysis id to restore"),
22
+ revisionId: z.string().describe("Revision id to restore"),
23
+ }),
24
+ http: { method: "POST" },
25
+ run: async (args) => {
26
+ const analysis = await restoreAnalysisRevision(
27
+ args.analysisId,
28
+ args.revisionId,
29
+ resolveScope(),
30
+ );
31
+ if (!analysis) {
32
+ throw new Error(
33
+ `Analysis revision "${args.revisionId}" was not found for analysis "${args.analysisId}".`,
34
+ );
35
+ }
36
+ return {
37
+ id: analysis.id,
38
+ name: analysis.name,
39
+ updatedAt: analysis.updatedAt,
40
+ message: `Restored analysis "${analysis.name}" from history.`,
41
+ };
42
+ },
43
+ });
@@ -0,0 +1,68 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import {
3
+ applyText,
4
+ hasCollabState,
5
+ seedFromText,
6
+ } from "@agent-native/core/collab";
7
+ import {
8
+ getRequestOrgId,
9
+ getRequestUserEmail,
10
+ } from "@agent-native/core/server";
11
+ import { z } from "zod";
12
+
13
+ import { restoreDashboardRevision } from "../server/lib/dashboards-store";
14
+
15
+ function resolveScope() {
16
+ const orgId = getRequestOrgId() || null;
17
+ const email = getRequestUserEmail();
18
+ if (!email) throw new Error("no authenticated user");
19
+ return { orgId, email };
20
+ }
21
+
22
+ async function syncToCollab(
23
+ dashboardId: string,
24
+ config: Record<string, unknown>,
25
+ ): Promise<void> {
26
+ const docId = `dash-${dashboardId}`;
27
+ const configStr = JSON.stringify(config);
28
+ try {
29
+ const exists = await hasCollabState(docId);
30
+ if (exists) {
31
+ await applyText(docId, configStr, "content", "agent");
32
+ } else {
33
+ await seedFromText(docId, configStr);
34
+ }
35
+ } catch {
36
+ // SQL is the source of truth; open editors also refetch on the dashboards signal.
37
+ }
38
+ }
39
+
40
+ export default defineAction({
41
+ description:
42
+ "Restore a dashboard to a saved history revision, snapshotting the current dashboard first.",
43
+ schema: z.object({
44
+ dashboardId: z.string().describe("Dashboard id to restore"),
45
+ revisionId: z.string().describe("Revision id to restore"),
46
+ }),
47
+ http: { method: "POST" },
48
+ run: async (args) => {
49
+ const dashboard = await restoreDashboardRevision(
50
+ args.dashboardId,
51
+ args.revisionId,
52
+ resolveScope(),
53
+ );
54
+ if (!dashboard) {
55
+ throw new Error(
56
+ `Dashboard revision "${args.revisionId}" was not found for dashboard "${args.dashboardId}".`,
57
+ );
58
+ }
59
+ await syncToCollab(dashboard.id, dashboard.config);
60
+ return {
61
+ id: dashboard.id,
62
+ kind: dashboard.kind,
63
+ name: dashboard.title,
64
+ updatedAt: dashboard.updatedAt,
65
+ message: `Restored dashboard "${dashboard.title}" from history.`,
66
+ };
67
+ },
68
+ });
@@ -57,6 +57,20 @@ export default defineAction({
57
57
  .array(z.string().email())
58
58
  .optional()
59
59
  .describe("Email recipients passed to the generic email channel."),
60
+ slackWebhookUrl: z
61
+ .string()
62
+ .optional()
63
+ .nullable()
64
+ .describe(
65
+ "Optional Slack incoming webhook URL for this alert rule. Overrides NOTIFICATIONS_SLACK_WEBHOOK_URL when set.",
66
+ ),
67
+ webhookUrl: z
68
+ .string()
69
+ .optional()
70
+ .nullable()
71
+ .describe(
72
+ "Optional generic webhook URL for this alert rule. Overrides NOTIFICATIONS_WEBHOOK_URL when set.",
73
+ ),
60
74
  enabled: z.boolean().optional(),
61
75
  }),
62
76
  http: { method: "POST" },
@@ -101,7 +101,7 @@ export default defineAction({
101
101
  .min(1000)
102
102
  .max(120000)
103
103
  .optional()
104
- .describe("Request timeout in milliseconds (default 15000)."),
104
+ .describe("Request timeout in milliseconds (default 10000)."),
105
105
  expectedStatus: statusMatcherSchema.optional(),
106
106
  assertions: z
107
107
  .array(assertionSchema)
@@ -42,10 +42,12 @@ export default defineAction({
42
42
  search?: string;
43
43
  searchParams?: Record<string, string>;
44
44
  } | null;
45
+ const selectedObject = await readAppState("selected-object");
45
46
 
46
47
  const screen: Record<string, unknown> = {};
47
48
  if (navigation) screen.navigation = navigation;
48
49
  if (url?.pathname) screen.pathname = url.pathname;
50
+ if (selectedObject) screen.selectedObject = selectedObject;
49
51
 
50
52
  // Surface the active URL filter params (f_*) so the agent doesn't have
51
53
  // to reason about the URL string or go hunting in settings for them.
@@ -219,6 +221,7 @@ export default defineAction({
219
221
  lastSeenAt: issue.lastSeenAt,
220
222
  eventCount: issue.eventCount,
221
223
  usersAffected: issue.usersAffected,
224
+ recentFrequency: issue.sparkline,
222
225
  assignee: issue.assignee,
223
226
  app: issue.app,
224
227
  template: issue.template,
@@ -231,6 +234,10 @@ export default defineAction({
231
234
  url: sample.url,
232
235
  occurredAt: sample.occurredAt,
233
236
  sessionRecordingPath: sample.sessionRecordingPath,
237
+ stack: sample.stack.slice(0, 8),
238
+ rawStackPreview: sample.rawStack
239
+ ? sample.rawStack.split("\n").slice(0, 8).join("\n")
240
+ : null,
234
241
  }
235
242
  : null,
236
243
  linkedSessions: detail.sessions.slice(0, 5),
@@ -425,6 +432,20 @@ export default defineAction({
425
432
  "feedback",
426
433
  ],
427
434
  },
435
+ {
436
+ id: "dashboards",
437
+ label: "Dashboard Usage",
438
+ path: "/agents?view=dashboards",
439
+ adminOnly: true,
440
+ action: "list-dashboard-usage-stats",
441
+ includes: [
442
+ "dashboard created and modified dates",
443
+ "last tracked modifier",
444
+ "view and engagement counts",
445
+ "saved view counts",
446
+ "hidden and archived state",
447
+ ],
448
+ },
428
449
  {
429
450
  id: "database",
430
451
  label: "App Databases",
@@ -439,6 +460,9 @@ export default defineAction({
439
460
  ],
440
461
  },
441
462
  ];
463
+ if (screen.agentsView === "dashboards") {
464
+ screen.dashboardUsageStatsAction = "list-dashboard-usage-stats";
465
+ }
442
466
  const email = getRequestUserEmail();
443
467
  if (email) {
444
468
  const orgId = getRequestOrgId() || null;
@@ -0,0 +1,181 @@
1
+ import { useT } from "@agent-native/core/client";
2
+ import { IconHistory, IconLoader2, IconRotate } from "@tabler/icons-react";
3
+ import { useState } from "react";
4
+ import { toast } from "sonner";
5
+
6
+ import {
7
+ AlertDialog,
8
+ AlertDialogAction,
9
+ AlertDialogCancel,
10
+ AlertDialogContent,
11
+ AlertDialogDescription,
12
+ AlertDialogFooter,
13
+ AlertDialogHeader,
14
+ AlertDialogTitle,
15
+ } from "@/components/ui/alert-dialog";
16
+ import { Button } from "@/components/ui/button";
17
+ import {
18
+ Sheet,
19
+ SheetContent,
20
+ SheetDescription,
21
+ SheetHeader,
22
+ SheetTitle,
23
+ } from "@/components/ui/sheet";
24
+ import {
25
+ type AnalysisRevision,
26
+ useAnalysisRevisions,
27
+ useRestoreAnalysisRevision,
28
+ } from "@/hooks/use-analysis-revisions";
29
+
30
+ function formatRelativeTime(dateStr: string): string {
31
+ const then = new Date(dateStr).getTime();
32
+ if (!Number.isFinite(then)) return dateStr;
33
+ const diffMs = Date.now() - then;
34
+ const diffMin = Math.floor(diffMs / 60_000);
35
+ const diffHr = Math.floor(diffMs / 3_600_000);
36
+ const diffDay = Math.floor(diffMs / 86_400_000);
37
+
38
+ if (diffMin < 1) return "Just now";
39
+ if (diffMin < 60) return `${diffMin}m ago`;
40
+ if (diffHr < 24) return `${diffHr}h ago`;
41
+ if (diffDay < 7) return `${diffDay}d ago`;
42
+ return new Date(dateStr).toLocaleDateString();
43
+ }
44
+
45
+ export function AnalysisHistoryPanel({
46
+ analysisId,
47
+ open,
48
+ onOpenChange,
49
+ canRestore = true,
50
+ }: {
51
+ analysisId: string;
52
+ open: boolean;
53
+ onOpenChange: (open: boolean) => void;
54
+ canRestore?: boolean;
55
+ }) {
56
+ const t = useT();
57
+ const { data: revisions, isLoading } = useAnalysisRevisions(
58
+ open ? analysisId : null,
59
+ );
60
+ const restoreRevision = useRestoreAnalysisRevision(analysisId);
61
+ const [pendingRestore, setPendingRestore] = useState<AnalysisRevision | null>(
62
+ null,
63
+ );
64
+
65
+ const doRestore = async (revision: AnalysisRevision) => {
66
+ try {
67
+ await restoreRevision.mutateAsync({
68
+ analysisId,
69
+ revisionId: revision.id,
70
+ });
71
+ toast.success(t("analyses.historyRestored"));
72
+ setPendingRestore(null);
73
+ onOpenChange(false);
74
+ } catch {
75
+ toast.error(t("analyses.historyRestoreFailed"));
76
+ }
77
+ };
78
+
79
+ return (
80
+ <>
81
+ <Sheet open={open} onOpenChange={onOpenChange}>
82
+ <SheetContent side="right" className="w-[85vw] max-w-[420px] p-0">
83
+ <SheetHeader className="px-4 pb-0 pt-4">
84
+ <SheetTitle className="flex items-center gap-2 text-sm font-medium">
85
+ <IconHistory size={16} />
86
+ {t("analyses.historyTitle")}
87
+ </SheetTitle>
88
+ <SheetDescription>
89
+ {t("analyses.historyDescription")}
90
+ </SheetDescription>
91
+ </SheetHeader>
92
+ <div className="mt-3 border-t border-border" />
93
+ <div className="h-[calc(100%-96px)] overflow-y-auto p-2">
94
+ {isLoading ? (
95
+ <div className="flex items-center justify-center py-12">
96
+ <IconLoader2
97
+ size={16}
98
+ className="animate-spin text-muted-foreground"
99
+ />
100
+ </div>
101
+ ) : !revisions?.length ? (
102
+ <div className="px-6 py-12 text-center text-xs text-muted-foreground">
103
+ {t("analyses.historyEmpty")}
104
+ </div>
105
+ ) : (
106
+ <div className="space-y-1">
107
+ {revisions.map((revision) => (
108
+ <div
109
+ key={revision.id}
110
+ className="rounded-lg border border-border bg-card p-3"
111
+ >
112
+ <div className="flex items-start justify-between gap-3">
113
+ <div className="min-w-0">
114
+ <p className="truncate text-xs font-medium">
115
+ {revision.name || t("common.untitledAnalysis")}
116
+ </p>
117
+ <p className="mt-0.5 text-[10px] text-muted-foreground">
118
+ {formatRelativeTime(revision.createdAt)}
119
+ {revision.createdBy
120
+ ? ` by ${revision.createdBy}`
121
+ : ""}
122
+ </p>
123
+ </div>
124
+ {canRestore ? (
125
+ <Button
126
+ type="button"
127
+ size="sm"
128
+ variant="outline"
129
+ className="h-7 shrink-0 px-2 text-[11px]"
130
+ onClick={() => setPendingRestore(revision)}
131
+ disabled={restoreRevision.isPending}
132
+ >
133
+ {restoreRevision.isPending ? (
134
+ <IconLoader2 size={13} className="animate-spin" />
135
+ ) : (
136
+ <IconRotate size={13} />
137
+ )}
138
+ <span className="ml-1">
139
+ {t("analyses.historyRestore")}
140
+ </span>
141
+ </Button>
142
+ ) : null}
143
+ </div>
144
+ </div>
145
+ ))}
146
+ </div>
147
+ )}
148
+ </div>
149
+ </SheetContent>
150
+ </Sheet>
151
+
152
+ <AlertDialog
153
+ open={pendingRestore !== null}
154
+ onOpenChange={(nextOpen) => {
155
+ if (!nextOpen) setPendingRestore(null);
156
+ }}
157
+ >
158
+ <AlertDialogContent>
159
+ <AlertDialogHeader>
160
+ <AlertDialogTitle>
161
+ {t("analyses.historyRestoreQuestion")}
162
+ </AlertDialogTitle>
163
+ <AlertDialogDescription>
164
+ {t("analyses.historyRestoreWarning")}
165
+ </AlertDialogDescription>
166
+ </AlertDialogHeader>
167
+ <AlertDialogFooter>
168
+ <AlertDialogCancel>{t("common.cancel")}</AlertDialogCancel>
169
+ <AlertDialogAction
170
+ onClick={() => {
171
+ if (pendingRestore) void doRestore(pendingRestore);
172
+ }}
173
+ >
174
+ {t("analyses.historyRestore")}
175
+ </AlertDialogAction>
176
+ </AlertDialogFooter>
177
+ </AlertDialogContent>
178
+ </AlertDialog>
179
+ </>
180
+ );
181
+ }