@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
@@ -0,0 +1,156 @@
1
+ type DemoTrendSeed = string | number;
2
+
3
+ function hashSeed(seed: string): number {
4
+ let hash = 2166136261;
5
+ for (let index = 0; index < seed.length; index += 1) {
6
+ hash ^= seed.charCodeAt(index);
7
+ hash = Math.imul(hash, 16777619);
8
+ }
9
+ return hash >>> 0;
10
+ }
11
+
12
+ function createRandom(seed: string): () => number {
13
+ let state = hashSeed(seed);
14
+ return () => {
15
+ state += 0x6d2b79f5;
16
+ let value = state;
17
+ value = Math.imul(value ^ (value >>> 15), value | 1);
18
+ value ^= value + Math.imul(value ^ (value >>> 7), value | 61);
19
+ return ((value ^ (value >>> 14)) >>> 0) / 4294967296;
20
+ };
21
+ }
22
+
23
+ function clamp(value: number, minimum: number, maximum: number): number {
24
+ return Math.min(maximum, Math.max(minimum, value));
25
+ }
26
+
27
+ function numericValue(value: unknown): number | null {
28
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
29
+ if (typeof value !== "string" || value.trim() === "") return null;
30
+ const numeric = Number(value);
31
+ return Number.isFinite(numeric) ? numeric : null;
32
+ }
33
+
34
+ function normalizedVolatility(
35
+ series: number[],
36
+ minimum: number,
37
+ range: number,
38
+ ) {
39
+ if (series.length < 3 || range === 0) return 0;
40
+ const normalized = series.map((value) => (value - minimum) / range);
41
+ const averageStep =
42
+ (normalized[normalized.length - 1] - normalized[0]) /
43
+ (normalized.length - 1);
44
+ const deviation = normalized
45
+ .slice(1)
46
+ .reduce(
47
+ (total, value, index) =>
48
+ total + Math.abs(value - normalized[index] - averageStep),
49
+ 0,
50
+ );
51
+ return clamp((deviation / (normalized.length - 1)) * 1.4, 0, 1);
52
+ }
53
+
54
+ function normalizedTrend(
55
+ length: number,
56
+ volatilityScore: number,
57
+ random: () => number,
58
+ ): number[] {
59
+ if (length <= 1) return [0];
60
+ if (length === 2) return [0, 1];
61
+
62
+ const volatility = 0.015 + volatilityScore * (0.22 + random() * 0.12);
63
+ const noiseMemory = 0.78 - volatilityScore * 0.58;
64
+ let noise = 0;
65
+ const values = Array.from({ length }, (_, index) => {
66
+ if (index === 0) return 0;
67
+ if (index === length - 1) return 1;
68
+
69
+ const progress = index / (length - 1);
70
+ noise = noise * noiseMemory + (random() * 2 - 1) * (1 - noiseMemory);
71
+ const taperedNoise = noise * volatility * Math.sin(Math.PI * progress);
72
+ return clamp(progress + taperedNoise, 0.025, 0.975);
73
+ });
74
+
75
+ // Pullback count and depth follow the source's normalized volatility. A
76
+ // smooth source remains a gentle rise; a jagged source gets several seeded
77
+ // reversals. Spacing the reversals across the series prevents them from
78
+ // collapsing into one noisy patch.
79
+ if (length >= 5 && volatilityScore >= 0.12) {
80
+ const maximumPullbacks = Math.min(3, Math.floor((length - 2) / 2));
81
+ const pullbackCount = Math.max(
82
+ 1,
83
+ Math.round(volatilityScore * maximumPullbacks),
84
+ );
85
+ for (let pullback = 0; pullback < pullbackCount; pullback += 1) {
86
+ const segmentCenter =
87
+ ((pullback + 1) * (length - 3)) / (pullbackCount + 1) + 1;
88
+ const jitter = (random() - 0.5) * Math.max(1, length / 10);
89
+ const dipIndex = Math.round(clamp(segmentCenter + jitter, 2, length - 2));
90
+ const center = dipIndex / (length - 1);
91
+ const amplitude = 0.025 + volatilityScore * (0.075 + random() * 0.12);
92
+ values[dipIndex - 1] = clamp(center + amplitude, 0.075, 0.925);
93
+ values[dipIndex] = clamp(center - amplitude, 0.05, 0.9);
94
+ }
95
+ }
96
+
97
+ return values;
98
+ }
99
+
100
+ /**
101
+ * Replace numeric chart series with a stable, seeded upward trend while
102
+ * retaining the query's original range and every non-series field. This is a
103
+ * presentation-only demo-mode transform: callers keep the real query result
104
+ * and opt individual line/area renderers into the returned rows.
105
+ */
106
+ export function createDemoChartTrendRows(
107
+ rows: Record<string, unknown>[],
108
+ yKeys: string[],
109
+ seed: DemoTrendSeed,
110
+ ): Record<string, unknown>[] {
111
+ if (rows.length === 0 || yKeys.length === 0) return rows;
112
+
113
+ let output: Record<string, unknown>[] | null = null;
114
+
115
+ for (const yKey of yKeys) {
116
+ const points = rows.flatMap((row, rowIndex) => {
117
+ const numeric = numericValue(row[yKey]);
118
+ return numeric === null
119
+ ? []
120
+ : [{ rowIndex, numeric, original: row[yKey] }];
121
+ });
122
+
123
+ if (points.length < 2) continue;
124
+
125
+ const minimum = Math.min(...points.map((point) => point.numeric));
126
+ const maximum = Math.max(...points.map((point) => point.numeric));
127
+ if (minimum === maximum) continue;
128
+
129
+ const random = createRandom(`${String(seed)}:${yKey}`);
130
+ const range = maximum - minimum;
131
+ const volatilityScore = normalizedVolatility(
132
+ points.map((point) => point.numeric),
133
+ minimum,
134
+ range,
135
+ );
136
+ const trend = normalizedTrend(points.length, volatilityScore, random);
137
+ const useStringValues = points.every(
138
+ (point) => typeof point.original === "string",
139
+ );
140
+
141
+ output ??= rows.map((row) => ({ ...row }));
142
+ points.forEach((point, pointIndex) => {
143
+ const numeric =
144
+ pointIndex === 0
145
+ ? minimum
146
+ : pointIndex === points.length - 1
147
+ ? maximum
148
+ : minimum + trend[pointIndex] * range;
149
+ output![point.rowIndex][yKey] = useStringValues
150
+ ? String(numeric)
151
+ : numeric;
152
+ });
153
+ }
154
+
155
+ return output ?? rows;
156
+ }
@@ -0,0 +1,26 @@
1
+ type SyncEvent = {
2
+ source?: string;
3
+ key?: string;
4
+ };
5
+
6
+ type Listener = () => void;
7
+
8
+ const listeners = new Set<Listener>();
9
+
10
+ export function isProviderCorpusJobSyncEvent(event: SyncEvent): boolean {
11
+ return (
12
+ (event.source === "action" && event.key === "provider-corpus-job") ||
13
+ event.source === "provider-corpus-jobs"
14
+ );
15
+ }
16
+
17
+ /** Forward the root's shared DB-sync event without opening another transport. */
18
+ export function notifyProviderCorpusJobSyncEvent(event: SyncEvent): void {
19
+ if (!isProviderCorpusJobSyncEvent(event)) return;
20
+ for (const listener of listeners) listener();
21
+ }
22
+
23
+ export function subscribeProviderCorpusJobSync(listener: Listener): () => void {
24
+ listeners.add(listener);
25
+ return () => listeners.delete(listener);
26
+ }
@@ -1,32 +1,18 @@
1
1
  import {
2
- agentNativePath,
3
2
  ChangelogSettingsCard,
4
3
  LanguagePicker,
5
4
  SettingsTabsPage,
6
5
  useAgentSettingsTabs,
7
- useBuilderConnectFlow,
8
- useBuilderStatus,
9
6
  useSession,
10
7
  useT,
11
8
  type SettingsSearchEntry,
12
9
  type SettingsTabItem,
13
10
  } from "@agent-native/core/client";
