@agent-native/core 0.120.1 → 0.120.3

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 (396) hide show
  1. package/corpus/README.md +3 -3
  2. package/corpus/core/CHANGELOG.md +29 -0
  3. package/corpus/core/docs/content/extensions.mdx +23 -4
  4. package/corpus/core/package.json +1 -1
  5. package/corpus/core/src/agent/production-agent.ts +4 -0
  6. package/corpus/core/src/agent/run-manager.ts +36 -10
  7. package/corpus/core/src/agent/types.ts +2 -0
  8. package/corpus/core/src/cli/context-xray-local.ts +1 -1
  9. package/corpus/core/src/cli/index.ts +63 -18
  10. package/corpus/core/src/cli/skills.ts +5 -0
  11. package/corpus/core/src/cli/telemetry.ts +118 -1
  12. package/corpus/core/src/client/AgentPanel.tsx +10 -0
  13. package/corpus/core/src/client/CommandMenu.tsx +13 -1
  14. package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +39 -4
  15. package/corpus/core/src/client/analytics.ts +13 -0
  16. package/corpus/core/src/client/error-capture.ts +6 -1
  17. package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +28 -8
  18. package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  19. package/corpus/core/src/client/navigation/index.ts +2 -0
  20. package/corpus/core/src/client/org/OrgSwitcher.tsx +14 -32
  21. package/corpus/core/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
  22. package/corpus/core/src/client/settings/SettingsPanel.tsx +10 -0
  23. package/corpus/core/src/deploy/build.ts +3 -0
  24. package/corpus/core/src/extensions/theme.ts +1 -1
  25. package/corpus/core/src/localization/default-messages.ts +2 -0
  26. package/corpus/core/src/server/analytics.ts +154 -25
  27. package/corpus/core/src/server/core-routes-plugin.ts +10 -1
  28. package/corpus/core/src/server/framework-request-handler.ts +17 -26
  29. package/corpus/core/src/styles/agent-native.css +13 -0
  30. package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +3 -0
  31. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +113 -51
  32. package/corpus/core/src/templates/chat/app/global.css +1 -1
  33. package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +2 -2
  34. package/corpus/core/src/templates/chat/netlify.toml +1 -0
  35. package/corpus/core/src/templates/default/app/global.css +1 -1
  36. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  37. package/corpus/core/src/tracking/error-capture.ts +151 -0
  38. package/corpus/core/src/tracking/index.ts +5 -0
  39. package/corpus/core/src/vite/client.ts +6 -0
  40. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +27 -43
  41. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +19 -8
  42. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +2 -2
  43. package/corpus/templates/analytics/AGENTS.md +20 -8
  44. package/corpus/templates/analytics/actions/get-explorer-dashboard.ts +3 -0
  45. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +140 -46
  46. package/corpus/templates/analytics/actions/migrate-analytics-artifacts.ts +48 -0
  47. package/corpus/templates/analytics/actions/save-analysis.ts +2 -3
  48. package/corpus/templates/analytics/actions/view-screen.ts +1 -1
  49. package/corpus/templates/analytics/app/components/dashboard/CumulativeNetChart.tsx +1 -1
  50. package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +1 -4
  51. package/corpus/templates/analytics/app/components/dashboard/DashboardMetadata.tsx +77 -0
  52. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +7 -1
  53. package/corpus/templates/analytics/app/components/dashboard/DataTable.tsx +1 -1
  54. package/corpus/templates/analytics/app/components/dashboard/DateRangePicker.tsx +2 -2
  55. package/corpus/templates/analytics/app/components/dashboard/MetricCard.tsx +1 -1
  56. package/corpus/templates/analytics/app/components/dashboard/RecentActivity.tsx +1 -1
  57. package/corpus/templates/analytics/app/components/dashboard/RevenueChart.tsx +1 -1
  58. package/corpus/templates/analytics/app/components/dashboard/RevenueComparisonChart.tsx +1 -1
  59. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +41 -9
  60. package/corpus/templates/analytics/app/components/dashboard/StatsCard.tsx +1 -1
  61. package/corpus/templates/analytics/app/components/dashboard/TimeSeriesChart.tsx +1 -1
  62. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +2 -0
  63. package/corpus/templates/analytics/app/components/layout/Layout.tsx +28 -14
  64. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
  65. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +255 -626
  66. package/corpus/templates/analytics/app/global.css +31 -1
  67. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -2
  68. package/corpus/templates/analytics/app/i18n-data.ts +80 -0
  69. package/corpus/templates/analytics/app/lib/dashboard-report-capture.ts +42 -0
  70. package/corpus/templates/analytics/app/pages/Agents.tsx +49 -2
  71. package/corpus/templates/analytics/app/pages/adhoc/_shared/KpiChart.tsx +1 -1
  72. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/ChartTypePicker.tsx +1 -1
  73. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/DateRangePicker.tsx +1 -1
  74. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/EventRow.tsx +1 -1
  75. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/SqlPreview.tsx +2 -2
  76. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +54 -11
  77. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +3 -3
  78. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +2 -2
  79. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +1 -1
  80. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +4 -54
  81. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +178 -69
  82. package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +2 -2
  83. package/corpus/templates/analytics/app/root.tsx +28 -0
  84. package/corpus/templates/analytics/app/routes/analyses._index.tsx +3 -2
  85. package/corpus/templates/analytics/app/routes/extensions._index.tsx +2 -2
  86. package/corpus/templates/analytics/changelog/2026-07-23-analytics-now-groups-saved-analyses-and-embedded-extensions-.md +6 -0
  87. package/corpus/templates/analytics/changelog/2026-07-23-dashboard-menus-show-who-created-and-last-updated-each-dashb.md +6 -0
  88. package/corpus/templates/analytics/changelog/2026-07-23-dashboard-usage-now-loads-reliably-for-organizations-with-ma.md +6 -0
  89. package/corpus/templates/analytics/changelog/2026-07-23-long-dashboard-building-requests-now-continue-without-stoppi.md +6 -0
  90. package/corpus/templates/analytics/changelog/2026-07-24-analytics-charts-now-explain-slow-loads-and-offer-a-direct-r.md +6 -0
  91. package/corpus/templates/analytics/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  92. package/corpus/templates/analytics/changelog/2026-07-24-daily-dashboard-emails-now-load-signed-reports-more-reliably.md +6 -0
  93. package/corpus/templates/analytics/changelog/2026-07-24-manage-agent-is-clearly-marked-as-a-link-to-its-dedicated-pa.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  95. package/corpus/templates/analytics/netlify.toml +4 -0
  96. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -1
  97. package/corpus/templates/analytics/server/db/schema.ts +9 -0
  98. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +21 -0
  99. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -1
  100. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +1 -0
  101. package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +11 -0
  102. package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +54 -0
  103. package/corpus/templates/analytics/server/lib/dashboard-report.ts +235 -26
  104. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +4 -1
  105. package/corpus/templates/analytics/server/lib/migrate-analytics-artifacts.ts +1062 -0
  106. package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -52
  107. package/corpus/templates/analytics/server/plugins/core-routes.ts +1 -1
  108. package/corpus/templates/analytics/server/plugins/db.ts +19 -0
  109. package/corpus/templates/analytics/shared/dashboard-report-timeouts.ts +1 -1
  110. package/corpus/templates/assets/actions/generate-image-batch.ts +36 -1
  111. package/corpus/templates/assets/actions/generate-image.ts +28 -1
  112. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +376 -0
  113. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +14 -4
  114. package/corpus/templates/assets/app/components/layout/Layout.tsx +5 -0
  115. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +164 -82
  116. package/corpus/templates/assets/app/global.css +1 -1
  117. package/corpus/templates/assets/app/i18n-data.ts +10 -0
  118. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +99 -10
  119. package/corpus/templates/assets/app/routes/extensions._index.tsx +2 -2
  120. package/corpus/templates/assets/app/routes/library.tsx +21 -198
  121. package/corpus/templates/assets/changelog/2026-07-21-unified-asset-preview-click-any-asset-to-open-one-preview-wi.md +6 -0
  122. package/corpus/templates/assets/changelog/2026-07-23-assets-image-generation-now-recovers-after-a-completed-tool-.md +6 -0
  123. package/corpus/templates/assets/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  124. package/corpus/templates/assets/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  125. package/corpus/templates/assets/netlify.toml +1 -0
  126. package/corpus/templates/brain/app/components/layout/Layout.tsx +3 -0
  127. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +114 -51
  128. package/corpus/templates/brain/app/global.css +1 -1
  129. package/corpus/templates/brain/app/routes/extensions._index.tsx +2 -2
  130. package/corpus/templates/brain/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  131. package/corpus/templates/brain/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  132. package/corpus/templates/brain/netlify.toml +1 -0
  133. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +110 -57
  134. package/corpus/templates/calendar/app/global.css +1 -1
  135. package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +2 -16
  136. package/corpus/templates/calendar/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  137. package/corpus/templates/calendar/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  138. package/corpus/templates/calendar/netlify.toml +1 -0
  139. package/corpus/templates/chat/app/components/layout/Layout.tsx +3 -0
  140. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +113 -51
  141. package/corpus/templates/chat/app/global.css +1 -1
  142. package/corpus/templates/chat/app/routes/extensions._index.tsx +2 -2
  143. package/corpus/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  144. package/corpus/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  145. package/corpus/templates/chat/netlify.toml +1 -0
  146. package/corpus/templates/clips/app/components/library/library-layout.tsx +117 -37
  147. package/corpus/templates/clips/app/components/library/organization-switcher.tsx +2 -2
  148. package/corpus/templates/clips/app/components/player/video-player.tsx +16 -1
  149. package/corpus/templates/clips/app/global.css +1 -1
  150. package/corpus/templates/clips/app/hooks/use-view-tracking.ts +55 -12
  151. package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +2 -16
  152. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +6 -5
  153. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +7 -7
  154. package/corpus/templates/clips/app/routes/share.$shareId.tsx +6 -5
  155. package/corpus/templates/clips/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  156. package/corpus/templates/clips/changelog/2026-07-23-meeting-recording-meters-and-dismissed-prompts.md +6 -0
  157. package/corpus/templates/clips/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  158. package/corpus/templates/clips/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  159. package/corpus/templates/clips/desktop/src/hooks/useMicMeter.ts +1 -1
  160. package/corpus/templates/clips/desktop/src/lib/meeting-notification-dismissal.ts +2 -0
  161. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +1 -3
  162. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +86 -0
  163. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +24 -0
  164. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +5 -69
  165. package/corpus/templates/clips/desktop/src/styles.css +35 -3
  166. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +13 -44
  167. package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +119 -17
  168. package/corpus/templates/clips/netlify.toml +1 -0
  169. package/corpus/templates/clips/server/plugins/db.ts +113 -68
  170. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +69 -49
  171. package/corpus/templates/content/app/global.css +1 -1
  172. package/corpus/templates/content/app/routes/_app.extensions._index.tsx +2 -2
  173. package/corpus/templates/content/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  174. package/corpus/templates/content/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  175. package/corpus/templates/content/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  176. package/corpus/templates/content/netlify.toml +1 -0
  177. package/corpus/templates/design/app/components/layout/Sidebar.tsx +115 -42
  178. package/corpus/templates/design/app/entry.client.tsx +14 -1
  179. package/corpus/templates/design/app/global.css +1 -1
  180. package/corpus/templates/design/app/routes/extensions._index.tsx +2 -2
  181. package/corpus/templates/design/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  182. package/corpus/templates/design/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  183. package/corpus/templates/design/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  184. package/corpus/templates/design/netlify.toml +1 -0
  185. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -1
  186. package/corpus/templates/dispatch/app/global.css +1 -1
  187. package/corpus/templates/dispatch/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  188. package/corpus/templates/dispatch/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  189. package/corpus/templates/dispatch/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  190. package/corpus/templates/dispatch/netlify.toml +1 -0
  191. package/corpus/templates/forms/app/components/layout/Layout.tsx +3 -0
  192. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +113 -82
  193. package/corpus/templates/forms/app/global.css +1 -1
  194. package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +2 -2
  195. package/corpus/templates/forms/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  196. package/corpus/templates/forms/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  197. package/corpus/templates/forms/changelog/2026-07-24-forms-sidebar-actions-now-keep-search-language-feedback-and-.md +6 -0
  198. package/corpus/templates/forms/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  199. package/corpus/templates/forms/netlify.toml +1 -0
  200. package/corpus/templates/macros/app/components/DailyProgress.tsx +5 -5
  201. package/corpus/templates/macros/app/components/ExerciseCard.tsx +2 -2
  202. package/corpus/templates/macros/app/components/MealCard.tsx +2 -2
  203. package/corpus/templates/macros/app/components/WeightCard.tsx +2 -2
  204. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +92 -34
  205. package/corpus/templates/macros/app/components/ui/button.tsx +1 -2
  206. package/corpus/templates/macros/app/components/ui/card.tsx +1 -1
  207. package/corpus/templates/macros/app/global.css +1 -1
  208. package/corpus/templates/macros/app/routes/_index.tsx +1 -1
  209. package/corpus/templates/macros/app/routes/analytics.tsx +4 -7
  210. package/corpus/templates/macros/app/routes/extensions._index.tsx +2 -2
  211. package/corpus/templates/macros/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  212. package/corpus/templates/macros/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  213. package/corpus/templates/macros/netlify.toml +1 -0
  214. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +125 -46
  215. package/corpus/templates/mail/app/global.css +1 -1
  216. package/corpus/templates/mail/app/routes/extensions._index.tsx +2 -2
  217. package/corpus/templates/mail/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  218. package/corpus/templates/mail/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  219. package/corpus/templates/mail/netlify.toml +1 -0
  220. package/corpus/templates/plan/app/components/layout/Layout.tsx +3 -0
  221. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +128 -65
  222. package/corpus/templates/plan/app/global.css +1 -1
  223. package/corpus/templates/plan/app/routes/extensions._index.tsx +2 -2
  224. package/corpus/templates/plan/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  225. package/corpus/templates/plan/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  226. package/corpus/templates/plan/netlify.toml +1 -0
  227. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +116 -36
  228. package/corpus/templates/slides/app/global.css +1 -1
  229. package/corpus/templates/slides/app/routes/extensions._index.tsx +2 -2
  230. package/corpus/templates/slides/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  231. package/corpus/templates/slides/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  232. package/corpus/templates/slides/netlify.toml +1 -0
  233. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +37 -6
  234. package/corpus/templates/tasks/app/global.css +1 -1
  235. package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -2
  236. package/corpus/templates/tasks/app/routes/settings.tsx +31 -0
  237. package/corpus/templates/tasks/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  238. package/corpus/templates/tasks/netlify.toml +1 -0
  239. package/corpus/toolkit/CHANGELOG.md +8 -0
  240. package/corpus/toolkit/README.md +8 -1
  241. package/corpus/toolkit/agent-native.eject.json +1 -1
  242. package/corpus/toolkit/package.json +1 -1
  243. package/corpus/toolkit/src/app-shell/index.ts +1 -0
  244. package/corpus/toolkit/src/app-shell/sidebar-footer-actions.tsx +48 -0
  245. package/corpus/toolkit/src/chat-history.css +52 -1
  246. package/corpus/toolkit/src/design-system/default-adapter.tsx +1 -1
  247. package/corpus/toolkit/src/ui/button.tsx +1 -2
  248. package/corpus/toolkit/src/ui/card.tsx +1 -1
  249. package/corpus/toolkit/src/ui/table.tsx +4 -11
  250. package/dist/agent/production-agent.d.ts.map +1 -1
  251. package/dist/agent/production-agent.js +4 -0
  252. package/dist/agent/production-agent.js.map +1 -1
  253. package/dist/agent/run-manager.d.ts +9 -0
  254. package/dist/agent/run-manager.d.ts.map +1 -1
  255. package/dist/agent/run-manager.js +25 -10
  256. package/dist/agent/run-manager.js.map +1 -1
  257. package/dist/agent/types.d.ts +2 -2
  258. package/dist/agent/types.d.ts.map +1 -1
  259. package/dist/agent/types.js.map +1 -1
  260. package/dist/cli/context-xray-local.js +1 -1
  261. package/dist/cli/context-xray-local.js.map +1 -1
  262. package/dist/cli/index.js +56 -17
  263. package/dist/cli/index.js.map +1 -1
  264. package/dist/cli/skills.d.ts.map +1 -1
  265. package/dist/cli/skills.js +5 -0
  266. package/dist/cli/skills.js.map +1 -1
  267. package/dist/cli/telemetry.d.ts +7 -0
  268. package/dist/cli/telemetry.d.ts.map +1 -1
  269. package/dist/cli/telemetry.js +91 -1
  270. package/dist/cli/telemetry.js.map +1 -1
  271. package/dist/client/AgentPanel.d.ts +7 -1
  272. package/dist/client/AgentPanel.d.ts.map +1 -1
  273. package/dist/client/AgentPanel.js +2 -2
  274. package/dist/client/AgentPanel.js.map +1 -1
  275. package/dist/client/CommandMenu.d.ts +2 -0
  276. package/dist/client/CommandMenu.d.ts.map +1 -1
  277. package/dist/client/CommandMenu.js +12 -1
  278. package/dist/client/CommandMenu.js.map +1 -1
  279. package/dist/client/agent-page/AgentTabsPage.d.ts +4 -0
  280. package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
  281. package/dist/client/agent-page/AgentTabsPage.js +8 -4
  282. package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
  283. package/dist/client/analytics.d.ts.map +1 -1
  284. package/dist/client/analytics.js +7 -0
  285. package/dist/client/analytics.js.map +1 -1
  286. package/dist/client/error-capture.d.ts.map +1 -1
  287. package/dist/client/error-capture.js +8 -1
  288. package/dist/client/error-capture.js.map +1 -1
  289. package/dist/client/extensions/ExtensionsListPage.d.ts +5 -1
  290. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  291. package/dist/client/extensions/ExtensionsListPage.js +6 -4
  292. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  293. package/dist/client/extensions/agent-native-extension-runtime.js +1 -1
  294. package/dist/client/extensions/agent-native-extension-runtime.js.map +1 -1
  295. package/dist/client/navigation/index.d.ts +1 -1
  296. package/dist/client/navigation/index.d.ts.map +1 -1
  297. package/dist/client/navigation/index.js +1 -1
  298. package/dist/client/navigation/index.js.map +1 -1
  299. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  300. package/dist/client/org/OrgSwitcher.js +9 -13
  301. package/dist/client/org/OrgSwitcher.js.map +1 -1
  302. package/dist/client/settings/ExtensionsSettingsContent.d.ts +2 -0
  303. package/dist/client/settings/ExtensionsSettingsContent.d.ts.map +1 -0
  304. package/dist/client/settings/ExtensionsSettingsContent.js +10 -0
  305. package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -0
  306. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  307. package/dist/client/settings/SettingsPanel.js +10 -1
  308. package/dist/client/settings/SettingsPanel.js.map +1 -1
  309. package/dist/deploy/build.js +1 -0
  310. package/dist/deploy/build.js.map +1 -1
  311. package/dist/extensions/theme.js +1 -1
  312. package/dist/extensions/theme.js.map +1 -1
  313. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  314. package/dist/localization/default-messages.d.ts +2 -0
  315. package/dist/localization/default-messages.d.ts.map +1 -1
  316. package/dist/localization/default-messages.js +2 -0
  317. package/dist/localization/default-messages.js.map +1 -1
  318. package/dist/observability/routes.d.ts +3 -3
  319. package/dist/progress/routes.d.ts +1 -1
  320. package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
  321. package/dist/provider-api/actions/provider-api.d.ts +9 -9
  322. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  323. package/dist/resources/handlers.d.ts +1 -1
  324. package/dist/server/analytics.d.ts +9 -4
  325. package/dist/server/analytics.d.ts.map +1 -1
  326. package/dist/server/analytics.js +111 -22
  327. package/dist/server/analytics.js.map +1 -1
  328. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  329. package/dist/server/core-routes-plugin.js +8 -1
  330. package/dist/server/core-routes-plugin.js.map +1 -1
  331. package/dist/server/framework-request-handler.d.ts.map +1 -1
  332. package/dist/server/framework-request-handler.js +17 -27
  333. package/dist/server/framework-request-handler.js.map +1 -1
  334. package/dist/server/realtime-token.d.ts +1 -1
  335. package/dist/styles/agent-native.css +13 -0
  336. package/dist/templates/chat/app/components/layout/Layout.tsx +3 -0
  337. package/dist/templates/chat/app/components/layout/Sidebar.tsx +113 -51
  338. package/dist/templates/chat/app/global.css +1 -1
  339. package/dist/templates/chat/app/routes/extensions._index.tsx +2 -2
  340. package/dist/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  341. package/dist/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  342. package/dist/templates/chat/netlify.toml +1 -0
  343. package/dist/templates/default/app/global.css +1 -1
  344. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  345. package/dist/tracking/error-capture.d.ts +14 -0
  346. package/dist/tracking/error-capture.d.ts.map +1 -0
  347. package/dist/tracking/error-capture.js +113 -0
  348. package/dist/tracking/error-capture.js.map +1 -0
  349. package/dist/tracking/index.d.ts +1 -0
  350. package/dist/tracking/index.d.ts.map +1 -1
  351. package/dist/tracking/index.js +1 -0
  352. package/dist/tracking/index.js.map +1 -1
  353. package/dist/vite/client.d.ts.map +1 -1
  354. package/dist/vite/client.js +2 -0
  355. package/dist/vite/client.js.map +1 -1
  356. package/docs/content/extensions.mdx +23 -4
  357. package/package.json +2 -2
  358. package/src/agent/production-agent.ts +4 -0
  359. package/src/agent/run-manager.ts +36 -10
  360. package/src/agent/types.ts +2 -0
  361. package/src/cli/context-xray-local.ts +1 -1
  362. package/src/cli/index.ts +63 -18
  363. package/src/cli/skills.ts +5 -0
  364. package/src/cli/telemetry.ts +118 -1
  365. package/src/client/AgentPanel.tsx +10 -0
  366. package/src/client/CommandMenu.tsx +13 -1
  367. package/src/client/agent-page/AgentTabsPage.tsx +39 -4
  368. package/src/client/analytics.ts +13 -0
  369. package/src/client/error-capture.ts +6 -1
  370. package/src/client/extensions/ExtensionsListPage.tsx +28 -8
  371. package/src/client/extensions/agent-native-extension-runtime.ts +1 -1
  372. package/src/client/navigation/index.ts +2 -0
  373. package/src/client/org/OrgSwitcher.tsx +14 -32
  374. package/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
  375. package/src/client/settings/SettingsPanel.tsx +10 -0
  376. package/src/deploy/build.ts +3 -0
  377. package/src/extensions/theme.ts +1 -1
  378. package/src/localization/default-messages.ts +2 -0
  379. package/src/server/analytics.ts +154 -25
  380. package/src/server/core-routes-plugin.ts +10 -1
  381. package/src/server/framework-request-handler.ts +17 -26
  382. package/src/styles/agent-native.css +13 -0
  383. package/src/templates/chat/app/components/layout/Layout.tsx +3 -0
  384. package/src/templates/chat/app/components/layout/Sidebar.tsx +113 -51
  385. package/src/templates/chat/app/global.css +1 -1
  386. package/src/templates/chat/app/routes/extensions._index.tsx +2 -2
  387. package/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +6 -0
  388. package/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +6 -0
  389. package/src/templates/chat/netlify.toml +1 -0
  390. package/src/templates/default/app/global.css +1 -1
  391. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  392. package/src/tracking/error-capture.ts +151 -0
  393. package/src/tracking/index.ts +5 -0
  394. package/src/vite/client.ts +6 -0
  395. package/corpus/templates/analytics/app/components/layout/NewAnalysisDialog.tsx +0 -165
  396. package/corpus/templates/analytics/app/pages/analyses/AnalysesList.tsx +0 -175
