@agent-native/core 0.79.16 → 0.79.18

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 (344) 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/index.ts +7 -1
  22. package/corpus/core/src/client/org/OrgSwitcher.tsx +5 -5
  23. package/corpus/core/src/client/org/TeamPage.tsx +11 -3
  24. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +216 -0
  25. package/corpus/core/src/client/settings/index.ts +5 -0
  26. package/corpus/core/src/file-upload/index.ts +1 -0
  27. package/corpus/core/src/file-upload/registry.ts +22 -6
  28. package/corpus/core/src/file-upload/types.ts +6 -1
  29. package/corpus/core/src/integrations/adapters/email.ts +26 -18
  30. package/corpus/core/src/integrations/adapters/slack.ts +8 -7
  31. package/corpus/core/src/integrations/adapters/telegram.ts +9 -11
  32. package/corpus/core/src/integrations/adapters/whatsapp.ts +12 -9
  33. package/corpus/core/src/integrations/plugin.ts +79 -13
  34. package/corpus/core/src/onboarding/default-steps.ts +6 -3
  35. package/corpus/core/src/onboarding/types.ts +1 -1
  36. package/corpus/core/src/org/handlers.ts +1 -1
  37. package/corpus/core/src/server/agent-chat-plugin.ts +4 -7
  38. package/corpus/core/src/server/better-auth-instance.ts +19 -62
  39. package/corpus/core/src/server/core-routes-plugin.ts +93 -180
  40. package/corpus/core/src/server/create-server.ts +55 -116
  41. package/corpus/core/src/server/email-actions.ts +3 -6
  42. package/corpus/core/src/server/email.ts +52 -17
  43. package/corpus/core/src/server/index.ts +2 -1
  44. package/corpus/core/src/server/scoped-key-storage.ts +223 -0
  45. package/corpus/core/src/shared/agent-env.ts +3 -3
  46. package/corpus/core/src/sharing/actions/share-resource.ts +1 -1
  47. package/corpus/core/src/styles/agent-native.css +55 -3
  48. package/corpus/core/src/templates/workspace-root/AGENTS.md +3 -2
  49. package/corpus/core/src/templates/workspace-root/README.md +1 -1
  50. package/corpus/core/src/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
  51. package/corpus/core/src/terminal/pty-server.ts +3 -38
  52. package/corpus/core/src/triggers/dispatcher.ts +1 -2
  53. package/corpus/templates/.retired/issues/package.json +7 -0
  54. package/corpus/templates/.retired/meeting-notes/package.json +7 -0
  55. package/corpus/templates/.retired/recruiting/package.json +7 -0
  56. package/corpus/templates/.retired/scheduling/package.json +7 -0
  57. package/corpus/templates/.retired/voice/package.json +7 -0
  58. package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
  59. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +0 -17
  60. package/corpus/templates/analytics/app/i18n/zh-TW.ts +7 -1
  61. package/corpus/templates/analytics/app/i18n-data.ts +71 -2
  62. package/corpus/templates/analytics/app/pages/Settings.tsx +120 -73
  63. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +0 -11
  64. package/corpus/templates/analytics/app/routes/catalog.tsx +33 -176
  65. package/corpus/templates/analytics/app/routes/team.tsx +3 -2
  66. package/corpus/templates/analytics/changelog/2026-06-26-dashboard-templates-are-tucked-into-settings-and-show-simple.md +6 -0
  67. package/corpus/templates/analytics/changelog/2026-06-26-the-sessions-page-shows-a-single-page-title-instead-of-repea.md +6 -0
  68. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +37 -28
  69. package/corpus/templates/assets/app/routes/settings.tsx +65 -43
  70. package/corpus/templates/assets/app/routes/team.tsx +2 -10
  71. package/corpus/templates/brain/app/routes/settings.tsx +390 -358
  72. package/corpus/templates/brain/app/routes/team.tsx +2 -8
  73. package/corpus/templates/calendar/actions/db-connect.ts +5 -29
  74. package/corpus/templates/calendar/app/components/CloudUpgrade.tsx +8 -51
  75. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +2 -1
  76. package/corpus/templates/calendar/app/components/calendar/GoogleSetupWizard.tsx +4 -2
  77. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +0 -2
  78. package/corpus/templates/calendar/app/pages/Settings.tsx +304 -271
  79. package/corpus/templates/calendar/app/routes/_app.team.tsx +2 -17
  80. package/corpus/templates/calendar/server/handlers/google-auth.ts +22 -9
  81. package/corpus/templates/calendar/server/lib/booking-emails.ts +1 -1
  82. package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +1 -1
  83. package/corpus/templates/calendar/server/lib/google-calendar.ts +48 -28
  84. package/corpus/templates/chat/app/components/layout/Header.tsx +0 -1
  85. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +4 -2
  86. package/corpus/templates/chat/app/routes/settings.tsx +54 -54
  87. package/corpus/templates/chat/app/routes/team.tsx +2 -10
  88. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +7 -2
  89. package/corpus/templates/clips/.agents/skills/recording/SKILL.md +1 -1
  90. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +7 -0
  91. package/corpus/templates/clips/AGENTS.md +8 -0
  92. package/corpus/templates/clips/actions/invite-member.ts +1 -1
  93. package/corpus/templates/clips/actions/request-transcript.ts +1 -1
  94. package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -3
  95. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +2 -0
  96. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +629 -643
  97. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +219 -155
  98. package/corpus/templates/clips/changelog/2026-06-26-long-desktop-recordings-are-checkpointed-so-macos-finalizati.md +6 -0
  99. package/corpus/templates/clips/changelog/2026-06-26-non-mac-desktop-recordings-wait-for-upload-transcription.md +6 -0
  100. package/corpus/templates/clips/changelog/2026-06-26-s3-compatible-storage-keys-now-save-securely-from-clips-sett.md +6 -0
  101. package/corpus/templates/clips/changelog/2026-06-26-shared-clip-links-guide-agents-through-processing-transcripts.md +6 -0
  102. package/corpus/templates/clips/changelog/2026-06-26-the-clip-details-sidebar-now-collapses-into-a-slide-out-pane.md +6 -0
  103. package/corpus/templates/clips/changelog/2026-06-26-the-clips-library-now-matches-the-shared-recessed-shell-styl.md +6 -0
  104. package/corpus/templates/clips/desktop/src/lib/recorder.ts +55 -3
  105. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +217 -5
  106. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -0
  107. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +176 -5
  108. package/corpus/templates/clips/server/lib/public-agent-context.ts +31 -0
  109. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +60 -14
  110. package/corpus/templates/clips/server/lib/video-storage.ts +37 -9
  111. package/corpus/templates/clips/server/routes/api/agent-transcript.json.get.ts +5 -0
  112. package/corpus/templates/content/app/components/layout/Header.tsx +0 -1
  113. package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +1 -0
  114. package/corpus/templates/content/app/routes/_app.settings.tsx +54 -55
  115. package/corpus/templates/content/app/routes/_app.team.tsx +2 -28
  116. package/corpus/templates/content/server/lib/notion.ts +43 -11
  117. package/corpus/templates/content/server/routes/api/notion/auth-url.get.ts +2 -2
  118. package/corpus/templates/content/server/routes/api/notion/status.get.ts +3 -3
  119. package/corpus/templates/design/app/routes/settings.tsx +60 -38
  120. package/corpus/templates/design/app/routes/team.tsx +2 -10
  121. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +2 -2
  122. package/corpus/templates/dispatch/app/routes/settings.tsx +70 -55
  123. package/corpus/templates/dispatch/app/routes/team.tsx +5 -1
  124. package/corpus/templates/forms/actions/db-connect.ts +7 -36
  125. package/corpus/templates/forms/actions/navigate.ts +2 -2
  126. package/corpus/templates/forms/app/components/CloudUpgrade.tsx +8 -47
  127. package/corpus/templates/forms/app/components/layout/Header.tsx +0 -1
  128. package/corpus/templates/forms/app/components/layout/Layout.tsx +42 -25
  129. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +35 -76
  130. package/corpus/templates/forms/app/global.css +9 -25
  131. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +4 -4
  132. package/corpus/templates/forms/app/i18n/ar-SA.ts +1 -0
  133. package/corpus/templates/forms/app/i18n/de-DE.ts +1 -0
  134. package/corpus/templates/forms/app/i18n/en-US.ts +1 -0
  135. package/corpus/templates/forms/app/i18n/es-ES.ts +1 -0
  136. package/corpus/templates/forms/app/i18n/fr-FR.ts +1 -0
  137. package/corpus/templates/forms/app/i18n/hi-IN.ts +1 -0
  138. package/corpus/templates/forms/app/i18n/ja-JP.ts +1 -0
  139. package/corpus/templates/forms/app/i18n/ko-KR.ts +1 -0
  140. package/corpus/templates/forms/app/i18n/pt-BR.ts +1 -0
  141. package/corpus/templates/forms/app/i18n/zh-CN.ts +1 -0
  142. package/corpus/templates/forms/app/i18n/zh-TW.ts +1 -0
  143. package/corpus/templates/forms/app/lib/route-prewarm.ts +9 -8
  144. package/corpus/templates/forms/app/pages/AskPage.tsx +70 -0
  145. package/corpus/templates/forms/app/pages/FormsListPage.tsx +74 -81
  146. package/corpus/templates/forms/app/root.tsx +1 -1
  147. package/corpus/templates/forms/app/routes/_app.ask.tsx +14 -0
  148. package/corpus/templates/forms/app/routes/_app.settings.tsx +54 -54
  149. package/corpus/templates/forms/app/routes/_app.team.tsx +2 -9
  150. package/corpus/templates/forms/app/routes/_index.tsx +21 -130
  151. package/corpus/templates/forms/changelog/2026-06-26-ask-forms-opens-as-a-standard-app-tab-with-a-simpler-sidebar.md +6 -0
  152. package/corpus/templates/forms/changelog/2026-06-26-forms-are-shown-in-a-tighter-row-list-with-a-denser-sidebar.md +6 -0
  153. package/corpus/templates/forms/shared/navigation.ts +4 -2
  154. package/corpus/templates/macros/app/routes/settings.tsx +54 -54
  155. package/corpus/templates/macros/app/routes/team.tsx +2 -10
  156. package/corpus/templates/mail/actions/helpers.ts +2 -2
  157. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +2 -1
  158. package/corpus/templates/mail/app/pages/SettingsPage.tsx +5 -5
  159. package/corpus/templates/mail/app/routes/team.tsx +3 -2
  160. package/corpus/templates/mail/server/handlers/emails.ts +3 -2
  161. package/corpus/templates/mail/server/handlers/google-auth.ts +19 -12
  162. package/corpus/templates/mail/server/lib/automation-engine.ts +3 -2
  163. package/corpus/templates/mail/server/lib/email-state.ts +2 -3
  164. package/corpus/templates/mail/server/lib/google-auth.ts +28 -11
  165. package/corpus/templates/mail/server/lib/jobs.ts +3 -2
  166. package/corpus/templates/mail/server/onboarding.ts +9 -6
  167. package/corpus/templates/mail/server/routes/api/attachments.get.ts +3 -3
  168. package/corpus/templates/plan/actions/request-plan-access.ts +1 -1
  169. package/corpus/templates/plan/app/components/layout/Header.tsx +0 -1
  170. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +4 -2
  171. package/corpus/templates/plan/app/lib/route-prewarm.ts +0 -4
  172. package/corpus/templates/plan/app/routes/settings.tsx +75 -73
  173. package/corpus/templates/plan/app/routes/team.tsx +2 -8
  174. package/corpus/templates/plan/server/lib/comment-notifications.ts +1 -1
  175. package/corpus/templates/slides/actions/check-image-gen.ts +2 -1
  176. package/corpus/templates/slides/actions/db-connect.ts +7 -45
  177. package/corpus/templates/slides/actions/edit-image.ts +6 -3
  178. package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
  179. package/corpus/templates/slides/actions/generate-image.ts +2 -2
  180. package/corpus/templates/slides/actions/generate-slides-ai.ts +5 -3
  181. package/corpus/templates/slides/actions/image-gen-status.ts +4 -3
  182. package/corpus/templates/slides/actions/image-search.ts +6 -3
  183. package/corpus/templates/slides/actions/search-images.ts +6 -3
  184. package/corpus/templates/slides/app/components/CloudUpgrade.tsx +8 -51
  185. package/corpus/templates/slides/app/components/layout/Header.tsx +0 -1
  186. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +0 -2
  187. package/corpus/templates/slides/app/routes/settings.tsx +54 -54
  188. package/corpus/templates/slides/app/routes/team.tsx +2 -12
  189. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +9 -9
  190. package/corpus/templates/slides/server/handlers/image-gen.ts +5 -1
  191. package/corpus/templates/slides/server/handlers/image-providers/gemini.ts +9 -1
  192. package/corpus/templates/slides/server/handlers/image-providers/index.ts +18 -8
  193. package/corpus/templates/slides/server/handlers/image-providers/openai.ts +10 -4
  194. package/corpus/templates/slides/server/handlers/image-providers/types.ts +1 -0
  195. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +59 -34
  196. package/corpus/templates/slides/server/register-secrets.ts +60 -0
  197. package/corpus/templates/videos/actions/db-connect.ts +7 -45
  198. package/corpus/templates/videos/app/components/CloudUpgrade.tsx +8 -51
  199. package/corpus/templates/videos/app/components/Sidebar.tsx +1 -9
  200. package/corpus/templates/videos/app/components/layout/Header.tsx +0 -1
  201. package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +0 -3
  202. package/corpus/templates/videos/app/routes/settings.tsx +54 -54
  203. package/corpus/templates/videos/app/routes/team.tsx +2 -8
  204. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  205. package/dist/agent/engine/builder-engine.js +8 -3
  206. package/dist/agent/engine/builder-engine.js.map +1 -1
  207. package/dist/cli/mcp.d.ts.map +1 -1
  208. package/dist/cli/mcp.js +3 -4
  209. package/dist/cli/mcp.js.map +1 -1
  210. package/dist/client/AssistantChat.d.ts.map +1 -1
  211. package/dist/client/AssistantChat.js +6 -2
  212. package/dist/client/AssistantChat.js.map +1 -1
  213. package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
  214. package/dist/client/chat/markdown-renderer.js +1 -0
  215. package/dist/client/chat/markdown-renderer.js.map +1 -1
  216. package/dist/client/index.d.ts +1 -1
  217. package/dist/client/index.d.ts.map +1 -1
  218. package/dist/client/index.js +1 -1
  219. package/dist/client/index.js.map +1 -1
  220. package/dist/client/org/OrgSwitcher.d.ts +3 -3
  221. package/dist/client/org/OrgSwitcher.js +2 -2
  222. package/dist/client/org/OrgSwitcher.js.map +1 -1
  223. package/dist/client/org/TeamPage.d.ts +6 -1
  224. package/dist/client/org/TeamPage.d.ts.map +1 -1
  225. package/dist/client/org/TeamPage.js +2 -2
  226. package/dist/client/org/TeamPage.js.map +1 -1
  227. package/dist/client/settings/SettingsTabsPage.d.ts +27 -0
  228. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -0
  229. package/dist/client/settings/SettingsTabsPage.js +108 -0
  230. package/dist/client/settings/SettingsTabsPage.js.map +1 -0
  231. package/dist/client/settings/index.d.ts +1 -0
  232. package/dist/client/settings/index.d.ts.map +1 -1
  233. package/dist/client/settings/index.js +1 -0
  234. package/dist/client/settings/index.js.map +1 -1
  235. package/dist/collab/awareness.d.ts +2 -2
  236. package/dist/collab/awareness.d.ts.map +1 -1
  237. package/dist/collab/routes.d.ts +1 -1
  238. package/dist/file-upload/index.d.ts +1 -1
  239. package/dist/file-upload/index.d.ts.map +1 -1
  240. package/dist/file-upload/index.js +1 -1
  241. package/dist/file-upload/index.js.map +1 -1
  242. package/dist/file-upload/registry.d.ts +1 -0
  243. package/dist/file-upload/registry.d.ts.map +1 -1
  244. package/dist/file-upload/registry.js +24 -6
  245. package/dist/file-upload/registry.js.map +1 -1
  246. package/dist/file-upload/types.d.ts +6 -1
  247. package/dist/file-upload/types.d.ts.map +1 -1
  248. package/dist/file-upload/types.js.map +1 -1
  249. package/dist/integrations/adapters/email.d.ts.map +1 -1
  250. package/dist/integrations/adapters/email.js +18 -18
  251. package/dist/integrations/adapters/email.js.map +1 -1
  252. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  253. package/dist/integrations/adapters/slack.js +8 -7
  254. package/dist/integrations/adapters/slack.js.map +1 -1
  255. package/dist/integrations/adapters/telegram.d.ts.map +1 -1
  256. package/dist/integrations/adapters/telegram.js +9 -9
  257. package/dist/integrations/adapters/telegram.js.map +1 -1
  258. package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
  259. package/dist/integrations/adapters/whatsapp.js +10 -9
  260. package/dist/integrations/adapters/whatsapp.js.map +1 -1
  261. package/dist/integrations/plugin.d.ts.map +1 -1
  262. package/dist/integrations/plugin.js +47 -13
  263. package/dist/integrations/plugin.js.map +1 -1
  264. package/dist/notifications/routes.d.ts +1 -1
  265. package/dist/onboarding/default-steps.d.ts.map +1 -1
  266. package/dist/onboarding/default-steps.js +6 -5
  267. package/dist/onboarding/default-steps.js.map +1 -1
  268. package/dist/onboarding/types.d.ts +1 -1
  269. package/dist/onboarding/types.d.ts.map +1 -1
  270. package/dist/onboarding/types.js.map +1 -1
  271. package/dist/org/handlers.js +1 -1
  272. package/dist/org/handlers.js.map +1 -1
  273. package/dist/progress/routes.d.ts +1 -1
  274. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  275. package/dist/server/agent-chat-plugin.js +4 -6
  276. package/dist/server/agent-chat-plugin.js.map +1 -1
  277. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  278. package/dist/server/better-auth-instance.d.ts.map +1 -1
  279. package/dist/server/better-auth-instance.js +17 -56
  280. package/dist/server/better-auth-instance.js.map +1 -1
  281. package/dist/server/core-routes-plugin.d.ts +1 -1
  282. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  283. package/dist/server/core-routes-plugin.js +67 -153
  284. package/dist/server/core-routes-plugin.js.map +1 -1
  285. package/dist/server/create-server.d.ts +3 -9
  286. package/dist/server/create-server.d.ts.map +1 -1
  287. package/dist/server/create-server.js +37 -91
  288. package/dist/server/create-server.js.map +1 -1
  289. package/dist/server/email-actions.d.ts +2 -3
  290. package/dist/server/email-actions.d.ts.map +1 -1
  291. package/dist/server/email-actions.js +3 -6
  292. package/dist/server/email-actions.js.map +1 -1
  293. package/dist/server/email.d.ts +3 -3
  294. package/dist/server/email.d.ts.map +1 -1
  295. package/dist/server/email.js +40 -19
  296. package/dist/server/email.js.map +1 -1
  297. package/dist/server/index.d.ts +3 -3
  298. package/dist/server/index.d.ts.map +1 -1
  299. package/dist/server/index.js +3 -3
  300. package/dist/server/index.js.map +1 -1
  301. package/dist/server/scoped-key-storage.d.ts +22 -0
  302. package/dist/server/scoped-key-storage.d.ts.map +1 -0
  303. package/dist/server/scoped-key-storage.js +152 -0
  304. package/dist/server/scoped-key-storage.js.map +1 -0
  305. package/dist/shared/agent-env.d.ts +3 -3
  306. package/dist/shared/agent-env.d.ts.map +1 -1
  307. package/dist/shared/agent-env.js +3 -3
  308. package/dist/shared/agent-env.js.map +1 -1
  309. package/dist/sharing/actions/share-resource.js +1 -1
  310. package/dist/sharing/actions/share-resource.js.map +1 -1
  311. package/dist/styles/agent-native.css +55 -3
  312. package/dist/templates/workspace-root/AGENTS.md +3 -2
  313. package/dist/templates/workspace-root/README.md +1 -1
  314. package/dist/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
  315. package/dist/terminal/pty-server.d.ts.map +1 -1
  316. package/dist/terminal/pty-server.js +3 -36
  317. package/dist/terminal/pty-server.js.map +1 -1
  318. package/dist/triggers/dispatcher.js +1 -1
  319. package/dist/triggers/dispatcher.js.map +1 -1
  320. package/docs/content/file-uploads.md +11 -4
  321. package/docs/content/locales/ar-SA/multi-app-workspace.md +3 -3
  322. package/docs/content/locales/de-DE/multi-app-workspace.md +3 -3
  323. package/docs/content/locales/es-ES/multi-app-workspace.md +3 -3
  324. package/docs/content/locales/fr-FR/multi-app-workspace.md +3 -3
  325. package/docs/content/locales/hi-IN/multi-app-workspace.md +3 -3
  326. package/docs/content/locales/ja-JP/multi-app-workspace.md +3 -3
  327. package/docs/content/locales/ko-KR/multi-app-workspace.md +3 -3
  328. package/docs/content/locales/pt-BR/multi-app-workspace.md +3 -3
  329. package/docs/content/locales/zh-CN/multi-app-workspace.md +3 -3
  330. package/docs/content/locales/zh-TW/multi-app-workspace.md +3 -3
  331. package/docs/content/multi-app-workspace.md +3 -3
  332. package/docs/content/template-clips.md +14 -5
  333. package/package.json +1 -1
  334. package/src/templates/workspace-root/AGENTS.md +3 -2
  335. package/src/templates/workspace-root/README.md +1 -1
  336. package/src/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
  337. package/corpus/core/src/server/env-var-writes.ts +0 -16
  338. package/corpus/templates/analytics/app/pages/Team.tsx +0 -9
  339. package/corpus/templates/calendar/app/pages/Team.tsx +0 -12
  340. package/corpus/templates/mail/app/pages/Team.tsx +0 -17
  341. package/dist/server/env-var-writes.d.ts +0 -10
  342. package/dist/server/env-var-writes.d.ts.map +0 -1
  343. package/dist/server/env-var-writes.js +0 -18
  344. 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";
@@ -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,9 +201,11 @@ 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
@@ -413,6 +437,10 @@ export default function RecordingPage() {
413
437
  if (!canUseNativeEditor && editing) setEditing(false);
414
438
  }, [canUseNativeEditor, editing]);
415
439
 
440
+ useEffect(() => {
441
+ if (editing || !isCompactLayout) setSidePanelOpen(false);
442
+ }, [editing, isCompactLayout]);
443
+
416
444
  useEffect(() => {
417
445
  if (!recording) return;
418
446
  document.title = isDefaultTitle(recording.title)
@@ -647,6 +675,158 @@ export default function RecordingPage() {
647
675
  );
648
676
  }
649
677
 
678
+ const renderSidePanel = (compact = false) => (
679
+ <Tabs
680
+ value={panel}
681
+ onValueChange={(v) => setPanel(v as SidePanel)}
682
+ className={cn("flex h-full flex-col", compact && "pt-8")}
683
+ >
684
+ <TabsList
685
+ className={cn(
686
+ "mx-3 mt-3 grid w-auto",
687
+ canEdit ? "grid-cols-5" : "grid-cols-4",
688
+ )}
689
+ >
690
+ <TabsTrigger value="agent" className="min-w-0 px-2 text-xs">
691
+ {t("recordingPage.agent")}
692
+ </TabsTrigger>
693
+ <TabsTrigger value="comments" className="min-w-0 px-2 text-xs">
694
+ {t("recordingPage.activity")}
695
+ </TabsTrigger>
696
+ <TabsTrigger value="transcript" className="min-w-0 px-2 text-xs">
697
+ {t("recordingPage.transcript")}
698
+ </TabsTrigger>
699
+ <TabsTrigger value="insights" className="min-w-0 px-2 text-xs">
700
+ {t("recordingPage.insights")}
701
+ </TabsTrigger>
702
+ {canEdit ? (
703
+ <TabsTrigger value="settings" className="min-w-0 px-2 text-xs">
704
+ {t("recordingPage.settings")}
705
+ </TabsTrigger>
706
+ ) : null}
707
+ </TabsList>
708
+
709
+ <TabsContent
710
+ value="agent"
711
+ className="mt-0 flex flex-1 min-h-0 flex-col data-[state=inactive]:hidden"
712
+ >
713
+ <AgentPanel
714
+ browserTabId={getBrowserTabId()}
715
+ emptyStateText={t("recordingPage.askAboutClip")}
716
+ dynamicSuggestions={false}
717
+ chatNotice={
718
+ generatedWorkflow ? (
719
+ <GeneratedWorkflowNotice workflow={generatedWorkflow} />
720
+ ) : null
721
+ }
722
+ suggestions={
723
+ canEdit
724
+ ? [
725
+ t("recordingPage.summarizeClip"),
726
+ t("recordingPage.generateChapters"),
727
+ t("recordingPage.findActionItems"),
728
+ t("recordingPage.draftRecap"),
729
+ ]
730
+ : [
731
+ t("recordingPage.summarizeClip"),
732
+ t("recordingPage.findKeyMoments"),
733
+ t("recordingPage.listFollowUpActions"),
734
+ t("recordingPage.draftQuestions"),
735
+ ]
736
+ }
737
+ />
738
+ </TabsContent>
739
+ <TabsContent
740
+ value="transcript"
741
+ className="flex-1 min-h-0 mt-3 data-[state=inactive]:hidden"
742
+ >
743
+ <TranscriptPanel
744
+ segments={transcriptSegments}
745
+ fullText={transcriptFullText}
746
+ durationMs={recording.durationMs}
747
+ currentMs={currentMs}
748
+ onSeek={(ms) => playerRef.current?.seek(ms)}
749
+ status={transcriptStatus}
750
+ failureReason={transcriptFailureReason}
751
+ cleanup={transcriptCleanup}
752
+ recordingTitle={recording.title}
753
+ onRetry={() => {
754
+ // Force a fresh transcript job, then let polling swap the panel
755
+ // back to the pending state while it runs.
756
+ fetch(
757
+ agentNativePath("/_agent-native/actions/request-transcript"),
758
+ {
759
+ method: "POST",
760
+ headers: { "Content-Type": "application/json" },
761
+ body: JSON.stringify({
762
+ recordingId: recording.id,
763
+ force: true,
764
+ }),
765
+ },
766
+ )
767
+ .then((res) => {
768
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
769
+ })
770
+ .catch((err) =>
771
+ toast.error(
772
+ t("recordingPage.retryFailed", {
773
+ message: err?.message ?? t("recordingPage.networkError"),
774
+ }),
775
+ ),
776
+ )
777
+ .finally(() => playerDataQ.refetch());
778
+ }}
779
+ />
780
+ </TabsContent>
781
+ <TabsContent
782
+ value="comments"
783
+ className="flex-1 min-h-0 mt-3 data-[state=inactive]:hidden"
784
+ >
785
+ <CommentsPanel
786
+ recordingId={recording.id}
787
+ comments={comments}
788
+ currentMs={currentMs}
789
+ currentUserEmail={session?.email}
790
+ enableComments={recording.enableComments}
791
+ onSeek={(ms) => playerRef.current?.seek(ms)}
792
+ queryKey={[
793
+ "action",
794
+ "get-recording-player-data",
795
+ { recordingId: recordingId ?? "" },
796
+ ]}
797
+ />
798
+ </TabsContent>
799
+ <TabsContent
800
+ value="insights"
801
+ className="flex-1 min-h-0 mt-3 overflow-y-auto data-[state=inactive]:hidden"
802
+ >
803
+ {canEdit ? (
804
+ <InsightsPanel
805
+ recordingId={recording.id}
806
+ durationMs={recording.durationMs}
807
+ />
808
+ ) : (
809
+ <InsightsUnavailableState />
810
+ )}
811
+ </TabsContent>
812
+ {canEdit ? (
813
+ <TabsContent
814
+ value="settings"
815
+ className="mt-3 flex flex-1 min-h-0 flex-col data-[state=inactive]:hidden"
816
+ >
817
+ <SettingsPanel
818
+ recording={recording}
819
+ visibility={recording.visibility}
820
+ ctas={ctas}
821
+ onClose={() => setPanel("agent")}
822
+ onRefetch={() => playerDataQ.refetch()}
823
+ showHeader={false}
824
+ />
825
+ </TabsContent>
826
+ ) : null}
827
+ </Tabs>
828
+ );
829
+
650
830
  return (
651
831
  <div className="flex h-screen w-full bg-background overflow-hidden">
652
832
  {/* Main video column */}
@@ -797,6 +977,23 @@ export default function RecordingPage() {
797
977
  </DropdownMenu>
798
978
  ) : null}
799
979
 
980
+ {!editing ? (
981
+ <Tooltip>
982
+ <TooltipTrigger asChild>
983
+ <Button
984
+ variant="outline"
985
+ size="icon"
986
+ className="xl:hidden"
987
+ onClick={() => setSidePanelOpen(true)}
988
+ aria-label={t("recordingPage.details")}
989
+ >
990
+ <IconLayoutSidebarRightExpand className="h-4 w-4" />
991
+ </Button>
992
+ </TooltipTrigger>
993
+ <TooltipContent>{t("recordingPage.details")}</TooltipContent>
994
+ </Tooltip>
995
+ ) : null}
996
+
800
997
  <ShareRecordingPopover
801
998
  recordingId={recording.id}
802
999
  recordingTitle={recording.title}
@@ -935,162 +1132,29 @@ export default function RecordingPage() {
935
1132
 
936
1133
  {/* Side panel */}
937
1134
  {!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"
1135
+ <>
1136
+ {isCompactLayout ? (
1137
+ <Sheet open={sidePanelOpen} onOpenChange={setSidePanelOpen}>
1138
+ <SheetContent
1139
+ side="right"
1140
+ className="flex h-full w-[calc(100vw-24px)] max-w-[420px] flex-col gap-0 p-0 sm:max-w-[420px]"
1081
1141
  >
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>
1142
+ <SheetTitle className="sr-only">
1143
+ {t("recordingPage.details")}
1144
+ </SheetTitle>
1145
+ <SheetDescription className="sr-only">
1146
+ {t("recordingPage.askAboutClip")}
1147
+ </SheetDescription>
1148
+ {renderSidePanel(true)}
1149
+ </SheetContent>
1150
+ </Sheet>
1151
+ ) : null}
1152
+ {!isCompactLayout ? (
1153
+ <aside className="hidden w-[380px] shrink-0 flex-col border-s border-border bg-background xl:flex">
1154
+ {renderSidePanel()}
1155
+ </aside>
1156
+ ) : null}
1157
+ </>
1094
1158
  ) : null}
1095
1159
  </div>
1096
1160
  );
@@ -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
+ 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 clip details sidebar now collapses into a slide-out panel on smaller screens.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-06-26
4
+ ---
5
+
6
+ The Clips library now matches the shared recessed shell styling.
@@ -86,6 +86,7 @@ const NATIVE_FULLSCREEN_RECORDING_FLAG = "clips:native-fullscreen-recording";
86
86
  const DEV_SYNTHETIC_CAPTURE_FLAG = "clips:dev-synthetic-capture";
87
87
  const LEGACY_DEV_REAL_CAPTURE_FLAG = "clips:dev-real-capture";
88
88
  const LIVE_UPLOAD_CHUNK_MS = 1_000;
89
+ const NATIVE_FULLSCREEN_SEGMENT_MS = 5 * 60_000;
89
90
  const CLOUD_CAPTURE_FRAME_RATE = 24;
90
91
  const CLOUD_CAPTURE_MAX_WIDTH = 1920;
91
92
  const CLOUD_CAPTURE_MAX_HEIGHT = 1080;
@@ -122,6 +123,13 @@ export function shouldUseNativeFullscreenRecording(
122
123
  return isMacPlatform();
123
124
  }
124
125
 
126
+ function shouldSaveLocalTranscriptionStartupFailure(): boolean {
127
+ // Local Whisper/SFSpeech capture is macOS-only today. Non-mac desktop builds
128
+ // should wait for upload transcription instead of publishing a misleading
129
+ // native-transcription failure before `request-transcript` runs.
130
+ return isMacPlatform();
131
+ }
132
+
125
133
  function shouldUseDevSyntheticCapture(): boolean {
126
134
  if (!import.meta.env.DEV) return false;
127
135
  if (typeof localStorage === "undefined") return false;
@@ -962,7 +970,7 @@ async function saveRecordingTranscript(
962
970
  recordingId,
963
971
  fullText: text,
964
972
  segments: transcript.segments,
965
- source: "whisper",
973
+ source: transcript.source ?? "whisper",
966
974
  }),
967
975
  });
968
976
  if (!res.ok) {
@@ -1753,6 +1761,8 @@ async function startNativeFullscreenRecording(
1753
1761
  let cancelPromise: Promise<void> | null = null;
1754
1762
  let stateUnlistens: UnlistenFn[] = [];
1755
1763
  let tickHandle: ReturnType<typeof setInterval> | null = null;
1764
+ let segmentRotateHandle: ReturnType<typeof setInterval> | null = null;
1765
+ let segmentRotateInFlight = false;
1756
1766
  // Pause/resume tracking. The Rust side actually stops the SCStream on
1757
1767
  // pause and starts a new segment on resume; on stop it concatenates
1758
1768
  // segments via AVFoundation. We keep the JS-side timer in sync so the
@@ -1760,6 +1770,37 @@ async function startNativeFullscreenRecording(
1760
1770
  let pausedAt: number | null = null;
1761
1771
  let accumulatedPauseMs = 0;
1762
1772
 
1773
+ function clearSegmentRotator() {
1774
+ if (segmentRotateHandle) {
1775
+ clearInterval(segmentRotateHandle);
1776
+ segmentRotateHandle = null;
1777
+ }
1778
+ }
1779
+
1780
+ function startSegmentRotator() {
1781
+ clearSegmentRotator();
1782
+ segmentRotateHandle = setInterval(() => {
1783
+ if (stopped || pausedAt != null || segmentRotateInFlight) return;
1784
+ segmentRotateInFlight = true;
1785
+ invoke("native_fullscreen_recording_rotate_segment")
1786
+ .catch((err) => {
1787
+ const message = err instanceof Error ? err.message : String(err);
1788
+ console.warn("[clips-recorder] native segment rotation failed:", err);
1789
+ if (
1790
+ !stopped &&
1791
+ pausedAt == null &&
1792
+ message.includes("paused recording")
1793
+ ) {
1794
+ pausedAt = Date.now();
1795
+ emitState();
1796
+ }
1797
+ })
1798
+ .finally(() => {
1799
+ segmentRotateInFlight = false;
1800
+ });
1801
+ }, NATIVE_FULLSCREEN_SEGMENT_MS);
1802
+ }
1803
+
1763
1804
  function emitState() {
1764
1805
  const now = Date.now();
1765
1806
  const pausedNowMs = pausedAt != null ? now - pausedAt : 0;
@@ -1781,6 +1822,7 @@ async function startNativeFullscreenRecording(
1781
1822
  stopped = true;
1782
1823
  console.log("[clips-recorder] native full-screen stop requested");
1783
1824
  if (!localOnly) showFinalizingFeedback();
1825
+ clearSegmentRotator();
1784
1826
  if (tickHandle) {
1785
1827
  clearInterval(tickHandle);
1786
1828
  tickHandle = null;
@@ -1940,6 +1982,7 @@ async function startNativeFullscreenRecording(
1940
1982
  if (stopped) return;
1941
1983
  cancelPromise = (async () => {
1942
1984
  stopped = true;
1985
+ clearSegmentRotator();
1943
1986
  if (tickHandle) {
1944
1987
  clearInterval(tickHandle);
1945
1988
  tickHandle = null;
@@ -2020,6 +2063,7 @@ async function startNativeFullscreenRecording(
2020
2063
  ]);
2021
2064
  stateUnlistens = toolbarUnlistens;
2022
2065
  tickHandle = setInterval(emitState, 500);
2066
+ startSegmentRotator();
2023
2067
  emit("clips:toolbar-enabled", true).catch(() => {});
2024
2068
  emitState();
2025
2069
 
@@ -2041,7 +2085,11 @@ async function startNativeFullscreenRecording(
2041
2085
  if (stopped && transcriptionCapture) {
2042
2086
  void transcriptionCapture.cancel().catch(() => {});
2043
2087
  transcriptionCapture = null;
2044
- } else if (wantsAudio && !transcriptionCapture) {
2088
+ } else if (
2089
+ wantsAudio &&
2090
+ !transcriptionCapture &&
2091
+ shouldSaveLocalTranscriptionStartupFailure()
2092
+ ) {
2045
2093
  void saveTranscriptFailure(
2046
2094
  "macOS Speech recognition could not start for this recording. Check Speech Recognition and Microphone permissions, then retry transcription.",
2047
2095
  );
@@ -2863,7 +2911,11 @@ async function startRecordingInner(
2863
2911
  if (stopped && transcriptionCapture) {
2864
2912
  void transcriptionCapture.cancel().catch(() => {});
2865
2913
  transcriptionCapture = null;
2866
- } else if (wantsAudio && !transcriptionCapture) {
2914
+ } else if (
2915
+ wantsAudio &&
2916
+ !transcriptionCapture &&
2917
+ shouldSaveLocalTranscriptionStartupFailure()
2918
+ ) {
2867
2919
  void saveTranscriptFailure(
2868
2920
  "macOS Speech recognition could not start for this recording. Check Speech Recognition and Microphone permissions, then retry transcription.",
2869
2921
  );