@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
@@ -5,6 +5,7 @@ import { getHeader, readRawBody as h3ReadRawBody } from "h3";
5
5
 
6
6
  import { getDbExec } from "../../db/client.js";
7
7
  import type { EnvKeyConfig } from "../../server/create-server.js";
8
+ import { resolveSecret } from "../../server/credential-provider.js";
8
9
  import {
9
10
  sendEmail,
10
11
  isEmailConfigured,
@@ -113,8 +114,9 @@ export function emailAdapter(): PlatformAdapter {
113
114
  },
114
115
 
115
116
  async verifyWebhook(event: H3Event): Promise<boolean> {
116
- const secret = process.env.EMAIL_INBOUND_WEBHOOK_SECRET;
117
- const provider = getEmailProvider();
117
+ const secret =
118
+ (await resolveSecret("EMAIL_INBOUND_WEBHOOK_SECRET")) ?? undefined;
119
+ const provider = await getEmailProvider();
118
120
 
119
121
  if (provider === "resend") {
120
122
  return verifyResendWebhook(event, secret);
@@ -132,8 +134,10 @@ export function emailAdapter(): PlatformAdapter {
132
134
  async parseIncomingMessage(
133
135
  event: H3Event,
134
136
  ): Promise<IncomingMessage | null> {
135
- const provider = getEmailProvider();
136
- const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();
137
+ const provider = await getEmailProvider();
138
+ const agentAddress = (
139
+ await resolveSecret("EMAIL_AGENT_ADDRESS")
140
+ )?.toLowerCase();
137
141
  if (!agentAddress) {
138
142
  console.warn("[email] EMAIL_AGENT_ADDRESS not configured");
139
143
  return null;
@@ -246,7 +250,7 @@ export function emailAdapter(): PlatformAdapter {
246
250
  message: OutgoingMessage,
247
251
  context: IncomingMessage,
248
252
  ): Promise<void> {
249
- const agentAddress = process.env.EMAIL_AGENT_ADDRESS;
253
+ const agentAddress = await resolveSecret("EMAIL_AGENT_ADDRESS");
250
254
  if (!agentAddress) {
251
255
  console.error("[email] EMAIL_AGENT_ADDRESS not configured");
252
256
  return;
@@ -259,9 +263,8 @@ export function emailAdapter(): PlatformAdapter {
259
263
  // EMAIL_FROM overrides the from-address — required when the receiving
260
264
  // address is on a sub-domain that can't be a verified sender (e.g.
261
265
  // *.resend.app). Inbound and outbound addresses can differ.
262
- const fromAddress = process.env.EMAIL_FROM
263
- ? process.env.EMAIL_FROM
264
- : `${displayName} <${agentAddress}>`;
266
+ const emailFrom = await resolveSecret("EMAIL_FROM");
267
+ const fromAddress = emailFrom || `${displayName} <${agentAddress}>`;
265
268
 
266
269
  const subject = context.platformContext.subject as string;
267
270
  const reSubject = subject.startsWith("Re: ") ? subject : `Re: ${subject}`;
@@ -276,7 +279,7 @@ export function emailAdapter(): PlatformAdapter {
276
279
  inReplyTo: context.platformContext.messageId as string,
277
280
  references: buildReferencesHeader(context.platformContext),
278
281
  cc: context.platformContext.isCC
279
- ? buildReplyAllCc(context)
282
+ ? buildReplyAllCc(context, agentAddress)
280
283
  : undefined,
281
284
  });
282
285
  } catch (err) {
@@ -288,7 +291,7 @@ export function emailAdapter(): PlatformAdapter {
288
291
  message: OutgoingMessage,
289
292
  target: OutboundTarget,
290
293
  ): Promise<void> {
291
- const agentAddress = process.env.EMAIL_AGENT_ADDRESS;
294
+ const agentAddress = await resolveSecret("EMAIL_AGENT_ADDRESS");
292
295
  if (!agentAddress) {
293
296
  console.error("[email] EMAIL_AGENT_ADDRESS not configured");
294
297
  return;
@@ -325,9 +328,11 @@ export function emailAdapter(): PlatformAdapter {
325
328
  },
326
329
 
327
330
  async getStatus(_baseUrl?: string): Promise<IntegrationStatus> {
328
- const hasAgentAddress = !!process.env.EMAIL_AGENT_ADDRESS;
329
- const hasEmailProvider = isEmailConfigured();
330
- const hasWebhookSecret = !!process.env.EMAIL_INBOUND_WEBHOOK_SECRET;
331
+ const hasAgentAddress = !!(await resolveSecret("EMAIL_AGENT_ADDRESS"));
332
+ const hasEmailProvider = await isEmailConfigured();
333
+ const hasWebhookSecret = !!(await resolveSecret(
334
+ "EMAIL_INBOUND_WEBHOOK_SECRET",
335
+ ));
331
336
  const configured = hasAgentAddress && hasEmailProvider;
332
337
 
333
338
  return {
@@ -339,10 +344,10 @@ export function emailAdapter(): PlatformAdapter {
339
344
  hasAgentAddress,
340
345
  hasEmailProvider,
341
346
  hasWebhookSecret,
342
- provider: getEmailProvider(),
347
+ provider: await getEmailProvider(),
343
348
  },
344
349
  error: !configured
345
- ? "Set EMAIL_AGENT_ADDRESS and either RESEND_API_KEY or SENDGRID_API_KEY"
350
+ ? "Save EMAIL_AGENT_ADDRESS and either RESEND_API_KEY or SENDGRID_API_KEY in settings"
346
351
  : undefined,
347
352
  };
348
353
  },
@@ -906,8 +911,11 @@ function buildReferencesHeader(ctx: Record<string, unknown>): string {
906
911
  * Build CC list for reply-all when agent was CC'd.
907
912
  * Include original To addresses and other CC addresses, excluding the agent and the original sender.
908
913
  */
909
- function buildReplyAllCc(context: IncomingMessage): string[] | undefined {
910
- const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();
914
+ function buildReplyAllCc(
915
+ context: IncomingMessage,
916
+ agentAddress: string,
917
+ ): string[] | undefined {
918
+ const normalizedAgentAddress = agentAddress.toLowerCase();
911
919
  const senderEmail = context.senderId?.toLowerCase();
912
920
  const toAddresses = (context.platformContext.to as string[]) || [];
913
921
  const ccAddresses = (context.platformContext.cc as string[]) || [];
@@ -916,7 +924,7 @@ function buildReplyAllCc(context: IncomingMessage): string[] | undefined {
916
924
  for (const addr of [...toAddresses, ...ccAddresses]) {
917
925
  const normalized = addr.toLowerCase().trim();
918
926
  // Exclude agent address and original sender (sender goes in To)
919
- if (normalized !== agentAddress && normalized !== senderEmail) {
927
+ if (normalized !== normalizedAgentAddress && normalized !== senderEmail) {
920
928
  allRecipients.add(normalized);
921
929
  }
922
930
  }
@@ -2,6 +2,7 @@ import type { H3Event } from "h3";
2
2
  import { createError, getHeader, readRawBody } from "h3";
3
3
 
4
4
  import type { EnvKeyConfig } from "../../server/create-server.js";
5
+ import { resolveSecret } from "../../server/credential-provider.js";
5
6
  import type {
6
7
  PlatformAdapter,
7
8
  IncomingMessage,
@@ -80,7 +81,7 @@ export function slackAdapter(): PlatformAdapter {
80
81
  },
81
82
 
82
83
  async verifyWebhook(event: H3Event): Promise<boolean> {
83
- const signingSecret = process.env.SLACK_SIGNING_SECRET;
84
+ const signingSecret = await resolveSecret("SLACK_SIGNING_SECRET");
84
85
  if (!signingSecret) return false;
85
86
 
86
87
  const signature = getHeader(event, "x-slack-signature");
@@ -185,7 +186,7 @@ export function slackAdapter(): PlatformAdapter {
185
186
  // redundant and added an extra chunk that we then had to overwrite.
186
187
  // We just set the native status and return null so sendResponse posts
187
188
  // the final reply as a fresh message.
188
- const token = process.env.SLACK_BOT_TOKEN;
189
+ const token = await resolveSecret("SLACK_BOT_TOKEN");
189
190
  if (!token) return null;
190
191
 
191
192
  const channelId = incoming.platformContext.channelId as string;
@@ -204,7 +205,7 @@ export function slackAdapter(): PlatformAdapter {
204
205
  context: IncomingMessage,
205
206
  opts?: { placeholderRef?: string },
206
207
  ): Promise<void> {
207
- const token = process.env.SLACK_BOT_TOKEN;
208
+ const token = await resolveSecret("SLACK_BOT_TOKEN");
208
209
  if (!token) {
209
210
  console.error("[slack] SLACK_BOT_TOKEN not configured");
210
211
  return;
@@ -297,7 +298,7 @@ export function slackAdapter(): PlatformAdapter {
297
298
  message: OutgoingMessage,
298
299
  target: OutboundTarget,
299
300
  ): Promise<void> {
300
- const token = process.env.SLACK_BOT_TOKEN;
301
+ const token = await resolveSecret("SLACK_BOT_TOKEN");
301
302
  if (!token) {
302
303
  console.error("[slack] SLACK_BOT_TOKEN not configured");
303
304
  return;
@@ -348,8 +349,8 @@ export function slackAdapter(): PlatformAdapter {
348
349
  },
349
350
 
350
351
  async getStatus(_baseUrl?: string): Promise<IntegrationStatus> {
351
- const hasToken = !!process.env.SLACK_BOT_TOKEN;
352
- const hasSecret = !!process.env.SLACK_SIGNING_SECRET;
352
+ const hasToken = !!(await resolveSecret("SLACK_BOT_TOKEN"));
353
+ const hasSecret = !!(await resolveSecret("SLACK_SIGNING_SECRET"));
353
354
  const configured = hasToken && hasSecret;
354
355
 
355
356
  return {
@@ -362,7 +363,7 @@ export function slackAdapter(): PlatformAdapter {
362
363
  hasSecret,
363
364
  },
364
365
  error: !configured
365
- ? "Set SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET in your environment"
366
+ ? "Save SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET in settings"
366
367
  : undefined,
367
368
  };
368
369
  },
@@ -2,6 +2,7 @@ import type { H3Event } from "h3";
2
2
  import { getHeader } from "h3";
3
3
 
4
4
  import type { EnvKeyConfig } from "../../server/create-server.js";
5
+ import { resolveSecret } from "../../server/credential-provider.js";
5
6
  import { readBody } from "../../server/h3-helpers.js";
6
7
  import type {
7
8
  PlatformAdapter,
@@ -86,7 +87,7 @@ export function telegramAdapter(): PlatformAdapter {
86
87
  },
87
88
 
88
89
  async verifyWebhook(event: H3Event): Promise<boolean> {
89
- const secret = process.env.TELEGRAM_WEBHOOK_SECRET;
90
+ const secret = await resolveSecret("TELEGRAM_WEBHOOK_SECRET");
90
91
  if (!secret) {
91
92
  if (shouldRefuseWhenSecretMissing()) {
92
93
  if (!_telegramUnverifiedWarned) {
@@ -105,7 +106,7 @@ export function telegramAdapter(): PlatformAdapter {
105
106
  );
106
107
  }
107
108
  // Dev mode: still require the bot token to be configured at all.
108
- return !!process.env.TELEGRAM_BOT_TOKEN;
109
+ return !!(await resolveSecret("TELEGRAM_BOT_TOKEN"));
109
110
  }
110
111
 
111
112
  const headerSecret = getHeader(event, "x-telegram-bot-api-secret-token");
@@ -172,7 +173,7 @@ export function telegramAdapter(): PlatformAdapter {
172
173
  message: OutgoingMessage,
173
174
  context: IncomingMessage,
174
175
  ): Promise<void> {
175
- const token = process.env.TELEGRAM_BOT_TOKEN;
176
+ const token = await resolveSecret("TELEGRAM_BOT_TOKEN");
176
177
  if (!token) {
177
178
  console.error("[telegram] TELEGRAM_BOT_TOKEN not configured");
178
179
  return;
@@ -224,7 +225,7 @@ export function telegramAdapter(): PlatformAdapter {
224
225
  message: OutgoingMessage,
225
226
  target: OutboundTarget,
226
227
  ): Promise<void> {
227
- const token = process.env.TELEGRAM_BOT_TOKEN;
228
+ const token = await resolveSecret("TELEGRAM_BOT_TOKEN");
228
229
  if (!token) {
229
230
  console.error("[telegram] TELEGRAM_BOT_TOKEN not configured");
230
231
  return;
@@ -272,14 +273,13 @@ export function telegramAdapter(): PlatformAdapter {
272
273
  },
273
274
 
274
275
  async getStatus(_baseUrl?: string): Promise<IntegrationStatus> {
275
- const hasToken = !!process.env.TELEGRAM_BOT_TOKEN;
276
+ const token = await resolveSecret("TELEGRAM_BOT_TOKEN");
277
+ const hasToken = !!token;
276
278
 
277
279
  let botName: string | undefined;
278
280
  if (hasToken) {
279
281
  try {
280
- const res = await fetch(
281
- `https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/getMe`,
282
- );
282
+ const res = await fetch(`https://api.telegram.org/bot${token}/getMe`);
283
283
  const data = (await res.json()) as {
284
284
  ok: boolean;
285
285
  result?: { username?: string };
@@ -299,9 +299,7 @@ export function telegramAdapter(): PlatformAdapter {
299
299
  hasToken,
300
300
  botUsername: botName,
301
301
  },
302
- error: !hasToken
303
- ? "Set TELEGRAM_BOT_TOKEN in your environment"
304
- : undefined,
302
+ error: !hasToken ? "Save TELEGRAM_BOT_TOKEN in settings" : undefined,
305
303
  };
306
304
  },
307
305
  };
@@ -2,6 +2,7 @@ import type { H3Event } from "h3";
2
2
  import { getQuery, getHeader, readRawBody as h3ReadRawBody } from "h3";
3
3
 
4
4
  import type { EnvKeyConfig } from "../../server/create-server.js";
5
+ import { resolveSecret } from "../../server/credential-provider.js";
5
6
  import type {
6
7
  PlatformAdapter,
7
8
  IncomingMessage,
@@ -103,7 +104,7 @@ export function whatsappAdapter(): PlatformAdapter {
103
104
  const mode = query["hub.mode"];
104
105
  const token = query["hub.verify_token"];
105
106
  const challenge = query["hub.challenge"];
106
- const expected = process.env.WHATSAPP_VERIFY_TOKEN;
107
+ const expected = await resolveSecret("WHATSAPP_VERIFY_TOKEN");
107
108
 
108
109
  if (mode === "subscribe" && expected && typeof token === "string") {
109
110
  // Timing-safe compare so an attacker can't measure character-wise
@@ -126,7 +127,7 @@ export function whatsappAdapter(): PlatformAdapter {
126
127
  },
127
128
 
128
129
  async verifyWebhook(event: H3Event): Promise<boolean> {
129
- const appSecret = process.env.WHATSAPP_APP_SECRET;
130
+ const appSecret = await resolveSecret("WHATSAPP_APP_SECRET");
130
131
  if (!appSecret) {
131
132
  if (shouldRefuseWhenSecretMissing()) {
132
133
  if (!_whatsappUnverifiedWarned) {
@@ -145,7 +146,7 @@ export function whatsappAdapter(): PlatformAdapter {
145
146
  );
146
147
  }
147
148
  // Dev mode: still require the access token to be configured at all.
148
- return !!process.env.WHATSAPP_ACCESS_TOKEN;
149
+ return !!(await resolveSecret("WHATSAPP_ACCESS_TOKEN"));
149
150
  }
150
151
 
151
152
  const signature = getHeader(event, "x-hub-signature-256");
@@ -223,8 +224,8 @@ export function whatsappAdapter(): PlatformAdapter {
223
224
  message: OutgoingMessage,
224
225
  context: IncomingMessage,
225
226
  ): Promise<void> {
226
- const accessToken = process.env.WHATSAPP_ACCESS_TOKEN;
227
- const phoneNumberId = process.env.WHATSAPP_PHONE_NUMBER_ID;
227
+ const accessToken = await resolveSecret("WHATSAPP_ACCESS_TOKEN");
228
+ const phoneNumberId = await resolveSecret("WHATSAPP_PHONE_NUMBER_ID");
228
229
  if (!accessToken || !phoneNumberId) {
229
230
  console.error(
230
231
  "[whatsapp] WHATSAPP_ACCESS_TOKEN or WHATSAPP_PHONE_NUMBER_ID not configured",
@@ -269,9 +270,11 @@ export function whatsappAdapter(): PlatformAdapter {
269
270
  },
270
271
 
271
272
  async getStatus(_baseUrl?: string): Promise<IntegrationStatus> {
272
- const hasAccessToken = !!process.env.WHATSAPP_ACCESS_TOKEN;
273
- const hasVerifyToken = !!process.env.WHATSAPP_VERIFY_TOKEN;
274
- const hasPhoneNumberId = !!process.env.WHATSAPP_PHONE_NUMBER_ID;
273
+ const hasAccessToken = !!(await resolveSecret("WHATSAPP_ACCESS_TOKEN"));
274
+ const hasVerifyToken = !!(await resolveSecret("WHATSAPP_VERIFY_TOKEN"));
275
+ const hasPhoneNumberId = !!(await resolveSecret(
276
+ "WHATSAPP_PHONE_NUMBER_ID",
277
+ ));
275
278
  const configured = hasAccessToken && hasVerifyToken && hasPhoneNumberId;
276
279
 
277
280
  return {
@@ -285,7 +288,7 @@ export function whatsappAdapter(): PlatformAdapter {
285
288
  hasPhoneNumberId,
286
289
  },
287
290
  error: !configured
288
- ? "Set WHATSAPP_ACCESS_TOKEN, WHATSAPP_VERIFY_TOKEN, and WHATSAPP_PHONE_NUMBER_ID"
291
+ ? "Save WHATSAPP_ACCESS_TOKEN, WHATSAPP_VERIFY_TOKEN, and WHATSAPP_PHONE_NUMBER_ID in settings"
289
292
  : undefined,
290
293
  };
291
294
  },
@@ -2,16 +2,18 @@ import { defineEventHandler, setResponseStatus, getMethod, getQuery } from "h3";
2
2
  import { getRequestHeader } from "h3";
3
3
  import { createRemoteJWKSet, jwtVerify } from "jose";
4
4
 
5
- import { getOrgContext } from "../org/context.js";
5
+ import { getOrgContext, resolveOrgIdForEmail } from "../org/context.js";
6
6
  import { loadResourcesForPrompt } from "../server/agent-chat-plugin.js";
7
7
  import { withConfiguredAppBasePath } from "../server/app-base-path.js";
8
8
  import { getSession } from "../server/auth.js";
9
9
  import { FRAMEWORK_ROUTE_PREFIX } from "../server/core-routes-plugin.js";
10
+ import { resolveSecret } from "../server/credential-provider.js";
10
11
  import {
11
12
  getH3App,
12
13
  markDefaultPluginProvided,
13
14
  } from "../server/framework-request-handler.js";
14
15
  import { readBody } from "../server/h3-helpers.js";
16
+ import { runWithRequestContext } from "../server/request-context.js";
15
17
  import {
16
18
  processA2AContinuationById,
17
19
  processDueA2AContinuations,
@@ -175,6 +177,12 @@ type RemoteCodeCommandEnvelope = {
175
177
  source?: unknown;
176
178
  };
177
179
 
180
+ type IntegrationCredentialContext = {
181
+ userEmail: string;
182
+ orgId?: string;
183
+ isIntegrationCaller?: boolean;
184
+ };
185
+
178
186
  const REMOTE_DEVICE_ONLINE_MS = 90_000;
179
187
 
180
188
  export async function enqueueRemoteCommand(
@@ -517,8 +525,7 @@ export function createIntegrationsPlugin(
517
525
  // init can leave us with an empty string forever. The getter
518
526
  // re-resolves on every webhook so freshly-set secrets work without
519
527
  // a redeploy.
520
- const getApiKey = () =>
521
- options?.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
528
+ const getApiKey = () => options?.apiKey ?? "";
522
529
 
523
530
  // Build the system prompt
524
531
  const baseSystemPrompt = options?.systemPrompt ?? INTEGRATION_SYSTEM_PROMPT;
@@ -569,6 +576,39 @@ export function createIntegrationsPlugin(
569
576
  };
570
577
  }
571
578
 
579
+ function toCredentialContext(
580
+ ctx: { ownerEmail: string; orgId: string | null },
581
+ opts?: { isIntegrationCaller?: boolean },
582
+ ): IntegrationCredentialContext {
583
+ return {
584
+ userEmail: ctx.ownerEmail,
585
+ ...(ctx.orgId ? { orgId: ctx.orgId } : {}),
586
+ ...(opts?.isIntegrationCaller ? { isIntegrationCaller: true } : {}),
587
+ };
588
+ }
589
+
590
+ async function credentialContextForIntegrationConfig(
591
+ config: Awaited<ReturnType<typeof getIntegrationConfig>>,
592
+ ): Promise<IntegrationCredentialContext | null> {
593
+ const ownerEmail =
594
+ typeof config?.owner === "string" ? config.owner.trim() : "";
595
+ if (!ownerEmail) return null;
596
+ const orgId = await resolveOrgIdForEmail(ownerEmail).catch(() => null);
597
+ return {
598
+ userEmail: ownerEmail,
599
+ ...(orgId ? { orgId } : {}),
600
+ isIntegrationCaller: true,
601
+ };
602
+ }
603
+
604
+ async function withCredentialContext<T>(
605
+ context: IntegrationCredentialContext | null,
606
+ fn: () => Promise<T>,
607
+ ): Promise<T> {
608
+ if (!context) return fn();
609
+ return runWithRequestContext(context, fn);
610
+ }
611
+
572
612
  async function requireRemoteDevice(event: any) {
573
613
  const token = extractBearerToken(
574
614
  getRequestHeader(event, "authorization"),
@@ -627,11 +667,15 @@ export function createIntegrationsPlugin(
627
667
  setResponseStatus(event, 405);
628
668
  return { error: "Method not allowed" };
629
669
  }
630
- if (!(await requireSession(event))) return { error: "unauthorized" };
631
670
  const baseUrl = getBaseUrl(event);
671
+ const ctx = await requireSessionContext(event);
672
+ if (!ctx) return { error: "unauthorized" };
673
+ const credentialContext = toCredentialContext(ctx);
632
674
  const statuses: IntegrationStatus[] = [];
633
675
  for (const adapter of adapters) {
634
- const status = await adapter.getStatus(baseUrl);
676
+ const status = await withCredentialContext(credentialContext, () =>
677
+ adapter.getStatus(baseUrl),
678
+ );
635
679
  const config = await getIntegrationConfig(adapter.platform);
636
680
  status.enabled = !!config?.configData?.enabled;
637
681
  status.webhookUrl = `${baseUrl}${P}/${adapter.platform}/webhook`;
@@ -1422,9 +1466,13 @@ export function createIntegrationsPlugin(
1422
1466
 
1423
1467
  // ─── GET /:platform/status ─────────────────────────────
1424
1468
  if (action === "status" && method === "GET") {
1425
- if (!(await requireSession(event))) return { error: "unauthorized" };
1469
+ const ctx = await requireSessionContext(event);
1470
+ if (!ctx) return { error: "unauthorized" };
1426
1471
  const baseUrl = getBaseUrl(event);
1427
- const status = await adapter.getStatus(baseUrl);
1472
+ const status = await withCredentialContext(
1473
+ toCredentialContext(ctx),
1474
+ () => adapter.getStatus(baseUrl),
1475
+ );
1428
1476
  const config = await getIntegrationConfig(platform);
1429
1477
  status.enabled = !!config?.configData?.enabled;
1430
1478
  status.webhookUrl = `${baseUrl}${P}/${platform}/webhook`;
@@ -1482,14 +1530,20 @@ export function createIntegrationsPlugin(
1482
1530
  return "ok";
1483
1531
  }
1484
1532
 
1533
+ const config = await getIntegrationConfig(platform);
1534
+ const credentialContext =
1535
+ await credentialContextForIntegrationConfig(config);
1536
+
1485
1537
  // Handle platform verification challenges (e.g. Slack url_verification)
1486
1538
  // before checking enable state or parsing the message.
1487
- const verification = await adapter.handleVerification(event);
1539
+ const verification = await withCredentialContext(
1540
+ credentialContext,
1541
+ () => adapter.handleVerification(event),
1542
+ );
1488
1543
  if (verification.handled) {
1489
1544
  return verification.response ?? "ok";
1490
1545
  }
1491
1546
 
1492
- const config = await getIntegrationConfig(platform);
1493
1547
  if (!config?.configData?.enabled) {
1494
1548
  setResponseStatus(event, 404);
1495
1549
  return { error: `Integration ${platform} is not enabled` };
@@ -1500,13 +1554,17 @@ export function createIntegrationsPlugin(
1500
1554
  // hangs on streaming providers), and that means handleWebhook's
1501
1555
  // own verifyWebhook step is bypassed. Without this call anyone
1502
1556
  // could POST a forged Slack/Telegram/email payload.
1503
- const isValid = await adapter.verifyWebhook(event);
1557
+ const isValid = await withCredentialContext(credentialContext, () =>
1558
+ adapter.verifyWebhook(event),
1559
+ );
1504
1560
  if (!isValid) {
1505
1561
  setResponseStatus(event, 401);
1506
1562
  return { error: "Invalid webhook signature" };
1507
1563
  }
1508
1564
 
1509
- const incoming = await adapter.parseIncomingMessage(event);
1565
+ const incoming = await withCredentialContext(credentialContext, () =>
1566
+ adapter.parseIncomingMessage(event),
1567
+ );
1510
1568
  if (!incoming) {
1511
1569
  setResponseStatus(event, 200);
1512
1570
  return "ok";
@@ -1582,10 +1640,18 @@ export function createIntegrationsPlugin(
1582
1640
  if (platform === "telegram") {
1583
1641
  const baseUrl = getBaseUrl(event);
1584
1642
  const webhookUrl = `${baseUrl}${P}/telegram/webhook`;
1585
- const token = process.env.TELEGRAM_BOT_TOKEN;
1643
+ const ctx = await requireSessionContext(event);
1644
+ if (!ctx) return { error: "unauthorized" };
1645
+ const token = await withCredentialContext(
1646
+ toCredentialContext(ctx),
1647
+ () => resolveSecret("TELEGRAM_BOT_TOKEN"),
1648
+ );
1586
1649
  if (!token) {
1587
1650
  setResponseStatus(event, 400);
1588
- return { error: "TELEGRAM_BOT_TOKEN not configured" };
1651
+ return {
1652
+ error:
1653
+ "TELEGRAM_BOT_TOKEN not configured. Save it in settings.",
1654
+ };
1589
1655
  }
1590
1656
  try {
1591
1657
  const res = await fetch(
@@ -17,6 +17,7 @@ import {
17
17
  import {
18
18
  canUseDeployCredentialFallbackForRequest,
19
19
  readDeployCredentialEnv,
20
+ resolveSecret,
20
21
  } from "../server/credential-provider.js";
21
22
  import { getSetting } from "../settings/store.js";
22
23
  import { registerOnboardingStep } from "./registry.js";
@@ -287,12 +288,14 @@ const emailStep: OnboardingStep = {
287
288
  },
288
289
  },
289
290
  ],
290
- isComplete: () => {
291
- if (process.env.RESEND_API_KEY) return true;
291
+ isComplete: async () => {
292
+ if (await resolveSecret("RESEND_API_KEY")) return true;
292
293
  // SendGrid rejects Resend's sandbox sender, so EMAIL_FROM must also be
293
294
  // set — otherwise sendEmail() throws at runtime even though the API key
294
295
  // is configured.
295
- if (process.env.SENDGRID_API_KEY) return !!process.env.EMAIL_FROM;
296
+ if (await resolveSecret("SENDGRID_API_KEY")) {
297
+ return !!(await resolveSecret("EMAIL_FROM"));
298
+ }
296
299
  return false;
297
300
  },
298
301
  };
@@ -9,7 +9,7 @@
9
9
 
10
10
  export type OnboardingMethodBadge = "recommended" | "beta" | "free" | "soon";
11
11
 
12
- /** Fields for a form-style onboarding method (key/value env-var entry). */
12
+ /** Fields for a form-style onboarding method (key/value secret entry). */
13
13
  export interface OnboardingFormField {
14
14
  key: string;
15
15
  label: string;
@@ -312,7 +312,7 @@ async function inviteOne(
312
312
 
313
313
  let emailSent = false;
314
314
  let emailError: string | undefined;
315
- if (isEmailConfigured()) {
315
+ if (await isEmailConfigured()) {
316
316
  try {
317
317
  const { subject, html, text } = renderInviteEmail({
318
318
  invitee: email,
@@ -5435,10 +5435,7 @@ export function createAgentChatPlugin(
5435
5435
  // Sub-agents must inherit the parent run's resolved key so
5436
5436
  // delegations spawned by agent-teams don't silently fall back
5437
5437
  // to the platform key while the parent uses BYO credentials.
5438
- apiKey:
5439
- runCtx?.userApiKey ??
5440
- options?.apiKey ??
5441
- process.env.ANTHROPIC_API_KEY,
5438
+ apiKey: runCtx?.userApiKey ?? options?.apiKey,
5442
5439
  })
5443
5440
  );
5444
5441
  },
@@ -6949,7 +6946,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
6949
6946
  const { getOwnerActiveApiKey } =
6950
6947
  await import("../agent/production-agent.js");
6951
6948
  const userApiKey = await getOwnerActiveApiKey(ownerEmail);
6952
- const apiKey = userApiKey ?? process.env.ANTHROPIC_API_KEY;
6949
+ const apiKey = userApiKey;
6953
6950
  if (!apiKey) {
6954
6951
  // Fallback: truncate the message
6955
6952
  return { title: cleanMessage.trim().slice(0, 60) };
@@ -7985,7 +7982,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
7985
7982
  : await buildSchemaBlock(owner, databaseToolsMode);
7986
7983
  return basePrompt + resources + schemaBlock;
7987
7984
  },
7988
- apiKey: options?.apiKey ?? process.env.ANTHROPIC_API_KEY,
7985
+ apiKey: options?.apiKey,
7989
7986
  model: options?.model,
7990
7987
  appId: options?.appId,
7991
7988
  };
@@ -8084,7 +8081,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
8084
8081
  : await buildSchemaBlock(owner, databaseToolsMode);
8085
8082
  return basePrompt + resources + schemaBlock;
8086
8083
  },
8087
- apiKey: options?.apiKey ?? process.env.ANTHROPIC_API_KEY,
8084
+ apiKey: options?.apiKey,
8088
8085
  model: options?.model,
8089
8086
  appId: options?.appId,
8090
8087
  });