@agent-native/core 0.98.0 → 0.98.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 (345) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +32 -0
  3. package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
  4. package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +1 -1
  5. package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
  6. package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +1 -1
  7. package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
  8. package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +1 -1
  9. package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
  10. package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +1 -1
  11. package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
  12. package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +1 -1
  13. package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
  14. package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +1 -1
  15. package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
  16. package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +1 -1
  17. package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
  18. package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +1 -1
  19. package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
  20. package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +1 -1
  21. package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
  22. package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +1 -1
  23. package/corpus/core/docs/content/pr-visual-recap.mdx +50 -1
  24. package/corpus/core/docs/content/template-plan.mdx +1 -1
  25. package/corpus/core/package.json +2 -2
  26. package/corpus/core/src/action-change-marker.ts +8 -1
  27. package/corpus/core/src/changelog/parse.ts +8 -3
  28. package/corpus/core/src/cli/plan-local.ts +43 -11
  29. package/corpus/core/src/cli/pr-visual-recap-workflow.ts +2 -9
  30. package/corpus/core/src/cli/recap.ts +356 -4
  31. package/corpus/core/src/cli/skills-content/local-files.ts +17 -12
  32. package/corpus/core/src/client/AgentPanel.tsx +2 -3
  33. package/corpus/core/src/client/AssistantChat.tsx +83 -39
  34. package/corpus/core/src/client/analytics.ts +125 -14
  35. package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +16 -2
  36. package/corpus/core/src/client/chat-model-groups.ts +28 -0
  37. package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +442 -85
  38. package/corpus/core/src/client/composer/TiptapComposer.tsx +46 -29
  39. package/corpus/core/src/client/composer/VoiceButton.tsx +2 -1
  40. package/corpus/core/src/client/composer/index.ts +5 -0
  41. package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +1206 -67
  42. package/corpus/core/src/client/index.ts +10 -0
  43. package/corpus/core/src/client/progress/RunsTray.tsx +13 -1
  44. package/corpus/core/src/client/session-replay.ts +10 -0
  45. package/corpus/core/src/client/settings/DemoModeSection.tsx +4 -28
  46. package/corpus/core/src/client/settings/SecretsSection.tsx +387 -266
  47. package/corpus/core/src/client/settings/SettingsPanel.tsx +117 -38
  48. package/corpus/core/src/client/url-scrub.ts +13 -0
  49. package/corpus/core/src/client/use-action.ts +12 -0
  50. package/corpus/core/src/client/use-agent-chat-home-handoff.ts +8 -1
  51. package/corpus/core/src/client/use-agent-engine-configured.ts +17 -3
  52. package/corpus/core/src/client/use-db-sync.ts +84 -34
  53. package/corpus/core/src/client/use-demo-mode-status.ts +44 -0
  54. package/corpus/core/src/client/use-pausing-interval.ts +14 -4
  55. package/corpus/core/src/integrations/scope-store.ts +1 -1
  56. package/corpus/core/src/integrations/usage-budget-store.ts +1 -1
  57. package/corpus/core/src/localization/default-messages.ts +44 -1
  58. package/corpus/core/src/mcp-client/workspace-servers.ts +4 -4
  59. package/corpus/core/src/secrets/crypto.ts +28 -8
  60. package/corpus/core/src/server/action-change.ts +5 -1
  61. package/corpus/core/src/server/action-routes.ts +8 -0
  62. package/corpus/core/src/server/poll.ts +1 -0
  63. package/corpus/core/src/server/realtime-voice.ts +299 -13
  64. package/corpus/core/src/styles/agent-native.css +2 -2
  65. package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
  66. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
  67. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
  68. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
  69. package/corpus/core/src/vite/client.ts +9 -1
  70. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +2 -2
  71. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +10 -5
  72. package/corpus/templates/analytics/AGENTS.md +17 -13
  73. package/corpus/templates/analytics/actions/navigate.ts +59 -5
  74. package/corpus/templates/analytics/actions/view-screen.ts +3 -6
  75. package/corpus/templates/analytics/app/components/ProviderCorpusJobNotifier.tsx +20 -3
  76. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +20 -5
  77. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
  78. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +21 -6
  79. package/corpus/templates/analytics/app/global.css +19 -20
  80. package/corpus/templates/analytics/app/lib/demo-chart-trend.ts +156 -0
  81. package/corpus/templates/analytics/app/lib/provider-corpus-job-sync.ts +26 -0
  82. package/corpus/templates/analytics/app/pages/Settings.tsx +35 -341
  83. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +38 -7
  84. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +1 -1
  85. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +3 -0
  86. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +333 -272
  87. package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +72 -17
  88. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +297 -108
  89. package/corpus/templates/analytics/app/root.tsx +28 -8
  90. package/corpus/templates/analytics/changelog/2026-06-24-first-party-signup-and-pageview-panels-now-honor-dashboard-filters.md +2 -1
  91. package/corpus/templates/analytics/changelog/2026-06-25-referrer-dashboard-panels-show-external-domains.md +2 -1
  92. package/corpus/templates/analytics/changelog/2026-07-06-mobile-chat-header-is-more-compact-and-the-menu-button-opens-navigation.md +1 -0
  93. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +1 -0
  94. package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +1 -0
  95. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +1 -0
  96. package/corpus/templates/analytics/changelog/2026-07-11-analytics-no-longer-repeatedly-restarts-background-requests-.md +6 -0
  97. package/corpus/templates/analytics/changelog/2026-07-11-analytics-only-asks-for-replay-storage-when-you-enable-sessi.md +6 -0
  98. package/corpus/templates/analytics/changelog/2026-07-11-charts-now-show-their-loading-skeleton-while-refreshing.md +6 -0
  99. package/corpus/templates/analytics/changelog/2026-07-11-realtime-voice-now-shows-a-clear-connection-indicator-comple.md +6 -0
  100. package/corpus/templates/analytics/changelog/2026-07-11-replay-event-counts-stay-hidden-until-recordings-finish-load.md +6 -0
  101. package/corpus/templates/analytics/changelog/2026-07-11-replay-storage-key-mismatches-show-actionable-setup-guidance.md +6 -0
  102. package/corpus/templates/analytics/changelog/2026-07-11-replay-timelines-group-continuous-scrolling-and-dev-tools-co.md +6 -0
  103. package/corpus/templates/analytics/changelog/2026-07-11-session-filters-now-stay-compact-in-a-settings-menu-at-mediu.md +6 -0
  104. package/corpus/templates/analytics/changelog/2026-07-11-session-replay-console-errors-now-link-to-matching-issues-or.md +6 -0
  105. package/corpus/templates/analytics/changelog/2026-07-11-session-replays-load-large-recordings-faster-and-surface-fai.md +6 -0
  106. package/corpus/templates/analytics/changelog/2026-07-11-session-replays-preserve-recorded-styles-and-viewport-layout.md +6 -0
  107. package/corpus/templates/analytics/changelog/2026-07-11-session-replays-stay-centered-instead-of-clipping-wide-recor.md +6 -0
  108. package/corpus/templates/analytics/changelog/2026-07-12-daily-dashboard-emails-reliably-include-the-complete-dashboa.md +6 -0
  109. package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-charts-trend-upward.md +6 -0
  110. package/corpus/templates/analytics/package.json +1 -1
  111. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -303
  112. package/corpus/templates/analytics/server/handlers/session-replay.ts +57 -0
  113. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +2 -0
  114. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +1 -1
  115. package/corpus/templates/analytics/server/lib/dashboard-report.ts +17 -33
  116. package/corpus/templates/analytics/server/lib/demo-dashboards.ts +16 -3
  117. package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +12 -0
  118. package/corpus/templates/analytics/server/lib/session-replay.ts +208 -2
  119. package/corpus/templates/analytics/server/plugins/onboarding.ts +7 -79
  120. package/corpus/templates/analytics/server/routes/api/session-replay/recordings/[recordingId]/chunks.get.ts +1 -0
  121. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +2 -2
  122. package/corpus/templates/assets/app/global.css +4 -4
  123. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +0 -1
  124. package/corpus/templates/assets/app/routes/library.tsx +0 -1
  125. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +2 -2
  126. package/corpus/templates/brain/app/global.css +5 -5
  127. package/corpus/templates/brain/app/root.tsx +0 -3
  128. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +2 -2
  129. package/corpus/templates/calendar/app/root.tsx +1 -0
  130. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +2 -2
  131. package/corpus/templates/clips/app/components/player/video-player.tsx +5 -1
  132. package/corpus/templates/clips/app/hooks/use-auto-title.ts +74 -8
  133. package/corpus/templates/clips/app/hooks/use-library.ts +12 -25
  134. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +20 -22
  135. package/corpus/templates/clips/changelog/2026-07-11-clips-no-longer-stay-stuck-on-preparing-clip-when-they-are-r.md +6 -0
  136. package/corpus/templates/clips/changelog/2026-07-11-generated-titles-no-longer-cause-continuous-background-refreshes.md +6 -0
  137. package/corpus/templates/clips/changelog/2026-07-11-s3-storage-setup-stays-collapsed-until-you-choose-it-as-the-.md +6 -0
  138. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +2 -2
  139. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +2 -2
  140. package/corpus/templates/content/app/hooks/use-comments.ts +0 -1
  141. package/corpus/templates/content/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
  142. package/corpus/templates/content/changelog/2026-07-12-the-left-sidebar-stays-fixed-horizontally-while-scrolling-on.md +6 -0
  143. package/corpus/templates/design/app/components/layout/Header.tsx +1 -1
  144. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +2 -2
  145. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +1 -2
  146. package/corpus/templates/macros/app/root.tsx +0 -3
  147. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +2 -2
  148. package/corpus/templates/mail/app/hooks/use-compose-state.ts +1 -0
  149. package/corpus/templates/mail/app/root.tsx +1 -12
  150. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +2 -2
  151. package/corpus/templates/plan/.agents/skills/visual-plan/references/local-files.md +17 -12
  152. package/corpus/templates/plan/.agents/skills/visual-recap/references/local-files.md +17 -12
  153. package/corpus/templates/plan/actions/validate-local-plan-source.ts +4 -4
  154. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +2 -1
  155. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +5 -2
  156. package/corpus/templates/plan/app/hooks/use-plans.ts +6 -13
  157. package/corpus/templates/plan/app/lib/plan-local-bridge.ts +41 -0
  158. package/corpus/templates/plan/app/lib/plan-tracking.ts +3 -0
  159. package/corpus/templates/plan/app/pages/PlansPage.tsx +14 -36
  160. package/corpus/templates/plan/app/root.tsx +13 -3
  161. package/corpus/templates/plan/changelog/2026-07-11-plan-refreshes-only-when-content-changes.md +6 -0
  162. package/corpus/templates/plan/changelog/2026-07-12-local-plan-source-now-stays-on-device.md +6 -0
  163. package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +4 -1
  164. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +1 -1
  165. package/corpus/templates/slides/app/components/layout/Header.tsx +1 -1
  166. package/corpus/templates/slides/app/context/DeckContext.tsx +1 -0
  167. package/corpus/templates/slides/app/hooks/use-slide-comments.ts +7 -31
  168. package/corpus/templates/slides/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
  169. package/dist/action-change-marker.d.ts +1 -0
  170. package/dist/action-change-marker.d.ts.map +1 -1
  171. package/dist/action-change-marker.js +7 -1
  172. package/dist/action-change-marker.js.map +1 -1
  173. package/dist/changelog/parse.d.ts +4 -2
  174. package/dist/changelog/parse.d.ts.map +1 -1
  175. package/dist/changelog/parse.js +5 -3
  176. package/dist/changelog/parse.js.map +1 -1
  177. package/dist/cli/plan-local.d.ts +6 -6
  178. package/dist/cli/plan-local.d.ts.map +1 -1
  179. package/dist/cli/plan-local.js +36 -7
  180. package/dist/cli/plan-local.js.map +1 -1
  181. package/dist/cli/pr-visual-recap-workflow.d.ts +2 -8
  182. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  183. package/dist/cli/pr-visual-recap-workflow.js +2 -8
  184. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  185. package/dist/cli/recap.d.ts +22 -1
  186. package/dist/cli/recap.d.ts.map +1 -1
  187. package/dist/cli/recap.js +286 -2
  188. package/dist/cli/recap.js.map +1 -1
  189. package/dist/cli/skills-content/local-files.d.ts +1 -1
  190. package/dist/cli/skills-content/local-files.d.ts.map +1 -1
  191. package/dist/cli/skills-content/local-files.js +17 -12
  192. package/dist/cli/skills-content/local-files.js.map +1 -1
  193. package/dist/client/AgentPanel.d.ts.map +1 -1
  194. package/dist/client/AgentPanel.js +2 -3
  195. package/dist/client/AgentPanel.js.map +1 -1
  196. package/dist/client/AssistantChat.d.ts +7 -0
  197. package/dist/client/AssistantChat.d.ts.map +1 -1
  198. package/dist/client/AssistantChat.js +62 -40
  199. package/dist/client/AssistantChat.js.map +1 -1
  200. package/dist/client/analytics.d.ts +8 -0
  201. package/dist/client/analytics.d.ts.map +1 -1
  202. package/dist/client/analytics.js +103 -13
  203. package/dist/client/analytics.js.map +1 -1
  204. package/dist/client/blocks/library/wireframe-kit.d.ts +2 -0
  205. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  206. package/dist/client/blocks/library/wireframe-kit.js +9 -2
  207. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  208. package/dist/client/chat-model-groups.d.ts.map +1 -1
  209. package/dist/client/chat-model-groups.js +24 -0
  210. package/dist/client/chat-model-groups.js.map +1 -1
  211. package/dist/client/composer/RealtimeVoiceMode.d.ts +40 -4
  212. package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
  213. package/dist/client/composer/RealtimeVoiceMode.js +172 -42
  214. package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
  215. package/dist/client/composer/TiptapComposer.d.ts +4 -0
  216. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  217. package/dist/client/composer/TiptapComposer.js +47 -29
  218. package/dist/client/composer/TiptapComposer.js.map +1 -1
  219. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  220. package/dist/client/composer/VoiceButton.js +2 -2
  221. package/dist/client/composer/VoiceButton.js.map +1 -1
  222. package/dist/client/composer/index.d.ts +2 -2
  223. package/dist/client/composer/index.d.ts.map +1 -1
  224. package/dist/client/composer/index.js +1 -1
  225. package/dist/client/composer/index.js.map +1 -1
  226. package/dist/client/composer/useRealtimeVoiceMode.d.ts +100 -3
  227. package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
  228. package/dist/client/composer/useRealtimeVoiceMode.js +952 -51
  229. package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
  230. package/dist/client/index.d.ts +3 -2
  231. package/dist/client/index.d.ts.map +1 -1
  232. package/dist/client/index.js +3 -2
  233. package/dist/client/index.js.map +1 -1
  234. package/dist/client/progress/RunsTray.d.ts.map +1 -1
  235. package/dist/client/progress/RunsTray.js +10 -1
  236. package/dist/client/progress/RunsTray.js.map +1 -1
  237. package/dist/client/session-replay.d.ts +2 -0
  238. package/dist/client/session-replay.d.ts.map +1 -1
  239. package/dist/client/session-replay.js +7 -0
  240. package/dist/client/session-replay.js.map +1 -1
  241. package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
  242. package/dist/client/settings/DemoModeSection.js +4 -23
  243. package/dist/client/settings/DemoModeSection.js.map +1 -1
  244. package/dist/client/settings/SecretsSection.d.ts +2 -3
  245. package/dist/client/settings/SecretsSection.d.ts.map +1 -1
  246. package/dist/client/settings/SecretsSection.js +46 -22
  247. package/dist/client/settings/SecretsSection.js.map +1 -1
  248. package/dist/client/settings/SettingsPanel.d.ts +9 -0
  249. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  250. package/dist/client/settings/SettingsPanel.js +46 -12
  251. package/dist/client/settings/SettingsPanel.js.map +1 -1
  252. package/dist/client/url-scrub.d.ts.map +1 -1
  253. package/dist/client/url-scrub.js +14 -0
  254. package/dist/client/url-scrub.js.map +1 -1
  255. package/dist/client/use-action.d.ts +2 -0
  256. package/dist/client/use-action.d.ts.map +1 -1
  257. package/dist/client/use-action.js +10 -0
  258. package/dist/client/use-action.js.map +1 -1
  259. package/dist/client/use-agent-chat-home-handoff.d.ts +2 -0
  260. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
  261. package/dist/client/use-agent-chat-home-handoff.js +7 -1
  262. package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
  263. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  264. package/dist/client/use-agent-engine-configured.js +17 -3
  265. package/dist/client/use-agent-engine-configured.js.map +1 -1
  266. package/dist/client/use-db-sync.d.ts +8 -2
  267. package/dist/client/use-db-sync.d.ts.map +1 -1
  268. package/dist/client/use-db-sync.js +57 -32
  269. package/dist/client/use-db-sync.js.map +1 -1
  270. package/dist/client/use-demo-mode-status.d.ts +12 -0
  271. package/dist/client/use-demo-mode-status.d.ts.map +1 -0
  272. package/dist/client/use-demo-mode-status.js +30 -0
  273. package/dist/client/use-demo-mode-status.js.map +1 -0
  274. package/dist/client/use-pausing-interval.d.ts.map +1 -1
  275. package/dist/client/use-pausing-interval.js +16 -4
  276. package/dist/client/use-pausing-interval.js.map +1 -1
  277. package/dist/collab/struct-routes.d.ts +1 -1
  278. package/dist/integrations/scope-store.js +1 -1
  279. package/dist/integrations/scope-store.js.map +1 -1
  280. package/dist/integrations/usage-budget-store.js +1 -1
  281. package/dist/integrations/usage-budget-store.js.map +1 -1
  282. package/dist/localization/default-messages.d.ts +41 -1
  283. package/dist/localization/default-messages.d.ts.map +1 -1
  284. package/dist/localization/default-messages.js +41 -1
  285. package/dist/localization/default-messages.js.map +1 -1
  286. package/dist/mcp-client/workspace-servers.js +4 -4
  287. package/dist/mcp-client/workspace-servers.js.map +1 -1
  288. package/dist/notifications/routes.d.ts +3 -3
  289. package/dist/progress/routes.d.ts +1 -1
  290. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  291. package/dist/resources/handlers.d.ts +3 -3
  292. package/dist/secrets/crypto.d.ts +7 -6
  293. package/dist/secrets/crypto.d.ts.map +1 -1
  294. package/dist/secrets/crypto.js +30 -11
  295. package/dist/secrets/crypto.js.map +1 -1
  296. package/dist/server/action-change.d.ts +1 -0
  297. package/dist/server/action-change.d.ts.map +1 -1
  298. package/dist/server/action-change.js +4 -1
  299. package/dist/server/action-change.js.map +1 -1
  300. package/dist/server/action-routes.d.ts.map +1 -1
  301. package/dist/server/action-routes.js +5 -0
  302. package/dist/server/action-routes.js.map +1 -1
  303. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  304. package/dist/server/poll.d.ts.map +1 -1
  305. package/dist/server/poll.js +1 -0
  306. package/dist/server/poll.js.map +1 -1
  307. package/dist/server/realtime-voice.d.ts +7 -0
  308. package/dist/server/realtime-voice.d.ts.map +1 -1
  309. package/dist/server/realtime-voice.js +222 -12
  310. package/dist/server/realtime-voice.js.map +1 -1
  311. package/dist/styles/agent-native.css +2 -2
  312. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
  313. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
  314. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
  315. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
  316. package/dist/vite/client.d.ts.map +1 -1
  317. package/dist/vite/client.js +6 -1
  318. package/dist/vite/client.js.map +1 -1
  319. package/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
  320. package/docs/content/locales/ar-SA/template-plan.mdx +1 -1
  321. package/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
  322. package/docs/content/locales/de-DE/template-plan.mdx +1 -1
  323. package/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
  324. package/docs/content/locales/es-ES/template-plan.mdx +1 -1
  325. package/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
  326. package/docs/content/locales/fr-FR/template-plan.mdx +1 -1
  327. package/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
  328. package/docs/content/locales/hi-IN/template-plan.mdx +1 -1
  329. package/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
  330. package/docs/content/locales/ja-JP/template-plan.mdx +1 -1
  331. package/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
  332. package/docs/content/locales/ko-KR/template-plan.mdx +1 -1
  333. package/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
  334. package/docs/content/locales/pt-BR/template-plan.mdx +1 -1
  335. package/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
  336. package/docs/content/locales/zh-CN/template-plan.mdx +1 -1
  337. package/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
  338. package/docs/content/locales/zh-TW/template-plan.mdx +1 -1
  339. package/docs/content/pr-visual-recap.mdx +50 -1
  340. package/docs/content/template-plan.mdx +1 -1
  341. package/package.json +2 -2
  342. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
  343. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
  344. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
  345. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
