@agent-native/core 0.114.15 → 0.115.1

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 (467) hide show
  1. package/agent-native.eject.json +2 -0
  2. package/bin/agent-native.js +35 -14
  3. package/bin/launcher.js +34 -0
  4. package/corpus/README.md +3 -3
  5. package/corpus/core/CHANGELOG.md +35 -0
  6. package/corpus/core/agent-native.eject.json +2 -0
  7. package/corpus/core/bin/agent-native.js +35 -14
  8. package/corpus/core/bin/launcher.js +34 -0
  9. package/corpus/core/docs/content/agent-native-toolkit.mdx +16 -0
  10. package/corpus/core/docs/content/recurring-jobs.mdx +35 -6
  11. package/corpus/core/export-snapshot.json +4 -0
  12. package/corpus/core/package.json +5 -1
  13. package/corpus/core/src/action.ts +22 -1
  14. package/corpus/core/src/agent/production-agent.ts +105 -3
  15. package/corpus/core/src/cli/templates-meta.ts +12 -0
  16. package/corpus/core/src/client/AssistantChat.tsx +53 -26
  17. package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +19 -0
  18. package/corpus/core/src/client/agent-page/use-jobs.ts +1 -0
  19. package/corpus/core/src/client/chat/message-components.tsx +35 -1
  20. package/corpus/core/src/client/chat/tool-call-display.tsx +38 -3
  21. package/corpus/core/src/connections/catalog.ts +20 -1
  22. package/corpus/core/src/connections/reader.ts +65 -0
  23. package/corpus/core/src/dashboard-storage/index.ts +27 -0
  24. package/corpus/core/src/dashboard-storage/panel-source.ts +168 -0
  25. package/corpus/core/src/dashboard-storage/schema.ts +62 -0
  26. package/corpus/core/src/dashboard-storage/store.ts +333 -0
  27. package/corpus/core/src/deploy/build.ts +95 -16
  28. package/corpus/core/src/eject/provider-api-definitions.ts +1 -0
  29. package/corpus/core/src/eject/workspace-connections.ts +1 -0
  30. package/corpus/core/src/extensions/actions.ts +199 -73
  31. package/corpus/core/src/jobs/actions/list-recurring-jobs.ts +2 -0
  32. package/corpus/core/src/jobs/scheduler.ts +71 -4
  33. package/corpus/core/src/jobs/tools.ts +31 -1
  34. package/corpus/core/src/localization/default-messages.ts +1 -0
  35. package/corpus/core/src/mcp-client/index.ts +6 -0
  36. package/corpus/core/src/provider-api/actions/provider-api.ts +1 -1
  37. package/corpus/core/src/provider-api/index.ts +190 -5
  38. package/corpus/core/src/secrets/register-framework-secrets.ts +8 -0
  39. package/corpus/core/src/server/agent-chat/context-tools.ts +9 -0
  40. package/corpus/core/src/server/agent-chat/framework-prompts.ts +2 -2
  41. package/corpus/core/src/server/agent-chat-plugin.ts +22 -2
  42. package/corpus/core/src/server/core-routes-plugin.ts +1 -0
  43. package/corpus/core/src/server/credential-provider.ts +9 -3
  44. package/corpus/core/src/server/workspace-provider-oauth.ts +181 -4
  45. package/corpus/core/src/styles/agent-native.css +45 -2
  46. package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  47. package/corpus/core/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  48. package/corpus/core/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  49. package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  50. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  51. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  52. package/corpus/core/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  53. package/corpus/core/src/triggers/actions.ts +11 -2
  54. package/corpus/core/src/triggers/dispatcher.ts +20 -1
  55. package/corpus/core/src/triggers/types.ts +5 -0
  56. package/corpus/core/src/vite/action-types-plugin.ts +9 -1
  57. package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +115 -0
  58. package/corpus/templates/analytics/AGENTS.md +11 -11
  59. package/corpus/templates/analytics/_gitignore +39 -0
  60. package/corpus/templates/analytics/actions/query-dashboard-panel.ts +30 -0
  61. package/corpus/templates/analytics/actions/update-dashboard.ts +2 -1
  62. package/corpus/templates/analytics/app/lib/sql-query.ts +11 -25
  63. package/corpus/templates/analytics/changelog/2026-07-21-fixed-extension-updates-failing-before-changes-could-be-appl.md +6 -0
  64. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +1 -0
  65. package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +51 -0
  66. package/corpus/templates/analytics/server/lib/prometheus.ts +1 -1
  67. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
  68. package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +115 -0
  69. package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +115 -0
  70. package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +115 -0
  71. package/corpus/templates/calendar/_gitignore +39 -0
  72. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  73. package/corpus/templates/chat/AGENTS.md +1 -1
  74. package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +115 -0
  75. package/corpus/templates/clips/AGENTS.md +7 -0
  76. package/corpus/templates/clips/actions/prepare-crm-call-evidence.ts +58 -0
  77. package/corpus/templates/clips/app/components/library/bulk-action-toolbar.tsx +25 -8
  78. package/corpus/templates/clips/app/components/library/library-grid.tsx +118 -9
  79. package/corpus/templates/clips/app/components/library/library-layout.tsx +1 -1
  80. package/corpus/templates/clips/app/components/library/recording-card.tsx +10 -8
  81. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +88 -11
  82. package/corpus/templates/clips/app/i18n/en-US.ts +6 -0
  83. package/corpus/templates/clips/app/routes/_app.trash.tsx +16 -1
  84. package/corpus/templates/clips/changelog/2026-07-21-crm-call-evidence-handoff.md +6 -0
  85. package/corpus/templates/clips/changelog/2026-07-21-recording-retries-and-restarts-keep-their-upload-session-so-.md +6 -0
  86. package/corpus/templates/clips/chrome-extension/src/background.ts +20 -5
  87. package/corpus/templates/clips/chrome-extension/src/native-recording-state.ts +19 -0
  88. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +8 -0
  89. package/corpus/templates/clips/desktop/src/app.tsx +24 -3
  90. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +9 -0
  91. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +54 -28
  92. package/corpus/templates/clips/server/plugins/agent-chat.ts +1 -0
  93. package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +115 -0
  94. package/corpus/templates/content/_gitignore +39 -0
  95. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +20 -38
  96. package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +40 -1
  97. package/corpus/templates/content/learnings.defaults.md +5 -0
  98. package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +115 -0
  99. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  100. package/corpus/templates/crm/.agents/skills/crm/SKILL.md +128 -0
  101. package/corpus/templates/crm/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  102. package/corpus/templates/crm/.agents/skills/feature-flags/SKILL.md +169 -0
  103. package/corpus/templates/crm/.agents/skills/upgrade-agent-native/SKILL.md +100 -0
  104. package/corpus/templates/crm/.env.example +5 -0
  105. package/corpus/templates/crm/AGENTS.md +120 -0
  106. package/corpus/templates/crm/CHANGELOG.md +1 -0
  107. package/corpus/templates/crm/DEVELOPING.md +66 -0
  108. package/corpus/templates/crm/README.md +106 -0
  109. package/corpus/templates/crm/_gitignore +12 -0
  110. package/corpus/templates/crm/actions/_crm-action-utils.ts +87 -0
  111. package/corpus/templates/crm/actions/_crm-dashboard.ts +69 -0
  112. package/corpus/templates/crm/actions/_crm-signal-utils.ts +79 -0
  113. package/corpus/templates/crm/actions/apply-crm-proposals.ts +203 -0
  114. package/corpus/templates/crm/actions/attach-call-evidence.ts +170 -0
  115. package/corpus/templates/crm/actions/configure-crm-connection.ts +126 -0
  116. package/corpus/templates/crm/actions/configure-native-crm.ts +44 -0
  117. package/corpus/templates/crm/actions/create-crm-record.ts +148 -0
  118. package/corpus/templates/crm/actions/create-crm-signal-tracker.ts +58 -0
  119. package/corpus/templates/crm/actions/delete-staged-dataset.ts +14 -0
  120. package/corpus/templates/crm/actions/get-crm-automation-recipe.ts +36 -0
  121. package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +33 -0
  122. package/corpus/templates/crm/actions/get-crm-dashboard.ts +14 -0
  123. package/corpus/templates/crm/actions/get-crm-overview.ts +13 -0
  124. package/corpus/templates/crm/actions/get-crm-pipeline-data.ts +61 -0
  125. package/corpus/templates/crm/actions/get-crm-record.ts +75 -0
  126. package/corpus/templates/crm/actions/install-crm-pipeline-dashboard.ts +81 -0
  127. package/corpus/templates/crm/actions/list-crm-dashboard-revisions.ts +15 -0
  128. package/corpus/templates/crm/actions/list-crm-dashboards.ts +15 -0
  129. package/corpus/templates/crm/actions/list-crm-proposals.ts +31 -0
  130. package/corpus/templates/crm/actions/list-crm-records.ts +79 -0
  131. package/corpus/templates/crm/actions/list-crm-saved-views.ts +15 -0
  132. package/corpus/templates/crm/actions/list-crm-signal-hits.ts +43 -0
  133. package/corpus/templates/crm/actions/list-crm-signal-trackers.ts +32 -0
  134. package/corpus/templates/crm/actions/list-crm-tasks.ts +22 -0
  135. package/corpus/templates/crm/actions/list-staged-datasets.ts +14 -0
  136. package/corpus/templates/crm/actions/list-workspace-connections.ts +47 -0
  137. package/corpus/templates/crm/actions/manage-crm-signal-tracker.ts +87 -0
  138. package/corpus/templates/crm/actions/manage-crm-task.ts +132 -0
  139. package/corpus/templates/crm/actions/navigate.ts +63 -0
  140. package/corpus/templates/crm/actions/provider-api-catalog.ts +22 -0
  141. package/corpus/templates/crm/actions/provider-api-docs.ts +54 -0
  142. package/corpus/templates/crm/actions/provider-api-request.ts +92 -0
  143. package/corpus/templates/crm/actions/query-staged-dataset.ts +44 -0
  144. package/corpus/templates/crm/actions/record-crm-call-insight.ts +160 -0
  145. package/corpus/templates/crm/actions/record-crm-smart-signal.ts +150 -0
  146. package/corpus/templates/crm/actions/restore-crm-dashboard-revision.ts +23 -0
  147. package/corpus/templates/crm/actions/review-crm-signal.ts +31 -0
  148. package/corpus/templates/crm/actions/run-crm-saved-view-program.ts +103 -0
  149. package/corpus/templates/crm/actions/run-crm-signal-trackers.ts +275 -0
  150. package/corpus/templates/crm/actions/run.ts +11 -0
  151. package/corpus/templates/crm/actions/save-crm-dashboard.ts +51 -0
  152. package/corpus/templates/crm/actions/save-crm-saved-view.ts +119 -0
  153. package/corpus/templates/crm/actions/sync-crm.ts +146 -0
  154. package/corpus/templates/crm/actions/update-crm-record.ts +508 -0
  155. package/corpus/templates/crm/actions/view-screen.ts +218 -0
  156. package/corpus/templates/crm/agent-native.app-skill.json +58 -0
  157. package/corpus/templates/crm/app/components/crm/CreateCrmRecordDialog.tsx +158 -0
  158. package/corpus/templates/crm/app/components/crm/CrmDashboardPanel.tsx +83 -0
  159. package/corpus/templates/crm/app/components/crm/CrmSignalsPanel.tsx +225 -0
  160. package/corpus/templates/crm/app/components/crm/IntelligenceSettings.tsx +413 -0
  161. package/corpus/templates/crm/app/components/crm/RecordActions.tsx +510 -0
  162. package/corpus/templates/crm/app/components/crm/RecordGrid.tsx +134 -0
  163. package/corpus/templates/crm/app/components/crm/RecordWorkspace.tsx +367 -0
  164. package/corpus/templates/crm/app/components/crm/SavedViewDataProgram.tsx +92 -0
  165. package/corpus/templates/crm/app/components/crm/Surface.tsx +96 -0
  166. package/corpus/templates/crm/app/components/crm/WorkOverview.tsx +180 -0
  167. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +106 -0
  168. package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +84 -0
  169. package/corpus/templates/crm/app/entry.client.tsx +16 -0
  170. package/corpus/templates/crm/app/entry.server.tsx +10 -0
  171. package/corpus/templates/crm/app/global.css +167 -0
  172. package/corpus/templates/crm/app/hooks/use-navigation-state.ts +60 -0
  173. package/corpus/templates/crm/app/i18n/en-US.ts +89 -0
  174. package/corpus/templates/crm/app/i18n/index.ts +34 -0
  175. package/corpus/templates/crm/app/lib/dashboard.ts +13 -0
  176. package/corpus/templates/crm/app/lib/navigation.ts +54 -0
  177. package/corpus/templates/crm/app/lib/tab-id.ts +1 -0
  178. package/corpus/templates/crm/app/lib/types.ts +172 -0
  179. package/corpus/templates/crm/app/lib/utils.ts +1 -0
  180. package/corpus/templates/crm/app/root.tsx +88 -0
  181. package/corpus/templates/crm/app/routes/_index.tsx +26 -0
  182. package/corpus/templates/crm/app/routes/accounts.tsx +41 -0
  183. package/corpus/templates/crm/app/routes/agent.tsx +5 -0
  184. package/corpus/templates/crm/app/routes/ask.tsx +53 -0
  185. package/corpus/templates/crm/app/routes/dashboard.tsx +118 -0
  186. package/corpus/templates/crm/app/routes/opportunities.tsx +41 -0
  187. package/corpus/templates/crm/app/routes/people.tsx +41 -0
  188. package/corpus/templates/crm/app/routes/proposals.tsx +266 -0
  189. package/corpus/templates/crm/app/routes/records.$recordId.tsx +35 -0
  190. package/corpus/templates/crm/app/routes/settings.tsx +63 -0
  191. package/corpus/templates/crm/app/routes/setup.tsx +308 -0
  192. package/corpus/templates/crm/app/routes/tasks.tsx +252 -0
  193. package/corpus/templates/crm/app/routes/views.tsx +333 -0
  194. package/corpus/templates/crm/app/routes.ts +17 -0
  195. package/corpus/templates/crm/app/vite-env.d.ts +6 -0
  196. package/corpus/templates/crm/changelog/2026-07-21-agent-native-crm.md +6 -0
  197. package/corpus/templates/crm/changelog/2026-07-21-clips-call-evidence-review-recipe.md +6 -0
  198. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-find-and-review-evidence-grounded-call-signals-w.md +6 -0
  199. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-manage-keyword-and-smart-call-signal-trackers-fr.md +6 -0
  200. package/corpus/templates/crm/changelog/2026-07-21-delegated-local-crm-automation.md +6 -0
  201. package/corpus/templates/crm/changelog/2026-07-21-native-sql.md +6 -0
  202. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboard.md +6 -0
  203. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboards-now-install-correctly-from-the-crm-actio.md +6 -0
  204. package/corpus/templates/crm/changelog/2026-07-21-salesforce-connection.md +6 -0
  205. package/corpus/templates/crm/components.json +20 -0
  206. package/corpus/templates/crm/docs/architecture/crm-contract.md +180 -0
  207. package/corpus/templates/crm/learnings.defaults.md +5 -0
  208. package/corpus/templates/crm/package.json +59 -0
  209. package/corpus/templates/crm/public/favicon.svg +1 -0
  210. package/corpus/templates/crm/public/icon-180.svg +1 -0
  211. package/corpus/templates/crm/public/manifest.json +11 -0
  212. package/corpus/templates/crm/react-router.config.ts +7 -0
  213. package/corpus/templates/crm/server/crm/adapter.ts +32 -0
  214. package/corpus/templates/crm/server/crm/crm-field-firewall.ts +64 -0
  215. package/corpus/templates/crm/server/crm/crm-mirror.ts +711 -0
  216. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +1143 -0
  217. package/corpus/templates/crm/server/crm/native-adapter.ts +1715 -0
  218. package/corpus/templates/crm/server/crm/read-through.ts +207 -0
  219. package/corpus/templates/crm/server/crm/salesforce-adapter.ts +1255 -0
  220. package/corpus/templates/crm/server/db/crm-store.ts +1170 -0
  221. package/corpus/templates/crm/server/db/index.ts +169 -0
  222. package/corpus/templates/crm/server/db/schema.ts +441 -0
  223. package/corpus/templates/crm/server/lib/intelligence/default-detectors.ts +65 -0
  224. package/corpus/templates/crm/server/lib/intelligence/evidence.ts +105 -0
  225. package/corpus/templates/crm/server/lib/intelligence/keyword-detector.ts +100 -0
  226. package/corpus/templates/crm/server/lib/intelligence/smart-detector.ts +144 -0
  227. package/corpus/templates/crm/server/lib/intelligence/summary.ts +141 -0
  228. package/corpus/templates/crm/server/lib/provider-api.ts +64 -0
  229. package/corpus/templates/crm/server/middleware/auth.ts +4 -0
  230. package/corpus/templates/crm/server/plugins/agent-chat.ts +68 -0
  231. package/corpus/templates/crm/server/plugins/auth.ts +14 -0
  232. package/corpus/templates/crm/server/plugins/core-routes.ts +17 -0
  233. package/corpus/templates/crm/server/plugins/db.ts +454 -0
  234. package/corpus/templates/crm/server/routes/[...page].get.ts +5 -0
  235. package/corpus/templates/crm/shared/crm-automation-recipes.ts +132 -0
  236. package/corpus/templates/crm/shared/crm-contract.ts +254 -0
  237. package/corpus/templates/crm/shared/crm-sales-config.ts +63 -0
  238. package/corpus/templates/crm/ssr-entry.ts +11 -0
  239. package/corpus/templates/crm/tsconfig.json +24 -0
  240. package/corpus/templates/crm/vite.config.ts +15 -0
  241. package/corpus/templates/crm/vitest.config.ts +5 -0
  242. package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +115 -0
  243. package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +115 -0
  244. package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +115 -0
  245. package/corpus/templates/forms/_gitignore +39 -0
  246. package/corpus/templates/forms/learnings.defaults.md +5 -0
  247. package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +115 -0
  248. package/corpus/templates/macros/_gitignore +39 -0
  249. package/corpus/templates/macros/learnings.defaults.md +5 -0
  250. package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +115 -0
  251. package/corpus/templates/mail/_gitignore +39 -0
  252. package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +115 -0
  253. package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +115 -0
  254. package/corpus/templates/slides/_gitignore +39 -0
  255. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +27 -0
  256. package/corpus/templates/tasks/_gitignore +39 -0
  257. package/corpus/toolkit/CHANGELOG.md +12 -0
  258. package/corpus/toolkit/README.md +30 -0
  259. package/corpus/toolkit/agent-native.eject.json +33 -0
  260. package/corpus/toolkit/package.json +15 -1
  261. package/corpus/toolkit/src/dashboard/DataTable.tsx +273 -0
  262. package/corpus/toolkit/src/dashboard/DateRangePicker.tsx +57 -0
  263. package/corpus/toolkit/src/dashboard/GenericChartPanel.tsx +461 -0
  264. package/corpus/toolkit/src/dashboard/MetricCard.tsx +54 -0
  265. package/corpus/toolkit/src/dashboard/StatsCard.tsx +49 -0
  266. package/corpus/toolkit/src/dashboard/dashboard-layout.ts +329 -0
  267. package/corpus/toolkit/src/dashboard/index.ts +6 -0
  268. package/corpus/toolkit/src/index.ts +1 -0
  269. package/corpus/toolkit/src/ui/calendar.tsx +8 -8
  270. package/corpus/toolkit/src/ui/date-picker.tsx +4 -1
  271. package/dist/action.d.ts +14 -1
  272. package/dist/action.d.ts.map +1 -1
  273. package/dist/action.js.map +1 -1
  274. package/dist/agent/production-agent.d.ts +3 -1
  275. package/dist/agent/production-agent.d.ts.map +1 -1
  276. package/dist/agent/production-agent.js +83 -3
  277. package/dist/agent/production-agent.js.map +1 -1
  278. package/dist/cli/templates-meta.d.ts.map +1 -1
  279. package/dist/cli/templates-meta.js +12 -0
  280. package/dist/cli/templates-meta.js.map +1 -1
  281. package/dist/client/AssistantChat.d.ts +4 -0
  282. package/dist/client/AssistantChat.d.ts.map +1 -1
  283. package/dist/client/AssistantChat.js +30 -17
  284. package/dist/client/AssistantChat.js.map +1 -1
  285. package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
  286. package/dist/client/agent-page/AgentJobsTab.js +3 -1
  287. package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
  288. package/dist/client/agent-page/use-jobs.d.ts +1 -0
  289. package/dist/client/agent-page/use-jobs.d.ts.map +1 -1
  290. package/dist/client/agent-page/use-jobs.js.map +1 -1
  291. package/dist/client/chat/message-components.d.ts +5 -0
  292. package/dist/client/chat/message-components.d.ts.map +1 -1
  293. package/dist/client/chat/message-components.js +17 -1
  294. package/dist/client/chat/message-components.js.map +1 -1
  295. package/dist/client/chat/tool-call-display.d.ts +3 -1
  296. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  297. package/dist/client/chat/tool-call-display.js +17 -7
  298. package/dist/client/chat/tool-call-display.js.map +1 -1
  299. package/dist/collab/awareness.d.ts +2 -2
  300. package/dist/collab/awareness.d.ts.map +1 -1
  301. package/dist/collab/routes.d.ts +1 -1
  302. package/dist/collab/struct-routes.d.ts +1 -1
  303. package/dist/connections/catalog.d.ts +17 -3
  304. package/dist/connections/catalog.d.ts.map +1 -1
  305. package/dist/connections/catalog.js +16 -1
  306. package/dist/connections/catalog.js.map +1 -1
  307. package/dist/connections/reader.d.ts +18 -0
  308. package/dist/connections/reader.d.ts.map +1 -1
  309. package/dist/connections/reader.js +41 -0
  310. package/dist/connections/reader.js.map +1 -1
  311. package/dist/dashboard-storage/index.d.ts +4 -0
  312. package/dist/dashboard-storage/index.d.ts.map +1 -0
  313. package/dist/dashboard-storage/index.js +4 -0
  314. package/dist/dashboard-storage/index.js.map +1 -0
  315. package/dist/dashboard-storage/panel-source.d.ts +68 -0
  316. package/dist/dashboard-storage/panel-source.d.ts.map +1 -0
  317. package/dist/dashboard-storage/panel-source.js +76 -0
  318. package/dist/dashboard-storage/panel-source.js.map +1 -0
  319. package/dist/dashboard-storage/schema.d.ts +562 -0
  320. package/dist/dashboard-storage/schema.d.ts.map +1 -0
  321. package/dist/dashboard-storage/schema.js +32 -0
  322. package/dist/dashboard-storage/schema.js.map +1 -0
  323. package/dist/dashboard-storage/store.d.ts +62 -0
  324. package/dist/dashboard-storage/store.d.ts.map +1 -0
  325. package/dist/dashboard-storage/store.js +227 -0
  326. package/dist/dashboard-storage/store.js.map +1 -0
  327. package/dist/deploy/build.d.ts +7 -0
  328. package/dist/deploy/build.d.ts.map +1 -1
  329. package/dist/deploy/build.js +78 -14
  330. package/dist/deploy/build.js.map +1 -1
  331. package/dist/eject/provider-api-definitions.d.ts +2 -1
  332. package/dist/eject/provider-api-definitions.d.ts.map +1 -1
  333. package/dist/eject/provider-api-definitions.js +1 -0
  334. package/dist/eject/provider-api-definitions.js.map +1 -1
  335. package/dist/eject/workspace-connections.d.ts.map +1 -1
  336. package/dist/eject/workspace-connections.js +1 -0
  337. package/dist/eject/workspace-connections.js.map +1 -1
  338. package/dist/extensions/actions.d.ts.map +1 -1
  339. package/dist/extensions/actions.js +165 -67
  340. package/dist/extensions/actions.js.map +1 -1
  341. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  342. package/dist/jobs/actions/list-recurring-jobs.d.ts +1 -0
  343. package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -1
  344. package/dist/jobs/actions/list-recurring-jobs.js +1 -0
  345. package/dist/jobs/actions/list-recurring-jobs.js.map +1 -1
  346. package/dist/jobs/scheduler.d.ts +17 -2
  347. package/dist/jobs/scheduler.d.ts.map +1 -1
  348. package/dist/jobs/scheduler.js +51 -2
  349. package/dist/jobs/scheduler.js.map +1 -1
  350. package/dist/jobs/tools.d.ts.map +1 -1
  351. package/dist/jobs/tools.js +32 -2
  352. package/dist/jobs/tools.js.map +1 -1
  353. package/dist/localization/default-messages.d.ts +1 -0
  354. package/dist/localization/default-messages.d.ts.map +1 -1
  355. package/dist/localization/default-messages.js +1 -0
  356. package/dist/localization/default-messages.js.map +1 -1
  357. package/dist/mcp-client/index.d.ts +2 -0
  358. package/dist/mcp-client/index.d.ts.map +1 -1
  359. package/dist/mcp-client/index.js +5 -0
  360. package/dist/mcp-client/index.js.map +1 -1
  361. package/dist/observability/routes.d.ts +1 -1
  362. package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
  363. package/dist/provider-api/actions/provider-api.d.ts +8 -6
  364. package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
  365. package/dist/provider-api/actions/provider-api.js +1 -1
  366. package/dist/provider-api/actions/provider-api.js.map +1 -1
  367. package/dist/provider-api/index.d.ts +11 -7
  368. package/dist/provider-api/index.d.ts.map +1 -1
  369. package/dist/provider-api/index.js +143 -5
  370. package/dist/provider-api/index.js.map +1 -1
  371. package/dist/resources/handlers.d.ts +1 -1
  372. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  373. package/dist/secrets/register-framework-secrets.js +7 -0
  374. package/dist/secrets/register-framework-secrets.js.map +1 -1
  375. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  376. package/dist/server/agent-chat/context-tools.js +9 -0
  377. package/dist/server/agent-chat/context-tools.js.map +1 -1
  378. package/dist/server/agent-chat/framework-prompts.js +2 -2
  379. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  380. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  381. package/dist/server/agent-chat-plugin.js +18 -2
  382. package/dist/server/agent-chat-plugin.js.map +1 -1
  383. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  384. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  385. package/dist/server/core-routes-plugin.js +1 -0
  386. package/dist/server/core-routes-plugin.js.map +1 -1
  387. package/dist/server/credential-provider.d.ts +4 -3
  388. package/dist/server/credential-provider.d.ts.map +1 -1
  389. package/dist/server/credential-provider.js +9 -3
  390. package/dist/server/credential-provider.js.map +1 -1
  391. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  392. package/dist/server/workspace-provider-oauth.d.ts.map +1 -1
  393. package/dist/server/workspace-provider-oauth.js +141 -4
  394. package/dist/server/workspace-provider-oauth.js.map +1 -1
  395. package/dist/styles/agent-native.css +45 -2
  396. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  397. package/dist/templates/chat/AGENTS.md +1 -1
  398. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  399. package/dist/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  400. package/dist/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  401. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  402. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  403. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  404. package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  405. package/dist/triggers/actions.d.ts.map +1 -1
  406. package/dist/triggers/actions.js +10 -2
  407. package/dist/triggers/actions.js.map +1 -1
  408. package/dist/triggers/dispatcher.d.ts.map +1 -1
  409. package/dist/triggers/dispatcher.js +15 -0
  410. package/dist/triggers/dispatcher.js.map +1 -1
  411. package/dist/triggers/types.d.ts +5 -0
  412. package/dist/triggers/types.d.ts.map +1 -1
  413. package/dist/triggers/types.js.map +1 -1
  414. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  415. package/dist/vite/action-types-plugin.js +4 -1
  416. package/dist/vite/action-types-plugin.js.map +1 -1
  417. package/docs/content/agent-native-toolkit.mdx +16 -0
  418. package/docs/content/recurring-jobs.mdx +35 -6
  419. package/package.json +6 -2
  420. package/src/action.ts +22 -1
  421. package/src/agent/production-agent.ts +105 -3
  422. package/src/cli/templates-meta.ts +12 -0
  423. package/src/client/AssistantChat.tsx +53 -26
  424. package/src/client/agent-page/AgentJobsTab.tsx +19 -0
  425. package/src/client/agent-page/use-jobs.ts +1 -0
  426. package/src/client/chat/message-components.tsx +35 -1
  427. package/src/client/chat/tool-call-display.tsx +38 -3
  428. package/src/connections/catalog.ts +20 -1
  429. package/src/connections/reader.ts +65 -0
  430. package/src/dashboard-storage/index.ts +27 -0
  431. package/src/dashboard-storage/panel-source.ts +168 -0
  432. package/src/dashboard-storage/schema.ts +62 -0
  433. package/src/dashboard-storage/store.ts +333 -0
  434. package/src/deploy/build.ts +95 -16
  435. package/src/eject/provider-api-definitions.ts +1 -0
  436. package/src/eject/workspace-connections.ts +1 -0
  437. package/src/extensions/actions.ts +199 -73
  438. package/src/jobs/actions/list-recurring-jobs.ts +2 -0
  439. package/src/jobs/scheduler.ts +71 -4
  440. package/src/jobs/tools.ts +31 -1
  441. package/src/localization/default-messages.ts +1 -0
  442. package/src/mcp-client/index.ts +6 -0
  443. package/src/provider-api/actions/provider-api.ts +1 -1
  444. package/src/provider-api/index.ts +190 -5
  445. package/src/secrets/register-framework-secrets.ts +8 -0
  446. package/src/server/agent-chat/context-tools.ts +9 -0
  447. package/src/server/agent-chat/framework-prompts.ts +2 -2
  448. package/src/server/agent-chat-plugin.ts +22 -2
  449. package/src/server/core-routes-plugin.ts +1 -0
  450. package/src/server/credential-provider.ts +9 -3
  451. package/src/server/workspace-provider-oauth.ts +181 -4
  452. package/src/styles/agent-native.css +45 -2
  453. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  454. package/src/templates/chat/AGENTS.md +1 -1
  455. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  456. package/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  457. package/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  458. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  459. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  460. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  461. package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  462. package/src/triggers/actions.ts +11 -2
  463. package/src/triggers/dispatcher.ts +20 -1
  464. package/src/triggers/types.ts +5 -0
  465. package/src/vite/action-types-plugin.ts +9 -1
  466. package/corpus/templates/analytics/server/handlers/sql-query.ts +0 -36
  467. package/corpus/templates/analytics/server/routes/api/sql-query.post.ts +0 -1