@@ -4,15 +4,16 @@ import {
4
4
  } from "@agent-native/core/client/agent-chat";
5
5
  import { appPath } from "@agent-native/core/client/api-path";
6
6
  import { DevDatabaseLink } from "@agent-native/core/client/db-admin";
7
- import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
8
7
  import { getBrowserTabId } from "@agent-native/core/client/hooks";
9
- import { useT } from "@agent-native/core/client/i18n";
8
+ import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
9
+ import { openCommandMenu } from "@agent-native/core/client/navigation";
10
10
  import {
11
11
  InvitationBanner,
12
12
  OrgSwitcher,
13
13
  useOrgRole,
14
14
  } from "@agent-native/core/client/org";
15
15
  import { FeedbackButton } from "@agent-native/core/client/ui";
16
+ import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
16
17
  import {
17
18
  IconInbox,
18
19
  IconArchive,
@@ -31,6 +32,7 @@ import {
31
32
  IconShare,
32
33
  IconHierarchy2,
33
34
  IconSettings,
35
+ IconSearch,
34
36
  } from "@tabler/icons-react";
35
37
  import { ReactNode, useEffect, useMemo, useState } from "react";
36
38
  import { NavLink, useLocation, useParams } from "react-router";
@@ -155,6 +157,59 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
155
157
  );
