@agent-native/core 0.79.17 → 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 +8 -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 +47 -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/player/transcript-panel.tsx +2 -0
  95. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +629 -643
  96. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +219 -155
  97. package/corpus/templates/clips/changelog/2026-06-26-long-desktop-recordings-are-checkpointed-so-macos-finalizati.md +6 -0
  98. package/corpus/templates/clips/changelog/2026-06-26-non-mac-desktop-recordings-wait-for-upload-transcription.md +6 -0
  99. package/corpus/templates/clips/changelog/2026-06-26-s3-compatible-storage-keys-now-save-securely-from-clips-sett.md +6 -0
  100. package/corpus/templates/clips/changelog/2026-06-26-shared-clip-links-guide-agents-through-processing-transcripts.md +6 -0
  101. package/corpus/templates/clips/changelog/2026-06-26-the-clip-details-sidebar-now-collapses-into-a-slide-out-pane.md +6 -0
  102. package/corpus/templates/clips/desktop/src/lib/recorder.ts +55 -3
  103. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +217 -5
  104. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -0
  105. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +176 -5
  106. package/corpus/templates/clips/server/lib/public-agent-context.ts +31 -0
  107. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +60 -14
  108. package/corpus/templates/clips/server/lib/video-storage.ts +37 -9
  109. package/corpus/templates/clips/server/routes/api/agent-transcript.json.get.ts +5 -0
  110. package/corpus/templates/content/app/components/layout/Header.tsx +0 -1
  111. package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +1 -0
  112. package/corpus/templates/content/app/routes/_app.settings.tsx +54 -55
  113. package/corpus/templates/content/app/routes/_app.team.tsx +2 -28
  114. package/corpus/templates/content/server/lib/notion.ts +43 -11
  115. package/corpus/templates/content/server/routes/api/notion/auth-url.get.ts +2 -2
  116. package/corpus/templates/content/server/routes/api/notion/status.get.ts +3 -3
  117. package/corpus/templates/design/app/routes/settings.tsx +60 -38
  118. package/corpus/templates/design/app/routes/team.tsx +2 -10
  119. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +2 -2
  120. package/corpus/templates/dispatch/app/routes/settings.tsx +70 -55
  121. package/corpus/templates/dispatch/app/routes/team.tsx +5 -1
  122. package/corpus/templates/forms/actions/db-connect.ts +7 -36
  123. package/corpus/templates/forms/actions/navigate.ts +2 -2
  124. package/corpus/templates/forms/app/components/CloudUpgrade.tsx +8 -47
  125. package/corpus/templates/forms/app/components/layout/Header.tsx +0 -1
  126. package/corpus/templates/forms/app/components/layout/Layout.tsx +42 -25
  127. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +35 -76
  128. package/corpus/templates/forms/app/global.css +9 -25
  129. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +4 -4
  130. package/corpus/templates/forms/app/i18n/ar-SA.ts +1 -0
  131. package/corpus/templates/forms/app/i18n/de-DE.ts +1 -0
  132. package/corpus/templates/forms/app/i18n/en-US.ts +1 -0
  133. package/corpus/templates/forms/app/i18n/es-ES.ts +1 -0
  134. package/corpus/templates/forms/app/i18n/fr-FR.ts +1 -0
  135. package/corpus/templates/forms/app/i18n/hi-IN.ts +1 -0
  136. package/corpus/templates/forms/app/i18n/ja-JP.ts +1 -0
  137. package/corpus/templates/forms/app/i18n/ko-KR.ts +1 -0
  138. package/corpus/templates/forms/app/i18n/pt-BR.ts +1 -0
  139. package/corpus/templates/forms/app/i18n/zh-CN.ts +1 -0
  140. package/corpus/templates/forms/app/i18n/zh-TW.ts +1 -0
  141. package/corpus/templates/forms/app/lib/route-prewarm.ts +9 -8
  142. package/corpus/templates/forms/app/pages/AskPage.tsx +70 -0
  143. package/corpus/templates/forms/app/pages/FormsListPage.tsx +74 -81
  144. package/corpus/templates/forms/app/root.tsx +1 -1
  145. package/corpus/templates/forms/app/routes/_app.ask.tsx +14 -0
  146. package/corpus/templates/forms/app/routes/_app.settings.tsx +54 -54
  147. package/corpus/templates/forms/app/routes/_app.team.tsx +2 -9
  148. package/corpus/templates/forms/app/routes/_index.tsx +21 -130
  149. package/corpus/templates/forms/changelog/2026-06-26-ask-forms-opens-as-a-standard-app-tab-with-a-simpler-sidebar.md +6 -0
  150. package/corpus/templates/forms/changelog/2026-06-26-forms-are-shown-in-a-tighter-row-list-with-a-denser-sidebar.md +6 -0
  151. package/corpus/templates/forms/shared/navigation.ts +4 -2
  152. package/corpus/templates/macros/app/routes/settings.tsx +54 -54
  153. package/corpus/templates/macros/app/routes/team.tsx +2 -10
  154. package/corpus/templates/mail/actions/helpers.ts +2 -2
  155. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +2 -1
  156. package/corpus/templates/mail/app/pages/SettingsPage.tsx +5 -5
  157. package/corpus/templates/mail/app/routes/team.tsx +3 -2
  158. package/corpus/templates/mail/server/handlers/emails.ts +3 -2
  159. package/corpus/templates/mail/server/handlers/google-auth.ts +19 -12
  160. package/corpus/templates/mail/server/lib/automation-engine.ts +3 -2
  161. package/corpus/templates/mail/server/lib/email-state.ts +2 -3
  162. package/corpus/templates/mail/server/lib/google-auth.ts +28 -11
  163. package/corpus/templates/mail/server/lib/jobs.ts +3 -2
  164. package/corpus/templates/mail/server/onboarding.ts +9 -6
  165. package/corpus/templates/mail/server/routes/api/attachments.get.ts +3 -3
  166. package/corpus/templates/plan/actions/request-plan-access.ts +1 -1
  167. package/corpus/templates/plan/app/components/layout/Header.tsx +0 -1
  168. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +4 -2
  169. package/corpus/templates/plan/app/lib/route-prewarm.ts +0 -4
  170. package/corpus/templates/plan/app/routes/settings.tsx +75 -73
  171. package/corpus/templates/plan/app/routes/team.tsx +2 -8
  172. package/corpus/templates/plan/server/lib/comment-notifications.ts +1 -1
  173. package/corpus/templates/slides/actions/check-image-gen.ts +2 -1
  174. package/corpus/templates/slides/actions/db-connect.ts +7 -45
  175. package/corpus/templates/slides/actions/edit-image.ts +6 -3
  176. package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
  177. package/corpus/templates/slides/actions/generate-image.ts +2 -2
  178. package/corpus/templates/slides/actions/generate-slides-ai.ts +5 -3
  179. package/corpus/templates/slides/actions/image-gen-status.ts +4 -3
  180. package/corpus/templates/slides/actions/image-search.ts +6 -3
  181. package/corpus/templates/slides/actions/search-images.ts +6 -3
  182. package/corpus/templates/slides/app/components/CloudUpgrade.tsx +8 -51
  183. package/corpus/templates/slides/app/components/layout/Header.tsx +0 -1
  184. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +0 -2
  185. package/corpus/templates/slides/app/routes/settings.tsx +54 -54
  186. package/corpus/templates/slides/app/routes/team.tsx +2 -12
  187. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +9 -9
  188. package/corpus/templates/slides/server/handlers/image-gen.ts +5 -1
  189. package/corpus/templates/slides/server/handlers/image-providers/gemini.ts +9 -1
  190. package/corpus/templates/slides/server/handlers/image-providers/index.ts +18 -8
  191. package/corpus/templates/slides/server/handlers/image-providers/openai.ts +10 -4
  192. package/corpus/templates/slides/server/handlers/image-providers/types.ts +1 -0
  193. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +59 -34
  194. package/corpus/templates/slides/server/register-secrets.ts +60 -0
  195. package/corpus/templates/videos/actions/db-connect.ts +7 -45
  196. package/corpus/templates/videos/app/components/CloudUpgrade.tsx +8 -51
  197. package/corpus/templates/videos/app/components/Sidebar.tsx +1 -9
  198. package/corpus/templates/videos/app/components/layout/Header.tsx +0 -1
  199. package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +0 -3
  200. package/corpus/templates/videos/app/routes/settings.tsx +54 -54
  201. package/corpus/templates/videos/app/routes/team.tsx +2 -8
  202. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  203. package/dist/agent/engine/builder-engine.js +8 -3
  204. package/dist/agent/engine/builder-engine.js.map +1 -1
  205. package/dist/cli/mcp.d.ts.map +1 -1
  206. package/dist/cli/mcp.js +3 -4
  207. package/dist/cli/mcp.js.map +1 -1
  208. package/dist/client/AssistantChat.d.ts.map +1 -1
  209. package/dist/client/AssistantChat.js +6 -2
  210. package/dist/client/AssistantChat.js.map +1 -1
  211. package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
  212. package/dist/client/chat/markdown-renderer.js +1 -0
  213. package/dist/client/chat/markdown-renderer.js.map +1 -1
  214. package/dist/client/index.d.ts +1 -1
  215. package/dist/client/index.d.ts.map +1 -1
  216. package/dist/client/index.js +1 -1
  217. package/dist/client/index.js.map +1 -1
  218. package/dist/client/org/OrgSwitcher.d.ts +3 -3
  219. package/dist/client/org/OrgSwitcher.js +2 -2
  220. package/dist/client/org/OrgSwitcher.js.map +1 -1
  221. package/dist/client/org/TeamPage.d.ts +6 -1
  222. package/dist/client/org/TeamPage.d.ts.map +1 -1
  223. package/dist/client/org/TeamPage.js +2 -2
  224. package/dist/client/org/TeamPage.js.map +1 -1
  225. package/dist/client/settings/SettingsTabsPage.d.ts +27 -0
  226. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -0
  227. package/dist/client/settings/SettingsTabsPage.js +108 -0
  228. package/dist/client/settings/SettingsTabsPage.js.map +1 -0
  229. package/dist/client/settings/index.d.ts +1 -0
  230. package/dist/client/settings/index.d.ts.map +1 -1
  231. package/dist/client/settings/index.js +1 -0
  232. package/dist/client/settings/index.js.map +1 -1
  233. package/dist/collab/routes.d.ts +1 -1
  234. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  235. package/dist/file-upload/index.d.ts +1 -1
  236. package/dist/file-upload/index.d.ts.map +1 -1
  237. package/dist/file-upload/index.js +1 -1
  238. package/dist/file-upload/index.js.map +1 -1
  239. package/dist/file-upload/registry.d.ts +1 -0
  240. package/dist/file-upload/registry.d.ts.map +1 -1
  241. package/dist/file-upload/registry.js +24 -6
  242. package/dist/file-upload/registry.js.map +1 -1
  243. package/dist/file-upload/types.d.ts +6 -1
  244. package/dist/file-upload/types.d.ts.map +1 -1
  245. package/dist/file-upload/types.js.map +1 -1
  246. package/dist/integrations/adapters/email.d.ts.map +1 -1
  247. package/dist/integrations/adapters/email.js +18 -18
  248. package/dist/integrations/adapters/email.js.map +1 -1
  249. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  250. package/dist/integrations/adapters/slack.js +8 -7
  251. package/dist/integrations/adapters/slack.js.map +1 -1
  252. package/dist/integrations/adapters/telegram.d.ts.map +1 -1
  253. package/dist/integrations/adapters/telegram.js +9 -9
  254. package/dist/integrations/adapters/telegram.js.map +1 -1
  255. package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
  256. package/dist/integrations/adapters/whatsapp.js +10 -9
  257. package/dist/integrations/adapters/whatsapp.js.map +1 -1
  258. package/dist/integrations/plugin.d.ts.map +1 -1
  259. package/dist/integrations/plugin.js +47 -13
  260. package/dist/integrations/plugin.js.map +1 -1
  261. package/dist/notifications/routes.d.ts +1 -1
  262. package/dist/observability/routes.d.ts +2 -2
  263. package/dist/onboarding/default-steps.d.ts.map +1 -1
  264. package/dist/onboarding/default-steps.js +6 -5
  265. package/dist/onboarding/default-steps.js.map +1 -1
  266. package/dist/onboarding/types.d.ts +1 -1
  267. package/dist/onboarding/types.d.ts.map +1 -1
  268. package/dist/onboarding/types.js.map +1 -1
  269. package/dist/org/handlers.js +1 -1
  270. package/dist/org/handlers.js.map +1 -1
  271. package/dist/progress/routes.d.ts +1 -1
  272. package/dist/resources/handlers.d.ts +3 -3
  273. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  274. package/dist/server/agent-chat-plugin.js +4 -6
  275. package/dist/server/agent-chat-plugin.js.map +1 -1
  276. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  277. package/dist/server/better-auth-instance.d.ts.map +1 -1
  278. package/dist/server/better-auth-instance.js +17 -56
  279. package/dist/server/better-auth-instance.js.map +1 -1
  280. package/dist/server/core-routes-plugin.d.ts +1 -1
  281. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  282. package/dist/server/core-routes-plugin.js +67 -153
  283. package/dist/server/core-routes-plugin.js.map +1 -1
  284. package/dist/server/create-server.d.ts +3 -9
  285. package/dist/server/create-server.d.ts.map +1 -1
  286. package/dist/server/create-server.js +37 -91
  287. package/dist/server/create-server.js.map +1 -1
  288. package/dist/server/email-actions.d.ts +2 -3
  289. package/dist/server/email-actions.d.ts.map +1 -1
  290. package/dist/server/email-actions.js +3 -6
  291. package/dist/server/email-actions.js.map +1 -1
  292. package/dist/server/email.d.ts +3 -3
  293. package/dist/server/email.d.ts.map +1 -1
  294. package/dist/server/email.js +40 -19
  295. package/dist/server/email.js.map +1 -1
  296. package/dist/server/index.d.ts +3 -3
  297. package/dist/server/index.d.ts.map +1 -1
  298. package/dist/server/index.js +3 -3
  299. package/dist/server/index.js.map +1 -1
  300. package/dist/server/scoped-key-storage.d.ts +22 -0
  301. package/dist/server/scoped-key-storage.d.ts.map +1 -0
  302. package/dist/server/scoped-key-storage.js +152 -0
  303. package/dist/server/scoped-key-storage.js.map +1 -0
  304. package/dist/server/transcribe-voice.d.ts +1 -1
  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 +47 -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
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Email transport for system emails (password resets, invitations, notifications).
3
3
  *