package/src/jobs/tools.ts CHANGED
@@ -18,6 +18,7 @@ import { isValidCron, nextOccurrence, describeCron } from "./cron.js";
18
18
  import {
19
19
  parseJobFrontmatter,
20
20
  buildJobContent,
21
+ normalizeJobMcpTools,
21
22
  type JobFrontmatter,
22
23
  } from "./scheduler.js";
23
24
 
@@ -106,6 +107,13 @@ async function runCreate(args: Record<string, any>): Promise<string> {
106
107
  });
107
108
  }
108
109
 
110
+ let mcpTools: string[] | undefined;
111
+ try {
112
+ mcpTools = normalizeJobMcpTools(args.mcpTools);
113
+ } catch (err) {
114
+ return JSON.stringify({ error: (err as Error).message });
115
+ }
116
+
109
117
  const owner = scope === "personal" ? getOwner() : getSharedOwner();
110
118
  const path = `jobs/${name}.md`;
111
119
  const now = new Date();
@@ -135,6 +143,7 @@ async function runCreate(args: Record<string, any>): Promise<string> {
135
143
  ...(typeof model === "string" && model.trim()
136
144
  ? { model: model.trim() }
137
145
  : {}),
146
+ ...(mcpTools?.length ? { mcpTools } : {}),
138
147
  };