@@ -938,7 +938,7 @@ export const dashboardCatalogEntries: DashboardCatalogEntry[] = [
938
938
  "referrals",
939
939
  "virality",
940
940
  ],
941
- panelCount: 51,
941
+ panelCount: 36,
942
942
  version: CATALOG_VERSION,
943
943
  recommended: true,
944
944
  visibleInCatalog: false,
@@ -42,9 +42,8 @@ const DASHBOARD_REPORT_SCREENSHOT_PARAM = "reportScreenshot";
42
42
  const DASHBOARD_REPORT_SETTINGS_PARAM = "reportSettings";
43
43
  const DASHBOARD_REPORT_CID = "dashboard-report-snapshot";
44
44
  const LOCAL_SCREENSHOT_TIMEOUT_MS = 90_000;
45
- const SERVERLESS_SCREENSHOT_TIMEOUT_MS = 60_000;
46
- const SERVERLESS_SECOND_READY_TIMEOUT_MS = 30_000;
47
- const MAX_SCREENSHOT_VIEWPORT_HEIGHT = 30_000;
45
+ const SERVERLESS_SCREENSHOT_TIMEOUT_MS = 90_000;
46
+ const SERVERLESS_SECOND_READY_TIMEOUT_MS = 45_000;
48
47
  const SCREENSHOT_VIEWPORT_PADDING = 64;