156
158
  const [headerSlot, setHeaderSlot] = useState<HTMLElement | null>(null);
157
159
  const showCollapsedSidebar = sidebarCollapsed && !isMobile;
160
+
161
+ const collapseButton = !isMobile ? (
162
+ <Tooltip>
163
+ <TooltipTrigger asChild>
164
+ <button
165
+ type="button"
166
+ aria-label={
167
+ showCollapsedSidebar
168
+ ? t("navigation.expandSidebar")
169
+ : t("navigation.collapseSidebar")
170
+ }
171
+ className="flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/60 hover:text-foreground"
172
+ onClick={() => setSidebarCollapsed((value) => !value)}
173
+ >
174
+ {showCollapsedSidebar ? (
175
+ <IconLayoutSidebarLeftExpand className="h-4 w-4" />
176
+ ) : (
177
+ <IconLayoutSidebarLeftCollapse className="h-4 w-4" />
178
+ )}
179
+ </button>
180
+ </TooltipTrigger>
181
+ <TooltipContent side="right">
182
+ {showCollapsedSidebar
183
+ ? t("navigation.expandSidebar")
184
+ : t("navigation.collapseSidebar")}
185
+ </TooltipContent>
186
+ </Tooltip>
187
+ ) : null;
188
+ const searchButton = (
189
+ <Tooltip>
190
+ <TooltipTrigger asChild>
191
+ <button
192
+ type="button"
193
+ aria-label={t("root.commandSearch")}
194
+ className="flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/60 hover:text-foreground"
195
+ onClick={openCommandMenu}
196
+ >
197
+ <IconSearch className="h-4 w-4" />
198
+ </button>
199
+ </TooltipTrigger>
200
+ <TooltipContent side="right">{t("root.commandSearch")}</TooltipContent>
201
+ </Tooltip>
202
+ );
203
+ const translateButton = (
204
+ <LanguagePicker variant="ghost-icon" label={t("settings.languageLabel")} />
205
+ );
206
+ const feedbackButton = (
207
+ <FeedbackButton
208
+ variant={showCollapsedSidebar ? "icon" : "sidebar"}
209
+ side="right"
210
+ className={showCollapsedSidebar ? "size-8" : "min-w-0"}
211
+ />
212
+ );
158
213
  const sidebarHasNewRecordingAction = isMobile