4
- * Providers are selected by env var:
4
+ * Providers are selected by scoped secrets:
5
5
  * RESEND_API_KEY — https://resend.com
6
6
  * SENDGRID_API_KEY — https://sendgrid.com
7
7
  * EMAIL_FROM — "Name <addr@domain>" (optional; defaults to Resend's sandbox)
@@ -10,6 +10,8 @@
10
10
  * so the reset-password flow still works end-to-end for local development.
11
11
  */
12
12
 
13
+ import { resolveSecret } from "./credential-provider.js";
14
+
13
15
  export type EmailProvider = "resend" | "sendgrid" | "dev";
14
16
 
15
17
  export interface EmailAttachment {
@@ -33,32 +35,65 @@ export interface SendEmailArgs {
33
35
  attachments?: EmailAttachment[];
34
36
  }
35
37
 
36
- export function isEmailConfigured(): boolean {
37
- return !!(process.env.RESEND_API_KEY || process.env.SENDGRID_API_KEY);
38
+ interface EmailTransportConfig {
39
+ provider: EmailProvider;
40
+ resendApiKey?: string;
41
+ sendgridApiKey?: string;
42
+ from?: string;
38
43
  }
39
44
 
40
- export function getEmailProvider(): EmailProvider {
41
- if (process.env.RESEND_API_KEY) return "resend";
42
- if (process.env.SENDGRID_API_KEY) return "sendgrid";
43
- return "dev";
45
+ async function resolveEmailTransport(): Promise<EmailTransportConfig> {
46
+ const [resendApiKey, sendgridApiKey, from] = await Promise.all([
47
+ resolveSecret("RESEND_API_KEY"),
48
+ resolveSecret("SENDGRID_API_KEY"),
49
+ resolveSecret("EMAIL_FROM"),
50
+ ]);
51
+ const resolvedFrom = from ?? undefined;
52
+ if (resendApiKey) {
53
+ return {
54
+ provider: "resend",
55
+ resendApiKey,
56
+ from: resolvedFrom,
57
+ };
58
+ }
59
+ if (sendgridApiKey) {
60
+ return {
61
+ provider: "sendgrid",
62
+ sendgridApiKey,
63
+ from: resolvedFrom,
64
+ };
65
+ }
66
+ return { provider: "dev", from: resolvedFrom };
44
67
  }
45
68
 
46
- function getFromAddress(override?: string, provider?: EmailProvider): string {
47
- const explicit = override || process.env.EMAIL_FROM;
69
+ export async function isEmailConfigured(): Promise<boolean> {
70
+ return (await resolveEmailTransport()).provider !== "dev";
71
+ }
72
+
73
+ export async function getEmailProvider(): Promise<EmailProvider> {
74
+ return (await resolveEmailTransport()).provider;
75
+ }
76
+
77
+ function getFromAddress(
78
+ config: EmailTransportConfig,
79
+ override?: string,
80
+ ): string {
81
+ const explicit = override || config.from;
48
82
  if (explicit) return explicit;
49
83
  // Resend lets unverified accounts send from its sandbox domain; SendGrid
50
84
  // does not, so falling back there would cause silent 403s at runtime.
51
- if (provider === "sendgrid") {
85
+ if (config.provider === "sendgrid") {
52
86
  throw new Error(
53
- "EMAIL_FROM is required when using SendGrid — set it to a verified sender address.",
87
+ "EMAIL_FROM is required when using SendGrid — save it as a verified sender address.",
54
88
  );
55
89
  }
56
90
  return "Agent Native <onboarding@resend.dev>";
57
91
  }
58
92
 
59
93
  export async function sendEmail(args: SendEmailArgs): Promise<void> {
60
- const provider = getEmailProvider();
61
- const from = getFromAddress(args.from, provider);
94
+ const config = await resolveEmailTransport();
95
+ const provider = config.provider;
96
+ const from = getFromAddress(config, args.from);
62
97
 
63
98
  if (provider === "resend") {
64
99
  const payload: Record<string, unknown> = {
@@ -89,7 +124,7 @@ export async function sendEmail(args: SendEmailArgs): Promise<void> {
89
124
  const res = await fetch("https://api.resend.com/emails", {
90
125
  method: "POST",
91
126
  headers: {
92
- Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
127
+ Authorization: `Bearer ${config.resendApiKey}`,
93
128
  "Content-Type": "application/json",
94
129
  },
95
130
  body: JSON.stringify(payload),
@@ -140,7 +175,7 @@ export async function sendEmail(args: SendEmailArgs): Promise<void> {
140
175
  const res = await fetch("https://api.sendgrid.com/v3/mail/send", {
141
176
  method: "POST",
142
177
  headers: {
143
- Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`,
178
+ Authorization: `Bearer ${config.sendgridApiKey}`,
144
179
  "Content-Type": "application/json",
145
180
  },
146
181
  body: JSON.stringify(sgPayload),
@@ -157,12 +192,12 @@ export async function sendEmail(args: SendEmailArgs): Promise<void> {
157
192
  // to send rather than silently leaking secrets to logs.
158
193
  if (process.env.NODE_ENV === "production") {
159
194
  throw new Error(
160
- "No email provider configured. Set RESEND_API_KEY or SENDGRID_API_KEY.",
195
+ "No email provider configured. Save RESEND_API_KEY or SENDGRID_API_KEY in settings.",
161
196
  );
162
197
  }
163
198
  console.log(
164
199
  `\n[agent-native:email] No email provider configured. ` +
165
- `Set RESEND_API_KEY or SENDGRID_API_KEY to send real emails.\n` +
200
+ `Save RESEND_API_KEY or SENDGRID_API_KEY in settings to send real emails.\n` +
166
201
  `---\nTo: ${args.to}\nFrom: ${from}\nSubject: ${args.subject}\n\n` +
167
202
  `${args.text || stripHtml(args.html)}\n---\n`,
168
203
  );
@@ -1,6 +1,5 @@
1
1
  export {
2
2
  createServer,
3
- upsertEnvFile,
4
3
  type CreateServerOptions,
5
4
  type EnvKeyConfig,
6
5
  } from "./create-server.js";
@@ -325,6 +324,7 @@ export {
325
324
  unregisterFileUploadProvider,
326
325
  listFileUploadProviders,
327
326
  getActiveFileUploadProvider,
327
+ getActiveFileUploadProviderForRequest,
328
328
  uploadFile,
329
329
  builderFileUploadProvider,
330
330
  type FileUploadInput,
@@ -381,6 +381,7 @@ export {
381
381
  resolveHasCompleteBuilderConnection,
382
382
  resolveBuilderCredentials,
383
383
  resolveBuilderCredential,
384
+ readDeployCredentialEnv,
384
385
  writeBuilderCredentials,
385
386
  deleteBuilderCredentials,
386
387
  resolveSecret,
@@ -0,0 +1,223 @@
1
+ import type { H3Event } from "h3";
2
+
3
+ import { getOrgContext } from "../org/context.js";
4
+ import {
5
+ getRequiredSecret,
6
+ type RegisteredSecret,
7
+ type SecretScope,
8
+ } from "../secrets/register.js";
9
+ import { writeAppSecret } from "../secrets/storage.js";
10
+ import { getSession } from "./auth.js";
11
+
12
+ const KEY_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
13
+
14
+ export type ScopedKeySaveRequestScope =
15
+ | "app"
16
+ | "auto"
17
+ | "org"
18
+ | "user"
19
+ | "workspace"
20
+ | undefined;
21
+
22
+ export interface ScopedKeyValue {
23
+ key: string;
24
+ value: string;
25
+ }
26
+
27
+ export interface ScopedKeySaveRow {
28
+ key: string;
29
+ scope: SecretScope;
30
+ scopeId: string;
31
+ }
32
+
33
+ export class ScopedKeyStorageError extends Error {
34
+ constructor(
35
+ readonly statusCode: number,
36
+ message: string,
37
+ ) {
38
+ super(message);
39
+ this.name = "ScopedKeyStorageError";
40
+ }
41
+ }
42
+
43
+ export function findUnsupportedScopedKeyNames(
44
+ vars: unknown,
45
+ allowedKeys: Iterable<string>,
46
+ ): string[] {
47
+ if (!Array.isArray(vars)) return [];
48
+
49
+ const allowed = new Set(allowedKeys);
50
+ const unsupported = new Set<string>();
51
+ for (const entry of vars) {
52
+ if (!entry || typeof entry !== "object") continue;
53
+ const key = (entry as { key?: unknown }).key;
54
+ const normalizedKey = typeof key === "string" ? key.trim() : "";
55
+ if (normalizedKey && !allowed.has(normalizedKey)) {
56
+ unsupported.add(normalizedKey);
57
+ }
58
+ }
59
+ return [...unsupported];
60
+ }
61
+
62
+ function redactSecretFromMessage(message: string, secretValue: string): string {
63
+ if (!message || !secretValue) return message;
64
+ return message.split(secretValue).join("[redacted]");
65
+ }
66
+
67
+ function normalizeKeyValueVars(vars: unknown): ScopedKeyValue[] {
68
+ if (!Array.isArray(vars) || vars.length === 0) {
69
+ throw new ScopedKeyStorageError(400, "vars array required");
70
+ }
71
+
72
+ const out: ScopedKeyValue[] = [];
73
+ for (const entry of vars) {
74
+ if (!entry || typeof entry !== "object") {
75
+ throw new ScopedKeyStorageError(400, "Each var must be an object");
76
+ }
77
+ const { key, value } = entry as { key?: unknown; value?: unknown };
78
+ const normalizedKey = typeof key === "string" ? key.trim() : "";
79
+ if (!normalizedKey || !KEY_NAME_RE.test(normalizedKey)) {
80
+ throw new ScopedKeyStorageError(
81
+ 400,
82
+ normalizedKey
83
+ ? `Invalid key name "${normalizedKey}"`
84
+ : "Each var requires a key",
85
+ );
86
+ }
87
+ const normalizedValue = typeof value === "string" ? value.trim() : "";
88
+ if (!normalizedValue) {
89
+ throw new ScopedKeyStorageError(
90
+ 400,
91
+ `Value for ${normalizedKey} must be non-empty`,
92
+ );
93
+ }
94
+ out.push({ key: normalizedKey, value: normalizedValue });
95
+ }
96
+ return out;
97
+ }
98
+
99
+ function resolveTargetScope(
100
+ secret: RegisteredSecret | undefined,
101
+ requestedScope: ScopedKeySaveRequestScope,
102
+ ): SecretScope {
103
+ if (secret?.kind === "api-key") return secret.scope;
104
+ if (requestedScope === "org") return "org";
105
+ if (requestedScope === "workspace" || requestedScope === "app") {
106
+ return "workspace";
107
+ }
108
+ return "user";
109
+ }
110
+
111
+ async function resolveScopeId(
112
+ event: H3Event,
113
+ scope: SecretScope,
114
+ ): Promise<{
115
+ scopeId: string;
116
+ orgRole: string | null;
117
+ orgId: string | null;
118
+ }> {
119
+ const session = await getSession(event).catch(() => null);
120
+ const email = session?.email ?? null;
121
+
122
+ if (scope === "user") {
123
+ if (!email) {
124
+ throw new ScopedKeyStorageError(401, "Sign in to save keys");
125
+ }
126
+ return { scopeId: email, orgRole: null, orgId: null };
127
+ }
128
+
129
+ const orgCtx = await getOrgContext(event).catch(() => null);
130
+ const orgId = orgCtx?.orgId ?? null;
131
+ const orgRole = orgCtx?.role ?? null;
132
+
133
+ if (scope === "org") {
134
+ if (!orgId) {
135
+ throw new ScopedKeyStorageError(401, "No active organization");
136
+ }
137
+ return { scopeId: orgId, orgRole, orgId };
138
+ }
139
+
140
+ if (orgId) {
141
+ return { scopeId: orgId, orgRole, orgId };
142
+ }
143
+ if (!email) {
144
+ throw new ScopedKeyStorageError(401, "Sign in to save workspace keys");
145
+ }
146
+ return { scopeId: `solo:${email}`, orgRole: null, orgId: null };
147
+ }
148
+
149
+ function assertCanMutateScope(
150
+ scope: SecretScope,
151
+ scopeId: string,
152
+ orgRole: string | null,
153
+ ): void {
154
+ if (scope === "user") return;
155
+ if (scope === "workspace" && scopeId.startsWith("solo:")) return;
156
+ if (orgRole === "owner" || orgRole === "admin") return;
157
+ throw new ScopedKeyStorageError(
158
+ 403,
159
+ scope === "org"
160
+ ? "Only organization owners and admins can set org-scoped keys"
161
+ : "Only organization owners and admins can set workspace-scoped keys",
162
+ );
163
+ }
164
+
165
+ async function validateRegisteredSecret(
166
+ secret: RegisteredSecret | undefined,
167
+ value: string,
168
+ ): Promise<void> {
169
+ if (!secret) return;
170
+ if (secret.kind === "oauth") {
171
+ throw new ScopedKeyStorageError(
172
+ 400,
173
+ `"${secret.key}" is an OAuth-kind secret and must be connected via OAuth`,
174
+ );
175
+ }
176
+ if (!secret.validator) return;
177
+ try {
178
+ const result = await secret.validator(value);
179
+ const ok = typeof result === "boolean" ? result : result?.ok === true;
180
+ if (ok) return;
181
+ const error =
182
+ typeof result === "object" && result && result.error
183
+ ? String(result.error)
184
+ : "Validator rejected the value";
185
+ throw new ScopedKeyStorageError(400, redactSecretFromMessage(error, value));
186
+ } catch (err) {
187
+ if (err instanceof ScopedKeyStorageError) throw err;
188
+ const message =
189
+ err instanceof Error
190
+ ? `Validator threw: ${err.message}`
191
+ : "Validator threw";
192
+ throw new ScopedKeyStorageError(
193
+ 400,
194
+ redactSecretFromMessage(message, value),
195
+ );
196
+ }
197
+ }
198
+
199
+ export async function saveKeyValuesToScopedSecrets(
200
+ event: H3Event,
201
+ vars: unknown,
202
+ requestedScope?: ScopedKeySaveRequestScope,
203
+ ): Promise<{ saved: string[]; rows: ScopedKeySaveRow[] }> {
204
+ const normalized = normalizeKeyValueVars(vars);
205
+ const rows: ScopedKeySaveRow[] = [];
206
+
207
+ for (const entry of normalized) {
208
+ const secret = getRequiredSecret(entry.key);
209
+ const scope = resolveTargetScope(secret, requestedScope);
210
+ const { scopeId, orgRole } = await resolveScopeId(event, scope);
211
+ assertCanMutateScope(scope, scopeId, orgRole);
212
+ await validateRegisteredSecret(secret, entry.value);
213
+ await writeAppSecret({
214
+ key: entry.key,
215
+ value: entry.value,
216
+ scope,
217
+ scopeId,
218
+ });
219
+ rows.push({ key: entry.key, scope, scopeId });
220
+ }
221
+
222
+ return { saved: rows.map((row) => row.key), rows };
223
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Isomorphic Agent Env Utility
2
+ * Isomorphic Agent Key Utility
3
3
  *
4
4
  * Works in both browser and Node.js contexts:
5
5
  * - Browser: sends via postMessage to the parent window
@@ -18,7 +18,7 @@ const isBrowser =
18
18
  typeof window !== "undefined" && typeof window.postMessage === "function";
19
19
 
20
20
  /**
21
- * Send env vars to the host (Builder cloud or Claude frame).
21
+ * Send key/value settings to the host for scoped secret persistence.
22
22
  * Automatically detects environment (browser vs Node.js) and uses the right transport.
23
23
  */
24
24
  function setVars(vars: EnvVar[]): void {
@@ -41,6 +41,6 @@ function setVars(vars: EnvVar[]): void {
41
41
  }
42
42
 
43
43
  export const agentEnv = {
44
- /** Send environment variables to the host for persistence */
44
+ /** Send key/value settings to the host for scoped secret persistence. */
45
45
  setVars,
46
46
  };
@@ -262,7 +262,7 @@ export default defineAction({
262
262
  if (
263
263
  args.notify !== false &&
264
264
  args.principalType === "user" &&
265
- isEmailConfigured() &&
265
+ (await isEmailConfigured()) &&
266
266
  !isSyntheticQaEmail(principalId)
267
267
  ) {
268
268
  try {
@@ -55,6 +55,8 @@
55
55
  --agent-native-lower-surface: hsl(
56
56
  var(--sidebar-background, var(--background))
57
57
  );
58
+ --agent-native-raised-surface: hsl(var(--background));
59
+ --agent-native-card-surface: hsl(var(--card));
58
60
  --agent-native-raised-border: hsl(var(--border));
59
61
  --agent-native-raised-radius: 8px;
60
62
  --agent-native-raised-shadow-left: -1px 0 3px rgb(0 0 0 / 0.018);
@@ -86,6 +88,16 @@
86
88
  hsl(var(--sidebar-background, var(--background))) 94%,
87
89
  black
88
90
  );
91
+ --agent-native-raised-surface: color-mix(
92
+ in srgb,
93
+ hsl(var(--background)) 78%,
94
+ hsl(var(--muted)) 22%
95
+ );
96
+ --agent-native-card-surface: color-mix(
97
+ in srgb,
98
+ var(--agent-native-raised-surface) 88%,
99
+ hsl(var(--muted)) 12%
100
+ );
89
101
  }
90
102
  }
91
103
 
@@ -126,7 +138,7 @@
126
138
  .agent-sidebar-main-surface {
127
139
  position: relative;
128
140
  z-index: 1;
129
- background: hsl(var(--background));
141
+ background: var(--agent-native-raised-surface);
130
142
  transition:
131
143
  border-radius 260ms cubic-bezier(0.32, 0.72, 0, 1),
132
144
  border-color 260ms cubic-bezier(0.32, 0.72, 0, 1),
@@ -136,17 +148,49 @@
136
148
  .agent-layout-shell
137
149
  :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
138
150
  > :first-child
139
- > :where(header, div).border-b:first-child,
151
+ > :where(header, div).border-b,
140
152
  .agent-layout-shell
141
153
  :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
142
- > :where(header, div).border-b:first-child,
154
+ > :where(header, div).border-b,
143
155
  .agent-layout-shell
144
156
  .agent-layout-left-drawer
145
157
  > :where(header, div).border-b:first-child,
158
+ .agent-layout-shell
159
+ .agent-layout-left-drawer
160
+ > :first-child
161
+ > :where(header, div).border-b,
146
162
  .agent-layout-shell .agent-native-shell-topbar {
147
163
  border-bottom-color: transparent !important;
148
164
  }
149
165
 
166
+ .agent-layout-shell
167
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
168
+ > :first-child
169
+ > :where(header, div).border-b,
170
+ .agent-layout-shell
171
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
172
+ > :where(header, div).border-b {
173
+ background-color: var(--agent-native-raised-surface) !important;
174
+ }
175
+
176
+ .agent-layout-shell
177
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
178
+ > :first-child
179
+ > :where(header, div).border-b.h-12,
180
+ .agent-layout-shell
181
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
182
+ > :where(header, div).border-b.h-12 {
183
+ min-height: 4rem;
184
+ height: 4rem;
185
+ }
186
+
187
+ .dark
188
+ .agent-layout-shell
189
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
190
+ :where(.bg-card) {
191
+ background-color: var(--agent-native-card-surface) !important;
192
+ }
193
+
150
194
  @media (min-width: 768px) {
151
195
  .agent-layout-main-surface,
152
196
  .agent-layout-shell > .agent-sidebar-shell > .agent-sidebar-main-surface {
@@ -170,7 +170,8 @@ Use the workspace root `.env` for shared identity and cross-app trust settings:
170
170
  - `WORKSPACE_OWNER_EMAIL` — initial owner/admin email for repairs and
171
171
  integration defaults.
172
172
  - `A2A_SECRET` — shared secret for cross-app A2A signing. Generate with
173
- `openssl rand -hex 32` or `pnpm repair:workspace-org -- --name ...`.
173
+ `openssl rand -hex 32` and configure through your deployment/scoped secret
174
+ manager.
174
175
 
175
176
  `DISPATCH_DEFAULT_OWNER_EMAIL` is optional. Set it only for trusted,
176
177
  single-workspace deployments where unlinked integration requests should run as
@@ -183,7 +184,7 @@ When asked to repair workspace org or A2A configuration:
183
184
  1. Read `.env` first. Do not infer the organization, domain, owner email, or
184
185
  secret from old examples.
185
186
  2. Run `pnpm repair:workspace-org -- --name "<org>" --domain example.com --owner-email owner@example.com`
186
- to create or update generic workspace identity values.
187
+ to validate generic workspace identity values without writing `.env`.
187
188
  3. Prefer the app's organization settings UI or authenticated org routes for
188
189
  changing `allowed_domain` and `a2a_secret`.
189
190
  4. If direct SQL is unavoidable, inspect the live schema first and use only
@@ -97,7 +97,7 @@ cross-app trust:
97
97
  - `A2A_SECRET` — shared signing secret for cross-app A2A calls.
98
98
 
99
99
  Run `pnpm repair:workspace-org -- --name "<org>" --domain example.com --owner-email owner@example.com`
100
- to fill or validate those values without committing secrets. Existing
100
+ to validate those values without writing env files. Existing
101
101
  organization rows should still be repaired through the app's org settings UI or
102
102
  authenticated org routes whenever possible.
103
103