49
48
 
50
49
  type DashboardScreenshotAttempt = {
@@ -328,42 +327,27 @@ async function scrollDashboardForLazyRendering(page: any): Promise<void> {
328
327
  })()`);
329
328
  }
330
329
 
331
- async function fitViewportToDashboardCapture(
330
+ async function fitViewportWidthToDashboardCapture(
332
331
  page: any,
333
332
  capture: any,
334
- minViewport: { width: number; height: number },
333
+ viewport: { width: number; height: number },
335
334
  ): Promise<void> {
336
335
  const box = await capture.boundingBox();
337
336
  if (!box) return;
338
337
 
339
- const size = {
340
- width: Math.max(
341
- minViewport.width,
342
- Math.min(1800, Math.ceil(box.width + SCREENSHOT_VIEWPORT_PADDING)),
343
- ),
344
- height: Math.max(
345
- minViewport.height,
346
- Math.min(
347
- MAX_SCREENSHOT_VIEWPORT_HEIGHT,
348
- Math.ceil(box.height + SCREENSHOT_VIEWPORT_PADDING),
349
- ),
350
- ),
351
- };
352
- await page.setViewportSize(size);
353
- await page.waitForTimeout(250);
354
-
355
- const resizedBox = await capture.boundingBox();
356
- if (!resizedBox) return;
357
- const resizedHeight = Math.ceil(
358
- resizedBox.height + SCREENSHOT_VIEWPORT_PADDING,
338
+ const width = Math.max(
339
+ viewport.width,
340
+ Math.min(1800, Math.ceil(box.width + SCREENSHOT_VIEWPORT_PADDING)),
359
341
  );
360
- if (resizedHeight > size.height) {
361
- await page.setViewportSize({
362
- width: size.width,
363
- height: Math.min(MAX_SCREENSHOT_VIEWPORT_HEIGHT, resizedHeight),
364
- });
365
- await page.waitForTimeout(250);
366
- }
342
+ if (width === viewport.width) return;
343
+
344
+ // Keep the render surface bounded. Playwright's locator screenshot captures
345
+ // the full element beyond the viewport, while growing Chromium to the full
346
+ // dashboard height can exhaust memory and close the browser on serverless
347
+ // workers. Width-only fitting preserves the full dashboard without that
348
+ // oversized render surface.
349
+ await page.setViewportSize({ width, height: viewport.height });
350
+ await page.waitForTimeout(250);
367
351
  }
368
352
 
369
353
  async function captureDashboardPng(
@@ -412,7 +396,7 @@ async function captureDashboardPng(
412
396
  await scrollDashboardForLazyRendering(page);
413
397
  await waitForDashboardReportReady(page, secondReadyTimeoutMs());
414
398
 
415
- await fitViewportToDashboardCapture(page, capture, attempt.viewport);
399
+ await fitViewportWidthToDashboardCapture(page, capture, attempt.viewport);
416
400
  await capture.scrollIntoViewIfNeeded();
417
401
  const image = await capture.screenshot({
418
402
  type: "png",
@@ -104,6 +104,15 @@ function publicState(state: DemoDashboardState): Record<string, unknown> {
104
104
  };
105
105
  }
106
106
 
107
+ function stateContent(state: DemoDashboardState): string {
108
+ return JSON.stringify({
109
+ version: state.version,
110
+ initializedAt: state.initializedAt,
111
+ dashboards: state.dashboards ?? {},
112
+ deleted: state.deleted ?? {},
113
+ });
114
+ }
115
+
107
116
  export function demoDashboardIdForUser(
108
117
  email: string,
109
118
  demoId: DemoDashboardId,
@@ -291,14 +300,18 @@ export async function ensureDemoDashboardsForUser(
291
300
  });
292
301
  }
293
302
 
294
- const updatedState: DemoDashboardState = {
303
+ const updatedStateContent: DemoDashboardState = {
295
304
  version: DEMO_DASHBOARD_VERSION,
296
305
  initializedAt: state.initializedAt ?? nowIso(),
297
- updatedAt: nowIso(),
298
306
  dashboards,
299
307
  deleted,
300
308
  };
301
- await writeDemoState(ctx.email, updatedState);
309
+ if (reset || stateContent(state) !== stateContent(updatedStateContent)) {
310
+ await writeDemoState(ctx.email, {
311
+ ...updatedStateContent,
312
+ updatedAt: nowIso(),
313
+ });
314
+ }
302
315
 
303
316
  const firstActive = results.find((row) => row.installed && !row.archivedAt);
304
317
  return {
@@ -50,6 +50,7 @@ const MOUSE_INTERACTION = {
50
50
  DblClick: 4,
51
51
  Focus: 5,
52
52
  } as const;
53
+ const SCROLL_MARKER_BURST_MS = 1_000;
53
54
 
54
55
  function appBasePath(): string {
55
56
  const raw = process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH || "";
@@ -499,6 +500,7 @@ function capReplayTimelineMarkers(
499
500
  function buildReplayTimeline(events: AgentReplayEvent[]) {
500
501
  const startedAt = replayStartedAt(events);
501
502
  const markers: ReplayTimelineMarker[] = [];
503
+ const lastScrollByTarget = new Map<string, number>();
502
504
 
503
505
  for (const event of events) {
504
506
  const timestamp = Number(event.timestamp ?? 0);
@@ -568,6 +570,15 @@ function buildReplayTimeline(events: AgentReplayEvent[]) {
568
570
  event.type === RRWEB_EVENT_TYPE.IncrementalSnapshot &&
569
571
  event.data?.source === INCREMENTAL_SOURCE.Scroll
570
572
  ) {
573
+ const target = String(event.data?.id ?? "viewport");
574
+ const previousTimestamp = lastScrollByTarget.get(target);
575
+ if (
576
+ previousTimestamp !== undefined &&
577
+ timestamp - previousTimestamp <= SCROLL_MARKER_BURST_MS
578
+ ) {
579
+ lastScrollByTarget.set(target, timestamp);
580
+ continue;
581
+ }
571
582
  markers.push({
572
583
  timestamp,
573
584
  offsetMs: Math.max(0, timestamp - startedAt),
@@ -575,6 +586,7 @@ function buildReplayTimeline(events: AgentReplayEvent[]) {
575
586
  label: "Scroll",
576
587
  detail: null,
577
588
  });
589
+ lastScrollByTarget.set(target, timestamp);
578
590
  } else if (
579
591
  event.type === RRWEB_EVENT_TYPE.IncrementalSnapshot &&
580
592
  event.data?.source === INCREMENTAL_SOURCE.MouseInteraction &&
@@ -16,7 +16,19 @@ import {
16
16
  roleSatisfies,
17
17
  type ShareRole,
18
18
  } from "@agent-native/core/sharing";
19
- import { and, asc, desc, eq, gte, isNull, lt, lte, or, sql } from "drizzle-orm";
19
+ import {
20
+ and,
21
+ asc,
22
+ desc,
23
+ eq,
24
+ gte,
25
+ inArray,
26
+ isNull,
27
+ lt,
28
+ lte,
29
+ or,
30
+ sql,
31
+ } from "drizzle-orm";
20
32
 
21
33
  import {
22
34
  isFailedSessionReplayNetworkStatus,
@@ -229,6 +241,10 @@ const DEFAULT_REPLAY_EVENTS_READ = 10_000;
229
241
  const MAX_REPLAY_EVENTS_READ = 100_000;
230
242
  const MAX_REPLAY_EVENTS_RESPONSE_BYTES =
231
243
  MAX_BLOB_REPLAY_CHUNK_BYTES + 512 * 1024;
244
+ export const MAX_REPLAY_CHUNK_READ_BATCH_SIZE = 20;
245
+ export const MAX_REPLAY_CHUNK_READ_BATCH_BYTES =
246
+ MAX_REPLAY_EVENTS_RESPONSE_BYTES;
247
+ const REPLAY_CHUNK_READ_CONCURRENCY = 10;
232
248
  const DEFAULT_SESSION_RECORDINGS_LIMIT = 50;
233
249
  const MAX_SESSION_RECORDINGS_LIMIT = 100;
234
250
  const DEFAULT_REPLAY_RETENTION_DAYS = 30;
@@ -1954,7 +1970,16 @@ async function readSessionReplayChunkBytesForRecording(
1954
1970
  const ref = decodeReplayBlobRef(row.storageRef);
1955
1971
  if (!ref)
1956
1972
  throw replayError("Session replay blob reference is invalid", 500);
1957
- const blob = await readPrivateBlob(ref.handle);
1973
+ const blob = await readPrivateBlob(ref.handle).catch((error) => {
1974
+ console.error(
1975
+ `[session-replay] Failed to decrypt blob chunk ${recording.id}/${row.seq}:`,
1976
+ error,
1977
+ );
1978
+ throw replayError(
1979
+ "Session replay storage could not be decrypted with this environment's encryption key. When using a production Analytics database locally, set ANALYTICS_SECRETS_ENCRYPTION_KEY to the matching production key.",
1980
+ 503,
1981
+ );
1982
+ });
1958
1983
  return {
1959
1984
  recording,
1960
1985
  seq: row.seq,
@@ -1972,6 +1997,187 @@ async function readSessionReplayChunkBytesForRecording(
1972
1997
  };
1973
1998
  }
1974
1999
 
2000
+ export interface SessionReplayChunkBatchItem {
2001
+ seq: number;
2002
+ checksum: string;
2003
+ byteLength: number;
2004
+ eventCount: number;
2005
+ events: unknown[];
2006
+ unavailable?: true;
2007
+ }
2008
+
2009
+ export interface SessionReplayChunkBatchResult {
2010
+ chunks: SessionReplayChunkBatchItem[];
2011
+ unavailableChunks: number;
2012
+ }
2013
+
2014
+ function validateReplayChunkReadSeqs(seqs: number[]): number[] {
2015
+ if (!seqs.length) {
2016
+ throw replayError("At least one replay chunk seq is required", 400);
2017
+ }
2018
+ if (seqs.length > MAX_REPLAY_CHUNK_READ_BATCH_SIZE) {
2019
+ throw replayError(
2020
+ `At most ${MAX_REPLAY_CHUNK_READ_BATCH_SIZE} replay chunks may be read per request`,
2021
+ 400,
2022
+ );
2023
+ }
2024
+ const unique = new Set<number>();
2025
+ for (const seq of seqs) {
2026
+ if (!Number.isSafeInteger(seq) || seq < 0) {
2027
+ throw replayError("Replay chunk seqs must be non-negative integers", 400);
2028
+ }
2029
+ if (unique.has(seq)) {
2030
+ throw replayError("Replay chunk seqs must be unique", 400);
2031
+ }
2032
+ unique.add(seq);
2033
+ }
2034
+ return [...seqs];
2035
+ }
2036
+
2037
+ function unavailableReplayChunkBatchItem(
2038
+ seq: number,
2039
+ row?: any,
2040
+ ): SessionReplayChunkBatchItem {
2041
+ return {
2042
+ seq,
2043
+ checksum: row?.checksum ?? "",
2044
+ byteLength: Number(row?.byteLength ?? 0),
2045
+ eventCount: Number(row?.eventCount ?? 0),
2046
+ events: [],
2047
+ unavailable: true,
2048
+ };
2049
+ }
2050
+
2051
+ async function readReplayChunkBatchRow(
2052
+ recording: SessionRecordingSummary,
2053
+ row: any,
2054
+ ): Promise<SessionReplayChunkBatchItem> {
2055
+ let json: string;
2056
+ if (row.storageKind === "blob" && row.storageRef) {
2057
+ const ref = decodeReplayBlobRef(row.storageRef);
2058
+ if (!ref) return unavailableReplayChunkBatchItem(row.seq, row);
2059
+ let blob: Awaited<ReturnType<typeof readPrivateBlob>>;
2060
+ try {
2061
+ blob = await readPrivateBlob(ref.handle);
2062
+ } catch (error) {
2063
+ console.error(
2064
+ `[session-replay] Failed to read blob chunk ${recording.id}/${row.seq}:`,
2065
+ error,
2066
+ );
2067
+ throw replayError(
2068
+ "Session replay storage could not be read with this environment's storage configuration or encryption key.",
2069
+ 503,
2070
+ );
2071
+ }
2072
+ try {
2073
+ json = gunzipSync(Buffer.from(blob.data)).toString("utf8");
2074
+ } catch {
2075
+ return unavailableReplayChunkBatchItem(row.seq, row);
2076
+ }
2077
+ } else if (row.inlineData) {
2078
+ json = row.inlineData;
2079
+ } else {
2080
+ return unavailableReplayChunkBatchItem(row.seq, row);
2081
+ }
2082
+
2083
+ return {
2084
+ seq: row.seq,
2085
+ checksum: row.checksum,
2086
+ byteLength: row.byteLength,
2087
+ eventCount: row.eventCount,
2088
+ events: parseInlineReplayEvents(json),
2089
+ };
2090
+ }
2091
+
2092
+ async function readSessionReplayChunkBatchForRecording(
2093
+ recording: SessionRecordingSummary,
2094
+ requestedSeqs: number[],
2095
+ ): Promise<SessionReplayChunkBatchResult> {
2096
+ const seqs = validateReplayChunkReadSeqs(requestedSeqs);
2097
+ const db = getDb() as any;
2098
+ // guard:allow-unscoped -- rows are loaded only after one recording-scoped resolveAccess check or a signed recording-scoped agent token verifies access.
2099
+ const rows = await db
2100
+ .select()
2101
+ .from(schema.sessionReplayChunks)
2102
+ .where(
2103
+ and(
2104
+ eq(schema.sessionReplayChunks.recordingId, recording.id),
2105
+ inArray(schema.sessionReplayChunks.seq, seqs),
2106
+ ),
2107
+ )
2108
+ .orderBy(asc(schema.sessionReplayChunks.seq));
2109
+
2110
+ const declaredBytes = rows.reduce(
2111
+ (total: number, row: any) => total + Math.max(0, Number(row.byteLength)),
2112
+ 0,
2113
+ );
2114
+ if (declaredBytes > MAX_REPLAY_CHUNK_READ_BATCH_BYTES) {
2115
+ throw replayError(
2116
+ `Replay chunk batches must be ${MAX_REPLAY_CHUNK_READ_BATCH_BYTES} bytes or smaller`,
2117
+ 413,
2118
+ );
2119
+ }
2120
+
2121
+ const rowBySeq = new Map<number, any>(
2122
+ rows.map((row: any) => [Number(row.seq), row]),
2123
+ );
2124
+ const chunks = new Array<SessionReplayChunkBatchItem>(seqs.length);
2125
+ let nextIndex = 0;
2126
+
2127
+ async function worker(): Promise<void> {
2128
+ while (nextIndex < seqs.length) {
2129
+ const index = nextIndex;
2130
+ nextIndex += 1;
2131
+ const seq = seqs[index];
2132
+ const row = rowBySeq.get(seq);
2133
+ chunks[index] = row
2134
+ ? await readReplayChunkBatchRow(recording, row)
2135
+ : unavailableReplayChunkBatchItem(seq);
2136
+ }
2137
+ }
2138
+
2139
+ await Promise.all(
2140
+ Array.from(
2141
+ {
2142
+ length: Math.min(REPLAY_CHUNK_READ_CONCURRENCY, seqs.length),
2143
+ },
2144
+ worker,
2145
+ ),
2146
+ );
2147
+
2148
+ const result = {
2149
+ chunks,
2150
+ unavailableChunks: chunks.filter((chunk) => chunk.unavailable).length,
2151
+ };
2152
+ if (
2153
+ Buffer.byteLength(JSON.stringify(result), "utf8") >
2154
+ MAX_REPLAY_CHUNK_READ_BATCH_BYTES
2155
+ ) {
2156
+ throw replayError(
2157
+ `Replay chunk batch responses must be ${MAX_REPLAY_CHUNK_READ_BATCH_BYTES} bytes or smaller`,
2158
+ 413,
2159
+ );
2160
+ }
2161
+ return result;
2162
+ }
2163
+
2164
+ export async function readSessionReplayChunkBatch(
2165
+ recordingId: string,
2166
+ seqs: number[],
2167
+ scope: SessionReplayScope,
2168
+ ): Promise<SessionReplayChunkBatchResult> {
2169
+ const recording = await getSessionReplaySummary(recordingId, scope);
2170
+ return readSessionReplayChunkBatchForRecording(recording, seqs);
2171
+ }
2172
+
2173
+ export async function readSessionReplayTokenizedChunkBatch(
2174
+ recordingId: string,
2175
+ seqs: number[],
2176
+ ): Promise<SessionReplayChunkBatchResult> {
2177
+ const recording = await getSessionReplayTokenizedSummary(recordingId);
2178
+ return readSessionReplayChunkBatchForRecording(recording, seqs);
2179
+ }
2180
+
1975
2181
  export async function getSessionReplayEvents(
1976
2182
  recordingId: string,
1977
2183
  scope: SessionReplayScope,
@@ -1,24 +1,17 @@
1
1
  /**
2
2
  * Custom onboarding plugin for Analytics.
3
3
  *
4
- * Overrides the framework's default onboarding plugin to add an optional
5
- * "Session replay storage" step and register the S3 file upload provider. Must
6
- * live in server/plugins/ so the framework skips its default onboarding plugin,
7
- * and all registrations share the same module context as the onboarding route
8
- * handlers (which read from the same in-memory Map).
9
- *
10
- * The step is `required: false` because session replay is opt-in: capturing
11
- * replays only matters once a site embeds the tracking SDK with replay enabled,
12
- * so we surface storage setup without forcing it into the onboarding checklist.
4
+ * Overrides the framework's default onboarding plugin to register the S3 file
5
+ * upload provider. Must live in server/plugins/ so the framework skips its
6
+ * default onboarding plugin, and all registrations share the same module
7
+ * context as the onboarding route handlers (which read from the same in-memory
8
+ * Map). Analytics only needs storage when someone enables session replay, so
9
+ * replay setup lives with that workflow instead of onboarding.
13
10
  */
14
11
 
15
12
  import { registerFileUploadProvider } from "@agent-native/core/file-upload";
16
- import {
17
- createOnboardingPlugin,
18
- registerOnboardingStep,
19
- } from "@agent-native/core/onboarding";
13
+ import { createOnboardingPlugin } from "@agent-native/core/onboarding";
20
14
 
21
- import { hasRequestReplayStorage } from "../lib/replay-storage.js";
22
15
  import { s3FileUploadProvider } from "../lib/s3-upload-provider.js";
23
16
 
24
17
  const basePlugin = createOnboardingPlugin();
@@ -29,69 +22,4 @@ export default async (nitroApp: any): Promise<void> => {
29
22
 
30
23
  // Register S3-compatible file upload provider for session-replay chunks.
31
24
  registerFileUploadProvider(s3FileUploadProvider);
32
-
33
- // Add the optional "Session replay storage" onboarding step.
34
- registerOnboardingStep({
35
- id: "replay-storage",
36
- order: 15,
37
- required: false,
38
- title: "Session replay storage",
39
- description:
40
- "Store session replay recordings with Builder.io or S3-compatible storage.",
41
- methods: [
42
- {
43
- id: "builder",
44
- kind: "builder-cli-auth",
45
- label: "Connect Builder.io",
46
- description:
47
- "Builder.io's free tier includes object storage for replay chunks.",
48
- primary: true,
49
- badge: "free",
50
- payload: { scope: "browser" },
51
- },
52
- {
53
- id: "s3",
54
- kind: "form",
55
- label: "Use S3-compatible storage",
56
- description:
57
- "AWS S3, Cloudflare R2, DigitalOcean Spaces, MinIO, or any S3-compatible service.",
58
- payload: {
59
- writeScope: "workspace",
60
- fields: [
61
- {
62
- key: "S3_ENDPOINT",
63
- label: "Endpoint URL",
64
- placeholder: "https://s3.us-east-1.amazonaws.com",
65
- },
66
- {
67
- key: "S3_BUCKET",
68
- label: "Bucket name",
69
- placeholder: "my-replays-bucket",
70
- },
71
- {
72
- key: "S3_ACCESS_KEY_ID",
73
- label: "Access key ID",
74
- placeholder: "AKIA...",
75
- },
76
- {
77
- key: "S3_SECRET_ACCESS_KEY",
78
- label: "Secret access key",
79
- secret: true,
80
- },
81
- {
82
- key: "S3_REGION",
83
- label: "Region (optional)",
84
- placeholder: "us-east-1",
85
- },
86
- {
87
- key: "S3_PUBLIC_BASE_URL",
88
- label: "Public base URL (optional)",
89
- placeholder: "https://cdn.example.com",
90
- },
91
- ],
92
- },
93
- },
94
- ],
95
- isComplete: hasRequestReplayStorage,
96
- });
97
25
  };
@@ -0,0 +1 @@
1
+ export { handleSessionReplayChunkBatch as default } from "../../../../../handlers/session-replay";
@@ -30,7 +30,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
30
30
  useDbSync({ queryClient });
31
31
  ```
