@agent-native/core 0.91.2 → 0.92.1

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 (538) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +31 -0
  3. package/corpus/core/docs/content/faq.mdx +17 -0
  4. package/corpus/core/docs/content/notifications.mdx +12 -6
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/agent/production-agent.ts +140 -46
  7. package/corpus/core/src/agent/tool-search.ts +71 -4
  8. package/corpus/core/src/application-state/store.ts +12 -1
  9. package/corpus/core/src/cli/index.ts +20 -0
  10. package/corpus/core/src/cli/upgrade.ts +798 -0
  11. package/corpus/core/src/client/AssistantChat.tsx +28 -15
  12. package/corpus/core/src/client/HighlightedCodeBlock.tsx +20 -3
  13. package/corpus/core/src/client/PoweredByBadge.tsx +1 -8
  14. package/corpus/core/src/client/agent-chat-adapter.ts +68 -16
  15. package/corpus/core/src/client/chat/message-components.tsx +85 -8
  16. package/corpus/core/src/client/chat/tool-call-display.tsx +355 -144
  17. package/corpus/core/src/client/chat/widgets/DataTableWidget.tsx +52 -1
  18. package/corpus/core/src/client/code-agent-chat-adapter.ts +2 -9
  19. package/corpus/core/src/client/db-admin/TableEditor.tsx +49 -0
  20. package/corpus/core/src/client/db-admin/export-utils.ts +13 -4
  21. package/corpus/core/src/client/db-admin/useAgentSync.ts +72 -0
  22. package/corpus/core/src/client/error-capture.ts +69 -7
  23. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +5 -1
  24. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +53 -8
  25. package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +5 -1
  26. package/corpus/core/src/client/extensions/portable-extension.ts +1 -0
  27. package/corpus/core/src/client/org/OrgSwitcher.tsx +12 -9
  28. package/corpus/core/src/client/org/TeamPage.tsx +77 -71
  29. package/corpus/core/src/client/session-replay.ts +3 -97
  30. package/corpus/core/src/client/settings/SettingsPanel.tsx +738 -441
  31. package/corpus/core/src/client/settings/SettingsSection.tsx +161 -17
  32. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +25 -9
  33. package/corpus/core/src/client/sse-event-processor.ts +29 -2
  34. package/corpus/core/src/db-admin/agent-tools.ts +8 -2
  35. package/corpus/core/src/db-admin/operations.ts +116 -4
  36. package/corpus/core/src/db-admin/routes.ts +1 -0
  37. package/corpus/core/src/db-admin/types.ts +4 -0
  38. package/corpus/core/src/extensions/actions.ts +113 -5
  39. package/corpus/core/src/extensions/html-shell.ts +5 -4
  40. package/corpus/core/src/extensions/routes.ts +10 -0
  41. package/corpus/core/src/navigation/index.ts +1 -1
  42. package/corpus/core/src/notifications/channels.ts +88 -25
  43. package/corpus/core/src/notifications/registry.ts +17 -3
  44. package/corpus/core/src/notifications/types.ts +4 -1
  45. package/corpus/core/src/resources/handlers.ts +10 -8
  46. package/corpus/core/src/server/agent-chat-plugin.ts +7 -3
  47. package/corpus/core/src/server/poll.ts +293 -8
  48. package/corpus/core/src/server/request-context.ts +7 -0
  49. package/corpus/core/src/styles/agent-conversation.css +1 -1
  50. package/corpus/core/src/styles/agent-native.css +27 -0
  51. package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
  52. package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  53. package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  54. package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +7 -0
  55. package/corpus/core/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  56. package/corpus/core/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
  57. package/corpus/core/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  58. package/corpus/core/src/templates/default/AGENTS.md +14 -5
  59. package/corpus/core/src/templates/default/package.json +2 -1
  60. package/corpus/core/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  61. package/corpus/core/src/templates/headless/AGENTS.md +13 -3
  62. package/corpus/core/src/templates/headless/package.json +1 -0
  63. package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
  64. package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  65. package/corpus/core/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
  66. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
  67. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
  68. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  69. package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
  70. package/corpus/core/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  71. package/corpus/core/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
  72. package/corpus/core/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  73. package/corpus/core/src/templates/workspace-core/AGENTS.md +7 -1
  74. package/corpus/core/src/templates/workspace-root/AGENTS.md +17 -5
  75. package/corpus/core/src/templates/workspace-root/package.json +1 -0
  76. package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +5 -0
  77. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
  78. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
  79. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +7 -0
  80. package/corpus/templates/analytics/.agents/skills/self-modifying-code/SKILL.md +20 -2
  81. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +5 -6
  82. package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +5 -1
  83. package/corpus/templates/analytics/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  84. package/corpus/templates/analytics/AGENTS.md +39 -18
  85. package/corpus/templates/analytics/actions/capture-test-error.ts +4 -0
  86. package/corpus/templates/analytics/actions/get-analytics-alert-rule-defaults.ts +23 -0
  87. package/corpus/templates/analytics/actions/get-error-issue.ts +1 -1
  88. package/corpus/templates/analytics/actions/list-analysis-revisions.ts +40 -0
  89. package/corpus/templates/analytics/actions/list-dashboard-revisions.ts +40 -0
  90. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +299 -0
  91. package/corpus/templates/analytics/actions/navigate.ts +4 -2
  92. package/corpus/templates/analytics/actions/restore-analysis-revision.ts +43 -0
  93. package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +68 -0
  94. package/corpus/templates/analytics/actions/save-analytics-alert-rule.ts +14 -0
  95. package/corpus/templates/analytics/actions/save-monitor.ts +15 -1
  96. package/corpus/templates/analytics/actions/view-screen.ts +24 -0
  97. package/corpus/templates/analytics/app/components/analysis/AnalysisHistoryPanel.tsx +181 -0
  98. package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +184 -0
  99. package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +41 -6
  100. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +122 -11
  101. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +22 -16
  102. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
  103. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +27 -21
  104. package/corpus/templates/analytics/app/hooks/use-analysis-revisions.ts +43 -0
  105. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +110 -0
  106. package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +43 -0
  107. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +8 -3
  108. package/corpus/templates/analytics/app/i18n/zh-TW.ts +64 -2
  109. package/corpus/templates/analytics/app/i18n-data.ts +783 -3
  110. package/corpus/templates/analytics/app/pages/Agents.tsx +359 -19
  111. package/corpus/templates/analytics/app/pages/Settings.tsx +3 -2
  112. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +34 -1
  113. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +28 -0
  114. package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +18 -1
  115. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +7 -10
  116. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +8 -2
  117. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +479 -23
  118. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +0 -9
  119. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +11 -0
  120. package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +9 -1
  121. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +157 -35
  122. package/corpus/templates/analytics/app/pages/monitoring/uptime/i18n.ts +17 -2
  123. package/corpus/templates/analytics/app/pages/monitoring/uptime/types.ts +4 -0
  124. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +80 -220
  125. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +9 -99
  126. package/corpus/templates/analytics/app/pages/settings/AlertRulesSettingsCard.tsx +262 -104
  127. package/corpus/templates/analytics/app/routes/team.tsx +1 -1
  128. package/corpus/templates/analytics/changelog/2026-07-08-admins-can-audit-dashboard-usage-ownership-and-cleanup-signa.md +6 -0
  129. package/corpus/templates/analytics/changelog/2026-07-08-agent-monitoring-stays-available-to-non-admins.md +6 -0
  130. package/corpus/templates/analytics/changelog/2026-07-08-alert-rules-are-easier-to-scan-expand-and-edit-from-settings.md +6 -0
  131. package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-forms-remember-last-email-recipients.md +6 -0
  132. package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-rules-can-now-use-per-rule-slack-and-webhook.md +6 -0
  133. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +5 -0
  134. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-tables-keep-their-size-while-loading.md +6 -0
  135. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-usage-now-counts-explorer-dashboard-traffic.md +6 -0
  136. package/corpus/templates/analytics/changelog/2026-07-08-demo-mode-session-emails-are-filtered-and-anonymized.md +6 -0
  137. package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-adds-stack-traces-and-frequency-bars.md +6 -0
  138. package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-now-shows-the-latest-occurrence-message-a.md +6 -0
  139. package/corpus/templates/analytics/changelog/2026-07-08-monitoring-errors-only-show-test-action-when-empty.md +6 -0
  140. package/corpus/templates/analytics/changelog/2026-07-08-monitoring-uptime-and-errors-tabs-now-clearly-show-which-view-is-active.md +6 -0
  141. package/corpus/templates/analytics/changelog/2026-07-08-production-session-replay-now-requires-private-blob-storage-.md +6 -0
  142. package/corpus/templates/analytics/changelog/2026-07-08-session-replay-uses-stock-rrweb-sizing-again-so-recorded.md +6 -0
  143. package/corpus/templates/analytics/changelog/2026-07-08-shared-extension-links-now-show-a-clear-message-when-you-do-.md +6 -0
  144. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-dashboard-menus-now-open-above-the-dashboard-canvas.md +6 -0
  145. package/corpus/templates/analytics/changelog/2026-07-08-team-settings-show-access-controls-next-to-member-lists.md +6 -0
  146. package/corpus/templates/analytics/changelog/2026-07-08-uptime-alerting-clarifies-in-app-inbox-vs-email-and-lets-you-paste-slack-or-webhook-urls-per-monitor.md +6 -0
  147. package/corpus/templates/analytics/changelog/2026-07-08-uptime-monitors-now-use-a-10-second-request-timeout-by-defau.md +6 -0
  148. package/corpus/templates/analytics/docs/uptime-monitoring.md +13 -11
  149. package/corpus/templates/analytics/server/db/schema-monitoring.ts +5 -1
  150. package/corpus/templates/analytics/server/db/schema.ts +56 -0
  151. package/corpus/templates/analytics/server/lib/analytics-alerts.ts +92 -0
  152. package/corpus/templates/analytics/server/lib/dashboards-store.ts +334 -5
  153. package/corpus/templates/analytics/server/lib/error-capture.ts +231 -36
  154. package/corpus/templates/analytics/server/lib/session-replay.ts +114 -8
  155. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +65 -16
  156. package/corpus/templates/analytics/server/plugins/db.ts +122 -2
  157. package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +1 -0
  158. package/corpus/templates/assets/.agents/skills/actions/SKILL.md +5 -0
  159. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
  160. package/corpus/templates/assets/.agents/skills/security/SKILL.md +7 -0
  161. package/corpus/templates/assets/.agents/skills/self-modifying-code/SKILL.md +20 -2
  162. package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +5 -1
  163. package/corpus/templates/assets/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  164. package/corpus/templates/assets/AGENTS.md +4 -0
  165. package/corpus/templates/assets/app/routes/settings.tsx +1 -1
  166. package/corpus/templates/assets/app/routes/team.tsx +1 -1
  167. package/corpus/templates/brain/.agents/skills/actions/SKILL.md +5 -0
  168. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +5 -0
  169. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
  170. package/corpus/templates/brain/.agents/skills/security/SKILL.md +7 -0
  171. package/corpus/templates/brain/.agents/skills/self-modifying-code/SKILL.md +20 -2
  172. package/corpus/templates/brain/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  173. package/corpus/templates/brain/AGENTS.md +4 -0
  174. package/corpus/templates/brain/app/routes/team.tsx +1 -1
  175. package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +5 -0
  176. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
  177. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +7 -0
  178. package/corpus/templates/calendar/.agents/skills/self-modifying-code/SKILL.md +20 -2
  179. package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +5 -1
  180. package/corpus/templates/calendar/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  181. package/corpus/templates/calendar/AGENTS.md +4 -0
  182. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +11 -2
  183. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +21 -8
  184. package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +7 -1
  185. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -2
  186. package/corpus/templates/calendar/app/lib/popover-click-guard.ts +48 -4
  187. package/corpus/templates/calendar/app/pages/Settings.tsx +1 -1
  188. package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
  189. package/corpus/templates/calendar/changelog/2026-07-08-clicking-empty-calendar-space-closes-an-open-event-popover-b.md +6 -0
  190. package/corpus/templates/chat/.agents/skills/actions/SKILL.md +5 -0
  191. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +5 -0
  192. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  193. package/corpus/templates/chat/.agents/skills/security/SKILL.md +7 -0
  194. package/corpus/templates/chat/.agents/skills/self-modifying-code/SKILL.md +20 -2
  195. package/corpus/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  196. package/corpus/templates/chat/AGENTS.md +4 -0
  197. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  198. package/corpus/templates/chat/app/routes/settings.tsx +2 -2
  199. package/corpus/templates/chat/app/routes/team.tsx +1 -1
  200. package/corpus/templates/clips/.agents/skills/actions/SKILL.md +5 -0
  201. package/corpus/templates/clips/.agents/skills/security/SKILL.md +7 -0
  202. package/corpus/templates/clips/.agents/skills/self-modifying-code/SKILL.md +20 -2
  203. package/corpus/templates/clips/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  204. package/corpus/templates/clips/AGENTS.md +4 -0
  205. package/corpus/templates/clips/actions/finalize-recording.ts +9 -3
  206. package/corpus/templates/clips/actions/set-thumbnail.ts +11 -2
  207. package/corpus/templates/clips/app/components/meetings/canvas-editor.tsx +1 -7
  208. package/corpus/templates/clips/app/components/player/player-controls.tsx +21 -13
  209. package/corpus/templates/clips/app/components/player/video-player.tsx +30 -75
  210. package/corpus/templates/clips/app/i18n/ar-SA.ts +6 -5
  211. package/corpus/templates/clips/app/i18n/de-DE.ts +6 -6
  212. package/corpus/templates/clips/app/i18n/en-US.ts +6 -5
  213. package/corpus/templates/clips/app/i18n/es-ES.ts +6 -5
  214. package/corpus/templates/clips/app/i18n/fr-FR.ts +6 -6
  215. package/corpus/templates/clips/app/i18n/hi-IN.ts +6 -5
  216. package/corpus/templates/clips/app/i18n/ja-JP.ts +6 -5
  217. package/corpus/templates/clips/app/i18n/ko-KR.ts +6 -5
  218. package/corpus/templates/clips/app/i18n/pt-BR.ts +6 -5
  219. package/corpus/templates/clips/app/i18n/zh-CN.ts +6 -5
  220. package/corpus/templates/clips/app/i18n/zh-TW.ts +6 -5
  221. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +51 -118
  222. package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-notes-stay-active-from-tray-and-shortcut-controls.md +6 -0
  223. package/corpus/templates/clips/changelog/2026-07-08-desktop-meeting-popovers-can-start-notes-and-join-the-meetin.md +6 -0
  224. package/corpus/templates/clips/changelog/2026-07-08-hosted-clip-uploads-now-clear-failed-buffered-chunks.md +6 -0
  225. package/corpus/templates/clips/changelog/2026-07-08-hosted-recording-uploads-now-avoid-sql-chunk-storage.md +6 -0
  226. package/corpus/templates/clips/changelog/2026-07-08-meeting-notes-keep-their-recording-state-when-the-desktop.md +6 -0
  227. package/corpus/templates/clips/changelog/2026-07-08-meeting-recaps-now-keep-summaries-action-items-and-transcrip.md +6 -0
  228. package/corpus/templates/clips/changelog/2026-07-08-meeting-reminder-dropdowns-now-expand-fully-instead-of-being.md +6 -0
  229. package/corpus/templates/clips/changelog/2026-07-08-video-playback-controls-now-match-loom-style-5-second-skips-.md +6 -0
  230. package/corpus/templates/clips/desktop/src/app.tsx +123 -3
  231. package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +15 -1
  232. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +23 -0
  233. package/corpus/templates/clips/desktop/src/styles.css +23 -1
  234. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +1 -3
  235. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +40 -6
  236. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +4 -2
  237. package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +3 -5
  238. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +23 -19
  239. package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +3 -3
  240. package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +0 -1
  241. package/corpus/templates/clips/desktop/src-tauri/src/state.rs +5 -0
  242. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +18 -6
  243. package/corpus/templates/clips/server/lib/recording-upload-state.ts +63 -0
  244. package/corpus/templates/clips/server/lib/video-storage.ts +4 -0
  245. package/corpus/templates/clips/server/routes/api/recordings/[recordingId]/thumbnail.post.ts +19 -13
  246. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +40 -1
  247. package/corpus/templates/content/.agents/skills/actions/SKILL.md +5 -0
  248. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
  249. package/corpus/templates/content/.agents/skills/security/SKILL.md +7 -0
  250. package/corpus/templates/content/.agents/skills/self-modifying-code/SKILL.md +20 -2
  251. package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +5 -1
  252. package/corpus/templates/content/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  253. package/corpus/templates/content/AGENTS.md +4 -0
  254. package/corpus/templates/content/actions/_batch-utils.ts +8 -0
  255. package/corpus/templates/content/actions/_builder-cms-read-client.ts +7 -5
  256. package/corpus/templates/content/actions/_database-source-utils.ts +776 -319
  257. package/corpus/templates/content/actions/_database-utils.ts +6 -1
  258. package/corpus/templates/content/actions/_property-utils.ts +168 -0
  259. package/corpus/templates/content/actions/add-content-database-source-field-property.ts +19 -12
  260. package/corpus/templates/content/actions/bind-content-database-source-field.ts +19 -12
  261. package/corpus/templates/content/actions/delete-document.ts +9 -13
  262. package/corpus/templates/content/actions/refresh-content-database-source.ts +5 -5
  263. package/corpus/templates/content/app/components/editor/body-hydration.ts +35 -11
  264. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +47 -5
  265. package/corpus/templates/content/app/hooks/use-documents.ts +8 -2
  266. package/corpus/templates/content/app/routes/_app.settings.tsx +2 -2
  267. package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
  268. package/corpus/templates/content/changelog/2026-07-08-builder-source-sync-now-completes-reliably-on-hosted-databases.md +6 -0
  269. package/corpus/templates/content/changelog/2026-07-08-fixed-builder-database-sync-so-large-sources-continue-past-t.md +6 -0
  270. package/corpus/templates/content/server/plugins/db.ts +19 -0
  271. package/corpus/templates/design/.agents/skills/actions/SKILL.md +5 -0
  272. package/corpus/templates/design/.agents/skills/security/SKILL.md +7 -0
  273. package/corpus/templates/design/.agents/skills/self-modifying-code/SKILL.md +20 -2
  274. package/corpus/templates/design/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  275. package/corpus/templates/design/AGENTS.md +4 -0
  276. package/corpus/templates/design/actions/take-design-screenshot.ts +12 -9
  277. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +57 -13
  278. package/corpus/templates/design/app/routes/team.tsx +1 -1
  279. package/corpus/templates/design/changelog/2026-07-08-local-images-added-to-designs-now-upload-to-file-storage-ins.md +6 -0
  280. package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +5 -0
  281. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +7 -0
  282. package/corpus/templates/dispatch/.agents/skills/self-modifying-code/SKILL.md +20 -2
  283. package/corpus/templates/dispatch/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  284. package/corpus/templates/dispatch/AGENTS.md +4 -0
  285. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
  286. package/corpus/templates/dispatch/app/routes/settings.tsx +2 -2
  287. package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
  288. package/corpus/templates/forms/.agents/skills/actions/SKILL.md +5 -0
  289. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
  290. package/corpus/templates/forms/.agents/skills/security/SKILL.md +7 -0
  291. package/corpus/templates/forms/.agents/skills/self-modifying-code/SKILL.md +20 -2
  292. package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +5 -1
  293. package/corpus/templates/forms/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  294. package/corpus/templates/forms/AGENTS.md +4 -0
  295. package/corpus/templates/forms/app/routes/_app.settings.tsx +2 -2
  296. package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
  297. package/corpus/templates/forms/shared/navigation.ts +1 -1
  298. package/corpus/templates/macros/.agents/skills/security/SKILL.md +7 -0
  299. package/corpus/templates/macros/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  300. package/corpus/templates/macros/AGENTS.md +4 -0
  301. package/corpus/templates/macros/app/routes/settings.tsx +2 -2
  302. package/corpus/templates/macros/app/routes/team.tsx +1 -1
  303. package/corpus/templates/mail/.agents/skills/actions/SKILL.md +5 -0
  304. package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +1 -1
  305. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
  306. package/corpus/templates/mail/.agents/skills/security/SKILL.md +7 -0
  307. package/corpus/templates/mail/.agents/skills/self-modifying-code/SKILL.md +20 -2
  308. package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +5 -1
  309. package/corpus/templates/mail/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  310. package/corpus/templates/mail/AGENTS.md +4 -0
  311. package/corpus/templates/mail/changelog/2026-07-08-mail-attachments-in-hosted-environments-now-require-file-sto.md +6 -0
  312. package/corpus/templates/mail/server/handlers/media.ts +26 -1
  313. package/corpus/templates/mail/server/lib/outgoing-email.ts +24 -1
  314. package/corpus/templates/mail/server/lib/upload-store.ts +2 -1
  315. package/corpus/templates/plan/.agents/skills/actions/SKILL.md +5 -0
  316. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +5 -0
  317. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
  318. package/corpus/templates/plan/.agents/skills/security/SKILL.md +7 -0
  319. package/corpus/templates/plan/.agents/skills/self-modifying-code/SKILL.md +20 -2
  320. package/corpus/templates/plan/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  321. package/corpus/templates/plan/AGENTS.md +4 -0
  322. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
  323. package/corpus/templates/plan/app/routes/settings.tsx +2 -2
  324. package/corpus/templates/plan/app/routes/team.tsx +1 -1
  325. package/corpus/templates/plan/changelog/2026-07-08-hosted-plan-images-now-require-connected-storage.md +6 -0
  326. package/corpus/templates/plan/server/lib/plan-assets.ts +33 -4
  327. package/corpus/templates/slides/.agents/skills/actions/SKILL.md +5 -0
  328. package/corpus/templates/slides/.agents/skills/security/SKILL.md +7 -0
  329. package/corpus/templates/slides/.agents/skills/self-modifying-code/SKILL.md +20 -2
  330. package/corpus/templates/slides/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  331. package/corpus/templates/slides/AGENTS.md +4 -0
  332. package/corpus/templates/slides/actions/generate-image-api.ts +15 -3
  333. package/corpus/templates/slides/app/routes/settings.tsx +2 -2
  334. package/corpus/templates/slides/app/routes/team.tsx +1 -1
  335. package/corpus/templates/slides/changelog/2026-07-08-generated-slide-images-now-return-hosted-file-storage-urls-i.md +6 -0
  336. package/corpus/templates/slides/shared/api.ts +1 -1
  337. package/corpus/templates/videos/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  338. package/corpus/templates/voice/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  339. package/dist/agent/production-agent.d.ts +5 -1
  340. package/dist/agent/production-agent.d.ts.map +1 -1
  341. package/dist/agent/production-agent.js +112 -42
  342. package/dist/agent/production-agent.js.map +1 -1
  343. package/dist/agent/tool-search.d.ts +2 -0
  344. package/dist/agent/tool-search.d.ts.map +1 -1
  345. package/dist/agent/tool-search.js +60 -4
  346. package/dist/agent/tool-search.js.map +1 -1
  347. package/dist/application-state/store.d.ts.map +1 -1
  348. package/dist/application-state/store.js +8 -2
  349. package/dist/application-state/store.js.map +1 -1
  350. package/dist/cli/index.js +19 -0
  351. package/dist/cli/index.js.map +1 -1
  352. package/dist/cli/upgrade.d.ts +100 -0
  353. package/dist/cli/upgrade.d.ts.map +1 -0
  354. package/dist/cli/upgrade.js +678 -0
  355. package/dist/cli/upgrade.js.map +1 -0
  356. package/dist/client/AssistantChat.d.ts.map +1 -1
  357. package/dist/client/AssistantChat.js +25 -14
  358. package/dist/client/AssistantChat.js.map +1 -1
  359. package/dist/client/HighlightedCodeBlock.d.ts +2 -0
  360. package/dist/client/HighlightedCodeBlock.d.ts.map +1 -1
  361. package/dist/client/HighlightedCodeBlock.js +10 -1
  362. package/dist/client/HighlightedCodeBlock.js.map +1 -1
  363. package/dist/client/PoweredByBadge.d.ts +1 -1
  364. package/dist/client/PoweredByBadge.d.ts.map +1 -1
  365. package/dist/client/PoweredByBadge.js +3 -9
  366. package/dist/client/PoweredByBadge.js.map +1 -1
  367. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  368. package/dist/client/agent-chat-adapter.js +60 -13
  369. package/dist/client/agent-chat-adapter.js.map +1 -1
  370. package/dist/client/chat/message-components.d.ts.map +1 -1
  371. package/dist/client/chat/message-components.js +61 -8
  372. package/dist/client/chat/message-components.js.map +1 -1
  373. package/dist/client/chat/tool-call-display.d.ts +12 -0
  374. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  375. package/dist/client/chat/tool-call-display.js +136 -42
  376. package/dist/client/chat/tool-call-display.js.map +1 -1
  377. package/dist/client/chat/widgets/DataTableWidget.d.ts.map +1 -1
  378. package/dist/client/chat/widgets/DataTableWidget.js +19 -2
  379. package/dist/client/chat/widgets/DataTableWidget.js.map +1 -1
  380. package/dist/client/code-agent-chat-adapter.js +2 -9
  381. package/dist/client/code-agent-chat-adapter.js.map +1 -1
  382. package/dist/client/db-admin/TableEditor.d.ts.map +1 -1
  383. package/dist/client/db-admin/TableEditor.js +19 -2
  384. package/dist/client/db-admin/TableEditor.js.map +1 -1
  385. package/dist/client/db-admin/export-utils.d.ts +2 -0
  386. package/dist/client/db-admin/export-utils.d.ts.map +1 -1
  387. package/dist/client/db-admin/export-utils.js +11 -3
  388. package/dist/client/db-admin/export-utils.js.map +1 -1
  389. package/dist/client/db-admin/useAgentSync.d.ts.map +1 -1
  390. package/dist/client/db-admin/useAgentSync.js +63 -0
  391. package/dist/client/db-admin/useAgentSync.js.map +1 -1
  392. package/dist/client/error-capture.d.ts.map +1 -1
  393. package/dist/client/error-capture.js +41 -7
  394. package/dist/client/error-capture.js.map +1 -1
  395. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  396. package/dist/client/extensions/EmbeddedExtension.js +3 -1
  397. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  398. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  399. package/dist/client/extensions/ExtensionViewer.js +32 -5
  400. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  401. package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
  402. package/dist/client/extensions/InlineExtensionFrame.js +3 -1
  403. package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
  404. package/dist/client/extensions/portable-extension.d.ts.map +1 -1
  405. package/dist/client/extensions/portable-extension.js +1 -0
  406. package/dist/client/extensions/portable-extension.js.map +1 -1
  407. package/dist/client/org/OrgSwitcher.d.ts +1 -1
  408. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  409. package/dist/client/org/OrgSwitcher.js +11 -6
  410. package/dist/client/org/OrgSwitcher.js.map +1 -1
  411. package/dist/client/org/TeamPage.d.ts.map +1 -1
  412. package/dist/client/org/TeamPage.js +5 -5
  413. package/dist/client/org/TeamPage.js.map +1 -1
  414. package/dist/client/session-replay.d.ts +0 -8
  415. package/dist/client/session-replay.d.ts.map +1 -1
  416. package/dist/client/session-replay.js +3 -80
  417. package/dist/client/session-replay.js.map +1 -1
  418. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  419. package/dist/client/settings/SettingsPanel.js +89 -33
  420. package/dist/client/settings/SettingsPanel.js.map +1 -1
  421. package/dist/client/settings/SettingsSection.d.ts +19 -4
  422. package/dist/client/settings/SettingsSection.d.ts.map +1 -1
  423. package/dist/client/settings/SettingsSection.js +33 -4
  424. package/dist/client/settings/SettingsSection.js.map +1 -1
  425. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  426. package/dist/client/settings/SettingsTabsPage.js +21 -10
  427. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  428. package/dist/client/sse-event-processor.d.ts +9 -0
  429. package/dist/client/sse-event-processor.d.ts.map +1 -1
  430. package/dist/client/sse-event-processor.js +20 -2
  431. package/dist/client/sse-event-processor.js.map +1 -1
  432. package/dist/db-admin/agent-tools.d.ts.map +1 -1
  433. package/dist/db-admin/agent-tools.js +7 -2
  434. package/dist/db-admin/agent-tools.js.map +1 -1
  435. package/dist/db-admin/operations.d.ts.map +1 -1
  436. package/dist/db-admin/operations.js +90 -4
  437. package/dist/db-admin/operations.js.map +1 -1
  438. package/dist/db-admin/routes.d.ts.map +1 -1
  439. package/dist/db-admin/routes.js +1 -0
  440. package/dist/db-admin/routes.js.map +1 -1
  441. package/dist/db-admin/types.d.ts +4 -0
  442. package/dist/db-admin/types.d.ts.map +1 -1
  443. package/dist/db-admin/types.js.map +1 -1
  444. package/dist/extensions/actions.d.ts.map +1 -1
  445. package/dist/extensions/actions.js +85 -5
  446. package/dist/extensions/actions.js.map +1 -1
  447. package/dist/extensions/html-shell.d.ts +5 -4
  448. package/dist/extensions/html-shell.d.ts.map +1 -1
  449. package/dist/extensions/html-shell.js.map +1 -1
  450. package/dist/extensions/routes.d.ts.map +1 -1
  451. package/dist/extensions/routes.js +8 -0
  452. package/dist/extensions/routes.js.map +1 -1
  453. package/dist/navigation/index.d.ts +1 -1
  454. package/dist/navigation/index.d.ts.map +1 -1
  455. package/dist/navigation/index.js +1 -1
  456. package/dist/navigation/index.js.map +1 -1
  457. package/dist/notifications/channels.d.ts +8 -3
  458. package/dist/notifications/channels.d.ts.map +1 -1
  459. package/dist/notifications/channels.js +61 -22
  460. package/dist/notifications/channels.js.map +1 -1
  461. package/dist/notifications/registry.d.ts.map +1 -1
  462. package/dist/notifications/registry.js +14 -3
  463. package/dist/notifications/registry.js.map +1 -1
  464. package/dist/notifications/types.d.ts +4 -1
  465. package/dist/notifications/types.d.ts.map +1 -1
  466. package/dist/notifications/types.js.map +1 -1
  467. package/dist/resources/handlers.d.ts +5 -0
  468. package/dist/resources/handlers.d.ts.map +1 -1
  469. package/dist/resources/handlers.js +9 -8
  470. package/dist/resources/handlers.js.map +1 -1
  471. package/dist/server/agent-chat-plugin.d.ts +5 -1
  472. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  473. package/dist/server/agent-chat-plugin.js +2 -2
  474. package/dist/server/agent-chat-plugin.js.map +1 -1
  475. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  476. package/dist/server/poll.d.ts +12 -4
  477. package/dist/server/poll.d.ts.map +1 -1
  478. package/dist/server/poll.js +236 -9
  479. package/dist/server/poll.js.map +1 -1
  480. package/dist/server/request-context.d.ts +7 -0
  481. package/dist/server/request-context.d.ts.map +1 -1
  482. package/dist/server/request-context.js.map +1 -1
  483. package/dist/styles/agent-conversation.css +1 -1
  484. package/dist/styles/agent-native.css +27 -0
  485. package/dist/templates/default/.agents/skills/actions/SKILL.md +5 -0
  486. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  487. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  488. package/dist/templates/default/.agents/skills/security/SKILL.md +7 -0
  489. package/dist/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  490. package/dist/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
  491. package/dist/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  492. package/dist/templates/default/AGENTS.md +14 -5
  493. package/dist/templates/default/package.json +2 -1
  494. package/dist/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  495. package/dist/templates/headless/AGENTS.md +13 -3
  496. package/dist/templates/headless/package.json +1 -0
  497. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
  498. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  499. package/dist/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
  500. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
  501. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
  502. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  503. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
  504. package/dist/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  505. package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
  506. package/dist/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  507. package/dist/templates/workspace-core/AGENTS.md +7 -1
  508. package/dist/templates/workspace-root/AGENTS.md +17 -5
  509. package/dist/templates/workspace-root/package.json +1 -0
  510. package/docs/content/faq.mdx +17 -0
  511. package/docs/content/notifications.mdx +12 -6
  512. package/package.json +2 -2
  513. package/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
  514. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  515. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  516. package/src/templates/default/.agents/skills/security/SKILL.md +7 -0
  517. package/src/templates/default/.agents/skills/self-modifying-code/SKILL.md +20 -2
  518. package/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
  519. package/src/templates/default/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  520. package/src/templates/default/AGENTS.md +14 -5
  521. package/src/templates/default/package.json +2 -1
  522. package/src/templates/headless/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  523. package/src/templates/headless/AGENTS.md +13 -3
  524. package/src/templates/headless/package.json +1 -0
  525. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
  526. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  527. package/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
  528. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
  529. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
  530. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  531. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
  532. package/src/templates/workspace-core/.agents/skills/self-modifying-code/SKILL.md +20 -2
  533. package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
  534. package/src/templates/workspace-core/.agents/skills/upgrade-agent-native/SKILL.md +87 -0
  535. package/src/templates/workspace-core/AGENTS.md +7 -1
  536. package/src/templates/workspace-root/AGENTS.md +17 -5
  537. package/src/templates/workspace-root/package.json +1 -0
  538. package/corpus/templates/analytics/changelog/2026-07-08-session-replay-clamps-ultra-wide-viewports-while-keeping-the.md +0 -6
