@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
@@ -37,7 +37,11 @@ import {
37
37
  import finalizeRecording from "../../../../../actions/finalize-recording.js";
38
38
  import { getDb, schema } from "../../../../db/index.js";
39
39
  import { debugLog } from "../../../../lib/debug.js";
40
- import { sumRecordingChunkBytes } from "../../../../lib/recording-upload-state.js";
40
+ import {
41
+ deleteRecordingChunks,
42
+ pruneStaleRecordingChunks,
43
+ sumRecordingChunkBytes,
44
+ } from "../../../../lib/recording-upload-state.js";
41
45
  import {
42
46
  getEventOwnerContext,
43
47
  ownerEmailMatches,
@@ -49,6 +53,7 @@ import {
49
53
  } from "../../../../lib/resumable-session.js";
50
54
  import { isStreamingUploadDisabled } from "../../../../lib/streaming-upload-mode.js";
51
55
  import {
56
+ allowsSqlRecordingChunkScratch,
52
57
  shouldRejectVideoUploadWithoutStorage,
53
58
  STORAGE_SETUP_REQUIRED_REASON,
54
59
  } from "../../../../lib/video-storage.js";
@@ -175,6 +180,13 @@ export default defineEventHandler(async (event: H3Event) => {
175
180
  debugLog("[chunk] resolved owner:", ownerEmail);
176
181
 
177
182
  return runWithRequestContext({ userEmail: ownerEmail, orgId }, async () => {
183
+ await pruneStaleRecordingChunks(ownerEmail).catch((err) => {
184
+ console.warn("[chunk] stale recording chunk prune failed:", {
185
+ ownerEmail,
186
+ err: err instanceof Error ? err.message : String(err),
187
+ });
188
+ });
189
+
178
190
  const db = getDb();
179
191
 
180
192
  // Verify the recording belongs to the current user.
@@ -271,6 +283,15 @@ export default defineEventHandler(async (event: H3Event) => {
271
283
  storageSetupRequired: true,
272
284
  };
273
285
  }
286
+ if (!allowsSqlRecordingChunkScratch()) {
287
+ setResponseStatus(event, 409);
288
+ return {
289
+ ok: false,
290
+ error:
291
+ "Recording upload storage is configured, but this upload did not start a resumable storage session. Refresh and start the recording again.",
292
+ storageSetupRequired: false,
293
+ };
294
+ }
274
295
 
275
296
  const raw = await readRawBody(event, false);
276
297
  const bodySize = raw ? raw.byteLength : 0;
@@ -320,6 +341,12 @@ export default defineEventHandler(async (event: H3Event) => {
320
341
  ? latestState.failureReason
321
342
  : "Recording upload has already failed.";
322
343
  if (latestState?.status === "failed") {
344
+ await deleteRecordingChunks(ownerEmail, recordingId).catch((err) => {
345
+ console.warn("[chunk] failed upload chunk cleanup failed:", {
346
+ recordingId,
347
+ err: err instanceof Error ? err.message : String(err),
348
+ });
349
+ });
323
350
  return failedUploadResponse(latestReason);
324
351
  }
325
352
 
@@ -333,6 +360,12 @@ export default defineEventHandler(async (event: H3Event) => {
333
360
  if (current?.status === "failed") {
334
361
  const reason =
335
362
  current.failureReason ?? "Recording upload has already failed.";
363
+ await deleteRecordingChunks(ownerEmail, recordingId).catch((err) => {
364
+ console.warn("[chunk] failed recording chunk cleanup failed:", {
365
+ recordingId,
366
+ err: err instanceof Error ? err.message : String(err),
367
+ });
368
+ });
336
369
  await writeAppState(`recording-upload-${recordingId}`, {
337
370
  recordingId,
338
371
  status: "failed",
@@ -364,6 +397,12 @@ export default defineEventHandler(async (event: H3Event) => {
364
397
  maxBytes: MAX_RECORDING_UPLOAD_BYTES,
365
398
  updatedAt: now,
366
399
  });
400
+ await deleteRecordingChunks(ownerEmail, recordingId).catch((err) => {
401
+ console.warn("[chunk] oversized upload chunk cleanup failed:", {
402
+ recordingId,
403
+ err: err instanceof Error ? err.message : String(err),
404
+ });
405
+ });
367
406
  setResponseStatus(event, 413);
368
407
  return {
369
408
  ok: false,
@@ -377,6 +377,11 @@ Most operations should be actions. You only need custom routes in `server/routes
377
377
  - **Webhooks** — external services POST to a specific URL
378
378
  - **OAuth callbacks** — redirect-based flows that need specific URL patterns
379
379
 
380
+ When the agent needs a durable image or file URL, call the core `upload-image`
381
+ action or use `uploadFile()` in server code. Do not write base64 into SQL,
382
+ markdown, deck/design JSON, or action results. `_agentImages` on action results
383
+ is for ephemeral vision previews only, not persistence.
384
+
380
385
  If it's a standard CRUD operation, data query, or a wrapper around an action, use the action instead.
381
386
 
382
387
  ## Legacy Pattern (bare export)
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
50
50
 
51
51
  For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
52
52
 
53
- 4. **Fallback** polling calls `/_agent-native/poll?since=N`. It runs every 2 seconds until SSE is connected, then relaxes to 15 seconds (`SSE_FALLBACK_INTERVAL_MS`). If SSE is disabled or unavailable (e.g., edge/serverless deployments), polling continues at the 2 s cadence. Polling is the universal serverless fallback it detects DB timestamp changes even when the write happened in a different process or invocation.
53
+ 4. **Fallback** polling calls `/_agent-native/poll?since=N`. It runs every 2 seconds until SSE is connected, then relaxes to 15 seconds (`SSE_FALLBACK_INTERVAL_MS`). If SSE is disabled or unavailable (e.g., edge/serverless deployments), polling continues at the 2 s cadence. Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
54
54
 
55
55
  5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
56
56
 
@@ -51,6 +51,13 @@ export default defineAction({
51
51
 
52
52
  The legacy `parameters:` field (plain JSON Schema) has no runtime validation — do not use it for new code.
53
53
 
54
+ ## Large Payloads
55
+
56
+ Do not accept or persist unbounded base64/file blobs through actions, SQL writes,
57
+ or `application_state`. Route uploads through the file-upload provider and store
58
+ references. This prevents database bloat, slow hot paths, and accidental secret
59
+ or customer-data embedding inside binary payloads.
60
+
54
61
  ## SQL Injection
55
62
 
56
63
  Never concatenate user input into SQL strings. Use Drizzle ORM's query builder (always safe) or parameterized queries:
@@ -13,7 +13,9 @@ metadata:
13
13
 
14
14
  ## Rule
15
15
 
16
- All application data lives in **SQL** (SQLite locally, persistent database in production). The agent and UI share the same database. Do not store durable app data in the filesystem unless the app is explicitly running a Local File Mode artifact flow described below.
16
+ All application data lives in **SQL** (SQLite locally, persistent database in production). The agent and UI share the same database. SQL stores structured records, metadata, references, and searchable text — not large raw file payloads. Do not store durable app data in the filesystem unless the app is explicitly running a Local File Mode artifact flow described below.
17
+
18
+ Large binary or file-like payloads (images, video/audio, PDFs, ZIPs, screenshots, session replay chunks, thumbnails, generated assets, `data:` URLs, and base64 file bodies) must go through configured file/blob storage such as `uploadFile()` or `putPrivateBlob()`. Persist only the returned URL, asset id, or opaque blob handle in SQL. If storage is unavailable in hosted or persistent-database mode, fail closed with setup guidance instead of falling back to base64 in `application_state`, `settings`, `resources`, or app tables. Local SQLite-only dev fallbacks may exist for tiny assets, but they must be capped, documented as dev-only, and kept off hot list/read paths.
17
19
 
18
20
  **Local File Mode exception:** some artifact apps (Content, Plans, Slides, Dashboards, Designs, etc.) can intentionally use repo files as the source of truth for the artifact itself. This must be explicit via `agent-native.json`, `AGENT_NATIVE_MODE=local-files`, or an app-owned local-file action helper. In that mode, the UI and agent still go through app actions, but those actions read/write scoped files through `@agent-native/core/local-artifacts` instead of SQL rows. App state, auth, settings, credentials, collaboration metadata, and hosted database mode remain SQL. File-to-database or file-to-provider synchronization is an explicit sync step, not an implicit side effect of editing.
19
21
 
@@ -136,6 +138,7 @@ Polling streams database changes to the UI. When the agent writes to the databas
136
138
  - Use the `settings` store for app configuration and user preferences
137
139
  - Use `application-state` for ephemeral UI state that the agent and UI share
138
140
  - Use `oauth-tokens` for OAuth credentials
141
+ - Use `uploadFile()` or `putPrivateBlob()` for large files/blob data and store only URLs, ids, or handles in SQL
139
142
  - Use core DB scripts (`db-schema`, `db-query`, `db-exec`, `db-patch`) for ad-hoc database operations
140
143
  - Use `db-exec --statements` instead of several separate `db-exec` calls for related writes; it is faster and rolls back the whole batch if one statement fails
141
144
  - Reach for `db-patch` instead of `db-exec UPDATE` whenever you're making a small change to a large text/JSON column — it's much cheaper on tokens
@@ -146,6 +149,7 @@ Polling streams database changes to the UI. When the agent writes to the databas
146
149
  - Don't store app state in localStorage, sessionStorage, or cookies (except for UI-only preferences like sidebar width)
147
150
  - Don't keep state only in memory (server variables, global stores)
148
151
  - Don't use Redis or any external state store for app data
152
+ - Don't store large files, base64 blobs, `data:` URLs, screenshots, videos, audio, PDFs, ZIPs, or session replay chunks directly in SQL rows, `application_state`, `settings`, or `resources`
149
153
  - Don't implement product features with raw SQL or `getDbExec()` when Drizzle can express the query
150
154
  - Don't write SQLite-only or Postgres-only SQL in app code
151
155
  - Don't interpolate user input directly into SQL queries — use Drizzle ORM's query builder
@@ -9,6 +9,10 @@ Detailed document editing, Notion, storage, and UI rules live in
9
9
 
10
10
  ## Core Rules
11
11
 
12
+ - Store large file/blob payloads in configured file/blob storage, not SQL: no
13
+ base64, `data:` URLs, images, video/audio, PDFs, ZIPs, screenshots,
14
+ thumbnails, or replay chunks in app tables, `application_state`, `settings`,
15
+ or `resources`; persist URLs, ids, or handles instead.
12
16
  - Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals. Use secrets/OAuth/runtime configuration and obvious placeholders in examples.
13
17
  - Use actions for documents, blocks, comments, media, sharing, navigation, and
14
18
  Notion integration. Do not mutate document rows directly unless a skill says to
@@ -43,7 +43,7 @@ export default function SettingsRoute() {
43
43
  extraTabs={agentSettingsTabs}
44
44
  generalSearchEntries={generalSearchEntries}
45
45
  general={
46
- <main className="mx-auto w-full max-w-3xl space-y-6">
46
+ <main className="mx-auto w-full max-w-2xl space-y-6">
47
47
  <p className="text-sm leading-6 text-muted-foreground">
48
48
  {t("settings.description")}
49
49
  </p>
@@ -77,7 +77,7 @@ export default function SettingsRoute() {
77
77
  </div>
78
78
  }
79
79
  whatsNew={
80
- <div className="mx-auto w-full max-w-3xl">
80
+ <div className="mx-auto w-full max-w-2xl">
81
81
  <ChangelogSettingsCard markdown={changelog} />
82
82
  </div>
83
83
  }
@@ -7,5 +7,5 @@ export function meta() {
7
7
  }
8
8
 
9
9
  export default function TeamRoute() {
10
- return <Navigate to="/settings#team" replace />;
10
+ return <Navigate to="/settings#organization" replace />;
11
11
  }
@@ -377,6 +377,11 @@ Most operations should be actions. You only need custom routes in `server/routes
377
377
  - **Webhooks** — external services POST to a specific URL
378
378
  - **OAuth callbacks** — redirect-based flows that need specific URL patterns
379
379
 
380
+ When the agent needs a durable image or file URL, call the core `upload-image`
381
+ action or use `uploadFile()` in server code. Do not write base64 into SQL,
382
+ markdown, deck/design JSON, or action results. `_agentImages` on action results
383
+ is for ephemeral vision previews only, not persistence.
384
+
380
385
  If it's a standard CRUD operation, data query, or a wrapper around an action, use the action instead.
381
386
 
382
387
  ## Legacy Pattern (bare export)
@@ -51,6 +51,13 @@ export default defineAction({
51
51
 
52
52
  The legacy `parameters:` field (plain JSON Schema) has no runtime validation — do not use it for new code.
53
53
 
54
+ ## Large Payloads
55
+
56
+ Do not accept or persist unbounded base64/file blobs through actions, SQL writes,
57
+ or `application_state`. Route uploads through the file-upload provider and store
58
+ references. This prevents database bloat, slow hot paths, and accidental secret
59
+ or customer-data embedding inside binary payloads.
60
+
54
61
  ## SQL Injection
55
62
 
56
63
  Never concatenate user input into SQL strings. Use Drizzle ORM's query builder (always safe) or parameterized queries:
@@ -9,6 +9,10 @@ patterns live in `.agents/skills/`.
9
9
 
10
10
  ## Core Rules
11
11
 
12
+ - Store large file/blob payloads in configured file/blob storage, not SQL: no
13
+ base64, `data:` URLs, images, video/audio, PDFs, ZIPs, screenshots,
14
+ thumbnails, or replay chunks in app tables, `application_state`, `settings`,
15
+ or `resources`; persist URLs, ids, or handles instead.
12
16
  - Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals. Use secrets/OAuth/runtime configuration and obvious placeholders in examples.
13
17
  - Use the app actions for designs, files, versions, design systems, variants,
14
18
  export, and sharing. Do not write design rows directly with SQL.
@@ -12,10 +12,9 @@
12
12
  * returns:
13
13
  *
14
14
  * - `screenshots[]` — a PNG per viewport, persisted through the shared
15
- * `uploadFile` provider (falls back to an inline base64 data URL when no
16
- * upload provider is configured, matching `set-thumbnail`'s fallback
17
- * pattern). The result carries a plain `url` per screenshot so a human can
18
- * view it by opening the link, or the agent can embed it as
15
+ * `uploadFile` provider. The result carries a plain `url` per screenshot
16
+ * when storage is configured so a human can view it by opening the link,
17
+ * or the agent can embed it as
19
18
  * `![...](url)` in its own chat reply today. NOTE: tool results are
20
19
  * currently text-only end-to-end — this action does not attach the PNG as
21
20
  * a model-visible image content block. The moment the engine supports
@@ -97,8 +96,9 @@ export interface ScreenshotDiagnostics {
97
96
  export interface ScreenshotResult {
98
97
  viewport: ScreenshotViewport;
99
98
  url: string;
100
- /** True when persisted via a durable upload provider; false for the inline data-URL fallback. */
99
+ /** True when persisted via a durable upload provider. */
101
100
  persisted: boolean;
101
+ uploadError?: string;
102
102
  bytes: number;
103
103
  diagnostics: ScreenshotDiagnostics;
104
104
  }
@@ -620,13 +620,16 @@ export default defineAction({
620
620
  ownerEmail,
621
621
  }).catch(() => null);
622
622
 
623
- const url =
624
- uploaded?.url ?? `data:image/png;base64,${png.toString("base64")}`;
625
-
626
623
  screenshots.push({
627
624
  viewport,
628
- url,
625
+ url: uploaded?.url ?? "",
629
626
  persisted: !!uploaded,
627
+ ...(uploaded?.url
628
+ ? {}
629
+ : {
630
+ uploadError:
631
+ "Screenshot was rendered but not returned because file storage is not configured.",
632
+ }),
630
633
  bytes: png.byteLength,
631
634
  diagnostics: {
632
635
  viewport,
@@ -1,3 +1,4 @@
1
+ import { callAction, useT } from "@agent-native/core/client";
1
2
  import { IconPhotoPlus, IconX } from "@tabler/icons-react";
2
3
  import { useEffect, useRef, useState } from "react";
3
4
 
@@ -32,6 +33,11 @@ export interface ImageFillBackgroundStyles {
32
33
  backgroundPosition?: string;
33
34
  }
34
35
 
36
+ type UploadImageResult = {
37
+ url?: string;
38
+ error?: string;
39
+ };
40
+
35
41
  const FIT_MODES: Array<{ mode: ImageFitMode; label: string }> = [
36
42
  { mode: "fill", label: "Fill" }, // i18n-ignore image fit mode
37
43
  { mode: "fit", label: "Fit" }, // i18n-ignore image fit mode
@@ -51,6 +57,19 @@ function escapeForQuotedUrl(url: string): string {
51
57
  return url.replace(/\\/g, "\\\\").replace(/"/g, "%22").replace(/\r?\n/g, "");
52
58
  }
53
59
 
60
+ function readFileAsDataUrl(file: File): Promise<string> {
61
+ return new Promise((resolve, reject) => {
62
+ const reader = new FileReader();
63
+ reader.onload = () =>
64
+ typeof reader.result === "string"
65
+ ? resolve(reader.result)
66
+ : reject(new Error("Image upload did not produce a data URL"));
67
+ reader.onerror = () =>
68
+ reject(reader.error ?? new Error("Image read failed"));
69
+ reader.readAsDataURL(file);
70
+ });
71
+ }
72
+
54
73
  const CHECKER_A = "#d4d4d4";
55
74
  const CHECKERBOARD_IMAGE = `linear-gradient(45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(-45deg, ${CHECKER_A} 25%, transparent 25%), linear-gradient(45deg, transparent 75%, ${CHECKER_A} 75%), linear-gradient(-45deg, transparent 75%, ${CHECKER_A} 75%)`;
56
75
  const FIT_MARKER_RE =
@@ -261,9 +280,12 @@ export function ImageFillControls({
261
280
  disabled = false,
262
281
  className,
263
282
  }: ImageFillControlsProps) {
283
+ const t = useT();
264
284
  const fileInputRef = useRef<HTMLInputElement>(null);
265
285
  const [urlDraft, setUrlDraft] = useState(value.url);
266
286
  const urlDraftRef = useRef(value.url);
287
+ const [uploadingImage, setUploadingImage] = useState(false);
288
+ const [uploadError, setUploadError] = useState<string | null>(null);
267
289
  // Guard re-syncing the draft from an external value change while the field
268
290
  // is focused (mirrors ScrubInput's `focused` pattern): without this, an
269
291
  // incoming prop update while the user is mid-typing a URL — e.g. a
@@ -281,20 +303,36 @@ export function ImageFillControls({
281
303
  onChange({ ...value, url: urlDraftRef.current.trim() });
282
304
  };
283
305
 
284
- const handleFilePick = (event: React.ChangeEvent<HTMLInputElement>) => {
306
+ const handleFilePick = async (event: React.ChangeEvent<HTMLInputElement>) => {
285
307
  const file = event.target.files?.[0];
286
308
  if (!file) return;
287
- const reader = new FileReader();
288
- reader.onload = () => {
289
- const dataUrl = typeof reader.result === "string" ? reader.result : "";
290
- if (dataUrl) {
291
- setUrlDraft(dataUrl);
292
- onChange({ ...value, url: dataUrl });
309
+ setUploadingImage(true);
310
+ setUploadError(null);
311
+ try {
312
+ const dataUrl = await readFileAsDataUrl(file);
313
+ const result = (await callAction("upload-image", {
314
+ data: dataUrl,
315
+ filename: file.name,
316
+ })) as UploadImageResult;
317
+ if (result.url) {
318
+ urlDraftRef.current = result.url;
319
+ setUrlDraft(result.url);
320
+ onChange({ ...value, url: result.url });
321
+ } else {
322
+ setUploadError(
323
+ result.error ||
324
+ "File storage is not configured. Connect an upload provider before using local images.",
325
+ );
293
326
  }
294
- };
295
- reader.readAsDataURL(file);
296
- // Allow re-selecting the same file later.
297
- event.target.value = "";
327
+ } catch (error) {
328
+ setUploadError(
329
+ error instanceof Error ? error.message : t("common.genericError"),
330
+ );
331
+ } finally {
332
+ setUploadingImage(false);
333
+ // Allow re-selecting the same file later.
334
+ event.target.value = "";
335
+ }
298
336
  };
299
337
 
300
338
  return (
@@ -376,13 +414,14 @@ export function ImageFillControls({
376
414
  <TooltipTrigger asChild>
377
415
  <button
378
416
  type="button"
379
- disabled={disabled}
417
+ disabled={disabled || uploadingImage}
380
418
  aria-label={"Upload image" /* i18n-ignore */}
381
419
  onClick={() => fileInputRef.current?.click()}
382
420
  className={cn(
383
421
  "flex size-6 shrink-0 items-center justify-center rounded-md border border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] text-muted-foreground hover:text-foreground",
384
422
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
385
- disabled && "pointer-events-none opacity-40",
423
+ (disabled || uploadingImage) &&
424
+ "pointer-events-none opacity-40",
386
425
  )}
387
426
  >
388
427
  <IconPhotoPlus className="size-3.5" />
@@ -398,6 +437,11 @@ export function ImageFillControls({
398
437
  onChange={handleFilePick}
399
438
  />
400
439
  </div>
440
+ {uploadError && (
441
+ <p className="text-[10px] leading-snug text-destructive">
442
+ {uploadError}
443
+ </p>
444
+ )}
401
445
 
402
446
  {/* ── Fit mode dropdown ─────────────────────────────────────────────── */}
403
447
  <Select
@@ -7,5 +7,5 @@ export function meta() {
7
7
  }
8
8
 
9
9
  export default function TeamRoute() {
10
- return <Navigate to="/settings#team" replace />;
10
+ return <Navigate to="/settings#organization" replace />;
11
11
  }
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-08
4
+ ---
5
+
6
+ Local images added to designs now upload to file storage instead of being saved as inline data URLs.
@@ -377,6 +377,11 @@ Most operations should be actions. You only need custom routes in `server/routes
377
377
  - **Webhooks** — external services POST to a specific URL
378
378
  - **OAuth callbacks** — redirect-based flows that need specific URL patterns
379
379
 
380
+ When the agent needs a durable image or file URL, call the core `upload-image`
381
+ action or use `uploadFile()` in server code. Do not write base64 into SQL,
382
+ markdown, deck/design JSON, or action results. `_agentImages` on action results
383
+ is for ephemeral vision previews only, not persistence.
384
+
380
385
  If it's a standard CRUD operation, data query, or a wrapper around an action, use the action instead.
381
386
 
382
387
  ## Legacy Pattern (bare export)
@@ -51,6 +51,13 @@ export default defineAction({
51
51
 
52
52
  The legacy `parameters:` field (plain JSON Schema) has no runtime validation — do not use it for new code.
53
53
 
54
+ ## Large Payloads
55
+
56
+ Do not accept or persist unbounded base64/file blobs through actions, SQL writes,
57
+ or `application_state`. Route uploads through the file-upload provider and store
58
+ references. This prevents database bloat, slow hot paths, and accidental secret
59
+ or customer-data embedding inside binary payloads.
60
+
54
61
  ## SQL Injection
55
62
 
56
63
  Never concatenate user input into SQL strings. Use Drizzle ORM's query builder (always safe) or parameterized queries:
@@ -8,6 +8,10 @@ specific essentials.
8
8
 
9
9
  ## Core Rules
10
10
 
11
+ - Store large file/blob payloads in configured file/blob storage, not SQL: no
12
+ base64, `data:` URLs, images, video/audio, PDFs, ZIPs, screenshots,
13
+ thumbnails, or replay chunks in app tables, `application_state`, `settings`,
14
+ or `resources`; persist URLs, ids, or handles instead.
11
15
  - Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals. Use secrets/OAuth/runtime configuration and obvious placeholders in examples.
12
16
  - Treat Dispatch as workspace infrastructure. Prefer actions over raw SQL for
13
17
  vault, integrations, resource grants, messaging, routing, and approvals.
@@ -216,7 +216,7 @@ function resolvePath(
216
216
  case "threads":
217
217
  return "/thread-debug";
218
218
  case "team":
219
- return "/settings#team";
219
+ return "/settings#organization";
220
220
  case "extensions":
221
221
  return command?.extensionId
222
222
  ? `/extensions/${encodeURIComponent(command.extensionId)}`
@@ -54,7 +54,7 @@ export default function SettingsRoute() {
54
54
  extraTabs={agentSettingsTabs}
55
55
  generalSearchEntries={generalSearchEntries}
56
56
  general={
57
- <div className="mx-auto w-full max-w-3xl space-y-6">
57
+ <div className="mx-auto w-full max-w-2xl space-y-6">
58
58
  <p className="text-sm leading-6 text-muted-foreground">
59
59
  {t("settings.description")}
60
60
  </p>
@@ -102,7 +102,7 @@ export default function SettingsRoute() {
102
102
  </div>
103
103
  }
104
104
  whatsNew={
105
- <div className="mx-auto w-full max-w-3xl">
105
+ <div className="mx-auto w-full max-w-2xl">
106
106
  <ChangelogSettingsCard markdown={changelog} />
107
107
  </div>
108
108
  }
@@ -1,5 +1,5 @@
1
1
  import { Navigate } from "react-router";
2
2
 
3
3
  export default function TeamRoute() {
4
- return <Navigate to="/settings#team" replace />;
4
+ return <Navigate to="/settings#organization" replace />;
5
5
  }
@@ -377,6 +377,11 @@ Most operations should be actions. You only need custom routes in `server/routes
377
377
  - **Webhooks** — external services POST to a specific URL
378
378
  - **OAuth callbacks** — redirect-based flows that need specific URL patterns
379
379
 
380
+ When the agent needs a durable image or file URL, call the core `upload-image`
381
+ action or use `uploadFile()` in server code. Do not write base64 into SQL,
382
+ markdown, deck/design JSON, or action results. `_agentImages` on action results
383
+ is for ephemeral vision previews only, not persistence.
384
+
380
385
  If it's a standard CRUD operation, data query, or a wrapper around an action, use the action instead.
381
386
 
382
387
  ## Legacy Pattern (bare export)
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
50
50
 
51
51
  For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
52
52
 
53
- 4. **Fallback** polling calls `/_agent-native/poll?since=N`. It runs every 2 seconds until SSE is connected, then relaxes to 15 seconds (`SSE_FALLBACK_INTERVAL_MS`). If SSE is disabled or unavailable (e.g., edge/serverless deployments), polling continues at the 2 s cadence. Polling is the universal serverless fallback it detects DB timestamp changes even when the write happened in a different process or invocation.
53
+ 4. **Fallback** polling calls `/_agent-native/poll?since=N`. It runs every 2 seconds until SSE is connected, then relaxes to 15 seconds (`SSE_FALLBACK_INTERVAL_MS`). If SSE is disabled or unavailable (e.g., edge/serverless deployments), polling continues at the 2 s cadence. Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
54
54
 
55
55
  5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
56
56
 
@@ -51,6 +51,13 @@ export default defineAction({
51
51
 
52
52
  The legacy `parameters:` field (plain JSON Schema) has no runtime validation — do not use it for new code.
53
53
 
54
+ ## Large Payloads
55
+
56
+ Do not accept or persist unbounded base64/file blobs through actions, SQL writes,
57
+ or `application_state`. Route uploads through the file-upload provider and store
58
+ references. This prevents database bloat, slow hot paths, and accidental secret
59
+ or customer-data embedding inside binary payloads.
60
+
54
61
  ## SQL Injection
55
62
 
56
63
  Never concatenate user input into SQL strings. Use Drizzle ORM's query builder (always safe) or parameterized queries:
@@ -13,7 +13,9 @@ metadata:
13
13
 
14
14
  ## Rule
15
15
 
16
- All application data lives in **SQL** (SQLite locally, persistent database in production). The agent and UI share the same database. Do not store durable app data in the filesystem unless the app is explicitly running a Local File Mode artifact flow described below.
16
+ All application data lives in **SQL** (SQLite locally, persistent database in production). The agent and UI share the same database. SQL stores structured records, metadata, references, and searchable text — not large raw file payloads. Do not store durable app data in the filesystem unless the app is explicitly running a Local File Mode artifact flow described below.
17
+
18
+ Large binary or file-like payloads (images, video/audio, PDFs, ZIPs, screenshots, session replay chunks, thumbnails, generated assets, `data:` URLs, and base64 file bodies) must go through configured file/blob storage such as `uploadFile()` or `putPrivateBlob()`. Persist only the returned URL, asset id, or opaque blob handle in SQL. If storage is unavailable in hosted or persistent-database mode, fail closed with setup guidance instead of falling back to base64 in `application_state`, `settings`, `resources`, or app tables. Local SQLite-only dev fallbacks may exist for tiny assets, but they must be capped, documented as dev-only, and kept off hot list/read paths.
17
19
 
18
20
  **Local File Mode exception:** some artifact apps (Content, Plans, Slides, Dashboards, Designs, etc.) can intentionally use repo files as the source of truth for the artifact itself. This must be explicit via `agent-native.json`, `AGENT_NATIVE_MODE=local-files`, or an app-owned local-file action helper. In that mode, the UI and agent still go through app actions, but those actions read/write scoped files through `@agent-native/core/local-artifacts` instead of SQL rows. App state, auth, settings, credentials, collaboration metadata, and hosted database mode remain SQL. File-to-database or file-to-provider synchronization is an explicit sync step, not an implicit side effect of editing.
19
21
 
@@ -136,6 +138,7 @@ Polling streams database changes to the UI. When the agent writes to the databas
136
138
  - Use the `settings` store for app configuration and user preferences
137
139
  - Use `application-state` for ephemeral UI state that the agent and UI share
138
140
  - Use `oauth-tokens` for OAuth credentials
141
+ - Use `uploadFile()` or `putPrivateBlob()` for large files/blob data and store only URLs, ids, or handles in SQL
139
142
  - Use core DB scripts (`db-schema`, `db-query`, `db-exec`, `db-patch`) for ad-hoc database operations
140
143
  - Use `db-exec --statements` instead of several separate `db-exec` calls for related writes; it is faster and rolls back the whole batch if one statement fails
141
144
  - Reach for `db-patch` instead of `db-exec UPDATE` whenever you're making a small change to a large text/JSON column — it's much cheaper on tokens
@@ -146,6 +149,7 @@ Polling streams database changes to the UI. When the agent writes to the databas
146
149
  - Don't store app state in localStorage, sessionStorage, or cookies (except for UI-only preferences like sidebar width)
147
150
  - Don't keep state only in memory (server variables, global stores)
148
151
  - Don't use Redis or any external state store for app data
152
+ - Don't store large files, base64 blobs, `data:` URLs, screenshots, videos, audio, PDFs, ZIPs, or session replay chunks directly in SQL rows, `application_state`, `settings`, or `resources`
149
153
  - Don't implement product features with raw SQL or `getDbExec()` when Drizzle can express the query
150
154
  - Don't write SQLite-only or Postgres-only SQL in app code
151
155
  - Don't interpolate user input directly into SQL queries — use Drizzle ORM's query builder
@@ -11,6 +11,10 @@ Detailed building, publishing, response, storage, and UI rules live in
11
11
 
12
12
  ## Core Rules
13
13
 
14
+ - Store large file/blob payloads in configured file/blob storage, not SQL: no
15
+ base64, `data:` URLs, images, video/audio, PDFs, ZIPs, screenshots,
16
+ thumbnails, or replay chunks in app tables, `application_state`, `settings`,
17
+ or `resources`; persist URLs, ids, or handles instead.
14
18
  - Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals. Use secrets/OAuth/runtime configuration and obvious placeholders in examples.
15
19
  - Use actions for form lifecycle, fields, publishing, responses, navigation,
16
20
  sharing, and database work. Do not bypass ownable access checks.
@@ -49,7 +49,7 @@ export default function SettingsRoute() {
49
49
  extraTabs={agentSettingsTabs}
50
50
  generalSearchEntries={generalSearchEntries}
51
51
  general={
52
- <div className="mx-auto w-full max-w-3xl space-y-6">
52
+ <div className="mx-auto w-full max-w-2xl space-y-6">
53
53
  <p className="text-sm leading-6 text-muted-foreground">
54
54
  {t("settings.description")}
55
55
  </p>
@@ -79,7 +79,7 @@ export default function SettingsRoute() {
79
79
  </div>
80
80
  }
81
81
  whatsNew={
82
- <div className="mx-auto w-full max-w-3xl">
82
+ <div className="mx-auto w-full max-w-2xl">
83
83
  <ChangelogSettingsCard markdown={changelog} />
84
84
  </div>
85
85
  }
@@ -5,5 +5,5 @@ export function meta() {
5
5
  }
6
6
 
7
7
  export default function TeamRoute() {
8
- return <Navigate to="/settings#team" replace />;
8
+ return <Navigate to="/settings#organization" replace />;
9
9
  }
@@ -73,7 +73,7 @@ export function formsRoutePath(target: FormsNavigationTarget): string | null {
73
73
  ? `/response-insights?formId=${encodeURIComponent(formId)}`
74
74
  : "/response-insights";
75
75
  case "team":
76
- return "/settings#team";
76
+ return "/settings#organization";
77
77
  case "extensions":
78
78
  return "/extensions";
79
79
  case "form-preview":
@@ -51,6 +51,13 @@ export default defineAction({
51
51
 
52
52
  The legacy `parameters:` field (plain JSON Schema) has no runtime validation — do not use it for new code.
53
53
 
54
+ ## Large Payloads
55
+
56
+ Do not accept or persist unbounded base64/file blobs through actions, SQL writes,
57
+ or `application_state`. Route uploads through the file-upload provider and store
58
+ references. This prevents database bloat, slow hot paths, and accidental secret
59
+ or customer-data embedding inside binary payloads.
60
+
54
61
  ## SQL Injection
55
62
 
56
63
  Never concatenate user input into SQL strings. Use Drizzle ORM's query builder (always safe) or parameterized queries: