@agent-native/core 0.79.17 → 0.79.19

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 (355) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +14 -0
  3. package/corpus/core/docs/content/file-uploads.md +11 -4
  4. package/corpus/core/docs/content/locales/ar-SA/multi-app-workspace.md +3 -3
  5. package/corpus/core/docs/content/locales/de-DE/multi-app-workspace.md +3 -3
  6. package/corpus/core/docs/content/locales/es-ES/multi-app-workspace.md +3 -3
  7. package/corpus/core/docs/content/locales/fr-FR/multi-app-workspace.md +3 -3
  8. package/corpus/core/docs/content/locales/hi-IN/multi-app-workspace.md +3 -3
  9. package/corpus/core/docs/content/locales/ja-JP/multi-app-workspace.md +3 -3
  10. package/corpus/core/docs/content/locales/ko-KR/multi-app-workspace.md +3 -3
  11. package/corpus/core/docs/content/locales/pt-BR/multi-app-workspace.md +3 -3
  12. package/corpus/core/docs/content/locales/zh-CN/multi-app-workspace.md +3 -3
  13. package/corpus/core/docs/content/locales/zh-TW/multi-app-workspace.md +3 -3
  14. package/corpus/core/docs/content/multi-app-workspace.md +3 -3
  15. package/corpus/core/docs/content/template-clips.md +14 -5
  16. package/corpus/core/package.json +1 -1
  17. package/corpus/core/src/agent/engine/builder-engine.ts +8 -3
  18. package/corpus/core/src/cli/mcp.ts +11 -6
  19. package/corpus/core/src/client/AssistantChat.tsx +6 -2
  20. package/corpus/core/src/client/chat/markdown-renderer.tsx +1 -0
  21. package/corpus/core/src/client/i18n.tsx +77 -65
  22. package/corpus/core/src/client/index.ts +7 -1
  23. package/corpus/core/src/client/org/OrgSwitcher.tsx +5 -5
  24. package/corpus/core/src/client/org/TeamPage.tsx +11 -3
  25. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +216 -0
  26. package/corpus/core/src/client/settings/index.ts +5 -0
  27. package/corpus/core/src/file-upload/index.ts +1 -0
  28. package/corpus/core/src/file-upload/registry.ts +22 -6
  29. package/corpus/core/src/file-upload/types.ts +6 -1
  30. package/corpus/core/src/integrations/adapters/email.ts +26 -18
  31. package/corpus/core/src/integrations/adapters/slack.ts +8 -7
  32. package/corpus/core/src/integrations/adapters/telegram.ts +9 -11
  33. package/corpus/core/src/integrations/adapters/whatsapp.ts +12 -9
  34. package/corpus/core/src/integrations/plugin.ts +79 -13
  35. package/corpus/core/src/onboarding/default-steps.ts +6 -3
  36. package/corpus/core/src/onboarding/types.ts +1 -1
  37. package/corpus/core/src/org/handlers.ts +1 -1
  38. package/corpus/core/src/server/agent-chat-plugin.ts +4 -7
  39. package/corpus/core/src/server/better-auth-instance.ts +19 -62
  40. package/corpus/core/src/server/core-routes-plugin.ts +93 -180
  41. package/corpus/core/src/server/create-server.ts +55 -116
  42. package/corpus/core/src/server/email-actions.ts +3 -6
  43. package/corpus/core/src/server/email.ts +52 -17
  44. package/corpus/core/src/server/index.ts +2 -1
  45. package/corpus/core/src/server/scoped-key-storage.ts +223 -0
  46. package/corpus/core/src/shared/agent-env.ts +3 -3
  47. package/corpus/core/src/sharing/actions/share-resource.ts +1 -1
  48. package/corpus/core/src/styles/agent-native.css +47 -3
  49. package/corpus/core/src/templates/workspace-root/AGENTS.md +3 -2
  50. package/corpus/core/src/templates/workspace-root/README.md +1 -1
  51. package/corpus/core/src/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
  52. package/corpus/core/src/terminal/pty-server.ts +3 -38
  53. package/corpus/core/src/triggers/dispatcher.ts +1 -2
  54. package/corpus/templates/.retired/issues/package.json +7 -0
  55. package/corpus/templates/.retired/meeting-notes/package.json +7 -0
  56. package/corpus/templates/.retired/recruiting/package.json +7 -0
  57. package/corpus/templates/.retired/scheduling/package.json +7 -0
  58. package/corpus/templates/.retired/voice/package.json +7 -0
  59. package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
  60. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -18
  61. package/corpus/templates/analytics/app/global.css +15 -0
  62. package/corpus/templates/analytics/app/i18n/zh-TW.ts +7 -1
  63. package/corpus/templates/analytics/app/i18n-data.ts +71 -2
  64. package/corpus/templates/analytics/app/pages/Ask.tsx +1 -1
  65. package/corpus/templates/analytics/app/pages/Settings.tsx +120 -73
  66. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +0 -11
  67. package/corpus/templates/analytics/app/routes/catalog.tsx +33 -176
  68. package/corpus/templates/analytics/app/routes/team.tsx +3 -2
  69. package/corpus/templates/analytics/changelog/2026-06-26-dashboard-templates-are-tucked-into-settings-and-show-simple.md +6 -0
  70. package/corpus/templates/analytics/changelog/2026-06-26-the-ask-tab-uses-a-softer-dark-gray-canvas-while-sidebar-cha.md +6 -0
  71. package/corpus/templates/analytics/changelog/2026-06-26-the-sessions-page-shows-a-single-page-title-instead-of-repea.md +6 -0
  72. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +37 -28
  73. package/corpus/templates/assets/app/routes/settings.tsx +65 -43
  74. package/corpus/templates/assets/app/routes/team.tsx +2 -10
  75. package/corpus/templates/brain/app/routes/settings.tsx +390 -358
  76. package/corpus/templates/brain/app/routes/team.tsx +2 -8
  77. package/corpus/templates/calendar/actions/db-connect.ts +5 -29
  78. package/corpus/templates/calendar/app/components/CloudUpgrade.tsx +8 -51
  79. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +2 -1
  80. package/corpus/templates/calendar/app/components/calendar/GoogleSetupWizard.tsx +4 -2
  81. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +0 -2
  82. package/corpus/templates/calendar/app/pages/Settings.tsx +304 -271
  83. package/corpus/templates/calendar/app/routes/_app.team.tsx +2 -17
  84. package/corpus/templates/calendar/server/handlers/google-auth.ts +22 -9
  85. package/corpus/templates/calendar/server/lib/booking-emails.ts +1 -1
  86. package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +1 -1
  87. package/corpus/templates/calendar/server/lib/google-calendar.ts +48 -28
  88. package/corpus/templates/chat/app/components/layout/Header.tsx +0 -1
  89. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +4 -2
  90. package/corpus/templates/chat/app/routes/settings.tsx +54 -54
  91. package/corpus/templates/chat/app/routes/team.tsx +2 -10
  92. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +7 -2
  93. package/corpus/templates/clips/.agents/skills/recording/SKILL.md +1 -1
  94. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +7 -0
  95. package/corpus/templates/clips/AGENTS.md +8 -0
  96. package/corpus/templates/clips/actions/invite-member.ts +1 -1
  97. package/corpus/templates/clips/actions/request-transcript.ts +1 -1
  98. package/corpus/templates/clips/app/components/library/library-layout.tsx +325 -333
  99. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +80 -40
  100. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +2 -0
  101. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +629 -643
  102. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +263 -158
  103. package/corpus/templates/clips/app/routes/share.$shareId.tsx +10 -2
  104. package/corpus/templates/clips/changelog/2026-06-26-long-desktop-recordings-are-checkpointed-so-macos-finalizati.md +6 -0
  105. package/corpus/templates/clips/changelog/2026-06-26-non-mac-desktop-recordings-wait-for-upload-transcription.md +6 -0
  106. package/corpus/templates/clips/changelog/2026-06-26-recording-details-button-stays-at-the-far-right-on-small-screen.md +6 -0
  107. package/corpus/templates/clips/changelog/2026-06-26-s3-compatible-storage-keys-now-save-securely-from-clips-sett.md +6 -0
  108. package/corpus/templates/clips/changelog/2026-06-26-shared-clip-links-guide-agents-through-processing-transcripts.md +6 -0
  109. package/corpus/templates/clips/changelog/2026-06-26-the-agent-sidebar-now-slides-in-smoothly-without-duplicate-e.md +6 -0
  110. package/corpus/templates/clips/changelog/2026-06-26-the-clip-details-sidebar-now-collapses-into-a-slide-out-pane.md +6 -0
  111. package/corpus/templates/clips/desktop/src/lib/recorder.ts +55 -3
  112. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +217 -5
  113. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -0
  114. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +176 -5
  115. package/corpus/templates/clips/server/lib/public-agent-context.ts +31 -0
  116. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +60 -14
  117. package/corpus/templates/clips/server/lib/video-storage.ts +37 -9
  118. package/corpus/templates/clips/server/routes/api/agent-transcript.json.get.ts +5 -0
  119. package/corpus/templates/content/app/components/layout/Header.tsx +0 -1
  120. package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +1 -0
  121. package/corpus/templates/content/app/routes/_app.settings.tsx +54 -55
  122. package/corpus/templates/content/app/routes/_app.team.tsx +2 -28
  123. package/corpus/templates/content/server/lib/notion.ts +43 -11
  124. package/corpus/templates/content/server/routes/api/notion/auth-url.get.ts +2 -2
  125. package/corpus/templates/content/server/routes/api/notion/status.get.ts +3 -3
  126. package/corpus/templates/design/app/routes/settings.tsx +60 -38
  127. package/corpus/templates/design/app/routes/team.tsx +2 -10
  128. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +2 -2
  129. package/corpus/templates/dispatch/app/routes/settings.tsx +70 -55
  130. package/corpus/templates/dispatch/app/routes/team.tsx +5 -1
  131. package/corpus/templates/forms/actions/db-connect.ts +7 -36
  132. package/corpus/templates/forms/actions/navigate.ts +2 -2
  133. package/corpus/templates/forms/app/components/CloudUpgrade.tsx +8 -47
  134. package/corpus/templates/forms/app/components/layout/Header.tsx +0 -1
  135. package/corpus/templates/forms/app/components/layout/Layout.tsx +42 -25
  136. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +35 -76
  137. package/corpus/templates/forms/app/global.css +9 -25
  138. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +4 -4
  139. package/corpus/templates/forms/app/i18n/ar-SA.ts +1 -0
  140. package/corpus/templates/forms/app/i18n/de-DE.ts +1 -0
  141. package/corpus/templates/forms/app/i18n/en-US.ts +1 -0
  142. package/corpus/templates/forms/app/i18n/es-ES.ts +1 -0
  143. package/corpus/templates/forms/app/i18n/fr-FR.ts +1 -0
  144. package/corpus/templates/forms/app/i18n/hi-IN.ts +1 -0
  145. package/corpus/templates/forms/app/i18n/ja-JP.ts +1 -0
  146. package/corpus/templates/forms/app/i18n/ko-KR.ts +1 -0
  147. package/corpus/templates/forms/app/i18n/pt-BR.ts +1 -0
  148. package/corpus/templates/forms/app/i18n/zh-CN.ts +1 -0
  149. package/corpus/templates/forms/app/i18n/zh-TW.ts +1 -0
  150. package/corpus/templates/forms/app/lib/route-prewarm.ts +9 -8
  151. package/corpus/templates/forms/app/pages/AskPage.tsx +70 -0
  152. package/corpus/templates/forms/app/pages/FormsListPage.tsx +74 -81
  153. package/corpus/templates/forms/app/root.tsx +1 -1
  154. package/corpus/templates/forms/app/routes/_app.ask.tsx +14 -0
  155. package/corpus/templates/forms/app/routes/_app.settings.tsx +54 -54
  156. package/corpus/templates/forms/app/routes/_app.team.tsx +2 -9
  157. package/corpus/templates/forms/app/routes/_index.tsx +21 -130
  158. package/corpus/templates/forms/changelog/2026-06-26-ask-forms-opens-as-a-standard-app-tab-with-a-simpler-sidebar.md +6 -0
  159. package/corpus/templates/forms/changelog/2026-06-26-forms-are-shown-in-a-tighter-row-list-with-a-denser-sidebar.md +6 -0
  160. package/corpus/templates/forms/shared/navigation.ts +4 -2
  161. package/corpus/templates/macros/app/routes/settings.tsx +54 -54
  162. package/corpus/templates/macros/app/routes/team.tsx +2 -10
  163. package/corpus/templates/mail/actions/helpers.ts +2 -2
  164. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +2 -1
  165. package/corpus/templates/mail/app/pages/SettingsPage.tsx +5 -5
  166. package/corpus/templates/mail/app/routes/team.tsx +3 -2
  167. package/corpus/templates/mail/server/handlers/emails.ts +3 -2
  168. package/corpus/templates/mail/server/handlers/google-auth.ts +19 -12
  169. package/corpus/templates/mail/server/lib/automation-engine.ts +3 -2
  170. package/corpus/templates/mail/server/lib/email-state.ts +2 -3
  171. package/corpus/templates/mail/server/lib/google-auth.ts +28 -11
  172. package/corpus/templates/mail/server/lib/jobs.ts +3 -2
  173. package/corpus/templates/mail/server/onboarding.ts +9 -6
  174. package/corpus/templates/mail/server/routes/api/attachments.get.ts +3 -3
  175. package/corpus/templates/plan/actions/request-plan-access.ts +1 -1
  176. package/corpus/templates/plan/app/components/layout/Header.tsx +0 -1
  177. package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +56 -4
  178. package/corpus/templates/plan/app/global.css +8 -3
  179. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +4 -2
  180. package/corpus/templates/plan/app/lib/route-prewarm.ts +0 -4
  181. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
  182. package/corpus/templates/plan/app/routes/settings.tsx +75 -73
  183. package/corpus/templates/plan/app/routes/team.tsx +2 -8
  184. package/corpus/templates/plan/changelog/2026-06-26-canvas-grid-panning-now-stays-smooth-and-fills-the-workspace.md +6 -0
  185. package/corpus/templates/plan/server/lib/comment-notifications.ts +1 -1
  186. package/corpus/templates/slides/actions/check-image-gen.ts +2 -1
  187. package/corpus/templates/slides/actions/db-connect.ts +7 -45
  188. package/corpus/templates/slides/actions/edit-image.ts +6 -3
  189. package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
  190. package/corpus/templates/slides/actions/generate-image.ts +2 -2
  191. package/corpus/templates/slides/actions/generate-slides-ai.ts +5 -3
  192. package/corpus/templates/slides/actions/image-gen-status.ts +4 -3
  193. package/corpus/templates/slides/actions/image-search.ts +6 -3
  194. package/corpus/templates/slides/actions/search-images.ts +6 -3
  195. package/corpus/templates/slides/app/components/CloudUpgrade.tsx +8 -51
  196. package/corpus/templates/slides/app/components/layout/Header.tsx +0 -1
  197. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +0 -2
  198. package/corpus/templates/slides/app/routes/settings.tsx +54 -54
  199. package/corpus/templates/slides/app/routes/team.tsx +2 -12
  200. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +9 -9
  201. package/corpus/templates/slides/server/handlers/image-gen.ts +5 -1
  202. package/corpus/templates/slides/server/handlers/image-providers/gemini.ts +9 -1
  203. package/corpus/templates/slides/server/handlers/image-providers/index.ts +18 -8
  204. package/corpus/templates/slides/server/handlers/image-providers/openai.ts +10 -4
  205. package/corpus/templates/slides/server/handlers/image-providers/types.ts +1 -0
  206. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +59 -34
  207. package/corpus/templates/slides/server/register-secrets.ts +60 -0
  208. package/corpus/templates/videos/actions/db-connect.ts +7 -45
  209. package/corpus/templates/videos/app/components/CloudUpgrade.tsx +8 -51
  210. package/corpus/templates/videos/app/components/Sidebar.tsx +1 -9
  211. package/corpus/templates/videos/app/components/layout/Header.tsx +0 -1
  212. package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +0 -3
  213. package/corpus/templates/videos/app/routes/settings.tsx +54 -54
  214. package/corpus/templates/videos/app/routes/team.tsx +2 -8
  215. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  216. package/dist/agent/engine/builder-engine.js +8 -3
  217. package/dist/agent/engine/builder-engine.js.map +1 -1
  218. package/dist/cli/mcp.d.ts.map +1 -1
  219. package/dist/cli/mcp.js +3 -4
  220. package/dist/cli/mcp.js.map +1 -1
  221. package/dist/client/AssistantChat.d.ts.map +1 -1
  222. package/dist/client/AssistantChat.js +6 -2
  223. package/dist/client/AssistantChat.js.map +1 -1
  224. package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
  225. package/dist/client/chat/markdown-renderer.js +1 -0
  226. package/dist/client/chat/markdown-renderer.js.map +1 -1
  227. package/dist/client/i18n.d.ts.map +1 -1
  228. package/dist/client/i18n.js +20 -9
  229. package/dist/client/i18n.js.map +1 -1
  230. package/dist/client/index.d.ts +1 -1
  231. package/dist/client/index.d.ts.map +1 -1
  232. package/dist/client/index.js +1 -1
  233. package/dist/client/index.js.map +1 -1
  234. package/dist/client/org/OrgSwitcher.d.ts +3 -3
  235. package/dist/client/org/OrgSwitcher.js +2 -2
  236. package/dist/client/org/OrgSwitcher.js.map +1 -1
  237. package/dist/client/org/TeamPage.d.ts +6 -1
  238. package/dist/client/org/TeamPage.d.ts.map +1 -1
  239. package/dist/client/org/TeamPage.js +2 -2
  240. package/dist/client/org/TeamPage.js.map +1 -1
  241. package/dist/client/settings/SettingsTabsPage.d.ts +27 -0
  242. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -0
  243. package/dist/client/settings/SettingsTabsPage.js +108 -0
  244. package/dist/client/settings/SettingsTabsPage.js.map +1 -0
  245. package/dist/client/settings/index.d.ts +1 -0
  246. package/dist/client/settings/index.d.ts.map +1 -1
  247. package/dist/client/settings/index.js +1 -0
  248. package/dist/client/settings/index.js.map +1 -1
  249. package/dist/file-upload/index.d.ts +1 -1
  250. package/dist/file-upload/index.d.ts.map +1 -1
  251. package/dist/file-upload/index.js +1 -1
  252. package/dist/file-upload/index.js.map +1 -1
  253. package/dist/file-upload/registry.d.ts +1 -0
  254. package/dist/file-upload/registry.d.ts.map +1 -1
  255. package/dist/file-upload/registry.js +24 -6
  256. package/dist/file-upload/registry.js.map +1 -1
  257. package/dist/file-upload/types.d.ts +6 -1
  258. package/dist/file-upload/types.d.ts.map +1 -1
  259. package/dist/file-upload/types.js.map +1 -1
  260. package/dist/integrations/adapters/email.d.ts.map +1 -1
  261. package/dist/integrations/adapters/email.js +18 -18
  262. package/dist/integrations/adapters/email.js.map +1 -1
  263. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  264. package/dist/integrations/adapters/slack.js +8 -7
  265. package/dist/integrations/adapters/slack.js.map +1 -1
  266. package/dist/integrations/adapters/telegram.d.ts.map +1 -1
  267. package/dist/integrations/adapters/telegram.js +9 -9
  268. package/dist/integrations/adapters/telegram.js.map +1 -1
  269. package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
  270. package/dist/integrations/adapters/whatsapp.js +10 -9
  271. package/dist/integrations/adapters/whatsapp.js.map +1 -1
  272. package/dist/integrations/plugin.d.ts.map +1 -1
  273. package/dist/integrations/plugin.js +47 -13
  274. package/dist/integrations/plugin.js.map +1 -1
  275. package/dist/notifications/routes.d.ts +3 -3
  276. package/dist/observability/routes.d.ts +6 -6
  277. package/dist/onboarding/default-steps.d.ts.map +1 -1
  278. package/dist/onboarding/default-steps.js +6 -5
  279. package/dist/onboarding/default-steps.js.map +1 -1
  280. package/dist/onboarding/types.d.ts +1 -1
  281. package/dist/onboarding/types.d.ts.map +1 -1
  282. package/dist/onboarding/types.js.map +1 -1
  283. package/dist/org/handlers.js +1 -1
  284. package/dist/org/handlers.js.map +1 -1
  285. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  286. package/dist/server/agent-chat-plugin.js +4 -6
  287. package/dist/server/agent-chat-plugin.js.map +1 -1
  288. package/dist/server/agent-engine-api-key-route.d.ts +2 -2
  289. package/dist/server/better-auth-instance.d.ts.map +1 -1
  290. package/dist/server/better-auth-instance.js +17 -56
  291. package/dist/server/better-auth-instance.js.map +1 -1
  292. package/dist/server/core-routes-plugin.d.ts +1 -1
  293. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  294. package/dist/server/core-routes-plugin.js +67 -153
  295. package/dist/server/core-routes-plugin.js.map +1 -1
  296. package/dist/server/create-server.d.ts +3 -9
  297. package/dist/server/create-server.d.ts.map +1 -1
  298. package/dist/server/create-server.js +37 -91
  299. package/dist/server/create-server.js.map +1 -1
  300. package/dist/server/email-actions.d.ts +2 -3
  301. package/dist/server/email-actions.d.ts.map +1 -1
  302. package/dist/server/email-actions.js +3 -6
  303. package/dist/server/email-actions.js.map +1 -1
  304. package/dist/server/email.d.ts +3 -3
  305. package/dist/server/email.d.ts.map +1 -1
  306. package/dist/server/email.js +40 -19
  307. package/dist/server/email.js.map +1 -1
  308. package/dist/server/index.d.ts +3 -3
  309. package/dist/server/index.d.ts.map +1 -1
  310. package/dist/server/index.js +3 -3
  311. package/dist/server/index.js.map +1 -1
  312. package/dist/server/scoped-key-storage.d.ts +22 -0
  313. package/dist/server/scoped-key-storage.d.ts.map +1 -0
  314. package/dist/server/scoped-key-storage.js +152 -0
  315. package/dist/server/scoped-key-storage.js.map +1 -0
  316. package/dist/shared/agent-env.d.ts +3 -3
  317. package/dist/shared/agent-env.d.ts.map +1 -1
  318. package/dist/shared/agent-env.js +3 -3
  319. package/dist/shared/agent-env.js.map +1 -1
  320. package/dist/sharing/actions/share-resource.js +1 -1
  321. package/dist/sharing/actions/share-resource.js.map +1 -1
  322. package/dist/styles/agent-native.css +47 -3
  323. package/dist/templates/workspace-root/AGENTS.md +3 -2
  324. package/dist/templates/workspace-root/README.md +1 -1
  325. package/dist/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
  326. package/dist/terminal/pty-server.d.ts.map +1 -1
  327. package/dist/terminal/pty-server.js +3 -36
  328. package/dist/terminal/pty-server.js.map +1 -1
  329. package/dist/triggers/dispatcher.js +1 -1
  330. package/dist/triggers/dispatcher.js.map +1 -1
  331. package/docs/content/file-uploads.md +11 -4
  332. package/docs/content/locales/ar-SA/multi-app-workspace.md +3 -3
  333. package/docs/content/locales/de-DE/multi-app-workspace.md +3 -3
  334. package/docs/content/locales/es-ES/multi-app-workspace.md +3 -3
  335. package/docs/content/locales/fr-FR/multi-app-workspace.md +3 -3
  336. package/docs/content/locales/hi-IN/multi-app-workspace.md +3 -3
  337. package/docs/content/locales/ja-JP/multi-app-workspace.md +3 -3
  338. package/docs/content/locales/ko-KR/multi-app-workspace.md +3 -3
  339. package/docs/content/locales/pt-BR/multi-app-workspace.md +3 -3
  340. package/docs/content/locales/zh-CN/multi-app-workspace.md +3 -3
  341. package/docs/content/locales/zh-TW/multi-app-workspace.md +3 -3
  342. package/docs/content/multi-app-workspace.md +3 -3
  343. package/docs/content/template-clips.md +14 -5
  344. package/package.json +1 -1
  345. package/src/templates/workspace-root/AGENTS.md +3 -2
  346. package/src/templates/workspace-root/README.md +1 -1
  347. package/src/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
  348. package/corpus/core/src/server/env-var-writes.ts +0 -16
  349. package/corpus/templates/analytics/app/pages/Team.tsx +0 -9
  350. package/corpus/templates/calendar/app/pages/Team.tsx +0 -12
  351. package/corpus/templates/mail/app/pages/Team.tsx +0 -17
  352. package/dist/server/env-var-writes.d.ts +0 -10
  353. package/dist/server/env-var-writes.d.ts.map +0 -1
  354. package/dist/server/env-var-writes.js +0 -18
  355. package/dist/server/env-var-writes.js.map +0 -1
