@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
@@ -9,6 +9,7 @@ import {
9
9
  encodeOAuthState,
10
10
  decodeOAuthState,
11
11
  resolveOAuthOwner,
12
+ resolveSecret,
12
13
  createOAuthSession,
13
14
  oauthCallbackResponse,
14
15
  oauthDesktopExchangePage,
@@ -16,6 +17,7 @@ import {
16
17
  setDesktopExchange,
17
18
  setDesktopExchangeError,
18
19
  safeReturnPath,
20
+ runWithRequestContext,
19
21
  } from "@agent-native/core/server";
20
22
  import {
21
23
  defineEventHandler,
@@ -41,9 +43,15 @@ const GOOGLE_IDENTITY_SCOPES = [
41
43
  "https://www.googleapis.com/auth/userinfo.profile",
42
44
  ];
43
45
 
44
- function resolveCalendarOAuthCredentials() {
45
- const clientId = process.env.GOOGLE_CLIENT_ID;
46
- const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
46
+ async function resolveCalendarOAuthCredentials(event: H3Event) {
47
+ const session = await getSession(event).catch(() => null);
48
+ const { clientId, clientSecret } = await runWithRequestContext(
49
+ { userEmail: session?.email, orgId: session?.orgId },
50
+ async () => ({
51
+ clientId: await resolveSecret("GOOGLE_CLIENT_ID"),
52
+ clientSecret: await resolveSecret("GOOGLE_CLIENT_SECRET"),
53
+ }),
54
+ );
47
55
  if (!clientId || !clientSecret) return null;
48
56
  return { clientId, clientSecret };
49
57
  }
@@ -192,7 +200,7 @@ export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
192
200
  const flowId = desktop ? (q.flow_id as string) || undefined : undefined;
193
201
  const calendarConnect = isCalendarConnectRequest(q, owner);
194
202
  const credentials = calendarConnect
195
- ? resolveCalendarOAuthCredentials()
203
+ ? await resolveCalendarOAuthCredentials(event)
196
204
  : resolveGoogleSignInCredentials();
197
205
 
198
206
  if (!credentials) {
@@ -200,7 +208,7 @@ export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
200
208
  return {
201
209
  error: "missing_credentials",
202
210
  message: calendarConnect
203
- ? "Google Calendar OAuth credentials are not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET."
211
+ ? "Google Calendar OAuth credentials are not configured. Save GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in settings."
204
212
  : "Google sign-in credentials are not configured. Set GOOGLE_SIGN_IN_CLIENT_ID and GOOGLE_SIGN_IN_CLIENT_SECRET.",
205
213
  };
206
214
  }
@@ -229,7 +237,7 @@ export const getGoogleAuthUrl = defineEventHandler(async (event: H3Event) => {
229
237
  });
230
238
 
231
239
  const url = calendarConnect
232
- ? getAuthUrl(undefined, redirectUri, state)
240
+ ? await getAuthUrl(undefined, redirectUri, state, owner)
233
241
  : `${GOOGLE_AUTH_URL}?${new URLSearchParams({
234
242
  client_id: credentials.clientId,
235
243
  redirect_uri: redirectUri,
@@ -364,12 +372,12 @@ export const getGoogleAddAccountUrl = defineEventHandler(
364
372
  setResponseStatus(event, 401);
365
373
  return { error: "Must be logged in to add an account" };
366
374
  }
367
- if (!process.env.GOOGLE_CLIENT_ID || !process.env.GOOGLE_CLIENT_SECRET) {
375
+ if (!(await resolveCalendarOAuthCredentials(event))) {
368
376
  setResponseStatus(event, 422);
369
377
  return {
370
378
  error: "missing_credentials",
371
379
  message:
372
- "Google OAuth credentials are not configured. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET.",
380
+ "Google OAuth credentials are not configured. Save GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in settings.",
373
381
  };
374
382
  }
375
383
  try {
@@ -393,7 +401,12 @@ export const getGoogleAddAccountUrl = defineEventHandler(
393
401
  app: OAUTH_STATE_APP_ID,
394
402
  flowId,
395
403
  });
396
- const url = getAuthUrl(undefined, redirectUri, state);
404
+ const url = await getAuthUrl(
405
+ undefined,
406
+ redirectUri,
407
+ state,
408
+ session.email,
409
+ );
397
410
  if (q.redirect === "1") {
398
411
  return oauthRedirectResponse(url);
399
412
  }
@@ -49,7 +49,7 @@ async function sendBestEffort(
49
49
  label: string,
50
50
  args: Parameters<typeof sendEmail>[0],
51
51
  ) {
52
- if (!isEmailConfigured()) return;
52
+ if (!(await isEmailConfigured())) return;
53
53
  try {
54
54
  await sendEmail(args);
55
55
  } catch (error) {
@@ -129,7 +129,7 @@ export async function sendEventGuestNotificationNote({
129
129
  };
130
130
  }
131
131
 
132
- if (!isEmailConfigured()) {
132
+ if (!(await isEmailConfigured())) {
133
133
  return {
134
134
  requested: true,
135
135
  recipientCount: recipients.length,
@@ -4,7 +4,12 @@ import {
4
4
  deleteOAuthTokens,
5
5
  listOAuthAccountsByOwner,
6
6
  } from "@agent-native/core/oauth-tokens";
7
- import { isOAuthConnected, getOAuthAccounts } from "@agent-native/core/server";
7
+ import {
8
+ isOAuthConnected,
9
+ getOAuthAccounts,
10
+ resolveSecret,
11
+ runWithRequestContext,
12
+ } from "@agent-native/core/server";
8
13
 
9
14
  import type {
10
15
  CalendarEvent,
@@ -56,48 +61,59 @@ function optionalString(value: unknown): string | undefined {
56
61
  return typeof value === "string" && value.length > 0 ? value : undefined;
57
62
  }
58
63
 
59
- function getOAuth2Credentials() {
60
- const credentials = resolveGoogleProviderCredentialCandidates()[0];
64
+ async function getOAuth2Credentials(owner?: string) {
65
+ const credentials = (
66
+ await resolveGoogleProviderCredentialCandidates(owner)
67
+ )[0];
61
68
  if (!credentials) {
62
69
  throw new Error(
63
- "GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET must be set in environment",
70
+ "GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET must be saved in settings",
64
71
  );
65
72
  }
66
73
  return credentials;
67
74
  }
68
75
 
69
- function getOAuth2RefreshCredentials() {
70
- const candidates = resolveGoogleProviderCredentialCandidates();
76
+ async function getOAuth2RefreshCredentials(owner?: string) {
77
+ const candidates = await resolveGoogleProviderCredentialCandidates(owner);
71
78
  if (!candidates.length) {
72
79
  throw new Error(
73
- "GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET must be set in environment",
80
+ "GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET must be saved in settings",
74
81
  );
75
82
  }
76
83
  return candidates;
77
84
  }
78
85
 
79
- function readCredentialPair(
86
+ async function readCredentialPair(
80
87
  clientIdKey: string,
81
88
  clientSecretKey: string,
82
- ): GoogleOAuthCredentials | null {
83
- const clientId = process.env[clientIdKey];
84
- const clientSecret = process.env[clientSecretKey];
89
+ ): Promise<GoogleOAuthCredentials | null> {
90
+ const [clientId, clientSecret] = await Promise.all([
91
+ resolveSecret(clientIdKey),
92
+ resolveSecret(clientSecretKey),
93
+ ]);
85
94
  if (!clientId || !clientSecret) return null;
86
95
  return { clientId, clientSecret };
87
96
  }
88
97
 
89
- function resolveGoogleProviderCredentialCandidates(): GoogleOAuthCredentials[] {
90
- const primary = readCredentialPair(
91
- "GOOGLE_CLIENT_ID",
92
- "GOOGLE_CLIENT_SECRET",
93
- );
94
- const legacy = readCredentialPair(
95
- "GOOGLE_LEGACY_CLIENT_ID",
96
- "GOOGLE_LEGACY_CLIENT_SECRET",
97
- );
98
- if (!primary) return legacy ? [legacy] : [];
99
- if (!legacy || legacy.clientId === primary.clientId) return [primary];
100
- return [primary, legacy];
98
+ async function resolveGoogleProviderCredentialCandidates(
99
+ owner?: string,
100
+ ): Promise<GoogleOAuthCredentials[]> {
101
+ const resolve = async () => {
102
+ const primary = await readCredentialPair(
103
+ "GOOGLE_CLIENT_ID",
104
+ "GOOGLE_CLIENT_SECRET",
105
+ );
106
+ const legacy = await readCredentialPair(
107
+ "GOOGLE_LEGACY_CLIENT_ID",
108
+ "GOOGLE_LEGACY_CLIENT_SECRET",
109
+ );
110
+ if (!primary) return legacy ? [legacy] : [];
111
+ if (!legacy || legacy.clientId === primary.clientId) return [primary];
112
+ return [primary, legacy];
113
+ };
114
+ return owner
115
+ ? runWithRequestContext({ userEmail: owner }, resolve)
116
+ : await resolve();
101
117
  }
102
118
 
103
119
  /**
@@ -356,7 +372,10 @@ async function getValidAccessToken(
356
372
  }
357
373
  try {
358
374
  let lastRefreshError: any;
359
- for (const { clientId, clientSecret } of getOAuth2RefreshCredentials()) {
375
+ for (const {
376
+ clientId,
377
+ clientSecret,
378
+ } of await getOAuth2RefreshCredentials(owner)) {
360
379
  try {
361
380
  const oauth2 = createOAuth2Client(clientId, clientSecret, "");
362
381
  const newTokens = await oauth2.refreshToken(tokens.refresh_token);
@@ -396,12 +415,13 @@ async function getValidAccessToken(
396
415
  return tokens.access_token;
397
416
  }
398
417
 
399
- export function getAuthUrl(
418
+ export async function getAuthUrl(
400
419
  origin?: string,
401
420
  redirectUri?: string,
402
421
  state?: string,
403
- ): string {
404
- const { clientId, clientSecret } = getOAuth2Credentials();
422
+ owner?: string,
423
+ ): Promise<string> {
424
+ const { clientId, clientSecret } = await getOAuth2Credentials(owner);
405
425
  const uri =
406
426
  redirectUri ||
407
427
  (origin ? `${origin}/_agent-native/google/callback` : undefined);
@@ -420,7 +440,7 @@ export async function exchangeCode(
420
440
  redirectUri?: string,
421
441
  owner?: string,
422
442
  ): Promise<string> {
423
- const { clientId, clientSecret } = getOAuth2Credentials();
443
+ const { clientId, clientSecret } = await getOAuth2Credentials(owner);
424
444
  const uri =
425
445
  redirectUri ||
426
446
  (origin ? `${origin}/_agent-native/google/callback` : undefined);
@@ -10,7 +10,6 @@ const pageTitleKeys: Record<string, string> = {
10
10
  "/": "navigation.chat",
11
11
  "/observability": "navigation.observability",
12
12
  "/settings": "navigation.settings",
13
- "/team": "navigation.team",
14
13
  };
15
14
 
16
15
  function resolveTitle(pathname: string, t: (key: string) => string): string {
@@ -60,7 +60,7 @@ function viewForPath(pathname: string): string {
60
60
  if (pathname.startsWith("/database")) return "database";
61
61
  if (pathname.startsWith("/extensions")) return "extensions";
62
62
  if (pathname.startsWith("/observability")) return "observability";
63
- if (pathname.startsWith("/team")) return "team";
63
+ if (pathname.startsWith("/team")) return "settings";
64
64
  return "chat";
65
65
  }
66
66
 
@@ -76,8 +76,10 @@ function pathForView(view?: string): string {
76
76
  return "/extensions";
77
77
  case "observability":
78
78
  return "/observability";
79
+ case "settings":
80
+ return "/settings";
79
81
  case "team":
80
- return "/team";
82
+ return "/settings#team";
81
83
  default:
82
84
  return "/";
83
85
  }
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  ChangelogSettingsCard,
3
3
  LanguagePicker,
4
+ SettingsTabsPage,
4
5
  openAgentSettings,
5
6
  useT,
6
7
  } from "@agent-native/core/client";
7
- import { Link } from "react-router";
8
+ import { TeamPage } from "@agent-native/core/client/org";
8
9
 
9
10
  import { useSetPageTitle } from "@/components/layout/HeaderActions";
10
11
  import { Button } from "@/components/ui/button";
@@ -29,60 +30,59 @@ export default function SettingsRoute() {
29
30
  useSetPageTitle(t("settings.title"));
30
31
 
31
32
  return (
32
- <main className="mx-auto w-full max-w-3xl space-y-6 px-4 py-6 sm:px-6 sm:py-10">
33
- <div className="space-y-1">
34
- <h1 className="text-2xl font-semibold tracking-tight">
35
- {t("settings.title")}
36
- </h1>
37
- <p className="text-sm leading-6 text-muted-foreground">
38
- {t("settings.description")}
39
- </p>
40
- </div>
33
+ <SettingsTabsPage
34
+ teamLabel={t("navigation.team")}
35
+ general={
36
+ <div className="mx-auto w-full max-w-3xl space-y-6">
37
+ <p className="text-sm leading-6 text-muted-foreground">
38
+ {t("settings.description")}
39
+ </p>
41
40
 
42
- <Card>
43
- <CardHeader>
44
- <CardTitle className="text-base">
45
- {t("settings.languageTitle")}
46
- </CardTitle>
47
- <CardDescription>{t("settings.languageDescription")}</CardDescription>
48
- </CardHeader>
49
- <CardContent className="max-w-xs space-y-1.5">
50
- <Label>{t("settings.languageLabel")}</Label>
51
- <LanguagePicker label={t("settings.languageLabel")} />
52
- </CardContent>
53
- </Card>
41
+ <Card>
42
+ <CardHeader>
43
+ <CardTitle className="text-base">
44
+ {t("settings.languageTitle")}
45
+ </CardTitle>
46
+ <CardDescription>
47
+ {t("settings.languageDescription")}
48
+ </CardDescription>
49
+ </CardHeader>
50
+ <CardContent className="max-w-xs space-y-1.5">
51
+ <Label>{t("settings.languageLabel")}</Label>
52
+ <LanguagePicker label={t("settings.languageLabel")} />
53
+ </CardContent>
54
+ </Card>
54
55
 
55
- <Card>
56
- <CardHeader>
57
- <CardTitle className="text-base">
58
- {t("settings.workspaceTitle")}
59
- </CardTitle>
60
- <CardDescription>
61
- {t("settings.workspaceDescription")}
62
- </CardDescription>
63
- </CardHeader>
64
- <CardContent>
65
- <Button variant="outline" asChild>
66
- <Link to="/team">{t("settings.openTeamSettings")}</Link>
67
- </Button>
68
- </CardContent>
69
- </Card>
70
-
71
- <Card>
72
- <CardHeader>
73
- <CardTitle className="text-base">
74
- {t("settings.agentTitle")}
75
- </CardTitle>
76
- <CardDescription>{t("settings.agentDescription")}</CardDescription>
77
- </CardHeader>
78
- <CardContent>
79
- <Button variant="outline" onClick={() => openAgentSettings()}>
80
- {t("settings.openAgentSettings")}
81
- </Button>
82
- </CardContent>
83
- </Card>
84
-
85
- <ChangelogSettingsCard markdown={changelog} />
86
- </main>
56
+ <Card>
57
+ <CardHeader>
58
+ <CardTitle className="text-base">
59
+ {t("settings.agentTitle")}
60
+ </CardTitle>
61
+ <CardDescription>
62
+ {t("settings.agentDescription")}
63
+ </CardDescription>
64
+ </CardHeader>
65
+ <CardContent>
66
+ <Button variant="outline" onClick={() => openAgentSettings()}>
67
+ {t("settings.openAgentSettings")}
68
+ </Button>
69
+ </CardContent>
70
+ </Card>
71
+ </div>
72
+ }
73
+ team={
74
+ <div className="mx-auto w-full max-w-3xl">
75
+ <TeamPage
76
+ showTitle={false}
77
+ createOrgDescription={t("pages.teamCreateOrgDescription")}
78
+ />
79
+ </div>
80
+ }
81
+ whatsNew={
82
+ <div className="mx-auto w-full max-w-3xl">
83
+ <ChangelogSettingsCard markdown={changelog} />
84
+ </div>
85
+ }
86
+ />
87
87
  );
88
88
  }
@@ -1,7 +1,5 @@
1
- import { useT } from "@agent-native/core/client";
2
- import { TeamPage } from "@agent-native/core/client/org";
1
+ import { Navigate } from "react-router";
3
2
 
4
- import { useSetPageTitle } from "@/components/layout/HeaderActions";
5
3
  import { APP_TITLE } from "@/lib/app-config";
6
4
 
7
5
  export function meta() {
@@ -9,11 +7,5 @@ export function meta() {
9
7
  }
10
8
 
11
9
  export default function TeamRoute() {
12
- const t = useT();
13
- useSetPageTitle(t("pages.teamTitle"));
14
- return (
15
- <main className="mx-auto w-full max-w-3xl px-4 py-6 sm:px-6 sm:py-10">
16
- <TeamPage createOrgDescription={t("pages.teamCreateOrgDescription")} />
17
- </main>
18
- );
10
+ return <Navigate to="/settings#team" replace />;
19
11
  }
@@ -11,7 +11,7 @@ description: >-
11
11
 
12
12
  ## Rule
13
13
 
14
- Every AI feature in Clips goes through the agent chat unless it is the narrow media-pipeline exception below. The UI and server should not add broad shadow agents or inline chat workflows. **Exception:** transcription. Transcription takes audio, not prompts — the `request-transcript` action calls the transcription API directly. Provider priority for transcription: **native** first (browser Web Speech API / desktop macOS SFSpeech, saved via `save-browser-transcript`, no key required) → **cloud fallback** when native text is missing: **Builder.io managed** Gemini (via `BUILDER_PRIVATE_KEY` or a connected Builder account, no extra key needed) → **Groq** `whisper-large-v3-turbo` via `GROQ_API_KEY` (fast, ~$0.04/hr). Clips never routes recording/meeting audio to OpenAI for transcription.
14
+ Every AI feature in Clips goes through the agent chat unless it is the narrow media-pipeline exception below. The UI and server should not add broad shadow agents or inline chat workflows. **Exception:** transcription. Transcription takes audio, not prompts — the `request-transcript` action calls the transcription API directly. Provider priority for transcription: **native** first (browser Web Speech API, desktop local Whisper/macOS SFSpeech when available, and desktop Web Speech fallback on non-mac, saved via `save-browser-transcript`, no key required) → **cloud fallback** when native text is missing: **Builder.io managed** Gemini (via `BUILDER_PRIVATE_KEY` or a connected Builder account, no extra key needed) → **Groq** `whisper-large-v3-turbo` via `GROQ_API_KEY` (fast, ~$0.04/hr). Clips never routes recording/meeting audio to OpenAI for transcription.
15
15
 
16
16
  Builder.io is the primary setup path: it brings managed AI credits, object
17
17
  storage, uploads, and transcription together. Bring-your-own-key setup belongs
@@ -99,7 +99,7 @@ Transcription takes an audio file and returns text + segments. That's not a prom
99
99
 
100
100
  **Provider priority:**
101
101
 
102
- 1. **Native (highest priority).** The browser's Web Speech API and desktop macOS SFSpeech capture run during recording and save results via `save-browser-transcript`. This gives an instant transcript with no API key. When `request-transcript` runs afterward, it preserves the ready native transcript and only falls back to a cloud provider if native text is missing.
102
+ 1. **Native (highest priority).** The browser's Web Speech API, desktop local Whisper/macOS SFSpeech when available, and desktop Web Speech fallback on non-mac run during recording and save results via `save-browser-transcript`. This gives an instant transcript with no API key when the local/browser recognizer is available. When `request-transcript` runs afterward, it preserves the ready native transcript and only falls back to a cloud provider if native text is missing.
103
103
  2. **Cloud fallback — Builder.io managed (Gemini).** When a Builder account is connected (`BUILDER_PRIVATE_KEY` or per-user OAuth, no separate API key needed), `request-transcript` calls `transcribeWithBuilder()`, which routes audio to Builder.io's managed Gemini transcription. Returns text plus timestamped segments.
104
104
  3. **Cloud fallback — Groq Whisper.** `GROQ_API_KEY` → `https://api.groq.com/openai/v1/audio/transcriptions`, model `whisper-large-v3-turbo`. Fast (~$0.04/hour of audio) Whisper-compatible speech-to-text used when Builder is unavailable.
105
105
 
@@ -107,6 +107,11 @@ Clips never routes recording/meeting audio to OpenAI for transcription. (Groq's
107
107
 
108
108
  If no native transcript exists and no cloud fallback is available (no Builder connection and no Groq key), the action writes `status="failed"` so the UI can show a friendly prompt.
109
109
 
110
+ If Builder transcription fails because credits are exhausted, explain that
111
+ Builder.io credits/upgrade or a Groq key are the supported speech-to-text
112
+ fallbacks. Generic OpenAI or Anthropic chat keys power chat, but they do not
113
+ transcribe Clips recordings.
114
+
110
115
  ### Secret registration
111
116
 
112
117
  Builder transcription needs no app-specific key (the connected Builder.io account or `BUILDER_PRIVATE_KEY` carries the grant). The only transcription API key declared in `server/register-secrets.ts` is the optional Groq key, so it appears in the agent sidebar settings UI:
@@ -30,7 +30,7 @@ Some recordings are linked to a meeting — when `meeting_id` is non-null on the
30
30
  3. **Create row.** As soon as the stream is granted, call `create-recording` to insert the row with `status: "uploading"` and a pre-generated id. That id is used for every subsequent chunk upload.
31
31
  4. **Record.** Start a `MediaRecorder` with `mimeType: "video/webm;codecs=vp9,opus"` (fallback to vp8, then browser default). Use `timeslice: 2000` so chunks arrive every 2s.
32
32
  5. **Upload each chunk.** `ondataavailable` POSTs the chunk bytes to `/api/uploads/chunk` with headers `X-Recording-Id` and `X-Chunk-Index`. Don't retry inline — buffer failed chunks in `IndexedDB` and let a background worker re-send.
33
- 6. **Live transcription.** Alongside the MediaRecorder, `useLiveTranscription` runs the Web Speech API to accumulate transcript text in real time. On stop, the client calls `save-browser-transcript` to persist the result immediately — no API key needed.
33
+ 6. **Live transcription.** Alongside the MediaRecorder, `useLiveTranscription` runs the Web Speech API to accumulate transcript text in real time. On stop, the client calls `save-browser-transcript` to persist the result immediately — no API key needed. Desktop recordings use local Whisper/macOS speech first when available, and fall back to Web Speech in the webview on non-mac before relying on upload transcription.
34
34
  7. **Finalize.** On stop, send the final chunk to `/api/uploads/:id/chunk?isFinal=1`. The route calls `finalize-recording`, which stitches chunks, uploads the finished media when storage is configured, transitions `status` to `ready`, then kicks off `request-transcript` for higher-quality output (see `ai-video-tools`).
35
35
  8. **Navigate.** Once the row is `ready` the UI navigates to `/r/:id`.
36
36
 
@@ -173,6 +173,13 @@ These endpoints follow the same access model as `/api/public-recording`:
173
173
  - Password-protected clips require `password=<pw>` once; successful JSON
174
174
  responses include short-lived tokenized links so the plaintext password is not
175
175
  copied into downstream agent prompts, browser history, or logs.
176
+ - If the context or transcript response reports `transcript.status` as
177
+ `"pending"`, wait 15-30 seconds and retry the context/transcript URL a few
178
+ times before falling back to frames or telling the user no transcript exists.
179
+ - If transcription failed because Builder transcription credits are exhausted,
180
+ tell the user to upgrade or connect Builder.io credits, or configure a Groq
181
+ key for backup speech-to-text. Generic OpenAI or Anthropic chat keys do not
182
+ transcribe Clips recordings.
176
183
  - Frame extraction must use the checked recording media path and must not expose
177
184
  raw provider URLs.
178
185
 
@@ -52,6 +52,14 @@ Detailed media, meeting, dictation, editing, and sharing rules live in
52
52
  segments; `/api/agent-frame.jpg?id=<recordingId>&atMs=<ms>` for a screen
53
53
  frame at a timestamp. Password-protected clips require the password once to
54
54
  mint a short-lived token returned inside agent-context links.
55
+ - If public agent context or transcript APIs report `transcript.status` as
56
+ `"pending"`, wait 15-30 seconds and retry the context/transcript URL a few
57
+ times, especially for long recordings. Do not pivot straight to frames or tell
58
+ the user there is no transcript until the retry budget is exhausted.
59
+ - If transcription failed because Builder transcription credits are exhausted,
60
+ tell the user that clearly and point them to Builder.io credits/upgrade or a
61
+ Groq key for backup speech-to-text. Generic OpenAI or Anthropic chat keys do
62
+ not transcribe Clips recordings.
55
63
  - Slack unfurls use `/api/slack/unfurl` for `link_shared` events and only
56
64
  return playable `chat.unfurl` video blocks for ready public clips with no
57
65
  password, no expiry hit, and no archive/trash marker. Private, org-only,
@@ -167,7 +167,7 @@ export default defineAction({
167
167
  status: "pending" as const,
168
168
  token,
169
169
  inviteUrl,
170
- emailConfigured: isEmailConfigured(),
170
+ emailConfigured: await isEmailConfigured(),
171
171
  };
172
172
  },
173
173
  });
@@ -1008,7 +1008,7 @@ export default defineAction({
1008
1008
  } catch (err) {
1009
1009
  const reason = (err as Error).message;
1010
1010
  const details = serializeError(err);
1011
- if (reason.includes("credits exhausted")) {
1011
+ if (reason.toLowerCase().includes("credits exhausted")) {
1012
1012
  const preserved = await preserveReadyTranscriptIfAvailable({
1013
1013
  db,
1014
1014
  recordingId: args.recordingId,