139
148
 
140
149
  const content = buildJobContent(meta, instructions);
@@ -148,6 +157,7 @@ async function runCreate(args: Record<string, any>): Promise<string> {
148
157
  scheduleDescription: describeCron(schedule),
149
158
  nextRun: next.toISOString(),
150
159
  scope: scope || "shared",
160
+ ...(mcpTools?.length ? { mcpTools } : {}),
151
161
  });
152
162
  }
153
163
 
@@ -184,6 +194,7 @@ async function runList(args: Record<string, any>): Promise<string> {
184
194
  deliveryPlatform: meta.deliveryPlatform || null,
185
195
  deliveryDestination: meta.deliveryDestination || null,
186
196
  model: meta.model || null,
197
+ mcpTools: meta.mcpTools || [],
187
198
  };
188
199
  }),
189
200
  );
@@ -243,6 +254,16 @@ async function runUpdate(args: Record<string, any>): Promise<string> {
243
254
  }
244
255
  if (typeof model === "string" && model.trim()) meta.model = model.trim();
245
256
 
257
+ if (args.mcpTools !== undefined) {
258
+ try {
259
+ const mcpTools = normalizeJobMcpTools(args.mcpTools) ?? [];
260
+ if (mcpTools.length) meta.mcpTools = mcpTools;
261
+ else delete meta.mcpTools;
262
+ } catch (err) {
263
+ return JSON.stringify({ error: (err as Error).message });
264
+ }
265
+ }
266
+
246
267
  const newBody = instructions || body;