32
32
 
33
- For each non-own event, `useDbSync` bumps a per-source counter (e.g. `dashboards`, `analyses`, `settings`, `action`) and invalidates a small fixed list of framework-internal prefixes (`["action"]`, `["app-state"]`, `["__set_url__"]`, etc.). It does **not** blanket-invalidate templates' own data queries for ordinary domain events — that caused a request storm in production. The exception is `source: "action"`: a successful mutating action is the framework-wide "agent changed app data" signal, so `useDbSync` also refreshes active React Query observers as a compatibility safety net for custom apps that have not yet moved every read to `useActionQuery` or source-versioned query keys.
33
+ For each non-own event, `useDbSync` bumps a per-source counter (e.g. `dashboards`, `analyses`, `settings`, `action`) and invalidates a small fixed list of framework-internal prefixes (`["action"]`, `["app-state"]`, `["__set_url__"]`, etc.). It does **not** blanket-invalidate templates' own data queries — that caused request storms in production. A successful mutating action refreshes active `useActionQuery` observers under the `["action"]` prefix. Browser actions carry a tab id so their originating tab ignores the sync echo while other tabs refresh. Legacy apps can opt into broader compatibility with `actionInvalidatePredicate`, but first-party apps should use action-backed or source-versioned query keys. Idle fallback polling runs once per minute; active agent work temporarily uses the faster cadence.
34
34
 