159
214
  ? sidebarOpen
160
215
  : !sidebarCollapsed;
@@ -241,9 +296,17 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
241
296
  icon: IconTrash,
242
297
  match: (p) => p.startsWith("/trash"),
243
298
  },
299
+ ];
300
+
301
+ const bottomNavItems: {
302
+ to: string;
303
+ label: string;
304
+ icon: React.ComponentType<{ className?: string }>;
305
+ match: (path: string) => boolean;
306
+ }[] = [
244
307
  {
245
308
  to: "/agent",
246
- label: t("navigation.agent"),
309
+ label: t("settings.agentTitle"),
247
310
  icon: IconHierarchy2,
248
311
  match: (p) => p.startsWith("/agent"),
249
312
  },
@@ -307,35 +370,6 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
307
370
  </>
308
371
  )}
309
372
  </div>
310
-
311
- <Tooltip>
312
- <TooltipTrigger asChild>
313
- <Button
314
- type="button"
315
- variant="ghost"
316
- size="icon"
317
- className="hidden h-7 w-7 shrink-0 text-muted-foreground hover:text-foreground md:inline-flex"
318
- aria-label={
319
- showCollapsedSidebar
320
- ? t("navigation.expandSidebar")
321
- : t("navigation.collapseSidebar")
322
- }
323
- aria-expanded={!showCollapsedSidebar}
324
- onClick={() => setSidebarCollapsed((value) => !value)}
325
- >
326
- {showCollapsedSidebar ? (
327
- <IconLayoutSidebarLeftExpand className="h-4 w-4" />
328
- ) : (
329
- <IconLayoutSidebarLeftCollapse className="h-4 w-4" />
330
- )}
331
- </Button>
332
- </TooltipTrigger>
333
- <TooltipContent side="right">
334
- {showCollapsedSidebar
335
- ? t("navigation.expandSidebar")
336
- : t("navigation.collapseSidebar")}
337
- </TooltipContent>
338
- </Tooltip>
339
373
  </div>