@@ -27,7 +27,7 @@ import {
27
27
  * - `o:<orgId>:sql-dashboard-{id}` → kind='sql', owner=caller, visibility='org'
28
28
  * - `adhoc-analysis-{id}` → owner=caller, legacy visibility from its source key
29
29
  */
30
- import { and, eq, isNotNull, isNull } from "drizzle-orm";
30
+ import { and, desc, eq, isNotNull, isNull } from "drizzle-orm";
31
31
 
32
32
  import { getDb, schema } from "../db/index.js";
33
33
 
@@ -44,6 +44,7 @@ export interface DashboardRecord {
44
44
  visibility: "private" | "org" | "public";
45
45
  createdAt: string;
46
46
  updatedAt: string;
47
+ updatedBy: string | null;
47
48
  /** ISO timestamp set when the dashboard is archived. Null = active. */
48
49
  archivedAt: string | null;
49
50
  /** ISO timestamp set when the dashboard is hidden from default navigation. */
@@ -55,6 +56,16 @@ export interface DashboardRecord {
55
56
  canManage?: boolean;
56
57
  }
57
58
 
59
+ export interface DashboardRevisionRecord {
60
+ id: string;
61
+ dashboardId: string;
62
+ kind: DashboardKind;
63
+ title: string;
64
+ config: Record<string, unknown>;
65
+ createdAt: string;
66
+ createdBy: string | null;
67
+ }
68
+
58
69
  export type DashboardArchiveFilter = "active" | "archived" | "all";
59
70
  export type DashboardHiddenFilter = "visible" | "hidden" | "all";
60
71
 
@@ -82,6 +93,20 @@ export interface AnalysisRecord {
82
93
  canManage?: boolean;
83
94
  }
84
95
 
96
+ export interface AnalysisRevisionRecord {
97
+ id: string;
98
+ analysisId: string;
99
+ name: string;
100
+ description: string;
101
+ question: string;
102
+ instructions: string;
103
+ dataSources: string[];
104
+ resultMarkdown: string;
105
+ resultData: Record<string, unknown> | null;
106
+ createdAt: string;
107
+ createdBy: string | null;
108
+ }
109
+
85
110
  interface AccessCtx {
86
111
  email: string;
87
112
  orgId: string | null;
@@ -90,6 +115,8 @@ interface AccessCtx {
90
115
  const SQL_PREFIX = "sql-dashboard-";
91
116
  const EXPLORER_PREFIX = "dashboard-";
92
117
  const ANALYSIS_PREFIX = "adhoc-analysis-";
118
+ const DASHBOARD_REVISION_LIMIT = 50;
119
+ const ANALYSIS_REVISION_LIMIT = 30;
93
120
 
94
121
  function nowIso(): string {
95
122
  return new Date().toISOString();
@@ -157,6 +184,7 @@ function rowToDashboard(row: any, role?: AccessRole): DashboardRecord {
157
184
  visibility: row.visibility,
158
185
  createdAt: row.createdAt,
159
186
  updatedAt: row.updatedAt,
187
+ updatedBy: row.updatedBy ?? null,
160
188
  archivedAt: row.archivedAt ?? null,
161
189
  hiddenAt: row.hiddenAt ?? null,
162
190
  hiddenBy: row.hiddenBy ?? null,
@@ -164,6 +192,19 @@ function rowToDashboard(row: any, role?: AccessRole): DashboardRecord {
164
192
  };
165
193
  }
166
194
 
195
+ function rowToDashboardRevision(row: any): DashboardRevisionRecord {
196
+ return {
197
+ id: row.id,
198
+ dashboardId: row.dashboardId,
199
+ kind: row.kind,
200
+ title: row.title,
201
+ config:
202
+ typeof row.config === "string" ? JSON.parse(row.config) : row.config,
203
+ createdAt: row.createdAt,
204
+ createdBy: row.createdBy ?? null,
205
+ };
206
+ }
207
+
167
208
  function configFromSettings(data: Record<string, unknown>): {
168
209
  title: string;
169
210
  config: Record<string, unknown>;
@@ -208,6 +249,7 @@ async function migrateDashboardFromSettings(
208
249
  visibility,
209
250
  createdAt,
210
251
  updatedAt,
252
+ updatedBy: ownerEmail,
211
253
  })
212
254
  .onConflictDoNothing();
213
255
  // guard:allow-unscoped — read-after-write of the row just inserted above
@@ -384,6 +426,42 @@ export async function listDashboards(
384
426
  return out;
385
427
  }
386
428
 
429
+ async function pruneDashboardRevisions(
430
+ db: any,
431
+ dashboardId: string,
432
+ ): Promise<void> {
433
+ const rows = await db
434
+ .select({ id: schema.dashboardRevisions.id })
435
+ .from(schema.dashboardRevisions)
436
+ .where(eq(schema.dashboardRevisions.dashboardId, dashboardId))
437
+ .orderBy(desc(schema.dashboardRevisions.createdAt));
438
+ const stale = rows.slice(DASHBOARD_REVISION_LIMIT);
439
+ for (const row of stale) {
440
+ await db
441
+ .delete(schema.dashboardRevisions)
442
+ .where(eq(schema.dashboardRevisions.id, row.id));
443
+ }
444
+ }
445
+
446
+ async function snapshotDashboardRevision(
447
+ db: any,
448
+ dashboard: DashboardRecord,
449
+ ctx: AccessCtx,
450
+ ): Promise<void> {
451
+ await db.insert(schema.dashboardRevisions).values({
452
+ id: `dashrev-${Date.now()}-${nanoidFallback()}`,
453
+ dashboardId: dashboard.id,
454
+ kind: dashboard.kind,
455
+ title: dashboard.title,
456
+ config: JSON.stringify(dashboard.config),
457
+ createdAt: nowIso(),
458
+ createdBy: ctx.email,
459
+ ownerEmail: dashboard.ownerEmail,
460
+ orgId: dashboard.orgId,
461
+ });
462
+ await pruneDashboardRevisions(db, dashboard.id);
463
+ }
464
+
387
465
  /**
388
466
  * Upsert a dashboard. On create, caller becomes owner and visibility defaults
389
467
  * to `private`; users explicitly promote useful dashboards to org/public via
@@ -399,18 +477,25 @@ export async function upsertDashboard(
399
477
  const existing = await getDashboard(id, ctx);
400
478
  const db = getDb() as any;
401
479
  const { title, config } = configFromSettings(body);
480
+ const configJson = JSON.stringify(config);
402
481
  if (existing) {
403
482
  await assertAccess("dashboard", id, "editor", {
404
483
  userEmail: ctx.email,
405
484
  orgId: ctx.orgId ?? undefined,
406
485
  });
486
+ const changed =
487
+ existing.kind !== kind ||
488
+ existing.title !== title ||
489
+ JSON.stringify(existing.config) !== configJson;
490
+ if (changed) await snapshotDashboardRevision(db, existing, ctx);
407
491
  await db
408
492
  .update(schema.dashboards)
409
493
  .set({
410
494
  kind,
411
495
  title,
412
- config: JSON.stringify(config),
496
+ config: configJson,
413
497
  updatedAt: nowIso(),
498
+ updatedBy: ctx.email,
414
499
  })
415
500
  .where(eq(schema.dashboards.id, id));
416
501
  } else {
@@ -422,6 +507,7 @@ export async function upsertDashboard(
422
507
  ownerEmail: ctx.email,
423
508
  orgId: ctx.orgId,
424
509
  visibility: "private",
510
+ updatedBy: ctx.email,
425
511
  });
426
512
  }
427
513
  const [row] = await db
@@ -442,6 +528,77 @@ export async function upsertDashboard(
442
528
  return dashboard;
443
529
  }
444
530
 
531
+ export async function listDashboardRevisions(
532
+ dashboardId: string,
533
+ ctx: AccessCtx,
534
+ ): Promise<DashboardRevisionRecord[]> {
535
+ const existing = await getDashboard(dashboardId, ctx);
536
+ if (!existing) return [];
537
+ await assertAccess("dashboard", dashboardId, "viewer", {
538
+ userEmail: ctx.email,
539
+ orgId: ctx.orgId ?? undefined,
540
+ });
541
+ const db = getDb() as any;
542
+ const rows = await db
543
+ .select()
544
+ .from(schema.dashboardRevisions)
545
+ .where(eq(schema.dashboardRevisions.dashboardId, dashboardId))
546
+ .orderBy(desc(schema.dashboardRevisions.createdAt))
547
+ .limit(DASHBOARD_REVISION_LIMIT);
548
+ return rows.map(rowToDashboardRevision);
549
+ }
550
+
551
+ export async function restoreDashboardRevision(
552
+ dashboardId: string,
553
+ revisionId: string,
554
+ ctx: AccessCtx,
555
+ ): Promise<DashboardRecord | null> {
556
+ const existing = await getDashboard(dashboardId, ctx);
557
+ if (!existing) return null;
558
+ await assertAccess("dashboard", dashboardId, "editor", {
559
+ userEmail: ctx.email,
560
+ orgId: ctx.orgId ?? undefined,
561
+ });
562
+ const db = getDb() as any;
563
+ const [revisionRow] = await db
564
+ .select()
565
+ .from(schema.dashboardRevisions)
566
+ .where(
567
+ and(
568
+ eq(schema.dashboardRevisions.id, revisionId),
569
+ eq(schema.dashboardRevisions.dashboardId, dashboardId),
570
+ ),
571
+ )
572
+ .limit(1);
573
+ if (!revisionRow) return null;
574
+ const revision = rowToDashboardRevision(revisionRow);
575
+ await snapshotDashboardRevision(db, existing, ctx);
576
+ await db
577
+ .update(schema.dashboards)
578
+ .set({
579
+ kind: revision.kind,
580
+ title: revision.title,
581
+ config: JSON.stringify(revision.config),
582
+ updatedAt: nowIso(),
583
+ updatedBy: ctx.email,
584
+ })
585
+ .where(eq(schema.dashboards.id, dashboardId));
586
+ const [row] = await db
587
+ .select()
588
+ .from(schema.dashboards)
589
+ .where(eq(schema.dashboards.id, dashboardId));
590
+ const dashboard = rowToDashboard(row);
591
+ recordScopedChange(
592
+ "dashboards",
593
+ "change",
594
+ dashboard.id,
595
+ dashboard.ownerEmail,
596
+ dashboard.orgId,
597
+ dashboard.visibility,
598
+ );
599
+ return dashboard;
600
+ }
601
+
445
602
  /**
446
603
  * Archive a dashboard (soft-delete). Requires editor. The row stays in the
447
604
  * dashboards table with `archived_at` set, so it disappears from the default
@@ -462,7 +619,7 @@ export async function archiveDashboard(
462
619
  const now = nowIso();
463
620
  await db
464
621
  .update(schema.dashboards)
465
- .set({ archivedAt: now, updatedAt: now })
622
+ .set({ archivedAt: now, updatedAt: now, updatedBy: ctx.email })
466
623
  .where(eq(schema.dashboards.id, id));
467
624
  const [row] = await db
468
625
  .select()
@@ -495,7 +652,7 @@ export async function unarchiveDashboard(
495
652
  const db = getDb() as any;
496
653
  await db
497
654
  .update(schema.dashboards)
498
- .set({ archivedAt: null, updatedAt: nowIso() })
655
+ .set({ archivedAt: null, updatedAt: nowIso(), updatedBy: ctx.email })
499
656
  .where(eq(schema.dashboards.id, id));
500
657
  const [row] = await db
501
658
  .select()
@@ -533,7 +690,12 @@ export async function hideDashboard(
533
690
  const now = nowIso();
534
691
  await db
535
692
  .update(schema.dashboards)
536
- .set({ hiddenAt: now, hiddenBy: ctx.email, updatedAt: now })
693
+ .set({
694
+ hiddenAt: now,
695
+ hiddenBy: ctx.email,
696
+ updatedAt: now,
697
+ updatedBy: ctx.email,
698
+ })
537
699
  .where(eq(schema.dashboards.id, id));
538
700
  const [row] = await db
539
701
  .select()
@@ -572,6 +734,7 @@ export async function unhideDashboard(
572
734
  hiddenAt: null,
573
735
  hiddenBy: null,
574
736
  updatedAt: now,
737
+ updatedBy: ctx.email,
575
738
  };
576
739
  if (!existing.ownerEmail) {
577
740
  patch.ownerEmail = ctx.email;
@@ -609,6 +772,9 @@ export async function removeDashboard(
609
772
  });
610
773
  const db = getDb() as any;
611
774
  await db.delete(schema.dashboards).where(eq(schema.dashboards.id, id));
775
+ await db
776
+ .delete(schema.dashboardRevisions)
777
+ .where(eq(schema.dashboardRevisions.dashboardId, id));
612
778
  await db
613
779
  .delete(schema.dashboardShares)
614
780
  .where(eq(schema.dashboardShares.resourceId, id));
@@ -658,6 +824,22 @@ function rowToAnalysis(row: any, role?: AccessRole): AnalysisRecord {
658
824
  };
659
825
  }
660
826
 
827
+ function rowToAnalysisRevision(row: any): AnalysisRevisionRecord {
828
+ return {
829
+ id: row.id,
830
+ analysisId: row.analysisId,
831
+ name: row.name,
832
+ description: row.description,
833
+ question: row.question,
834
+ instructions: row.instructions,
835
+ dataSources: safeJsonParse(row.dataSources, []),
836
+ resultMarkdown: row.resultMarkdown,
837
+ resultData: row.resultData ? safeJsonParse(row.resultData, null) : null,
838
+ createdAt: row.createdAt,
839
+ createdBy: row.createdBy ?? null,
840
+ };
841
+ }
842
+
661
843
  function safeJsonParse<T>(s: unknown, fallback: T): T {
662
844
  if (typeof s !== "string") return fallback;
663
845
  try {
@@ -880,6 +1062,48 @@ export async function listAnalyses(
880
1062
  return out;
881
1063
  }
882
1064
 
1065
+ async function pruneAnalysisRevisions(
1066
+ db: any,
1067
+ analysisId: string,
1068
+ ): Promise<void> {
1069
+ const rows = await db
1070
+ .select({ id: schema.analysisRevisions.id })
1071
+ .from(schema.analysisRevisions)
1072
+ .where(eq(schema.analysisRevisions.analysisId, analysisId))
1073
+ .orderBy(desc(schema.analysisRevisions.createdAt));
1074
+ const stale = rows.slice(ANALYSIS_REVISION_LIMIT);
1075
+ for (const row of stale) {
1076
+ await db
1077
+ .delete(schema.analysisRevisions)
1078
+ .where(eq(schema.analysisRevisions.id, row.id));
1079
+ }
1080
+ }
1081
+
1082
+ async function snapshotAnalysisRevision(
1083
+ db: any,
1084
+ analysis: AnalysisRecord,
1085
+ ctx: AccessCtx,
1086
+ ): Promise<void> {
1087
+ await db.insert(schema.analysisRevisions).values({
1088
+ id: `analysisrev-${Date.now()}-${nanoidFallback()}`,
1089
+ analysisId: analysis.id,
1090
+ name: analysis.name,
1091
+ description: analysis.description,
1092
+ question: analysis.question,
1093
+ instructions: analysis.instructions,
1094
+ dataSources: JSON.stringify(analysis.dataSources),
1095
+ resultMarkdown: analysis.resultMarkdown,
1096
+ resultData: analysis.resultData
1097
+ ? JSON.stringify(analysis.resultData)
1098
+ : null,
1099
+ createdAt: nowIso(),
1100
+ createdBy: ctx.email,
1101
+ ownerEmail: analysis.ownerEmail,
1102
+ orgId: analysis.orgId,
1103
+ });
1104
+ await pruneAnalysisRevisions(db, analysis.id);
1105
+ }
1106
+
883
1107
  export async function upsertAnalysis(
884
1108
  id: string,
885
1109
  body: {
@@ -913,6 +1137,32 @@ export async function upsertAnalysis(
913
1137
  patch.resultData = body.resultData
914
1138
  ? JSON.stringify(body.resultData)
915
1139
  : null;
1140
+ const next = {
1141
+ name: (patch.name as string | undefined) ?? existing.name,
1142
+ description:
1143
+ (patch.description as string | undefined) ?? existing.description,
1144
+ question: (patch.question as string | undefined) ?? existing.question,
1145
+ instructions:
1146
+ (patch.instructions as string | undefined) ?? existing.instructions,
1147
+ dataSources:
1148
+ body.dataSources !== undefined
1149
+ ? body.dataSources
1150
+ : existing.dataSources,
1151
+ resultMarkdown:
1152
+ (patch.resultMarkdown as string | undefined) ?? existing.resultMarkdown,
1153
+ resultData:
1154
+ body.resultData !== undefined ? body.resultData : existing.resultData,
1155
+ };
1156
+ const changed =
1157
+ next.name !== existing.name ||
1158
+ next.description !== existing.description ||
1159
+ next.question !== existing.question ||
1160
+ next.instructions !== existing.instructions ||
1161
+ JSON.stringify(next.dataSources) !==
1162
+ JSON.stringify(existing.dataSources) ||
1163
+ next.resultMarkdown !== existing.resultMarkdown ||
1164
+ JSON.stringify(next.resultData) !== JSON.stringify(existing.resultData);
1165
+ if (changed) await snapshotAnalysisRevision(db, existing, ctx);
916
1166
  await db
917
1167
  .update(schema.analyses)
918
1168
  .set(patch)
@@ -944,6 +1194,82 @@ export async function upsertAnalysis(
944
1194
  return rowToAnalysis(row);
945
1195
  }
946
1196
 
1197
+ export async function listAnalysisRevisions(
1198
+ analysisId: string,
1199
+ ctx: AccessCtx,
1200
+ ): Promise<AnalysisRevisionRecord[]> {
1201
+ const existing = await getAnalysis(analysisId, ctx);
1202
+ if (!existing) return [];
1203
+ await assertAccess("analysis", analysisId, "viewer", {
1204
+ userEmail: ctx.email,
1205
+ orgId: ctx.orgId ?? undefined,
1206
+ });
1207
+ const db = getDb() as any;
1208
+ const rows = await db
1209
+ .select()
1210
+ .from(schema.analysisRevisions)
1211
+ .where(eq(schema.analysisRevisions.analysisId, analysisId))
1212
+ .orderBy(desc(schema.analysisRevisions.createdAt))
1213
+ .limit(ANALYSIS_REVISION_LIMIT);
1214
+ return rows.map(rowToAnalysisRevision);
1215
+ }
1216
+
1217
+ export async function restoreAnalysisRevision(
1218
+ analysisId: string,
1219
+ revisionId: string,
1220
+ ctx: AccessCtx,
1221
+ ): Promise<AnalysisRecord | null> {
1222
+ const existing = await getAnalysis(analysisId, ctx);
1223
+ if (!existing) return null;
1224
+ await assertAccess("analysis", analysisId, "editor", {
1225
+ userEmail: ctx.email,
1226
+ orgId: ctx.orgId ?? undefined,
1227
+ });
1228
+ const db = getDb() as any;
1229
+ const [revisionRow] = await db
1230
+ .select()
1231
+ .from(schema.analysisRevisions)
1232
+ .where(
1233
+ and(
1234
+ eq(schema.analysisRevisions.id, revisionId),
1235
+ eq(schema.analysisRevisions.analysisId, analysisId),
1236
+ ),
1237
+ )
1238
+ .limit(1);
1239
+ if (!revisionRow) return null;
1240
+ const revision = rowToAnalysisRevision(revisionRow);
1241
+ await snapshotAnalysisRevision(db, existing, ctx);
1242
+ await db
1243
+ .update(schema.analyses)
1244
+ .set({
1245
+ name: revision.name,
1246
+ description: revision.description,
1247
+ question: revision.question,
1248
+ instructions: revision.instructions,
1249
+ dataSources: JSON.stringify(revision.dataSources),
1250
+ resultMarkdown: revision.resultMarkdown,
1251
+ resultData: revision.resultData
1252
+ ? JSON.stringify(revision.resultData)
1253
+ : null,
1254
+ updatedAt: nowIso(),
1255
+ })
1256
+ .where(eq(schema.analyses.id, analysisId));
1257
+ const [row] = await db
1258
+ .select()
1259
+ .from(schema.analyses)
1260
+ .where(eq(schema.analyses.id, analysisId));
1261
+ const analysis = rowToAnalysis(row);
1262
+ recordScopedChange(
1263
+ "analyses",
1264
+ "change",
1265
+ analysis.id,
1266
+ analysis.ownerEmail,
1267
+ analysis.orgId,
1268
+ analysis.visibility,
1269
+ );
1270
+ return analysis;
1271
+ }
1272
+
947
1273
  export async function removeAnalysis(
948
1274
  id: string,
949
1275
  ctx: AccessCtx,
@@ -956,6 +1282,9 @@ export async function removeAnalysis(
956
1282
  });
957
1283
  const db = getDb() as any;
958
1284
  await db.delete(schema.analyses).where(eq(schema.analyses.id, id));
1285
+ await db
1286
+ .delete(schema.analysisRevisions)
1287
+ .where(eq(schema.analysisRevisions.analysisId, id));
959
1288
  await db
960
1289
  .delete(schema.analysisShares)
961
1290
  .where(eq(schema.analysisShares.resourceId, id));