247
268
  const content = buildJobContent(meta, newBody);
248
269
  await resourcePut(resource.owner, resource.path, content);
@@ -254,6 +275,7 @@ async function runUpdate(args: Record<string, any>): Promise<string> {
254
275
  scheduleDescription: describeCron(meta.schedule),
255
276
  enabled: meta.enabled,
256
277
  nextRun: meta.nextRun,
278
+ mcpTools: meta.mcpTools || [],
257
279
  });
258
280
  }
259
281
 
@@ -295,7 +317,9 @@ Actions:
295
317
  - "update": Update a job's schedule, instructions, or enabled state. Requires name.
296
318
  - "delete": Delete a recurring job. Requires name. Always confirm with the user first.
297
319
 
298
- Cron format is 5 fields: minute hour day-of-month month day-of-week. Common patterns: '0 9 * * *' (daily 9am), '0 9 * * 1-5' (weekdays 9am), '0 * * * *' (every hour), '0 9 * * 1' (Mondays 9am), '*/30 * * * *' (every 30 min).`,
320
+ Cron format is 5 fields: minute hour day-of-month month day-of-week. Common patterns: '0 9 * * *' (daily 9am), '0 9 * * 1-5' (weekdays 9am), '0 * * * *' (every hour), '0 9 * * 1' (Mondays 9am), '*/30 * * * *' (every 30 min).
321
+
322
+ For jobs that use a connected MCP, pass the exact tool names in mcpTools. This binds only those tools to the background run; OAuth credentials remain in the connector and are resolved for the job's user/org context.`,
299
323
  parameters: {
300
324
  type: "object",
301
325
  properties: {
@@ -342,6 +366,12 @@ Cron format is 5 fields: minute hour day-of-month month day-of-week. Common patt
342
366
  description:
343
367
  "Optional model id for this routine. The channel/app/engine default is used when omitted.",
344
368
  },
369
+ mcpTools: {
370
+ type: "array",
371
+ items: { type: "string" },
372
+ description:
373
+ 'Optional explicit MCP capabilities for this job. Use the connected tool names exactly as advertised, for example ["mcp__meeting-notes__list_meetings", "mcp__meeting-notes__get_transcript"]. The job runs only with these tools; credentials remain in the connector.',
374
+ },
345
375
  },