35
35
  3. **Templates fold per-source counters into their query keys.** This is the pattern that makes "agent writes show up without a manual refresh" reliable:
36
36
 
@@ -117,7 +117,7 @@ useQuery({
117
117
  | UI not updating after agent writes | Is `useDbSync` called with the correct `queryClient`? Does the affected query have an active observer? |
118
118
  | Poll endpoint not responding | Is `/_agent-native/poll` accessible? Is the server running? |
119
119
  | SSE not connecting | Is `/_agent-native/events` accessible and authenticated? Polling should still keep the UI fresh as fallback. |
120
- | High CPU / event storms | The agent is writing rapidly. Add `staleTime` to queries to debounce refetches. |
120
+ | High CPU / event storms | Use targeted source keys, settle bursty list counters, and avoid broad action invalidation. |
121
121
 
122
122
  ## Jitter Prevention
123
123
 
@@ -257,14 +257,14 @@
257
257
  [data-agent-empty-state="centered"]
258
258
  .agent-composer-area {
259
259
  width: 100%;
260
- max-width: min(760px, 90%);
260
+ max-width: min(570px, 90%);
261
261
  padding: 0;
262
262
  }
263
263
 
264
264
  .assets-create-chat-panel
265
265
  [data-agent-empty-state="centered"]
266
266
  .agent-composer-root {
267
- min-height: 10.5rem;
267
+ min-height: 7.875rem;
268
268
  border-color: hsl(var(--border));
269
269
  border-radius: 1rem;
270
270
  background: hsl(var(--card));
@@ -274,7 +274,7 @@
274
274
  .assets-create-chat-panel
275
275
  [data-agent-empty-state="centered"]
276
276
  .agent-composer-prosemirror {
277
- min-height: 6.75rem;
277
+ min-height: 5.0625rem;
278
278
  font-size: 1rem;
279
279
  line-height: 1.625rem;
280
280
  }
@@ -305,6 +305,6 @@
305
305
  .assets-create-chat-panel
306
306
  [data-agent-empty-state="centered"]
307
307
  .agent-composer-root {
308
- min-height: 9rem;
308
+ min-height: 6.75rem;
309
309
  }
310
310
  }
@@ -429,7 +429,6 @@ export function BrandKitDetailRoute({
429
429
  signal,
430
430
  });
431
431
  },
432
- refetchInterval: 1000,
433
432
  });