340
374
  <div className="min-h-0 flex-1 overflow-y-auto">
341
375
  {showCollapsedSidebar ? (
@@ -519,6 +553,49 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
519
553
  )}
520
554
  </div>
521
555
 
556
+ <div className="shrink-0">
557
+ {showCollapsedSidebar ? (
558
+ <nav className="flex flex-col items-center gap-1 px-2 py-1">
559
+ {bottomNavItems.map(({ to, label, icon: Icon, match }) => (
560
+ <Tooltip key={to}>
561
+ <TooltipTrigger asChild>
562
+ <NavLink
563
+ to={to}
564
+ aria-label={label}
565
+ className={cn(
566
+ "flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/60 hover:text-foreground",
567
+ match(location.pathname) &&
568
+ "bg-primary/10 text-primary hover:bg-primary/10 hover:text-primary",
569
+ )}
570
+ >
571
+ <Icon className="h-4 w-4" />
572
+ </NavLink>
573
+ </TooltipTrigger>
574
+ <TooltipContent side="right">{label}</TooltipContent>
575
+ </Tooltip>
576
+ ))}
577
+ </nav>
578
+ ) : (
579
+ <nav className="space-y-0.5 border-t border-border px-2 py-1">
580
+ {bottomNavItems.map(({ to, label, icon: Icon, match }) => (
581
+ <NavLink
582
+ key={to}
583
+ to={to}
584
+ className={cn(
585
+ "flex items-center gap-2 rounded px-2 py-1.5 text-xs",
586
+ match(location.pathname)
587
+ ? "bg-primary/10 font-medium text-primary"
588
+ : "text-foreground hover:bg-accent/60",
589
+ )}
590
+ >
591
+ <Icon className="h-4 w-4" />
592
+ <span className="flex-1 truncate">{label}</span>
593
+ </NavLink>
594
+ ))}
595
+ </nav>
596
+ )}
597
+ </div>
598
+
522
599
  {!showCollapsedSidebar && (
523
600
  <>
524
601
  <div className="shrink-0 space-y-1.5 px-2 py-1.5">
@@ -539,17 +616,20 @@ export function LibraryLayout({ children }: LibraryLayoutProps) {
539
616
  {(isMobile || !pageHasHeaderSearch) && <SearchBar />}
540
617
  </div>
541
618
 
542
- <div className="shrink-0 px-1 py-1">
543
- <ExtensionsSidebarSection />
544
- </div>
545
-
546
619
  <div className="shrink-0 space-y-2 px-3 py-2">
547
620
  <OrgSwitcher settingsPath="/settings/organization" />
548
621
  <DevDatabaseLink />
549
- <FeedbackButton />
550
622
  </div>
551
623
  </>
552
624
  )}
625
+ <SidebarFooterActions
626
+ collapsed={showCollapsedSidebar}
627
+ feedback={feedbackButton}
628
+ translate={translateButton}
629
+ search={searchButton}
630
+ collapse={collapseButton}
631
+ className={showCollapsedSidebar ? undefined : "px-0 py-0"}
632
+ />
553
633
  </aside>
554
634
 
555
635
  <AgentSidebar
@@ -59,8 +59,8 @@ export function OrganizationSwitcher({ className }: OrganizationSwitcherProps) {
59
59
  <button
60
60
  type="button"
61
61
  className={cn(
62
- "flex w-full items-center gap-2 rounded-md border border-border bg-background px-2 py-1.5 text-start",
63
- "hover:bg-accent",
62
+ "flex w-full items-center gap-2 rounded-md border-0 bg-accent/50 px-2 py-1.5 text-start",
63
+ "hover:bg-accent/70",
64
64
  className,
65
65
  )}
66
66
  >
@@ -209,6 +209,13 @@ export interface VideoPlayerProps {
209
209
  * a visible frame for missing or blank auto-generated library thumbnails.
210
210
  */
211
211
  role?: "owner" | "admin" | "editor" | "viewer";
212
+ /**
213
+ * Called with the live `<video>` DOM node whenever it is created or
214
+ * destroyed (e.g. swapping to/from the Loom iframe or unsupported-format
215
+ * placeholder). Lets a caller key an effect off the actual element
216
+ * lifecycle instead of polling an imperative-handle getter.
217
+ */
218
+ onVideoElementChange?: (video: HTMLVideoElement | null) => void;
212
219
  }
213
220
 
214
221
  export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
@@ -245,6 +252,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
245
252
  cover,
246
253
  recordingId,
247
254
  role,
255
+ onVideoElementChange,
248
256
  } = props;
249
257
 
250
258
  const resolvedVideoSrc = useMemo(
@@ -252,6 +260,13 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
252
260
  [videoUrl],
253
261
  );
254
262
  const videoRef = useRef<HTMLVideoElement | null>(null);
263
+ const setVideoNode = useCallback(
264
+ (el: HTMLVideoElement | null) => {
265
+ videoRef.current = el;
266
+ onVideoElementChange?.(el);
267
+ },
268
+ [onVideoElementChange],
269
+ );
255
270
  const containerRef = useRef<HTMLDivElement | null>(null);
256
271
  const idleTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
257
272
  const touchTapCandidateRef = useRef<{
@@ -1262,7 +1277,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
1262
1277
  </div>
1263
1278
  ) : activeVideoSrc ? (
1264
1279
  <video
1265
- ref={videoRef}
1280
+ ref={setVideoNode}
1266
1281
  src={domVideoSrc}
1267
1282
  poster={resolveLocalUrl(thumbnailUrl)}
1268
1283
  // `crossOrigin` is only needed so the owner's canvas thumbnail
@@ -22,7 +22,7 @@
22
22
  --muted-foreground: 0 0% 45%;
23
23
  --accent: 0 0% 95%;
24
24
  --accent-foreground: 0 0% 15%;
25
- --destructive: 0 84% 60%;
25
+ --destructive: 0 91% 71%;
26
26
  --destructive-foreground: 0 0% 98%;
27
27
  --border: 0 0% 90%;
28
28
  --input: 0 0% 90%;
@@ -34,7 +34,14 @@ function createViewSessionId(recordingId: string): string {
34
34
 
35
35
  export interface UseViewTrackingOpts {
36
36
  recordingId: string;
37
- videoRef: React.RefObject<HTMLVideoElement | null>;
37
+ /**
38
+ * The live `<video>` DOM node, or `null` when there is none (e.g. a Loom
39
+ * iframe embed). Pass the actual element — not a ref wrapper — so this
40
+ * hook's effect can depend on it directly and React's own dependency
41
+ * comparison decides when to reattach, instead of hand-rolled identity
42
+ * bookkeeping.
43
+ */
44
+ videoEl: HTMLVideoElement | null;
38
45
  durationMs: number;
39
46
  /** Disable tracking entirely (e.g. for the recording's owner viewing their own clip). */
40
47
  disabled?: boolean;
@@ -46,10 +53,24 @@ export interface UseViewTrackingOpts {
46
53
  * Wires up the view-event tracker for a player instance. Fires a "view-start"
47
54
  * on mount, then throttled "watch-progress" every 5s while playing, plus
48
55
  * seek/pause/resume events and a final flush on unmount.
56
+ *
57
+ * The effect depends on `[recordingId, videoEl, trackOpenWithoutVideo,
58
+ * disabled]`, so React naturally creates a fresh closure — and runs the
59
+ * previous one's cleanup — exactly when any of those actually change (a
60
+ * different video element, a different recording, or the no-video/embed
61
+ * mode flipping). Each closure captures its own `recordingId` and `videoEl`,
62
+ * so a cleanup's final flush always describes the session it belonged to,
63
+ * never a session that has since replaced it.
64
+ *
65
+ * `durationMs` is intentionally excluded from the dependency array — it can
66
+ * load asynchronously after the video/recording is already attached, and
67
+ * reattaching just for that would be wasted work. It's kept in a ref that's
68
+ * synced every render and read fresh inside `post()`.
49
69
  */
50
70
  export function useViewTracking(opts: UseViewTrackingOpts) {
51
- const { recordingId, videoRef, durationMs, disabled, trackOpenWithoutVideo } =
71
+ const { recordingId, videoEl, durationMs, disabled, trackOpenWithoutVideo } =
52
72
  opts;
73
+
53
74
  const watchMsRef = useRef(0);
54
75
  const lastTickRef = useRef<number | null>(null);
55
76
  const startedRef = useRef(false);
@@ -57,11 +78,25 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
57
78
  const lastSentProgressRef = useRef(0);
58
79
  const maxPctRef = useRef(0);
59
80
  const viewSessionRef = useRef<string | null>(null);
81
+ const durationMsRef = useRef(durationMs);
82
+ const recordingIdRef = useRef(recordingId);
83
+
84
+ durationMsRef.current = durationMs;
85
+ recordingIdRef.current = recordingId;
60
86
 
61
87
  useEffect(() => {
62
88
  if (disabled) return;
63
- const video = videoRef.current;
64
- if (!video) {
89
+
90
+ // Reset per-session counters — this effect only reruns when the video
91
+ // element, recording, or embed mode actually change.
92
+ watchMsRef.current = 0;
93
+ lastTickRef.current = null;
94
+ startedRef.current = false;
95
+ lastSentProgressRef.current = 0;
96
+ maxPctRef.current = 0;
97
+ viewSessionRef.current = null;
98
+
99
+ if (!videoEl) {
65
100
  if (
66
101
  !trackOpenWithoutVideo ||
67
102
  !recordingId ||
@@ -69,6 +104,10 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
69
104
  ) {
70
105
  return;
71
106
  }
107
+ // Persists for the hook's lifetime (never reset on cleanup): this is
108
+ // what stops a React StrictMode dev mount->cleanup->remount cycle
109
+ // from double-posting the same iframe-open view-start, since — unlike
110
+ // the with-video path below — there's no native DOM event gating it.
72
111
  openTrackedRecordingRef.current = recordingId;
73
112
  viewSessionRef.current = createViewSessionId(recordingId);
74
113
  fetch(`${appBasePath()}/api/view-event`, {
@@ -90,6 +129,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
90
129
  return;
91
130
  }
92
131
 
132
+ const video = videoEl;
93
133
  const sessionId = getSessionId();
94
134
  viewSessionRef.current = createViewSessionId(recordingId);
95
135
  let progressTimer: ReturnType<typeof setInterval> | null = null;
@@ -105,8 +145,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
105
145
  | "reaction",
106
146
  extra?: Record<string, unknown>,
107
147
  ) {
108
- const v = videoRef.current;
109
- if (!v) return;
148
+ const durationMs = durationMsRef.current;
110
149
  const completedPct =
111
150
  durationMs > 0 ? (watchMsRef.current / durationMs) * 100 : 0;
112
151
  maxPctRef.current = Math.max(
@@ -120,12 +159,13 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
120
159
  body: JSON.stringify({
121
160
  recordingId,
122
161
  kind,
123
- timestampMs: Math.floor(v.currentTime * 1000),
162
+ timestampMs: Math.floor(video.currentTime * 1000),
124
163
  sessionId,
125
164
  viewSessionId: viewSessionRef.current,
126
165
  totalWatchMs: Math.floor(watchMsRef.current),
127
166
  completedPct: Math.floor(maxPctRef.current),
128
- scrubbedToEnd: v.duration > 0 && v.currentTime >= v.duration - 0.5,
167
+ scrubbedToEnd:
168
+ video.duration > 0 && video.currentTime >= video.duration - 0.5,
129
169
  payload: extra,
130
170
  }),
131
171
  }).catch(() => {});
@@ -186,10 +226,13 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
186
226
  video.removeEventListener("seeked", onSeek);
187
227
  video.removeEventListener("ended", onEnded);
188
228
  if (progressTimer) clearInterval(progressTimer);
189
- // Flush final progress.
229
+ // Flush final progress, still scoped to this closure's own video and
230
+ // recordingId — never one a later render has since moved on to.
190
231
  if (startedRef.current) post("watch-progress");
191
232
  };
192
- }, [recordingId, videoRef, durationMs, disabled, trackOpenWithoutVideo]);
233
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- durationMs is
234
+ // deliberately excluded; it's read live from durationMsRef inside post().
235
+ }, [recordingId, videoEl, trackOpenWithoutVideo, disabled]);
193
236
 
194
237
  return {
195
238
  reportCtaClick: () => {
@@ -198,7 +241,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
198
241
  keepalive: true,
199
242
  headers: { "Content-Type": "application/json" },
200
243
  body: JSON.stringify({
201
- recordingId,
244
+ recordingId: recordingIdRef.current,
202
245
  kind: "cta-click",
203
246
  sessionId: getSessionId(),
204
247
  }),
@@ -210,7 +253,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
210
253
  keepalive: true,
211
254
  headers: { "Content-Type": "application/json" },
212
255
  body: JSON.stringify({
213
- recordingId,
256
+ recordingId: recordingIdRef.current,
214
257
  kind: "reaction",
215
258
  sessionId: getSessionId(),
216
259
  payload: { emoji },
@@ -1,19 +1,5 @@
1
- import { ExtensionsListPage } from "@agent-native/core/client/extensions";
2
- import { useT } from "@agent-native/core/client/i18n";
3
-
4
- import { PageHeader } from "@/components/library/page-header";
1
+ import { Navigate } from "react-router";
5
2
 
6
3
  export default function ExtensionsRoute() {
7
- const t = useT();
8
-
9
- return (
10
- <>
11
- <PageHeader>
12
- <h1 className="text-base font-semibold tracking-tight truncate">
13
- {t("navigation.extensions")}
14
- </h1>
15
- </PageHeader>
16
- <ExtensionsListPage />
17
- </>
18
- );
4
+ return <Navigate to="/settings#extensions" replace />;
19
5
  }
@@ -131,13 +131,13 @@ export default function EmbedRoute() {
131
131
  const firstCta = ctas[0] ?? null;
132
132
  const isLoomEmbedBacked = isLoomEmbedBackedRecording(recording);
133
133
 
134
+ const [trackedVideoEl, setTrackedVideoEl] = useState<HTMLVideoElement | null>(
135
+ null,
136
+ );
137
+
134
138
  const tracking = useViewTracking({
135
139
  recordingId: shareId ?? "",
136
- videoRef: {
137
- get current() {
138
- return playerRef.current?.video ?? null;
139
- },
140
- } as any,
140
+ videoEl: trackedVideoEl,
141
141
  durationMs: recording?.durationMs ?? 0,
142
142
  trackOpenWithoutVideo: isLoomEmbedBacked,
143
143
  });
@@ -193,6 +193,7 @@ export default function EmbedRoute() {
193
193
  <div className="fixed inset-0 h-dvh w-dvw overflow-hidden bg-black">
194
194
  <VideoPlayer
195
195
  ref={playerRef}
196
+ onVideoElementChange={setTrackedVideoEl}
196
197
  recordingId={recording.id}
197
198
  videoUrl={recording.videoUrl}
198
199
  videoFormat={recording.videoFormat}
@@ -800,16 +800,15 @@ export default function RecordingPage() {
800
800
 
801
801
  usePlayerShortcuts({ playerRef, chapters });
802
802
 
803
+ const [trackedVideoEl, setTrackedVideoEl] = useState<HTMLVideoElement | null>(
804
+ null,
805
+ );
806
+
803
807
  const tracking = useViewTracking({
804
808
  recordingId: recordingId ?? "",
805
- videoRef: {
806
- get current() {
807
- return playerRef.current?.video ?? null;
808
- },
809
- } as any,
809
+ videoEl: trackedVideoEl,
810
810
  durationMs: recording?.durationMs ?? 0,
811
- // Skip tracking for the owner they shouldn't inflate their own views.
812
- disabled: role === "owner",
811
+ disabled: role === "owner", // Skip tracking for the owner: they shouldn't inflate their own views.
813
812
  });
814
813
 
815
814
  if (!recordingId) return null;
@@ -1545,6 +1544,7 @@ export default function RecordingPage() {
1545
1544
  <div className="relative aspect-video w-full xl:min-h-0 xl:flex-1 xl:aspect-auto">
1546
1545
  <VideoPlayer
1547
1546
  ref={playerRef}
1547
+ onVideoElementChange={setTrackedVideoEl}
1548
1548
  recordingId={recording.id}
1549
1549
  videoUrl={recording.videoUrl}
1550
1550
  videoFormat={recording.videoFormat}
@@ -579,13 +579,13 @@ export default function ShareRoute() {
579
579
 
580
580
  usePlayerShortcuts({ playerRef });
581
581
 
582
+ const [trackedVideoEl, setTrackedVideoEl] = useState<HTMLVideoElement | null>(
583
+ null,
584
+ );
585
+
582
586
  const tracking = useViewTracking({
583
587
  recordingId: shareId ?? "",
584
- videoRef: {
585
- get current() {
586
- return playerRef.current?.video ?? null;
587
- },
588
- } as any,
588
+ videoEl: trackedVideoEl,
589
589
  durationMs: recording?.durationMs ?? 0,
590
590
  trackOpenWithoutVideo: isLoomEmbedBacked,
591
591
  });
@@ -961,6 +961,7 @@ export default function ShareRoute() {
961
961
  <div className="aspect-video w-full lg:min-h-0 lg:flex-1 lg:aspect-auto">
962
962
  <VideoPlayer
963
963
  ref={playerRef}
964
+ onVideoElementChange={setTrackedVideoEl}
964
965
  recordingId={recording.id}
965
966
  videoUrl={recording.videoUrl}
966
967
  videoFormat={recording.videoFormat}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-23
4
+ ---
5
+
6
+ Agent settings are clearly labeled Manage agent in the sidebar.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-23
4
+ ---
5
+
6
+ Meeting recording meters now use thin, responsive audio bars, while dismissed reminders stay dismissed and frontmost Zoom detection stays quiet unless Auto mode is enabled.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Secondary controls and dashboard surfaces now use quieter borderless styling.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-07-24
4
+ ---
5
+
6
+ Sidebar utility controls now follow a consistent footer order.
@@ -88,7 +88,7 @@ export function sampleLevels(
88
88
  const levels: number[] = [];
89
89
  for (let i = 0; i < barCount; i++) {
90
90
  const idx = Math.min(usable - 1, Math.floor((i / barCount) * usable));
91
- levels.push(data[idx] / 255);
91
+ levels.push(Math.min(1, (data[idx] / 255) * 1.65));
92
92
  }
93
93
  return levels;
94
94
  }
@@ -3,6 +3,7 @@ import { invoke } from "@tauri-apps/api/core";
3
3
  export interface DismissibleMeetingNotification {
4
4
  type: "calendar" | "adhoc";
5
5
  meetingId: string;
6
+ joinUrl?: string | null;
6
7
  platform?: string | null;
7
8
  scheduledStart?: string | null;
8
9
  scheduledEnd?: string | null;
@@ -21,6 +22,7 @@ export async function dismissMeetingNotification(
21
22
  await nativeInvoke("dismiss_meeting_notification", {
22
23
  meetingId: notification.meetingId,
23
24
  notificationType: notification.type,
25
+ joinUrl: notification.joinUrl ?? null,
24
26
  platform: notification.platform ?? null,
25
27
  scheduledStart: notification.scheduledStart ?? null,
26
28
  scheduledEnd: notification.scheduledEnd ?? null,
@@ -1139,7 +1139,7 @@ export function installDesktopVoiceDictation(
1139
1139
  * `stop()` works the same way as for the browser path.
1140
1140
  *
1141
1141
  * No `getUserMedia()` here — the audio engine handles the mic on the Rust
1142
- * side. The synthetic meter still drives the flow-bar's waveform.
1142
+ * side and emits the real level events consumed by the flow bar.
1143
1143
  */
1144
1144
  const startNative = async (
1145
1145
  cleanupProvider?: ServerVoiceProvider,
@@ -1191,7 +1191,6 @@ export function installDesktopVoiceDictation(
1191
1191
  };
1192
1192
  session = next;
1193
1193
  startInFlight = false;
1194
- startSyntheticMeter(next);
1195
1194
  try {
1196
1195
  // Bias the recognizer toward the user's learned vocabulary. Stage
1197
1196
  // the list via a separate command so meeting capture can pass mic
@@ -1299,7 +1298,6 @@ export function installDesktopVoiceDictation(
1299
1298
  };
1300
1299
  session = next;
1301
1300
  startInFlight = false;
1302
- startSyntheticMeter(next);
1303
1301
  if (stopRequestedBeforeReady) {
1304
1302
  stop();
1305
1303
  }