14
11
  import { TeamPage } from "@agent-native/core/client/org";
15
- import {
16
- IconBell,
17
- IconCheck,
18
- IconChevronDown,
19
- IconCloud,
20
- IconExternalLink,
21
- IconKey,
22
- IconLoader2,
23
- IconServer,
24
- } from "@tabler/icons-react";
25
- import { useMemo, useState } from "react";
12
+ import { IconBell } from "@tabler/icons-react";
13
+ import { useMemo } from "react";
26
14
  import { Link } from "react-router";
27
- import { toast } from "sonner";
28
15
 
29
- import { Badge } from "@/components/ui/badge";
30
16
  import { Button } from "@/components/ui/button";
31
17
  import {
32
18
  Card,
@@ -35,90 +21,13 @@ import {
35
21
  CardHeader,
36
22
  CardTitle,
37
23
  } from "@/components/ui/card";
38
- import {
39
- Collapsible,
40
- CollapsibleContent,
41
- CollapsibleTrigger,
42
- } from "@/components/ui/collapsible";
43
- import { Input } from "@/components/ui/input";
44
24
  import { Label } from "@/components/ui/label";
45
- import { useReplayStorageStatus } from "@/hooks/use-replay-storage-status";
46
- import { cn } from "@/lib/utils";
47
25
 
48
26
  import changelog from "../../CHANGELOG.md?raw";
27
+ import { useReplayStorageStatus } from "../hooks/use-replay-storage-status";
28
+ import { ReplayStorageHint } from "./sessions/SessionsPage";
49
29
  import { AlertRulesSettingsCard } from "./settings/AlertRulesSettingsCard";
50
30
 
51
- const S3_STORAGE_FIELDS = [
52
- {
53
- key: "S3_ENDPOINT",
54
- labelKey: "settings.s3EndpointLabel",
55
- placeholder: "https://s3.us-east-1.amazonaws.com",
56
- required: true,
57
- },
58
- {
59
- key: "S3_BUCKET",
60
- labelKey: "settings.s3BucketLabel",
61
- placeholder: "my-replays-bucket",
62
- required: true,
63
- },
64
- {
65
- key: "S3_ACCESS_KEY_ID",
66
- labelKey: "settings.s3AccessKeyLabel",
67
- placeholder: "AKIA...",
68
- required: true,
69
- },
70
- {
71
- key: "S3_SECRET_ACCESS_KEY",
72
- labelKey: "settings.s3SecretAccessKeyLabel",
73
- placeholder: "••••••••",
74
- required: true,
75
- secret: true,
76
- },
77
- {
78
- key: "S3_REGION",
79
- labelKey: "settings.s3RegionLabel",
80
- placeholder: "us-east-1",
81
- },
82
- {
83
- key: "S3_PUBLIC_BASE_URL",
84
- labelKey: "settings.s3PublicBaseUrlLabel",
85
- placeholder: "https://cdn.example.com",
86
- },
87
- ] as const;
88
-
89
- async function saveS3StorageSettings(
90
- values: Record<string, string>,
91
- ): Promise<void> {
92
- const vars = S3_STORAGE_FIELDS.map((field) => ({
93
- key: field.key,
94
- value: (values[field.key] ?? "").trim(),
95
- })).filter((entry) => entry.value.length > 0);
96
-
97
- if (vars.length === 0) {
98
- throw new Error("Enter at least one storage value.");
99
- }
100
-
101
- for (const { key, value } of vars) {
102
- const res = await fetch(agentNativePath("/_agent-native/secrets/adhoc"), {
103
- method: "POST",
104
- headers: { "Content-Type": "application/json" },
105
- body: JSON.stringify({
106
- name: key,
107
- value,
108
- scope: "workspace",
109
- description: "Analytics S3-compatible replay storage", // i18n-ignore -- secret metadata description, not visible UI
110
- }),
111
- });
112
-
113
- if (!res.ok) {
114
- const body = (await res.json().catch(() => null)) as {
115
- error?: string;
116
- } | null;
117
- throw new Error(body?.error ?? `Save failed (${res.status})`);
118
- }
119
- }
120
- }
121
-
122
31
  export default function Settings() {
123
32
  // Settings is also reachable directly from the full-page agent surface.
124
33
  // Read the session from the framework's owning AppProviders boundary rather
@@ -127,73 +36,7 @@ export default function Settings() {
127
36
  const { session: auth } = useSession();
128
37
  const t = useT();
129
38
  const agentSettingsTabs = useAgentSettingsTabs();
130
-
131
- const storageStatus = useReplayStorageStatus();
132
- const builderStatus = useBuilderStatus();
133
- const builderConnect = useBuilderConnectFlow({
134
- popupUrl:
135
- builderStatus.status?.cliAuthUrl ?? builderStatus.status?.connectUrl,
136
- trackingSource: "analytics_settings",
137
- trackingFlow: "replay_storage",
138
- onConnected: async () => {
139
- await Promise.all([storageStatus.refetch(), builderStatus.refetch()]);
140
- toast.success(t("settings.builderConnectedToast"));
141
- },
142
- });
143
-
144
- const [savingStorage, setSavingStorage] = useState(false);
145
- const [s3Values, setS3Values] = useState<Record<string, string>>({});
146
- const [s3Expanded, setS3Expanded] = useState(false);
147
-
148
- const storageConfigured = !!storageStatus.data?.configured;
149
- const activeProviderName = storageStatus.data?.activeProvider?.name ?? null;
150
- const activeProviderId = storageStatus.data?.activeProvider?.id ?? null;
151
- const builderConnected = Boolean(
152
- builderConnect.configured ||
153
- builderStatus.status?.configured ||
154
- storageStatus.data?.builderConfigured ||
155
- activeProviderId === "builder",
156
- );
157
- const builderOrgName =
158
- builderConnect.orgName ?? builderStatus.status?.orgName ?? null;
159
- const builderStatusLoading =
160
- storageStatus.isLoading ||
161
- builderStatus.loading ||
162
- !builderConnect.hasFetchedStatus;
163
- const s3Configured = activeProviderId === "s3";
164
- const s3Collapsed = builderConnected && !s3Expanded;
165
-
166
- async function handleSaveS3Storage() {
167
- const missing = s3Configured
168
- ? []
169
- : S3_STORAGE_FIELDS.filter(
170
- (field) =>
171
- "required" in field &&
172
- field.required &&
173
- !(s3Values[field.key] ?? "").trim(),
174
- );
175
- if (missing.length > 0) {
176
- toast.error(t("settings.storageRequired"));
177
- return;
178
- }
179
-
180
- setSavingStorage(true);
181
- try {
182
- await saveS3StorageSettings(s3Values);
183
- setS3Values((current) => ({
184
- ...current,
185
- S3_SECRET_ACCESS_KEY: "",
186
- }));
187
- await storageStatus.refetch();
188
- toast.success(t("settings.storageSaved"));
189
- } catch (err) {
190
- toast.error(
191
- err instanceof Error ? err.message : t("settings.storageSaveFailed"),
192
- );
193
- } finally {
194
- setSavingStorage(false);
195
- }
196
- }
39
+ const replayStorageStatus = useReplayStorageStatus();
197
40
 
198
41
  const extraTabs = useMemo<SettingsTabItem[]>(
199
42
  () => [
@@ -227,18 +70,22 @@ export default function Settings() {
227
70
  keywords: "data sources api keys manage credentials",
228
71
  hash: "credentials",
229
72
  },
230
- {
231
- id: "analytics-replay-storage",
232
- label: t("settings.replayStorage"),
233
- keywords: "storage s3 builder replay bucket cloud",
234
- hash: "replay-storage",
235
- },
236
73
  {
237
74
  id: "analytics-dashboard-templates",
238
75
  label: t("settings.dashboardTemplates"),
239
76
  keywords: "templates catalog dashboards",
240
77
  hash: "dashboard-templates",
241
78
  },
79
+ ...(replayStorageStatus.data?.configured
80
+ ? [
81
+ {
82
+ id: "analytics-replay-storage",
83
+ label: t("sessions.storageSetupTitle"),
84
+ keywords: "session replay recording storage s3 bucket builder",
85
+ hash: "replay-storage",
86
+ },
87
+ ]
88
+ : []),
242
89
  {
243
90
  id: "analytics-language",
244
91
  label: t("settings.languageTitle"),
@@ -252,7 +99,7 @@ export default function Settings() {
252
99
  hash: "about",
253
100
  },
254
101
  ],
255
- [t],
102
+ [replayStorageStatus.data?.configured, t],
256
103
  );
257
104
 
258
105
  return (
@@ -302,178 +149,6 @@ export default function Settings() {
302
149
  </CardContent>
303
150
  </Card>
304
151
 
305
- <Card
306
- id="replay-storage"
307
- className="bg-card border-border/50 scroll-mt-16"
308
- >
309
- <CardHeader>
310
- <CardTitle className="text-base flex items-center gap-2">
311
- <IconCloud className="size-4 text-primary" />
312
- {t("settings.replayStorage")}
313
- </CardTitle>
314
- <CardDescription>
315
- {t("settings.replayStorageDescription")}
316
- </CardDescription>
317
- </CardHeader>
318
- <CardContent className="space-y-4">
319
- <div
320
- className={cn(
321
- "flex flex-col gap-3 rounded-md border px-3 py-3 sm:flex-row sm:items-center sm:justify-between",
322
- builderConnected
323
- ? "border-primary/35 bg-primary/5"
324
- : "border-border bg-accent/30",
325
- )}
326
- >
327
- <div className="min-w-0">
328
- <div className="flex items-center gap-2 text-sm font-medium">
329
- {builderConnected ? (
330
- <IconCheck className="h-4 w-4 text-primary" />
331
- ) : (
332
- <IconKey className="h-4 w-4 text-muted-foreground" />
333
- )}
334
- {builderStatusLoading
335
- ? t("settings.checkingBuilder")
336
- : builderConnected
337
- ? t("settings.builderConnected")
338
- : t("settings.connectBuilder")}
339
- </div>
340
- <p className="mt-0.5 text-xs text-muted-foreground">
341
- {builderConnected
342
- ? builderOrgName
343
- ? t("settings.builderConnectedFor", {
344
- orgName: builderOrgName,
345
- })
346
- : t("settings.builderConnectedGeneric")
347
- : t("settings.builderIncludes")}
348
- </p>
349
- </div>
350
- {builderConnected ? (
351
- <Badge variant="secondary" className="shrink-0">
352
- {t("settings.connected")}
353
- </Badge>
354
- ) : (
355
- <Button
356
- type="button"
357
- variant="outline"
358
- size="sm"
359
- className="shrink-0"
360
- onClick={() =>
361
- builderConnect.start({
362
- trackingSource: "analytics_settings_replay_storage",
363
- trackingFlow: "replay_storage",
364
- })
365
- }
366
- disabled={builderConnect.connecting || builderStatusLoading}
367
- >
368
- {builderConnect.connecting ? (
369
- <IconLoader2 className="h-4 w-4 animate-spin" />
370
- ) : (
371
- <IconExternalLink className="h-4 w-4" />
372
- )}
373
- {t("settings.connectBuilder")}
374
- </Button>
375
- )}
376
- </div>
377
-
378
- <Collapsible
379
- open={builderConnected ? !s3Collapsed : true}
380
- onOpenChange={(open) => setS3Expanded(open)}
381
- >
382
- <div className="rounded-md border border-border">
383
- <div className="flex flex-col gap-3 px-3 py-3 sm:flex-row sm:items-center sm:justify-between">
384
- <div className="min-w-0">
385
- <div className="flex flex-wrap items-center gap-2 text-sm font-medium">
386
- <IconServer className="h-4 w-4 text-muted-foreground" />
387
- {t("settings.s3Title")}
388
- <Badge variant="outline" className="text-[10px]">
389
- {t("settings.secondary")}
390
- </Badge>
391
- {s3Configured ? (
392
- <Badge variant="secondary" className="text-[10px]">
393
- {t("settings.active")}
394
- </Badge>
395
- ) : null}
396
- </div>
397
- <p className="mt-0.5 text-xs text-muted-foreground">
398
- {builderConnected
399
- ? t("settings.s3BuilderConnectedDescription")
400
- : storageConfigured && activeProviderName
401
- ? t("settings.s3CurrentProvider", {
402
- providerName: activeProviderName,
403
- })
404
- : t("settings.s3OwnBucketDescription")}
405
- </p>
406
- </div>
407
- {builderConnected ? (
408
- <CollapsibleTrigger asChild>
409
- <Button
410
- type="button"
411
- variant="ghost"
412
- size="sm"
413
- className="shrink-0"
414
- >
415
- {s3Collapsed
416
- ? t("settings.configureS3")
417
- : t("settings.hideS3")}
418
- <IconChevronDown
419
- className={cn(
420
- "h-4 w-4 transition-transform",
421
- !s3Collapsed && "rotate-180",
422
- )}
423
- />
424
- </Button>
425
- </CollapsibleTrigger>
426
- ) : null}
427
- </div>
428
-
429
- <CollapsibleContent>
430
- <div className="space-y-4 border-t border-border px-3 py-4">
431
- <div className="grid gap-4 sm:grid-cols-2">
432
- {S3_STORAGE_FIELDS.map((field) => (
433
- <div key={field.key} className="space-y-1.5">
434
- <Label htmlFor={field.key}>
435
- {t(field.labelKey)}
436
- </Label>
437
- <Input
438
- id={field.key}
439
- type={
440
- "secret" in field && field.secret
441
- ? "password"
442
- : "text"
443
- }
444
- value={s3Values[field.key] ?? ""}
445
- onChange={(event) =>
446
- setS3Values((current) => ({
447
- ...current,
448
- [field.key]: event.target.value,
449
- }))
450
- }
451
- placeholder={field.placeholder}
452
- autoComplete="off"
453
- disabled={savingStorage}
454
- />
455
- </div>
456
- ))}
457
- </div>
458
-
459
- <div className="flex justify-end">
460
- <Button
461
- onClick={handleSaveS3Storage}
462
- disabled={savingStorage || storageStatus.isLoading}
463
- >
464
- {savingStorage && (
465
- <IconLoader2 className="h-4 w-4 animate-spin" />
466
- )}
467
- {t("settings.saveStorage")}
468
- </Button>
469
- </div>
470
- </div>
471
- </CollapsibleContent>
472
- </div>
473
- </Collapsible>
474
- </CardContent>
475
- </Card>
476
-
477
152
  <Card
478
153
  id="dashboard-templates"
479
154
  className="bg-card border-border/50 scroll-mt-16"
@@ -495,6 +170,25 @@ export default function Settings() {
495
170
  </CardContent>
496
171
  </Card>
497
172
 
173
+ {replayStorageStatus.data?.configured ? (
174
+ <Card
175
+ id="replay-storage"
176
+ className="bg-card border-border/50 scroll-mt-16"
177
+ >
178
+ <CardHeader>
179
+ <CardTitle className="text-base">
180
+ {t("sessions.storageSetupTitle")}
181
+ </CardTitle>
182
+ <CardDescription>
183
+ {t("sessions.storageSetupDescription")}
184
+ </CardDescription>
185
+ </CardHeader>
186
+ <CardContent>
187
+ <ReplayStorageHint />
188
+ </CardContent>
189
+ </Card>
190
+ ) : null}
191
+
498
192
  <Card id="language" className="bg-card border-border/50 scroll-mt-16">
499
193
  <CardHeader>
500
194
  <CardTitle className="text-base">
@@ -43,9 +43,8 @@ export function ErrorsPanel() {
43
43
  const queryClient = useQueryClient();
44
44
  const [searchParams, setSearchParams] = useSearchParams();
45
45
  const selectedId = searchParams.get("issue");
46
-
47
- const [status, setStatus] = useState<StatusFilter>("unresolved");
48
- const [search, setSearch] = useState("");
46
+ const status = errorStatusFromSearchParams(searchParams);
47
+ const search = searchParams.get("q") ?? "";
49
48
  const debouncedSearch = useDebouncedValue(search, 250);
50
49
 
51
50
  const sync = useChangeVersions(["error-issues", "action"]);
@@ -96,9 +95,32 @@ export function ErrorsPanel() {
96
95
  }
97
96
  : selectedId
98
97
  ? { view: "errors", issueId: selectedId }
99
- : { view: "errors" };
98
+ : {
99
+ view: "errors",
100
+ status,
101
+ ...(search.trim() ? { query: search.trim() } : {}),
102
+ };
100
103
  void setClientAppState("monitoring", value).catch(() => {});
101
- }, [selectedIssue, selectedId]);
104
+ }, [search, selectedIssue, selectedId, status]);
105
+
106
+ const updateFilters = (next: { status?: StatusFilter; search?: string }) => {
107
+ setSearchParams(
108
+ (prev) => {
109
+ const params = new URLSearchParams(prev);
110
+ if (next.status) {
111
+ if (next.status === "unresolved") params.delete("status");
112
+ else params.set("status", next.status);
113
+ }
114
+ if (next.search !== undefined) {
115
+ const query = next.search.trim();
116
+ if (query) params.set("q", next.search);
117
+ else params.delete("q");
118
+ }
119
+ return params;
120
+ },
121
+ { replace: true },
122
+ );
123
+ };
102
124
 
103
125
  const selectIssue = (id: string | null) => {
104
126
  setSearchParams(
@@ -188,9 +210,9 @@ export function ErrorsPanel() {
188
210
  issues={issues}
189
211
  isLoading={isLoading}
190
212
  status={status}
191
- onStatusChange={setStatus}
213
+ onStatusChange={(nextStatus) => updateFilters({ status: nextStatus })}
192
214
  search={search}
193
- onSearchChange={setSearch}
215
+ onSearchChange={(nextSearch) => updateFilters({ search: nextSearch })}
194
216
  onRefresh={() => void refetch()}
195
217
  isFetching={isFetching}
196
218
  onSelect={selectIssue}
@@ -200,3 +222,12 @@ export function ErrorsPanel() {
200
222
  />
201
223
  );
202
224
  }
225
+
226
+ export function errorStatusFromSearchParams(
227
+ searchParams: URLSearchParams,
228
+ ): StatusFilter {
229
+ const status = searchParams.get("status");
230
+ return status === "resolved" || status === "ignored" || status === "all"
231
+ ? status
232
+ : "unresolved";
233
+ }