@@ -24,6 +24,7 @@ import {
24
24
  IconClipboardCopy,
25
25
  IconFileText,
26
26
  IconSparkles,
27
+ IconLayoutSidebarRightExpand,
27
28
  } from "@tabler/icons-react";
28
29
  import { useQuery } from "@tanstack/react-query";
29
30
  import { useCallback, useEffect, useRef, useState } from "react";
@@ -33,7 +34,7 @@ import { toast } from "sonner";
33
34
  import { EditableRecordingTitle } from "@/components/editable-recording-title";
34
35
  import { EditorLayout } from "@/components/editor/editor-layout";
35
36
  import { CommentsPanel } from "@/components/player/comments-panel";
36
- import { DeleteRecordingMenu } from "@/components/player/delete-recording-menu";
37
+ import { RecordingOptionsMenu } from "@/components/player/delete-recording-menu";
37
38
  import { InsightsPanel } from "@/components/player/insights-panel";
38
39
  import { ReactionsTray } from "@/components/player/reactions-tray";
39
40
  import { SettingsPanel } from "@/components/player/settings-panel";
@@ -54,6 +55,12 @@ import {
54
55
  DropdownMenuSeparator,
55
56
  DropdownMenuTrigger,
56
57
  } from "@/components/ui/dropdown-menu";