434
433
 
435
434
  useEffect(() => {
@@ -1617,7 +1617,6 @@ function LibraryCandidateStage({
1617
1617
  { signal },
1618
1618
  );
1619
1619
  },
1620
- refetchInterval: 1000,
1621
1620
  });
1622
1621
  const isAllAssetsStage = !activeLibraryId;
1623
1622
  const liveLibraryId = activeLibraryId ?? variants?.libraryId ?? null;
@@ -30,7 +30,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
30
30
  useDbSync({ queryClient });
31
31
  ```
32
32
 
33
- For each non-own event, `useDbSync` bumps a per-source counter (e.g. `dashboards`, `analyses`, `settings`, `action`) and invalidates a small fixed list of framework-internal prefixes (`["action"]`, `["app-state"]`, `["__set_url__"]`, etc.). It does **not** blanket-invalidate templates' own data queries for ordinary domain events — that caused a request storm in production. The exception is `source: "action"`: a successful mutating action is the framework-wide "agent changed app data" signal, so `useDbSync` also refreshes active React Query observers as a compatibility safety net for custom apps that have not yet moved every read to `useActionQuery` or source-versioned query keys.
33
+ For each non-own event, `useDbSync` bumps a per-source counter (e.g. `dashboards`, `analyses`, `settings`, `action`) and invalidates a small fixed list of framework-internal prefixes (`["action"]`, `["app-state"]`, `["__set_url__"]`, etc.). It does **not** blanket-invalidate templates' own data queries — that caused request storms in production. A successful mutating action refreshes active `useActionQuery` observers under the `["action"]` prefix. Browser actions carry a tab id so their originating tab ignores the sync echo while other tabs refresh. Legacy apps can opt into broader compatibility with `actionInvalidatePredicate`, but first-party apps should use action-backed or source-versioned query keys. Idle fallback polling runs once per minute; active agent work temporarily uses the faster cadence.
34
34
 
35
35
  3. **Templates fold per-source counters into their query keys.** This is the pattern that makes "agent writes show up without a manual refresh" reliable:
36
36
 
@@ -117,7 +117,7 @@ useQuery({
117
117
  | UI not updating after agent writes | Is `useDbSync` called with the correct `queryClient`? Does the affected query have an active observer? |
118
118
  | Poll endpoint not responding | Is `/_agent-native/poll` accessible? Is the server running? |
119
119
  | SSE not connecting | Is `/_agent-native/events` accessible and authenticated? Polling should still keep the UI fresh as fallback. |
120
- | High CPU / event storms | The agent is writing rapidly. Add `staleTime` to queries to debounce refetches. |
120
+ | High CPU / event storms | Use targeted source keys, settle bursty list counters, and avoid broad action invalidation. |
121
121
 
122
122
  ## Jitter Prevention
123
123
 
@@ -135,7 +135,7 @@
135
135
  .brain-chat-panel [data-agent-empty-state="centered"] .brain-chat-intro {
136
136
  display: grid;
137
137
  width: 100%;
138
- max-width: min(760px, 90%);
138
+ max-width: min(570px, 90%);
139
139
  gap: 0.5rem;
140
140
  margin: 0 auto 1rem;
141
141
  text-align: center;
@@ -165,12 +165,12 @@
165
165
 
166
166
  .brain-chat-panel [data-agent-empty-state="centered"] .agent-composer-area {
167
167
  width: 100%;
168
- max-width: min(760px, 90%);
168
+ max-width: min(570px, 90%);
169
169
  padding: 0;
170
170
  }
171
171
 
172
172
  .brain-chat-panel [data-agent-empty-state="centered"] .agent-composer-root {
173
- min-height: 10.5rem;
173
+ min-height: 7.875rem;
174
174
  border-color: hsl(var(--border));
175
175
  border-radius: 1rem;
176
176
  background: hsl(var(--card));
@@ -187,7 +187,7 @@
187
187
  .brain-chat-panel
188
188
  [data-agent-empty-state="centered"]
189
189
  .agent-composer-prosemirror {
190
- min-height: 6.75rem;
190
+ min-height: 5.0625rem;
191
191
  font-size: 1rem;
192
192
  line-height: 1.625rem;
193
193
  }
@@ -212,6 +212,6 @@
212
212
  }
213
213
 
214
214
  .brain-chat-panel [data-agent-empty-state="centered"] .agent-composer-root {
215
- min-height: 9rem;
215
+ min-height: 6.75rem;
216
216
  }
217
217
  }
@@ -204,9 +204,6 @@ export default function Root() {
204
204
  // Brain has a faster sync cadence for source distillation status;
205
205
  // 20 s keeps the source list fresh without hammering the server.
206
206
  staleTime: 20_000,
207
- // Brain shows live ingestion progress — refetch on focus to pick
208
- // up background sync jobs that don't emit DB events.
209
- refetchOnWindowFocus: true,
210
207
  // Flat retry: Brain data fetches are rarely auth failures so a
211
208
  // flat count is sufficient.
212
209
  retry: 1,