346
376
  required: ["action"],
347
377
  },
@@ -453,6 +453,7 @@ const messages = {
453
453
  cancel: "Cancel",
454
454
  recurringDetails: "Recurring job details",
455
455
  instructions: "Instructions",
456
+ mcpTools: "Connected MCP tools",
456
457
  automationsLoadError: "Could not load automations.",
457
458
  automationsEmpty: "No automations yet.",
458
459
  automationEventTrigger: "On {{event}}",
@@ -166,6 +166,8 @@ import {
166
166
 
167
167
  export interface McpActionEntryOptions {
168
168
  invocationPolicy?: McpToolInvocationPolicy;
169
+ /** Restrict the generated entries to an explicit background capability set. */
170
+ toolNames?: readonly string[];
169
171
  }
170
172
 
171
173
  export function mcpToolsToActionEntries(
@@ -173,7 +175,11 @@ export function mcpToolsToActionEntries(
173
175
  options: McpActionEntryOptions = {},
174
176
  ): Record<string, ActionEntry> {
175
177
  const entries: Record<string, ActionEntry> = {};
178
+ const selectedToolNames = options.toolNames
179
+ ? new Set(options.toolNames)
180
+ : undefined;
176
181
  for (const tool of manager.getTools().filter(isVisibleToModel)) {
182
+ if (selectedToolNames && !selectedToolNames.has(tool.name)) continue;
177
183
  entries[tool.name] = mcpToolToActionEntry(manager, tool, options);
178
184
  }
179
185
  return entries;
@@ -177,7 +177,7 @@ export function createProviderApiRequestSchema(
177
177
  .string()
178
178
  .optional()
179
179
  .describe(
180
- "Optional shared workspace connection id to use when the provider has multiple granted connections.",
180
+ "Shared workspace connection id to use when the provider has multiple granted connections. Required when provider-api-catalog marks requiresConnectionId.",
181
181
  ),
182
182
  accountId: z
183
183
  .string()
@@ -73,6 +73,7 @@ export const PROVIDER_API_IDS = [
73
73
  "granola",
74
74
  "grafana",
75
75
  "hubspot",
76
+ "salesforce",
76
77
  "jira",
77
78
  "mixpanel",
78
79
  "notion",
@@ -384,6 +385,7 @@ export interface ProviderApiConfig {
384
385
  id: ProviderApiId;
385
386
  label: string;
386
387
  defaultBaseUrl: string;
388
+ requiresConnectionId?: boolean;
387
389
  baseUrlCredentialKey?: string;
388
390
  auth: ProviderApiAuthKind;
389
391
  credentialKeys: readonly string[];
@@ -1212,6 +1214,43 @@ const PROVIDER_CONFIGS: Record<ProviderApiId, ProviderApiConfig> = {
1212
1214
  },
1213
1215
  ],
1214
1216
  },
1217
+ salesforce: {
1218
+ id: "salesforce",
1219
+ label: "Salesforce",
1220
+ defaultBaseUrl: "https://login.salesforce.com",
1221
+ requiresConnectionId: true,
1222
+ auth: {
1223
+ type: "oauth-bearer",
1224
+ oauthProvider: "salesforce",
1225
+ tokenLabel: "Salesforce OAuth token",
1226
+ workspaceProvider: "salesforce",
1227
+ },
1228
+ credentialKeys: ["SALESFORCE_OAUTH_ACCOUNT"],
1229
+ docsUrls: [
1230
+ "https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/",
1231
+ ],
1232
+ allowedHostSuffixes: [],
1233
+ templateUses: ["analytics", "brain", "crm", "dispatch"],
1234
+ examples: [
1235
+ {
1236
+ label: "List recent Accounts",
1237
+ method: "GET",
1238
+ path: "/services/data/v60.0/sobjects/Account",
1239
+ },
1240
+ {
1241
+ label: "Query Opportunity records with SOQL",
1242
+ method: "GET",
1243
+ path: "/services/data/v60.0/query",
1244
+ query: {
1245
+ q: "SELECT Id, Name, StageName, Amount, CloseDate FROM Opportunity LIMIT 100",
1246
+ },
1247
+ },
1248
+ ],
1249
+ notes: [
1250
+ "Workspace OAuth stores the Salesforce instance URL on the connection. Requests with a connectionId use that instance instead of the login host.",
1251
+ "CRM templates own object allow-lists, field projections, and API-version selection.",
1252
+ ],
1253
+ },
1215
1254
  jira: {
1216
1255
  id: "jira",
1217
1256
  label: "Jira Cloud",
@@ -1574,6 +1613,7 @@ export function listProviderApiCatalog(
1574
1613
  id: config.id,
1575
1614
  label: config.label,
1576
1615
  defaultBaseUrl: config.defaultBaseUrl,
1616
+ requiresConnectionId: config.requiresConnectionId ?? false,
1577
1617
  baseUrlCredentialKey: config.baseUrlCredentialKey ?? null,
1578
1618
  auth: describeAuth(config.auth),
1579
1619
  credentialKeys: config.credentialKeys,
@@ -1749,6 +1789,11 @@ export async function executeProviderApiRequest(
1749
1789
 
1750
1790
  // --- built-in provider path (original code) ---
1751
1791
  const config = builtIn!;
1792
+ if (config.requiresConnectionId && !args.connectionId?.trim()) {
1793
+ throw new Error(
1794
+ `${config.label} Provider API requests require a workspace connectionId.`,
1795
+ );
1796
+ }
1752
1797
  const ctx = requireRuntimeCredentialContext(
1753
1798
  runtime,
1754
1799
  config.credentialKeys[0] ?? config.id,
@@ -1951,9 +1996,9 @@ export async function executeProviderApiRequest(
1951
1996
  }
1952
1997
 
1953
1998
  /**
1954
- * Resolve a provider OAuth token for a trusted server-side UI bridge such as
1955
- * Google Picker. Callers must keep the result out of agent, MCP, A2A, logs,
1956
- * persistence, and extension/tool surfaces.
1999
+ * Resolve a provider OAuth token for a trusted server-side integration bridge
2000
+ * such as a CRM adapter or Google Picker. Callers must keep the result out of
2001
+ * agent, MCP, A2A, logs, persistence, and extension/tool surfaces.
1957
2002
  */
1958
2003
  export async function resolveProviderApiOAuthAccessToken(
1959
2004
  args: {
@@ -3304,7 +3349,9 @@ async function resolveWorkspaceOAuthBaseUrl(
3304
3349
  auth.type === "oauth-bearer-or-basic"
3305
3350
  ? auth.workspaceProvider
3306
3351
  : undefined;
3307
- if (workspaceProvider !== "jira") return null;
3352
+ if (workspaceProvider !== "jira" && workspaceProvider !== "salesforce") {
3353
+ return null;
3354
+ }
3308
3355
  let resolved: Awaited<ReturnType<typeof resolveWorkspaceConnectionForApp>>;
3309
3356
  try {
3310
3357
  resolved = await resolveWorkspaceConnectionForApp({
@@ -3325,11 +3372,33 @@ async function resolveWorkspaceOAuthBaseUrl(
3325
3372
  if (!resolved.available || !resolved.connection) return null;
3326
3373
  const connectionConfig = resolved.connection.config;
3327
3374
  if (connectionConfig.credentialMode !== "oauth") return null;
3328
- const baseUrl = connectionConfig.atlassianApiBaseUrl;
3375
+ const baseUrl =
3376
+ workspaceProvider === "salesforce"
3377
+ ? connectionConfig.salesforceInstanceUrl
3378
+ : connectionConfig.atlassianApiBaseUrl;
3329
3379
  if (typeof baseUrl !== "string" || !baseUrl.trim()) return null;
3380
+ if (workspaceProvider === "salesforce" && !isSalesforceInstanceUrl(baseUrl)) {
3381
+ return null;
3382
+ }
3330
3383
  return baseUrl.replace(/\/+$/, "");
3331
3384
  }
3332
3385
 
3386
+ function isSalesforceInstanceUrl(value: string): boolean {
3387
+ try {
3388
+ const url = new URL(value);
3389
+ const host = url.hostname.toLowerCase();
3390
+ return (
3391
+ url.protocol === "https:" &&
3392
+ !url.username &&
3393
+ !url.password &&
3394
+ !url.port &&
3395
+ (host === "salesforce.com" || host.endsWith(".salesforce.com"))
3396
+ );
3397
+ } catch {
3398
+ return false;
3399
+ }
3400
+ }
3401
+
3333
3402
  async function resolvePlaceholders(
3334
3403
  config: ProviderApiConfig,
3335
3404
  runtime: ProviderApiRuntimeOptions,
@@ -4024,6 +4093,7 @@ async function resolveOAuthBearerToken(options: {
4024
4093
  ctx: CredentialContext;
4025
4094
  accountId?: string | null;
4026
4095
  ownerEmail?: string | null;
4096
+ salesforceLoginUrl?: string | null;
4027
4097
  }): Promise<ProviderApiResolvedCredential> {
4028
4098
  const ownerEmail = options.ownerEmail?.trim() || options.ctx.userEmail;
4029
4099
  const accounts = await listOAuthAccountsByOwner(
@@ -4050,6 +4120,7 @@ async function resolveOAuthBearerToken(options: {
4050
4120
  accountId: account.accountId,
4051
4121
  ownerEmail,
4052
4122
  tokens,
4123
+ salesforceLoginUrl: options.salesforceLoginUrl,
4053
4124
  });
4054
4125
  return {
4055
4126
  key: `${options.auth.oauthProvider.toUpperCase()}_OAUTH_TOKEN`,
@@ -4126,6 +4197,11 @@ async function resolveOptionalConnectionBoundOAuthBearerToken(options: {
4126
4197
  ctx: options.ctx,
4127
4198
  accountId: connectionAccountId,
4128
4199
  ownerEmail: resolved.connection.ownerEmail,
4200
+ salesforceLoginUrl:
4201
+ options.auth.oauthProvider === "salesforce" &&
4202
+ typeof resolved.connection.config?.salesforceLoginUrl === "string"
4203
+ ? resolved.connection.config.salesforceLoginUrl
4204
+ : null,
4129
4205
  });
4130
4206
  return {
4131
4207
  ...credential,
@@ -4139,6 +4215,7 @@ async function getValidOAuthAccessToken(options: {
4139
4215
  accountId: string;
4140
4216
  ownerEmail: string;
4141
4217
  tokens: OAuthTokens;
4218
+ salesforceLoginUrl?: string | null;
4142
4219
  }): Promise<string> {
4143
4220
  const accessToken =
4144
4221
  options.tokens.access_token ?? options.tokens.accessToken ?? "";
@@ -4177,6 +4254,9 @@ async function getValidOAuthAccessToken(options: {
4177
4254
  if (options.oauthProvider === "hubspot") {
4178
4255
  return refreshHubSpotOAuthToken(options, refreshToken);
4179
4256
  }
4257
+ if (options.oauthProvider === "salesforce") {
4258
+ return refreshSalesforceOAuthToken(options, refreshToken);
4259
+ }
4180
4260
  if (options.oauthProvider === "jira") {
4181
4261
  return refreshJiraOAuthToken(options, refreshToken);
4182
4262
  }
@@ -4484,6 +4564,102 @@ async function refreshHubSpotOAuthToken(
4484
4564
  return data.access_token;
4485
4565
  }
4486
4566
 
4567
+ async function refreshSalesforceOAuthToken(
4568
+ options: {
4569
+ oauthProvider: string;
4570
+ accountId: string;
4571
+ ownerEmail: string;
4572
+ tokens: OAuthTokens;
4573
+ salesforceLoginUrl?: string | null;
4574
+ },
4575
+ refreshToken: string,
4576
+ ): Promise<string> {
4577
+ const credentials =
4578
+ await resolveOAuthClientCredentialCandidates("SALESFORCE");
4579
+ if (!credentials.length) {
4580
+ throw new Error(
4581
+ "SALESFORCE_CLIENT_ID/SECRET not set for Salesforce OAuth refresh.",
4582
+ );
4583
+ }
4584
+
4585
+ let response: Response | null = null;
4586
+ let data: {
4587
+ access_token?: string;
4588
+ refresh_token?: string;
4589
+ expires_in?: number;
4590
+ token_type?: string;
4591
+ } = {};
4592
+ for (const credential of credentials) {
4593
+ const result = await fetchBoundedOAuthRefreshJson<{
4594
+ access_token?: string;
4595
+ refresh_token?: string;
4596
+ expires_in?: number;
4597
+ token_type?: string;
4598
+ }>(
4599
+ salesforceOAuthRefreshUrl(options.salesforceLoginUrl),
4600
+ {
4601
+ method: "POST",
4602
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
4603
+ body: new URLSearchParams({
4604
+ grant_type: "refresh_token",
4605
+ client_id: credential.clientId,
4606
+ client_secret: credential.clientSecret,
4607
+ refresh_token: refreshToken,
4608
+ }),
4609
+ },
4610
+ "Salesforce",
4611
+ );
4612
+ response = result.response;
4613
+ data = result.data;
4614
+ if (response.ok && data.access_token) break;
4615
+ }
4616
+
4617
+ if (!response?.ok || !data.access_token) {
4618
+ throw new Error(
4619
+ `Salesforce OAuth refresh failed (${response?.status ?? 0}).`,
4620
+ );
4621
+ }
4622
+ const updated = {
4623
+ ...options.tokens,
4624
+ access_token: data.access_token,
4625
+ refresh_token: data.refresh_token ?? refreshToken,
4626
+ token_type: data.token_type ?? options.tokens.token_type,
4627
+ ...(Number.isFinite(data.expires_in) && (data.expires_in ?? 0) > 0
4628
+ ? { expiry_date: Date.now() + (data.expires_in as number) * 1_000 }
4629
+ : {}),
4630
+ };
4631
+ await saveOAuthTokens(
4632
+ options.oauthProvider,
4633
+ options.accountId,
4634
+ updated as unknown as Record<string, unknown>,
4635
+ options.ownerEmail,
4636
+ );
4637
+ return data.access_token;
4638
+ }
4639
+
4640
+ function salesforceOAuthRefreshUrl(value: string | null | undefined): string {
4641
+ const loginUrl = value?.trim() || "https://login.salesforce.com";
4642
+ try {
4643
+ const url = new URL(loginUrl);
4644
+ if (
4645
+ url.protocol !== "https:" ||
4646
+ url.username ||
4647
+ url.password ||
4648
+ url.port ||
4649
+ url.pathname !== "/" ||
4650
+ url.search ||
4651
+ url.hash ||
4652
+ (url.hostname !== "login.salesforce.com" &&
4653
+ url.hostname !== "test.salesforce.com")
4654
+ ) {
4655
+ throw new Error("Invalid Salesforce OAuth login URL.");
4656
+ }
4657
+ return `${url.origin}/services/oauth2/token`;
4658
+ } catch {
4659
+ throw new Error("Invalid Salesforce OAuth login URL.");
4660
+ }
4661
+ }
4662
+
4487
4663
  async function refreshJiraOAuthToken(
4488
4664
  options: {
4489
4665
  oauthProvider: string;
@@ -4796,6 +4972,15 @@ async function resolveOAuthClientCredentialCandidates(
4796
4972
  ].filter((value): value is { clientId: string; clientSecret: string } =>
4797
4973
  Boolean(value),
4798
4974
  );
4975
+ if (provider === "SALESFORCE") {
4976
+ const [consumerKey, consumerSecret] = await Promise.all([
4977
+ resolveSecret("SALESFORCE_CONSUMER_KEY"),
4978
+ resolveSecret("SALESFORCE_CONSUMER_SECRET"),
4979
+ ]);
4980
+ if (consumerKey && consumerSecret) {
4981
+ candidates.push({ clientId: consumerKey, clientSecret: consumerSecret });
4982
+ }
4983
+ }
4799
4984
  const seen = new Set<string>();
4800
4985
  return candidates.filter((candidate) => {
4801
4986
  if (seen.has(candidate.clientId)) return false;
@@ -48,6 +48,14 @@ export function registerFrameworkSecrets(): void {
48
48
  docsUrl:
49
49
  "https://developers.hubspot.com/docs/apps/developer-platform/build-apps/authentication/oauth/oauth-quickstart-guide",
50
50
  },
51
+ {
52
+ id: "salesforce",
53
+ credentialPrefix: "SALESFORCE",
54
+ oauthProvider: "salesforce",
55
+ label: "Salesforce",
56
+ docsUrl:
57
+ "https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_understanding_web_server_oauth_flow.htm",
58
+ },
51
59
  {
52
60
  id: "jira",
53
61
  credentialPrefix: "JIRA",
@@ -97,6 +97,15 @@ Convert natural language to 5-field cron format:
97
97
  - "every hour" → \`0 * * * *\`
98
98
  - "every monday at 9am" → \`0 9 * * 1\`
99
99
 
100
+ When a recurring job needs a connected MCP, discover the exact MCP tool names
101
+ available in the current user/org context and pass them in the create call's
102
+ \`mcpTools\` array. Bind only the tools the job needs; do not put an MCP URL,
103
+ OAuth token, or arbitrary endpoint in the instructions. The scheduler resolves
104
+ the selected tools with the job owner's existing connector grant and fails
105
+ clearly if a connector is revoked or a selected tool disappears. For imports,
106
+ normalize the provider response and call the app's bounded idempotent import
107
+ action once with the full batch rather than issuing one write per item.
108
+
100
109
  #### Suggesting "Save as automation"
101
110
 
102
111
  When you finish a task that has obvious recurring value — daily inbox triage, weekly metrics summaries, archive sweeps, status digests, anything the user would plausibly want re-run on a fresh cadence — close the response with ONE short line offering to save it. Examples:
@@ -74,7 +74,7 @@ Keep \`create-extension\` payloads compact enough to finish quickly. For complex
74
74
 
75
75
  Generated UI content can use appAction(), appFetch(), dbQuery(), extensionFetch(), extensionData, agentNative.ui.output(value, opts?), and agentNative.chat.send(...)/sendToAgentChat(...). Use appAction() for app data writes, and dbQuery() only for read-only inspection of known app SQL tables. It can receive chat inputs through slotContext/window.onSlotContext. Use agentNative.ui.output for passive current values from knobs, sliders, selections, and controls; it writes application state at \`inline-ui:<extensionId>:output\` scoped to the inline extension id returned by \`render-inline-extension\` or \`show-extension-inline\`. When the user later says "use that value", "apply the current setting", or similar, read it with \`readAppState("inline-ui:<id>:output")\` instead of asking them to send it again. Use agentNative.chat.send for visible submit/apply actions that should put a message into chat. Transient extensionData is browser-local and not agent-readable, synced, promoted, or garbage-collected; use application_state/appFetch, appAction, ui.output, or chat.send for anything the agent or app must observe. Use semantic Tailwind classes like bg-background, text-foreground, bg-primary, border-border, and text-muted-foreground so the UI inherits the parent app theme.
76
76
 
77
- If the user asks to change, edit, fix, style, rename, or add behavior to an existing extension/widget/dashboard/calculator/mini-app, use the current extension id from \`<current-screen>\` or \`<current-url>\` when present. Call \`get-extension\` only if you need to inspect its content, then \`update-extension\` with that id. After one content read, keep the body in working memory and move to focused \`update-extension\` \`edits\`/\`patches\`; do not loop on repeated \`get-extension\` + \`run-code\` string scans before writing. For a data-only repair, preserve the existing layout, CSS, copy, and interactions: never send a reconstructed full \`content\` body. The update action blocks full-body replacement by default; use \`allowFullReplacement=true\` only when the user explicitly requests a broad visual rewrite or supplies a complete replacement body. If a focused patch fails, read the current body and change the target rather than retrying identical arguments. Use \`list-extensions\` only when no current id/name is available. Existing extension edits are SQL data updates, not source-code changes, even when the request says "change the UI" or "fix this". Do **NOT** call \`connect-builder\` for existing extension edits.
77
+ If the user asks to change, edit, fix, style, rename, or add behavior to an existing extension/widget/dashboard/calculator/mini-app, use the current extension id from \`<current-screen>\` or \`<current-url>\` when present. Call \`get-extension\` only if you need to inspect its content, then call \`update-extension\` with exactly \`id\`, \`operation\`, and \`payloadJson\`; encode the operation payload as a JSON string and never send empty placeholder fields. After one content read, keep the body in working memory and use \`operation="edit"\` with focused \`edits\`/\`patches\` inside \`payloadJson\`; do not loop on repeated \`get-extension\` + \`run-code\` string scans before writing. For a data-only repair, preserve the existing layout, CSS, copy, and interactions. Use \`operation="replace"\` only when the user explicitly requests a broad visual rewrite or supplies a complete replacement body. Use \`operation="metadata"\` for name/description/icon, and use \`set-resource-visibility\` for sharing changes. If a focused patch fails, read the current body and change the target rather than retrying identical arguments. Use \`list-extensions\` only when no current id/name is available. Existing extension edits are SQL data updates, not source-code changes, even when the request says "change the UI" or "fix this". Do **NOT** call \`connect-builder\` for existing extension edits.
78
78
 
79
79
  In Act mode, when in doubt — if the request asks for a new small interactive utility and does not need reuse, choose \`render-inline-extension\`; if it mentions saving/reuse or asks for an extension/widget/dashboard/calculator/mini-app, choose \`create-extension\`. If it references an existing one or the current extension page, choose \`update-extension\`. Do **not** preface the call with planning text like "let me build the dashboard…" — just call the right extension action directly.
80
80
 
@@ -115,7 +115,7 @@ Keep the first \`create-extension\` call compact and working. If the request is
115
115
 
116
116
  Generated UI can read chat inputs from slotContext/window.onSlotContext, see/update app state through appFetch/appAction, use extensionData, record passive current values through agentNative.ui.output(value, opts?), and send visible results through agentNative.chat.send(...) or sendToAgentChat(...). ui.output writes \`inline-ui:<extensionId>:output\` in application state; when the user asks to use the current slider/selection/value, read \`readAppState("inline-ui:<id>:output")\`. Transient extensionData is browser-local only, so do not rely on it for values the agent or app must observe. Use semantic Tailwind theme classes.
117
117
 
118
- If the user asks to change, edit, fix, style, rename, or add behavior to an existing extension/widget/dashboard/calculator/mini-app, use the current extension id from \`<current-screen>\` or \`<current-url>\` when present. Call \`get-extension\` only if you need to inspect its content, then \`update-extension\` with that id. After one content read, use focused \`update-extension\` \`edits\`/\`patches\`; do not repeatedly re-read and scan the same HTML with \`run-code\` before writing. For a data-only repair, preserve the existing layout, CSS, copy, and interactions: never send a reconstructed full \`content\` body. The update action blocks full-body replacement by default; use \`allowFullReplacement=true\` only when the user explicitly requests a broad visual rewrite or supplies a complete replacement body. If a focused patch fails, read the current body and change the target rather than retrying identical arguments. Use \`list-extensions\` only when no current id/name is available. Existing extension edits are SQL data updates, not source-code changes. Do NOT call \`connect-builder\` for them.
118
+ If the user asks to change, edit, fix, style, rename, or add behavior to an existing extension/widget/dashboard/calculator/mini-app, use the current extension id from \`<current-screen>\` or \`<current-url>\` when present. Call \`get-extension\` only if you need to inspect its content, then call \`update-extension\` with exactly \`id\`, \`operation\`, and \`payloadJson\`; encode the operation payload as a JSON string and never send empty placeholder fields. After one content read, use \`operation="edit"\` with focused \`edits\`/\`patches\` inside \`payloadJson\`; do not repeatedly re-read and scan the same HTML with \`run-code\` before writing. For a data-only repair, preserve the existing layout, CSS, copy, and interactions. Use \`operation="replace"\` only when the user explicitly requests a broad visual rewrite or supplies a complete replacement body. Use \`operation="metadata"\` for name/description/icon, and use \`set-resource-visibility\` for sharing changes. If a focused patch fails, read the current body and change the target rather than retrying identical arguments. Use \`list-extensions\` only when no current id/name is available. Existing extension edits are SQL data updates, not source-code changes. Do NOT call \`connect-builder\` for them.
119
119
 
120
120
  For existing extensions, use \`get-extension\` or \`update-extension\` directly when \`<current-screen>\` or \`<current-url>\` provides an \`extensionId\`. Use \`list-extensions\` only to browse or resolve an unknown name. Use \`hide-extension\` when the user wants a shared extension removed only from their own view. Do not query the legacy \`tools\` table directly.
121
121
 
@@ -124,6 +124,7 @@ import {
124
124
  verifyInternalToken,
125
125
  extractBearerToken,
126
126
  } from "../integrations/internal-token.js";
127
+ import type { RecurringJobContext } from "../jobs/scheduler.js";
127
128
  import {
128
129
  McpClientManager,
129
130
  loadMcpConfig,
@@ -575,6 +576,22 @@ export function createAgentChatPlugin(
575
576
  }
576
577
  setGlobalMcpManager(mcpManager);
577
578
  const mcpActionEntries = mcpToolsToActionEntries(mcpManager);
579
+ const getJobMcpActionEntries = (
580
+ job?: RecurringJobContext,
581
+ ): Record<string, ActionEntry> => {
582
+ const requested = job?.meta.mcpTools ?? [];
583
+ if (requested.length === 0) return {};
584
+ const entries = mcpToolsToActionEntries(mcpManager, {
585
+ toolNames: requested,
586
+ });
587
+ const missing = requested.filter((toolName) => !entries[toolName]);
588
+ if (missing.length > 0) {
589
+ throw new Error(
590
+ `Configured MCP tools are unavailable in this run: ${missing.join(", ")}. Reconnect the MCP server or update the job's capability list.`,
591
+ );
592
+ }
593
+ return entries;
594
+ };
578
595
 
579
596
  // Mount status + management routes so the settings UI can list / add /
580
597
  // remove remote MCP servers and hot-reload the running manager.
@@ -2632,6 +2649,7 @@ export function createAgentChatPlugin(
2632
2649
  // through the settings UI). getEngineTools() in production-agent re-reads
2633
2650
  // the registry per request, so updates here propagate without restart.
2634
2651
  mcpManager.onChange(() => {
2652
+ syncMcpActionEntries(mcpManager, mcpActionEntries);
2635
2653
  syncMcpActionEntries(mcpManager, prodActions);
2636
2654
  });
2637
2655
 
@@ -5524,7 +5542,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5524
5542
  const { processRecurringJobs } = await import("../jobs/scheduler.js");
5525
5543
 
5526
5544
  const schedulerDeps = {
5527
- getActions: () => ({
5545
+ getActions: (job?: RecurringJobContext) => ({
5528
5546
  ...templateScripts,
5529
5547
  ...resourceScripts,
5530
5548
  ...docsScripts,
@@ -5537,6 +5555,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5537
5555
  ...fetchTool,
5538
5556
  ...webSearchTool,
5539
5557
  ...toolActions,
5558
+ ...getJobMcpActionEntries(job),
5540
5559
  }),
5541
5560
  getSystemPrompt: async (owner: string) => {
5542
5561
  const resources = await loadResourcesForPrompt(
@@ -5557,10 +5576,11 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5557
5576
  // first request on the same compact surface as interactive chat
5558
5577
  // instead of the full jobTools/automationTools/notificationTools/
5559
5578
  // fetchTool/webSearchTool/toolActions catalog every tick.
5560
- getInitialToolNames: () => [
5579
+ getInitialToolNames: (job?: RecurringJobContext) => [
5561
5580
  ...effectiveInitialToolNames,
5562
5581
  "manage-jobs",
5563
5582
  "manage-progress",
5583
+ ...(job?.meta.mcpTools ?? []),
5564
5584
  ],
5565
5585
  apiKey: options?.apiKey,
5566
5586
  model: options?.model,
@@ -1233,6 +1233,7 @@ export function createCoreRoutesPlugin(
1233
1233
  "google_drive",
1234
1234
  "github",
1235
1235
  "hubspot",
1236
+ "salesforce",
1236
1237
  "jira",
1237
1238
  "sentry",
1238
1239
  "notion",
@@ -75,6 +75,9 @@ export function readDeployCredentialEnv(key: string): string | undefined {
75
75
 
76
76
  const APP_PROVIDED_DEPLOY_CREDENTIAL_KEYS = new Set([
77
77
  "ANTHROPIC_API_KEY",
78
+ "EMAIL_FROM",
79
+ "EMAIL_INBOUND_WEBHOOK_SECRET",
80
+ "EMAIL_AGENT_ADDRESS",
78
81
  "OPENAI_API_KEY",
79
82
  "OPENAI_BASE_URL",
80
83
  "OPENROUTER_API_KEY",
@@ -84,6 +87,8 @@ const APP_PROVIDED_DEPLOY_CREDENTIAL_KEYS = new Set([
84
87
  "GROQ_API_KEY",
85
88
  "MISTRAL_API_KEY",
86
89
  "COHERE_API_KEY",
90
+ "RESEND_API_KEY",
91
+ "SENDGRID_API_KEY",
87
92
  ]);
88
93
 
89
94
  function isAppProvidedDeployCredentialKey(key: string | undefined): boolean {
@@ -97,9 +102,10 @@ function isAppProvidedDeployCredentialKey(key: string | undefined): boolean {
97
102
  * identity-bearing provider keys so one deploy key does not silently
98
103
  * impersonate another tenant. App-provided service credentials are different:
99
104
  * they configure the deployed app itself rather than identifying a user. This
100
- * includes LLM keys that let the app developer pay for model usage and OAuth
101
- * client credentials whose per-user identity remains in scoped OAuth tokens.
102
- * Key-aware callers may use those env vars.
105
+ * includes LLM keys that let the app developer pay for model usage, email
106
+ * transport configuration owned by the deployment, and OAuth client
107
+ * credentials whose per-user identity remains in scoped OAuth tokens. Key-aware
108
+ * callers may use those env vars.
103
109
  *
104
110
  * @deprecated Use `canUseDeployCredentialFallbackForRequest()` for generic
105
111
  * provider secrets. This stricter helper remains for legacy call sites with