58
+ import {
59
+ Sheet,
60
+ SheetContent,
61
+ SheetDescription,
62
+ SheetTitle,
63
+ } from "@/components/ui/sheet";
57
64
  import { Spinner } from "@/components/ui/spinner";
58
65
  import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
59
66
  import {
@@ -100,6 +107,20 @@ interface GeneratedWorkflowState {
100
107
  error?: string;
101
108
  }
102
109
 
110
+ function useIsCompactRecordingLayout() {
111
+ const [isCompact, setIsCompact] = useState(false);
112
+
113
+ useEffect(() => {
114
+ const query = window.matchMedia("(max-width: 1279px)");
115
+ const update = () => setIsCompact(query.matches);
116
+ update();
117
+ query.addEventListener("change", update);
118
+ return () => query.removeEventListener("change", update);
119
+ }, []);
120
+
121
+ return isCompact;
122
+ }
123
+
103
124
  function isNativeSaveFailureReason(reason: string | null | undefined): boolean {
104
125
  return /native recording upload|native fullscreen|screencapture|avconvert/i.test(
105
126
  reason ?? "",
@@ -129,6 +150,7 @@ function nativeSaveFailureMessage(reason: string | null | undefined): string {
129
150
 
130
151
  function InsightsUnavailableState() {
131
152
  const t = useT();
153
+
132
154
  return (
133
155
  <div className="flex h-full flex-col items-center justify-center px-8 py-12 text-center">
134
156
  <p className="text-sm font-medium text-foreground">
@@ -179,15 +201,18 @@ export default function RecordingPage() {
179
201
  const playerRef = useRef<VideoPlayerHandle | null>(null);
180
202
 
181
203
  const [panel, setPanel] = useState<SidePanel>("agent");
204
+ const [sidePanelOpen, setSidePanelOpen] = useState(false);
182
205
  const [theaterMode, setTheaterMode] = useState(false);
183
206
  const [editing, setEditing] = useState(false);
184
207
  const [currentMs, setCurrentMs] = useState(0);
208
+ const isCompactLayout = useIsCompactRecordingLayout();
185
209
  const transcriptKickedRef = useRef<string | null>(null);
186
210
  // When the recording lands in the processing state but never flips to
187
211
  // 'ready', stop spinning forever and surface an error banner so the user
188
212
  // can retry or report the issue instead of staring at a spinner.
189
213
  const [processingTimeout, setProcessingTimeout] = useState(false);
190
214
  const [retryingFinalize, setRetryingFinalize] = useState(false);
215
+ const [downloading, setDownloading] = useState(false);
191
216
 
192
217
  useEffect(() => {
193
218
  if (
@@ -282,6 +307,30 @@ export default function RecordingPage() {
282
307
  const isLoomRecording = isLoomRecordingSource(recording);
283
308
  const canUseNativeEditor = canEdit && !isLoomEmbedBacked;
284
309
  const canDelete = role === "owner";
310
+ const canDownloadRecording = Boolean(
311
+ recording?.enableDownloads && recording.videoUrl && !isLoomEmbedBacked,
312
+ );
313
+ const downloadRecording = useCallback(async () => {
314
+ if (!recording?.videoUrl) return;
315
+ setDownloading(true);
316
+ try {
317
+ const res = await fetch(recording.videoUrl);
318
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
319
+ const blob = await res.blob();
320
+ const url = URL.createObjectURL(blob);
321
+ const a = document.createElement("a");
322
+ a.href = url;
323
+ a.download = `${sanitizeFilename(recording.title || "clip")}.mp4`;
324
+ document.body.appendChild(a);
325
+ a.click();
326
+ a.remove();
327
+ URL.revokeObjectURL(url);
328
+ } catch {
329
+ window.open(recording.videoUrl, "_blank", "noopener,noreferrer");
330
+ } finally {
331
+ setDownloading(false);
332
+ }
333
+ }, [recording?.title, recording?.videoUrl]);
285
334
  const retryFinalizeAfterStorage = useCallback(async () => {
286
335
  if (!recordingId) return;
287
336
  setRetryingFinalize(true);
@@ -413,6 +462,10 @@ export default function RecordingPage() {
413
462
  if (!canUseNativeEditor && editing) setEditing(false);
414
463
  }, [canUseNativeEditor, editing]);
415
464
 
465
+ useEffect(() => {
466
+ if (editing || !isCompactLayout) setSidePanelOpen(false);
467
+ }, [editing, isCompactLayout]);
468
+
416
469
  useEffect(() => {
417
470
  if (!recording) return;
418
471
  document.title = isDefaultTitle(recording.title)
@@ -647,6 +700,158 @@ export default function RecordingPage() {
647
700
  );
648
701
  }
649
702
 
703
+ const renderSidePanel = (compact = false) => (
704
+ <Tabs
705
+ value={panel}
706
+ onValueChange={(v) => setPanel(v as SidePanel)}
707
+ className={cn("flex h-full flex-col", compact && "pt-8")}
708
+ >
709
+ <TabsList
710
+ className={cn(
711
+ "mx-3 mt-3 grid w-auto",
712
+ canEdit ? "grid-cols-5" : "grid-cols-4",
713
+ )}
714
+ >
715
+ <TabsTrigger value="agent" className="min-w-0 px-2 text-xs">
716
+ {t("recordingPage.agent")}
717
+ </TabsTrigger>
718
+ <TabsTrigger value="comments" className="min-w-0 px-2 text-xs">
719
+ {t("recordingPage.activity")}
720
+ </TabsTrigger>
721
+ <TabsTrigger value="transcript" className="min-w-0 px-2 text-xs">
722
+ {t("recordingPage.transcript")}
723
+ </TabsTrigger>
724
+ <TabsTrigger value="insights" className="min-w-0 px-2 text-xs">
725
+ {t("recordingPage.insights")}
726
+ </TabsTrigger>
727
+ {canEdit ? (
728
+ <TabsTrigger value="settings" className="min-w-0 px-2 text-xs">
729
+ {t("recordingPage.settings")}
730
+ </TabsTrigger>
731
+ ) : null}
732
+ </TabsList>
733
+
734
+ <TabsContent
735
+ value="agent"
736
+ className="mt-0 flex flex-1 min-h-0 flex-col data-[state=inactive]:hidden"
737
+ >
738
+ <AgentPanel
739
+ browserTabId={getBrowserTabId()}
740
+ emptyStateText={t("recordingPage.askAboutClip")}
741
+ dynamicSuggestions={false}
742
+ chatNotice={
743
+ generatedWorkflow ? (
744
+ <GeneratedWorkflowNotice workflow={generatedWorkflow} />
745
+ ) : null
746
+ }
747
+ suggestions={
748
+ canEdit
749
+ ? [
750
+ t("recordingPage.summarizeClip"),
751
+ t("recordingPage.generateChapters"),
752
+ t("recordingPage.findActionItems"),
753
+ t("recordingPage.draftRecap"),
754
+ ]
755
+ : [
756
+ t("recordingPage.summarizeClip"),
757
+ t("recordingPage.findKeyMoments"),
758
+ t("recordingPage.listFollowUpActions"),
759
+ t("recordingPage.draftQuestions"),
760
+ ]
761
+ }
762
+ />
763
+ </TabsContent>
764
+ <TabsContent
765
+ value="transcript"
766
+ className="flex-1 min-h-0 mt-3 data-[state=inactive]:hidden"
767
+ >
768
+ <TranscriptPanel
769
+ segments={transcriptSegments}
770
+ fullText={transcriptFullText}
771
+ durationMs={recording.durationMs}
772
+ currentMs={currentMs}
773
+ onSeek={(ms) => playerRef.current?.seek(ms)}
774
+ status={transcriptStatus}
775
+ failureReason={transcriptFailureReason}
776
+ cleanup={transcriptCleanup}
777
+ recordingTitle={recording.title}
778
+ onRetry={() => {
779
+ // Force a fresh transcript job, then let polling swap the panel
780
+ // back to the pending state while it runs.
781
+ fetch(
782
+ agentNativePath("/_agent-native/actions/request-transcript"),
783
+ {
784
+ method: "POST",
785
+ headers: { "Content-Type": "application/json" },
786
+ body: JSON.stringify({
787
+ recordingId: recording.id,
788
+ force: true,
789
+ }),
790
+ },
791
+ )
792
+ .then((res) => {
793
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
794
+ })
795
+ .catch((err) =>
796
+ toast.error(
797
+ t("recordingPage.retryFailed", {
798
+ message: err?.message ?? t("recordingPage.networkError"),
799
+ }),
800
+ ),
801
+ )
802
+ .finally(() => playerDataQ.refetch());
803
+ }}
804
+ />
805
+ </TabsContent>
806
+ <TabsContent
807
+ value="comments"
808
+ className="flex-1 min-h-0 mt-3 data-[state=inactive]:hidden"
809
+ >
810
+ <CommentsPanel
811
+ recordingId={recording.id}
812
+ comments={comments}
813
+ currentMs={currentMs}
814
+ currentUserEmail={session?.email}
815
+ enableComments={recording.enableComments}
816
+ onSeek={(ms) => playerRef.current?.seek(ms)}
817
+ queryKey={[
818
+ "action",
819
+ "get-recording-player-data",
820
+ { recordingId: recordingId ?? "" },
821
+ ]}
822
+ />
823
+ </TabsContent>
824
+ <TabsContent
825
+ value="insights"
826
+ className="flex-1 min-h-0 mt-3 overflow-y-auto data-[state=inactive]:hidden"
827
+ >
828
+ {canEdit ? (
829
+ <InsightsPanel
830
+ recordingId={recording.id}
831
+ durationMs={recording.durationMs}
832
+ />
833
+ ) : (
834
+ <InsightsUnavailableState />
835
+ )}
836
+ </TabsContent>
837
+ {canEdit ? (
838
+ <TabsContent
839
+ value="settings"
840
+ className="mt-3 flex flex-1 min-h-0 flex-col data-[state=inactive]:hidden"
841
+ >
842
+ <SettingsPanel
843
+ recording={recording}
844
+ visibility={recording.visibility}
845
+ ctas={ctas}
846
+ onClose={() => setPanel("agent")}
847
+ onRefetch={() => playerDataQ.refetch()}
848
+ showHeader={false}
849
+ />
850
+ </TabsContent>
851
+ ) : null}
852
+ </Tabs>
853
+ );
854
+
650
855
  return (
651
856
  <div className="flex h-screen w-full bg-background overflow-hidden">
652
857
  {/* Main video column */}
@@ -797,6 +1002,23 @@ export default function RecordingPage() {
797
1002
  </DropdownMenu>
798
1003
  ) : null}
799
1004
 
1005
+ {!editing ? (
1006
+ <Tooltip>
1007
+ <TooltipTrigger asChild>
1008
+ <Button
1009
+ variant="outline"
1010
+ size="icon"
1011
+ className="xl:hidden"
1012
+ onClick={() => setSidePanelOpen(true)}
1013
+ aria-label={t("recordingPage.details")}
1014
+ >
1015
+ <IconLayoutSidebarRightExpand className="h-4 w-4" />
1016
+ </Button>
1017
+ </TooltipTrigger>
1018
+ <TooltipContent>{t("recordingPage.details")}</TooltipContent>
1019
+ </Tooltip>
1020
+ ) : null}
1021
+
800
1022
  <ShareRecordingPopover
801
1023
  recordingId={recording.id}
802
1024
  recordingTitle={recording.title}
@@ -814,9 +1036,15 @@ export default function RecordingPage() {
814
1036
  </Button>
815
1037
  </ShareRecordingPopover>
816
1038
 
817
- {canDelete ? (
818
- <DeleteRecordingMenu
1039
+ {canDelete || canDownloadRecording ? (
1040
+ <RecordingOptionsMenu
819
1041
  recordingId={recording.id}
1042
+ canDelete={canDelete}
1043
+ canDownload={canDownloadRecording}
1044
+ downloadPending={downloading}
1045
+ onDownload={() => {
1046
+ void downloadRecording();
1047
+ }}
820
1048
  onDeleted={() => navigate("/library", { replace: true })}
821
1049
  />
822
1050
  ) : null}
@@ -935,162 +1163,29 @@ export default function RecordingPage() {
935
1163
 
936
1164
  {/* Side panel */}
937
1165
  {!editing ? (
938
- <aside className="w-[380px] border-s border-border flex flex-col shrink-0 bg-background">
939
- <Tabs
940
- value={panel}
941
- onValueChange={(v) => setPanel(v as SidePanel)}
942
- className="flex flex-col h-full"
943
- >
944
- <TabsList
945
- className={cn(
946
- "mx-3 mt-3 grid w-auto",
947
- canEdit ? "grid-cols-5" : "grid-cols-4",
948
- )}
949
- >
950
- <TabsTrigger value="agent" className="min-w-0 px-2 text-xs">
951
- {t("recordingPage.agent")}
952
- </TabsTrigger>
953
- <TabsTrigger value="comments" className="min-w-0 px-2 text-xs">
954
- {t("recordingPage.activity")}
955
- </TabsTrigger>
956
- <TabsTrigger value="transcript" className="min-w-0 px-2 text-xs">
957
- {t("recordingPage.transcript")}
958
- </TabsTrigger>
959
- <TabsTrigger value="insights" className="min-w-0 px-2 text-xs">
960
- {t("recordingPage.insights")}
961
- </TabsTrigger>
962
- {canEdit ? (
963
- <TabsTrigger value="settings" className="min-w-0 px-2 text-xs">
964
- {t("recordingPage.settings")}
965
- </TabsTrigger>
966
- ) : null}
967
- </TabsList>
968
-
969
- <TabsContent
970
- value="agent"
971
- className="mt-0 flex flex-1 min-h-0 flex-col data-[state=inactive]:hidden"
972
- >
973
- <AgentPanel
974
- browserTabId={getBrowserTabId()}
975
- emptyStateText={t("recordingPage.askAboutClip")}
976
- dynamicSuggestions={false}
977
- chatNotice={
978
- generatedWorkflow ? (
979
- <GeneratedWorkflowNotice workflow={generatedWorkflow} />
980
- ) : null
981
- }
982
- suggestions={
983
- canEdit
984
- ? [
985
- t("recordingPage.summarizeClip"),
986
- t("recordingPage.generateChapters"),
987
- t("recordingPage.findActionItems"),
988
- t("recordingPage.draftRecap"),
989
- ]
990
- : [
991
- t("recordingPage.summarizeClip"),
992
- t("recordingPage.findKeyMoments"),
993
- t("recordingPage.listFollowUpActions"),
994
- t("recordingPage.draftQuestions"),
995
- ]
996
- }
997
- />
998
- </TabsContent>
999
- <TabsContent
1000
- value="transcript"
1001
- className="flex-1 min-h-0 mt-3 data-[state=inactive]:hidden"
1002
- >
1003
- <TranscriptPanel
1004
- segments={transcriptSegments}
1005
- fullText={transcriptFullText}
1006
- durationMs={recording.durationMs}
1007
- currentMs={currentMs}
1008
- onSeek={(ms) => playerRef.current?.seek(ms)}
1009
- status={transcriptStatus}
1010
- failureReason={transcriptFailureReason}
1011
- cleanup={transcriptCleanup}
1012
- recordingTitle={recording.title}
1013
- onRetry={() => {
1014
- // Re-run transcription now that the user may have connected
1015
- // Builder/Gemini or after a one-off network error. The action
1016
- // flips the row to 'pending' first, so the UI swaps back to
1017
- // "Transcribing…".
1018
- fetch(
1019
- agentNativePath(
1020
- "/_agent-native/actions/request-transcript",
1021
- ),
1022
- {
1023
- method: "POST",
1024
- headers: { "Content-Type": "application/json" },
1025
- body: JSON.stringify({
1026
- recordingId: recording.id,
1027
- force: true,
1028
- }),
1029
- },
1030
- )
1031
- .then((res) => {
1032
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
1033
- })
1034
- .catch((err) =>
1035
- toast.error(
1036
- t("recordingPage.retryFailed", {
1037
- message:
1038
- err?.message ?? t("recordingPage.networkError"),
1039
- }),
1040
- ),
1041
- )
1042
- .finally(() => playerDataQ.refetch());
1043
- }}
1044
- />
1045
- </TabsContent>
1046
- <TabsContent
1047
- value="comments"
1048
- className="flex-1 min-h-0 mt-3 data-[state=inactive]:hidden"
1049
- >
1050
- <CommentsPanel
1051
- recordingId={recording.id}
1052
- comments={comments}
1053
- currentMs={currentMs}
1054
- currentUserEmail={session?.email}
1055
- enableComments={recording.enableComments}
1056
- onSeek={(ms) => playerRef.current?.seek(ms)}
1057
- queryKey={[
1058
- "action",
1059
- "get-recording-player-data",
1060
- { recordingId: recordingId ?? "" },
1061
- ]}
1062
- />
1063
- </TabsContent>
1064
- <TabsContent
1065
- value="insights"
1066
- className="flex-1 min-h-0 mt-3 overflow-y-auto data-[state=inactive]:hidden"
1067
- >
1068
- {canEdit ? (
1069
- <InsightsPanel
1070
- recordingId={recording.id}
1071
- durationMs={recording.durationMs}
1072
- />
1073
- ) : (
1074
- <InsightsUnavailableState />
1075
- )}
1076
- </TabsContent>
1077
- {canEdit ? (
1078
- <TabsContent
1079
- value="settings"
1080
- className="mt-3 flex flex-1 min-h-0 flex-col data-[state=inactive]:hidden"
1166
+ <>
1167
+ {isCompactLayout ? (
1168
+ <Sheet open={sidePanelOpen} onOpenChange={setSidePanelOpen}>
1169
+ <SheetContent
1170
+ side="right"
1171
+ className="flex h-full w-[calc(100vw-24px)] max-w-[420px] flex-col gap-0 p-0 sm:max-w-[420px]"
1081
1172
  >
1082
- <SettingsPanel
1083
- recording={recording}
1084
- visibility={recording.visibility}
1085
- ctas={ctas}
1086
- onClose={() => setPanel("agent")}
1087
- onRefetch={() => playerDataQ.refetch()}
1088
- showHeader={false}
1089
- />
1090
- </TabsContent>
1091
- ) : null}
1092
- </Tabs>
1093
- </aside>
1173
+ <SheetTitle className="sr-only">
1174
+ {t("recordingPage.details")}
1175
+ </SheetTitle>
1176
+ <SheetDescription className="sr-only">
1177
+ {t("recordingPage.askAboutClip")}
1178
+ </SheetDescription>
1179
+ {renderSidePanel(true)}
1180
+ </SheetContent>
1181
+ </Sheet>
1182
+ ) : null}
1183
+ {!isCompactLayout ? (
1184
+ <aside className="hidden w-[380px] shrink-0 flex-col border-s border-border bg-background xl:flex">
1185
+ {renderSidePanel()}
1186
+ </aside>
1187
+ ) : null}
1188
+ </>
1094
1189
  ) : null}
1095
1190
  </div>
1096
1191
  );
@@ -1220,6 +1315,16 @@ function displayRecordingTitle(title: string | null | undefined): string {
1220
1315
  return isDefaultTitle(title) ? "Untitled Clip" : (title ?? "").trim();
1221
1316
  }
1222
1317
 
1318
+ function sanitizeFilename(name: string): string {
1319
+ return (
1320
+ name
1321
+ .trim()
1322
+ .replace(/[^\w.-]+/g, "-")
1323
+ .replace(/^-+|-+$/g, "")
1324
+ .slice(0, 80) || "clip"
1325
+ );
1326
+ }
1327
+
1223
1328
  function shouldShowGeneratedTitleSkeleton(
1224
1329
  recording: { title: string | null | undefined; createdAt?: string | null },
1225
1330
  transcriptStatus?: string,
@@ -38,7 +38,7 @@ import { useLoaderData, useNavigate, useParams } from "react-router";
38
38
  import { CaptureInstallButton } from "@/components/capture-install-options";
39
39
  import { AccessPasswordPrompt } from "@/components/player/access-password-prompt";
40
40
  import { CommentsPanel } from "@/components/player/comments-panel";
41
- import { DeleteRecordingMenu } from "@/components/player/delete-recording-menu";
41
+ import { RecordingOptionsMenu } from "@/components/player/delete-recording-menu";
42
42
  import { ReactionsTray } from "@/components/player/reactions-tray";
43
43
  import { ShareRecordingPopover } from "@/components/player/share-dialog";
44
44
  import { SignInPromptDialog } from "@/components/player/sign-in-prompt-dialog";
@@ -797,8 +797,16 @@ export default function ShareRoute() {
797
797
  </DropdownMenu>
798
798
  ) : null}
799
799
  {viewerIsOwner ? (
800
- <DeleteRecordingMenu
800
+ <RecordingOptionsMenu
801
801
  recordingId={recording.id}
802
+ canDelete
803
+ canDownload={canDownloadRecording}
804
+ downloadPending={downloading}
805
+ downloadLabel={t("sharePage.downloadMp4")}
806
+ downloadingLabel={t("sharePage.downloading")}
807
+ onDownload={() => {
808
+ void downloadRecording();
809
+ }}
802
810
  onDeleted={() => navigate("/library", { replace: true })}
803
811
  />
804
812
  ) : null}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-26
4
+ ---
5
+
6
+ Long desktop recordings are checkpointed so macOS finalization failures can recover the saved portions.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-26
4
+ ---
5
+
6
+ Non-Mac desktop recordings now try Web Speech transcripts before falling back to upload transcription.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-26
4
+ ---
5
+
6
+ The recording details button stays at the far right on small screens.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-26
4
+ ---
5
+
6
+ S3-compatible storage keys now save securely from Clips Settings without requiring deployment env vars.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-06-26
4
+ ---
5
+
6
+ Shared clip links now guide agents through processing transcripts and exhausted transcription credits.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-26
4
+ ---
5
+
6
+ The agent sidebar now slides in smoothly without duplicate edge borders.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-26
4
+ ---
5
+
6
+ The clip details sidebar now collapses into a slide-out panel on smaller screens.