@agent-native/core 0.114.16 → 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 (456) hide show
  1. package/agent-native.eject.json +2 -0
  2. package/corpus/README.md +3 -3
  3. package/corpus/core/CHANGELOG.md +29 -0
  4. package/corpus/core/agent-native.eject.json +2 -0
  5. package/corpus/core/docs/content/agent-native-toolkit.mdx +16 -0
  6. package/corpus/core/docs/content/recurring-jobs.mdx +35 -6
  7. package/corpus/core/export-snapshot.json +4 -0
  8. package/corpus/core/package.json +5 -1
  9. package/corpus/core/src/action.ts +22 -1
  10. package/corpus/core/src/agent/production-agent.ts +105 -3
  11. package/corpus/core/src/cli/templates-meta.ts +12 -0
  12. package/corpus/core/src/client/AssistantChat.tsx +53 -26
  13. package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +19 -0
  14. package/corpus/core/src/client/agent-page/use-jobs.ts +1 -0
  15. package/corpus/core/src/client/chat/message-components.tsx +35 -1
  16. package/corpus/core/src/client/chat/tool-call-display.tsx +38 -3
  17. package/corpus/core/src/connections/catalog.ts +20 -1
  18. package/corpus/core/src/connections/reader.ts +65 -0
  19. package/corpus/core/src/dashboard-storage/index.ts +27 -0
  20. package/corpus/core/src/dashboard-storage/panel-source.ts +168 -0
  21. package/corpus/core/src/dashboard-storage/schema.ts +62 -0
  22. package/corpus/core/src/dashboard-storage/store.ts +333 -0
  23. package/corpus/core/src/deploy/build.ts +95 -16
  24. package/corpus/core/src/eject/provider-api-definitions.ts +1 -0
  25. package/corpus/core/src/eject/workspace-connections.ts +1 -0
  26. package/corpus/core/src/extensions/actions.ts +199 -73
  27. package/corpus/core/src/jobs/actions/list-recurring-jobs.ts +2 -0
  28. package/corpus/core/src/jobs/scheduler.ts +71 -4
  29. package/corpus/core/src/jobs/tools.ts +31 -1
  30. package/corpus/core/src/localization/default-messages.ts +1 -0
  31. package/corpus/core/src/mcp-client/index.ts +6 -0
  32. package/corpus/core/src/provider-api/actions/provider-api.ts +1 -1
  33. package/corpus/core/src/provider-api/index.ts +190 -5
  34. package/corpus/core/src/secrets/register-framework-secrets.ts +8 -0
  35. package/corpus/core/src/server/agent-chat/context-tools.ts +9 -0
  36. package/corpus/core/src/server/agent-chat/framework-prompts.ts +2 -2
  37. package/corpus/core/src/server/agent-chat-plugin.ts +22 -2
  38. package/corpus/core/src/server/core-routes-plugin.ts +1 -0
  39. package/corpus/core/src/server/credential-provider.ts +9 -3
  40. package/corpus/core/src/server/workspace-provider-oauth.ts +181 -4
  41. package/corpus/core/src/styles/agent-native.css +45 -2
  42. package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  43. package/corpus/core/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  44. package/corpus/core/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  45. package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  46. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  47. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  48. package/corpus/core/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  49. package/corpus/core/src/triggers/actions.ts +11 -2
  50. package/corpus/core/src/triggers/dispatcher.ts +20 -1
  51. package/corpus/core/src/triggers/types.ts +5 -0
  52. package/corpus/core/src/vite/action-types-plugin.ts +9 -1
  53. package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +115 -0
  54. package/corpus/templates/analytics/AGENTS.md +11 -11
  55. package/corpus/templates/analytics/_gitignore +39 -0
  56. package/corpus/templates/analytics/actions/query-dashboard-panel.ts +30 -0
  57. package/corpus/templates/analytics/actions/update-dashboard.ts +2 -1
  58. package/corpus/templates/analytics/app/lib/sql-query.ts +11 -25
  59. package/corpus/templates/analytics/changelog/2026-07-21-fixed-extension-updates-failing-before-changes-could-be-appl.md +6 -0
  60. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +1 -0
  61. package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +51 -0
  62. package/corpus/templates/analytics/server/lib/prometheus.ts +1 -1
  63. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
  64. package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +115 -0
  65. package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +115 -0
  66. package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +115 -0
  67. package/corpus/templates/calendar/_gitignore +39 -0
  68. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  69. package/corpus/templates/chat/AGENTS.md +1 -1
  70. package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +115 -0
  71. package/corpus/templates/clips/AGENTS.md +7 -0
  72. package/corpus/templates/clips/actions/prepare-crm-call-evidence.ts +58 -0
  73. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +88 -11
  74. package/corpus/templates/clips/changelog/2026-07-21-crm-call-evidence-handoff.md +6 -0
  75. package/corpus/templates/clips/changelog/2026-07-21-recording-retries-and-restarts-keep-their-upload-session-so-.md +6 -0
  76. package/corpus/templates/clips/chrome-extension/src/background.ts +20 -5
  77. package/corpus/templates/clips/chrome-extension/src/native-recording-state.ts +19 -0
  78. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +8 -0
  79. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +9 -0
  80. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +54 -28
  81. package/corpus/templates/clips/server/plugins/agent-chat.ts +1 -0
  82. package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +115 -0
  83. package/corpus/templates/content/_gitignore +39 -0
  84. package/corpus/templates/content/learnings.defaults.md +5 -0
  85. package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +115 -0
  86. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  87. package/corpus/templates/crm/.agents/skills/crm/SKILL.md +128 -0
  88. package/corpus/templates/crm/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  89. package/corpus/templates/crm/.agents/skills/feature-flags/SKILL.md +169 -0
  90. package/corpus/templates/crm/.agents/skills/upgrade-agent-native/SKILL.md +100 -0
  91. package/corpus/templates/crm/.env.example +5 -0
  92. package/corpus/templates/crm/AGENTS.md +120 -0
  93. package/corpus/templates/crm/CHANGELOG.md +1 -0
  94. package/corpus/templates/crm/DEVELOPING.md +66 -0
  95. package/corpus/templates/crm/README.md +106 -0
  96. package/corpus/templates/crm/_gitignore +12 -0
  97. package/corpus/templates/crm/actions/_crm-action-utils.ts +87 -0
  98. package/corpus/templates/crm/actions/_crm-dashboard.ts +69 -0
  99. package/corpus/templates/crm/actions/_crm-signal-utils.ts +79 -0
  100. package/corpus/templates/crm/actions/apply-crm-proposals.ts +203 -0
  101. package/corpus/templates/crm/actions/attach-call-evidence.ts +170 -0
  102. package/corpus/templates/crm/actions/configure-crm-connection.ts +126 -0
  103. package/corpus/templates/crm/actions/configure-native-crm.ts +44 -0
  104. package/corpus/templates/crm/actions/create-crm-record.ts +148 -0
  105. package/corpus/templates/crm/actions/create-crm-signal-tracker.ts +58 -0
  106. package/corpus/templates/crm/actions/delete-staged-dataset.ts +14 -0
  107. package/corpus/templates/crm/actions/get-crm-automation-recipe.ts +36 -0
  108. package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +33 -0
  109. package/corpus/templates/crm/actions/get-crm-dashboard.ts +14 -0
  110. package/corpus/templates/crm/actions/get-crm-overview.ts +13 -0
  111. package/corpus/templates/crm/actions/get-crm-pipeline-data.ts +61 -0
  112. package/corpus/templates/crm/actions/get-crm-record.ts +75 -0
  113. package/corpus/templates/crm/actions/install-crm-pipeline-dashboard.ts +81 -0
  114. package/corpus/templates/crm/actions/list-crm-dashboard-revisions.ts +15 -0
  115. package/corpus/templates/crm/actions/list-crm-dashboards.ts +15 -0
  116. package/corpus/templates/crm/actions/list-crm-proposals.ts +31 -0
  117. package/corpus/templates/crm/actions/list-crm-records.ts +79 -0
  118. package/corpus/templates/crm/actions/list-crm-saved-views.ts +15 -0
  119. package/corpus/templates/crm/actions/list-crm-signal-hits.ts +43 -0
  120. package/corpus/templates/crm/actions/list-crm-signal-trackers.ts +32 -0
  121. package/corpus/templates/crm/actions/list-crm-tasks.ts +22 -0
  122. package/corpus/templates/crm/actions/list-staged-datasets.ts +14 -0
  123. package/corpus/templates/crm/actions/list-workspace-connections.ts +47 -0
  124. package/corpus/templates/crm/actions/manage-crm-signal-tracker.ts +87 -0
  125. package/corpus/templates/crm/actions/manage-crm-task.ts +132 -0
  126. package/corpus/templates/crm/actions/navigate.ts +63 -0
  127. package/corpus/templates/crm/actions/provider-api-catalog.ts +22 -0
  128. package/corpus/templates/crm/actions/provider-api-docs.ts +54 -0
  129. package/corpus/templates/crm/actions/provider-api-request.ts +92 -0
  130. package/corpus/templates/crm/actions/query-staged-dataset.ts +44 -0
  131. package/corpus/templates/crm/actions/record-crm-call-insight.ts +160 -0
  132. package/corpus/templates/crm/actions/record-crm-smart-signal.ts +150 -0
  133. package/corpus/templates/crm/actions/restore-crm-dashboard-revision.ts +23 -0
  134. package/corpus/templates/crm/actions/review-crm-signal.ts +31 -0
  135. package/corpus/templates/crm/actions/run-crm-saved-view-program.ts +103 -0
  136. package/corpus/templates/crm/actions/run-crm-signal-trackers.ts +275 -0
  137. package/corpus/templates/crm/actions/run.ts +11 -0
  138. package/corpus/templates/crm/actions/save-crm-dashboard.ts +51 -0
  139. package/corpus/templates/crm/actions/save-crm-saved-view.ts +119 -0
  140. package/corpus/templates/crm/actions/sync-crm.ts +146 -0
  141. package/corpus/templates/crm/actions/update-crm-record.ts +508 -0
  142. package/corpus/templates/crm/actions/view-screen.ts +218 -0
  143. package/corpus/templates/crm/agent-native.app-skill.json +58 -0
  144. package/corpus/templates/crm/app/components/crm/CreateCrmRecordDialog.tsx +158 -0
  145. package/corpus/templates/crm/app/components/crm/CrmDashboardPanel.tsx +83 -0
  146. package/corpus/templates/crm/app/components/crm/CrmSignalsPanel.tsx +225 -0
  147. package/corpus/templates/crm/app/components/crm/IntelligenceSettings.tsx +413 -0
  148. package/corpus/templates/crm/app/components/crm/RecordActions.tsx +510 -0
  149. package/corpus/templates/crm/app/components/crm/RecordGrid.tsx +134 -0
  150. package/corpus/templates/crm/app/components/crm/RecordWorkspace.tsx +367 -0
  151. package/corpus/templates/crm/app/components/crm/SavedViewDataProgram.tsx +92 -0
  152. package/corpus/templates/crm/app/components/crm/Surface.tsx +96 -0
  153. package/corpus/templates/crm/app/components/crm/WorkOverview.tsx +180 -0
  154. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +106 -0
  155. package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +84 -0
  156. package/corpus/templates/crm/app/entry.client.tsx +16 -0
  157. package/corpus/templates/crm/app/entry.server.tsx +10 -0
  158. package/corpus/templates/crm/app/global.css +167 -0
  159. package/corpus/templates/crm/app/hooks/use-navigation-state.ts +60 -0
  160. package/corpus/templates/crm/app/i18n/en-US.ts +89 -0
  161. package/corpus/templates/crm/app/i18n/index.ts +34 -0
  162. package/corpus/templates/crm/app/lib/dashboard.ts +13 -0
  163. package/corpus/templates/crm/app/lib/navigation.ts +54 -0
  164. package/corpus/templates/crm/app/lib/tab-id.ts +1 -0
  165. package/corpus/templates/crm/app/lib/types.ts +172 -0
  166. package/corpus/templates/crm/app/lib/utils.ts +1 -0
  167. package/corpus/templates/crm/app/root.tsx +88 -0
  168. package/corpus/templates/crm/app/routes/_index.tsx +26 -0
  169. package/corpus/templates/crm/app/routes/accounts.tsx +41 -0
  170. package/corpus/templates/crm/app/routes/agent.tsx +5 -0
  171. package/corpus/templates/crm/app/routes/ask.tsx +53 -0
  172. package/corpus/templates/crm/app/routes/dashboard.tsx +118 -0
  173. package/corpus/templates/crm/app/routes/opportunities.tsx +41 -0
  174. package/corpus/templates/crm/app/routes/people.tsx +41 -0
  175. package/corpus/templates/crm/app/routes/proposals.tsx +266 -0
  176. package/corpus/templates/crm/app/routes/records.$recordId.tsx +35 -0
  177. package/corpus/templates/crm/app/routes/settings.tsx +63 -0
  178. package/corpus/templates/crm/app/routes/setup.tsx +308 -0
  179. package/corpus/templates/crm/app/routes/tasks.tsx +252 -0
  180. package/corpus/templates/crm/app/routes/views.tsx +333 -0
  181. package/corpus/templates/crm/app/routes.ts +17 -0
  182. package/corpus/templates/crm/app/vite-env.d.ts +6 -0
  183. package/corpus/templates/crm/changelog/2026-07-21-agent-native-crm.md +6 -0
  184. package/corpus/templates/crm/changelog/2026-07-21-clips-call-evidence-review-recipe.md +6 -0
  185. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-find-and-review-evidence-grounded-call-signals-w.md +6 -0
  186. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-manage-keyword-and-smart-call-signal-trackers-fr.md +6 -0
  187. package/corpus/templates/crm/changelog/2026-07-21-delegated-local-crm-automation.md +6 -0
  188. package/corpus/templates/crm/changelog/2026-07-21-native-sql.md +6 -0
  189. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboard.md +6 -0
  190. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboards-now-install-correctly-from-the-crm-actio.md +6 -0
  191. package/corpus/templates/crm/changelog/2026-07-21-salesforce-connection.md +6 -0
  192. package/corpus/templates/crm/components.json +20 -0
  193. package/corpus/templates/crm/docs/architecture/crm-contract.md +180 -0
  194. package/corpus/templates/crm/learnings.defaults.md +5 -0
  195. package/corpus/templates/crm/package.json +59 -0
  196. package/corpus/templates/crm/public/favicon.svg +1 -0
  197. package/corpus/templates/crm/public/icon-180.svg +1 -0
  198. package/corpus/templates/crm/public/manifest.json +11 -0
  199. package/corpus/templates/crm/react-router.config.ts +7 -0
  200. package/corpus/templates/crm/server/crm/adapter.ts +32 -0
  201. package/corpus/templates/crm/server/crm/crm-field-firewall.ts +64 -0
  202. package/corpus/templates/crm/server/crm/crm-mirror.ts +711 -0
  203. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +1143 -0
  204. package/corpus/templates/crm/server/crm/native-adapter.ts +1715 -0
  205. package/corpus/templates/crm/server/crm/read-through.ts +207 -0
  206. package/corpus/templates/crm/server/crm/salesforce-adapter.ts +1255 -0
  207. package/corpus/templates/crm/server/db/crm-store.ts +1170 -0
  208. package/corpus/templates/crm/server/db/index.ts +169 -0
  209. package/corpus/templates/crm/server/db/schema.ts +441 -0
  210. package/corpus/templates/crm/server/lib/intelligence/default-detectors.ts +65 -0
  211. package/corpus/templates/crm/server/lib/intelligence/evidence.ts +105 -0
  212. package/corpus/templates/crm/server/lib/intelligence/keyword-detector.ts +100 -0
  213. package/corpus/templates/crm/server/lib/intelligence/smart-detector.ts +144 -0
  214. package/corpus/templates/crm/server/lib/intelligence/summary.ts +141 -0
  215. package/corpus/templates/crm/server/lib/provider-api.ts +64 -0
  216. package/corpus/templates/crm/server/middleware/auth.ts +4 -0
  217. package/corpus/templates/crm/server/plugins/agent-chat.ts +68 -0
  218. package/corpus/templates/crm/server/plugins/auth.ts +14 -0
  219. package/corpus/templates/crm/server/plugins/core-routes.ts +17 -0
  220. package/corpus/templates/crm/server/plugins/db.ts +454 -0
  221. package/corpus/templates/crm/server/routes/[...page].get.ts +5 -0
  222. package/corpus/templates/crm/shared/crm-automation-recipes.ts +132 -0
  223. package/corpus/templates/crm/shared/crm-contract.ts +254 -0
  224. package/corpus/templates/crm/shared/crm-sales-config.ts +63 -0
  225. package/corpus/templates/crm/ssr-entry.ts +11 -0
  226. package/corpus/templates/crm/tsconfig.json +24 -0
  227. package/corpus/templates/crm/vite.config.ts +15 -0
  228. package/corpus/templates/crm/vitest.config.ts +5 -0
  229. package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +115 -0
  230. package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +115 -0
  231. package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +115 -0
  232. package/corpus/templates/forms/_gitignore +39 -0
  233. package/corpus/templates/forms/learnings.defaults.md +5 -0
  234. package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +115 -0
  235. package/corpus/templates/macros/_gitignore +39 -0
  236. package/corpus/templates/macros/learnings.defaults.md +5 -0
  237. package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +115 -0
  238. package/corpus/templates/mail/_gitignore +39 -0
  239. package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +115 -0
  240. package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +115 -0
  241. package/corpus/templates/slides/_gitignore +39 -0
  242. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +27 -0
  243. package/corpus/templates/tasks/_gitignore +39 -0
  244. package/corpus/toolkit/CHANGELOG.md +12 -0
  245. package/corpus/toolkit/README.md +30 -0
  246. package/corpus/toolkit/agent-native.eject.json +33 -0
  247. package/corpus/toolkit/package.json +15 -1
  248. package/corpus/toolkit/src/dashboard/DataTable.tsx +273 -0
  249. package/corpus/toolkit/src/dashboard/DateRangePicker.tsx +57 -0
  250. package/corpus/toolkit/src/dashboard/GenericChartPanel.tsx +461 -0
  251. package/corpus/toolkit/src/dashboard/MetricCard.tsx +54 -0
  252. package/corpus/toolkit/src/dashboard/StatsCard.tsx +49 -0
  253. package/corpus/toolkit/src/dashboard/dashboard-layout.ts +329 -0
  254. package/corpus/toolkit/src/dashboard/index.ts +6 -0
  255. package/corpus/toolkit/src/index.ts +1 -0
  256. package/corpus/toolkit/src/ui/calendar.tsx +8 -8
  257. package/corpus/toolkit/src/ui/date-picker.tsx +4 -1
  258. package/dist/action.d.ts +14 -1
  259. package/dist/action.d.ts.map +1 -1
  260. package/dist/action.js.map +1 -1
  261. package/dist/agent/production-agent.d.ts +3 -1
  262. package/dist/agent/production-agent.d.ts.map +1 -1
  263. package/dist/agent/production-agent.js +83 -3
  264. package/dist/agent/production-agent.js.map +1 -1
  265. package/dist/cli/templates-meta.d.ts.map +1 -1
  266. package/dist/cli/templates-meta.js +12 -0
  267. package/dist/cli/templates-meta.js.map +1 -1
  268. package/dist/client/AssistantChat.d.ts +4 -0
  269. package/dist/client/AssistantChat.d.ts.map +1 -1
  270. package/dist/client/AssistantChat.js +30 -17
  271. package/dist/client/AssistantChat.js.map +1 -1
  272. package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
  273. package/dist/client/agent-page/AgentJobsTab.js +3 -1
  274. package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
  275. package/dist/client/agent-page/use-jobs.d.ts +1 -0
  276. package/dist/client/agent-page/use-jobs.d.ts.map +1 -1
  277. package/dist/client/agent-page/use-jobs.js.map +1 -1
  278. package/dist/client/chat/message-components.d.ts +5 -0
  279. package/dist/client/chat/message-components.d.ts.map +1 -1
  280. package/dist/client/chat/message-components.js +17 -1
  281. package/dist/client/chat/message-components.js.map +1 -1
  282. package/dist/client/chat/tool-call-display.d.ts +3 -1
  283. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  284. package/dist/client/chat/tool-call-display.js +17 -7
  285. package/dist/client/chat/tool-call-display.js.map +1 -1
  286. package/dist/collab/awareness.d.ts +2 -2
  287. package/dist/collab/awareness.d.ts.map +1 -1
  288. package/dist/collab/routes.d.ts +1 -1
  289. package/dist/collab/struct-routes.d.ts +1 -1
  290. package/dist/connections/catalog.d.ts +17 -3
  291. package/dist/connections/catalog.d.ts.map +1 -1
  292. package/dist/connections/catalog.js +16 -1
  293. package/dist/connections/catalog.js.map +1 -1
  294. package/dist/connections/reader.d.ts +18 -0
  295. package/dist/connections/reader.d.ts.map +1 -1
  296. package/dist/connections/reader.js +41 -0
  297. package/dist/connections/reader.js.map +1 -1
  298. package/dist/dashboard-storage/index.d.ts +4 -0
  299. package/dist/dashboard-storage/index.d.ts.map +1 -0
  300. package/dist/dashboard-storage/index.js +4 -0
  301. package/dist/dashboard-storage/index.js.map +1 -0
  302. package/dist/dashboard-storage/panel-source.d.ts +68 -0
  303. package/dist/dashboard-storage/panel-source.d.ts.map +1 -0
  304. package/dist/dashboard-storage/panel-source.js +76 -0
  305. package/dist/dashboard-storage/panel-source.js.map +1 -0
  306. package/dist/dashboard-storage/schema.d.ts +562 -0
  307. package/dist/dashboard-storage/schema.d.ts.map +1 -0
  308. package/dist/dashboard-storage/schema.js +32 -0
  309. package/dist/dashboard-storage/schema.js.map +1 -0
  310. package/dist/dashboard-storage/store.d.ts +62 -0
  311. package/dist/dashboard-storage/store.d.ts.map +1 -0
  312. package/dist/dashboard-storage/store.js +227 -0
  313. package/dist/dashboard-storage/store.js.map +1 -0
  314. package/dist/deploy/build.d.ts +7 -0
  315. package/dist/deploy/build.d.ts.map +1 -1
  316. package/dist/deploy/build.js +78 -14
  317. package/dist/deploy/build.js.map +1 -1
  318. package/dist/eject/provider-api-definitions.d.ts +2 -1
  319. package/dist/eject/provider-api-definitions.d.ts.map +1 -1
  320. package/dist/eject/provider-api-definitions.js +1 -0
  321. package/dist/eject/provider-api-definitions.js.map +1 -1
  322. package/dist/eject/workspace-connections.d.ts.map +1 -1
  323. package/dist/eject/workspace-connections.js +1 -0
  324. package/dist/eject/workspace-connections.js.map +1 -1
  325. package/dist/extensions/actions.d.ts.map +1 -1
  326. package/dist/extensions/actions.js +165 -67
  327. package/dist/extensions/actions.js.map +1 -1
  328. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  329. package/dist/jobs/actions/list-recurring-jobs.d.ts +1 -0
  330. package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -1
  331. package/dist/jobs/actions/list-recurring-jobs.js +1 -0
  332. package/dist/jobs/actions/list-recurring-jobs.js.map +1 -1
  333. package/dist/jobs/scheduler.d.ts +17 -2
  334. package/dist/jobs/scheduler.d.ts.map +1 -1
  335. package/dist/jobs/scheduler.js +51 -2
  336. package/dist/jobs/scheduler.js.map +1 -1
  337. package/dist/jobs/tools.d.ts.map +1 -1
  338. package/dist/jobs/tools.js +32 -2
  339. package/dist/jobs/tools.js.map +1 -1
  340. package/dist/localization/default-messages.d.ts +1 -0
  341. package/dist/localization/default-messages.d.ts.map +1 -1
  342. package/dist/localization/default-messages.js +1 -0
  343. package/dist/localization/default-messages.js.map +1 -1
  344. package/dist/mcp-client/index.d.ts +2 -0
  345. package/dist/mcp-client/index.d.ts.map +1 -1
  346. package/dist/mcp-client/index.js +5 -0
  347. package/dist/mcp-client/index.js.map +1 -1
  348. package/dist/notifications/routes.d.ts +3 -3
  349. package/dist/observability/routes.d.ts +5 -5
  350. package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
  351. package/dist/provider-api/actions/provider-api.d.ts +8 -6
  352. package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
  353. package/dist/provider-api/actions/provider-api.js +1 -1
  354. package/dist/provider-api/actions/provider-api.js.map +1 -1
  355. package/dist/provider-api/index.d.ts +11 -7
  356. package/dist/provider-api/index.d.ts.map +1 -1
  357. package/dist/provider-api/index.js +143 -5
  358. package/dist/provider-api/index.js.map +1 -1
  359. package/dist/resources/handlers.d.ts +1 -1
  360. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  361. package/dist/secrets/register-framework-secrets.js +7 -0
  362. package/dist/secrets/register-framework-secrets.js.map +1 -1
  363. package/dist/secrets/routes.d.ts +9 -9
  364. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  365. package/dist/server/agent-chat/context-tools.js +9 -0
  366. package/dist/server/agent-chat/context-tools.js.map +1 -1
  367. package/dist/server/agent-chat/framework-prompts.js +2 -2
  368. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  369. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  370. package/dist/server/agent-chat-plugin.js +18 -2
  371. package/dist/server/agent-chat-plugin.js.map +1 -1
  372. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  373. package/dist/server/core-routes-plugin.js +1 -0
  374. package/dist/server/core-routes-plugin.js.map +1 -1
  375. package/dist/server/credential-provider.d.ts +4 -3
  376. package/dist/server/credential-provider.d.ts.map +1 -1
  377. package/dist/server/credential-provider.js +9 -3
  378. package/dist/server/credential-provider.js.map +1 -1
  379. package/dist/server/transcribe-voice.d.ts +1 -1
  380. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  381. package/dist/server/workspace-provider-oauth.d.ts.map +1 -1
  382. package/dist/server/workspace-provider-oauth.js +141 -4
  383. package/dist/server/workspace-provider-oauth.js.map +1 -1
  384. package/dist/styles/agent-native.css +45 -2
  385. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  386. package/dist/templates/chat/AGENTS.md +1 -1
  387. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  388. package/dist/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  389. package/dist/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  390. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  391. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  392. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  393. package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  394. package/dist/triggers/actions.d.ts.map +1 -1
  395. package/dist/triggers/actions.js +10 -2
  396. package/dist/triggers/actions.js.map +1 -1
  397. package/dist/triggers/dispatcher.d.ts.map +1 -1
  398. package/dist/triggers/dispatcher.js +15 -0
  399. package/dist/triggers/dispatcher.js.map +1 -1
  400. package/dist/triggers/types.d.ts +5 -0
  401. package/dist/triggers/types.d.ts.map +1 -1
  402. package/dist/triggers/types.js.map +1 -1
  403. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  404. package/dist/vite/action-types-plugin.js +4 -1
  405. package/dist/vite/action-types-plugin.js.map +1 -1
  406. package/docs/content/agent-native-toolkit.mdx +16 -0
  407. package/docs/content/recurring-jobs.mdx +35 -6
  408. package/package.json +6 -2
  409. package/src/action.ts +22 -1
  410. package/src/agent/production-agent.ts +105 -3
  411. package/src/cli/templates-meta.ts +12 -0
  412. package/src/client/AssistantChat.tsx +53 -26
  413. package/src/client/agent-page/AgentJobsTab.tsx +19 -0
  414. package/src/client/agent-page/use-jobs.ts +1 -0
  415. package/src/client/chat/message-components.tsx +35 -1
  416. package/src/client/chat/tool-call-display.tsx +38 -3
  417. package/src/connections/catalog.ts +20 -1
  418. package/src/connections/reader.ts +65 -0
  419. package/src/dashboard-storage/index.ts +27 -0
  420. package/src/dashboard-storage/panel-source.ts +168 -0
  421. package/src/dashboard-storage/schema.ts +62 -0
  422. package/src/dashboard-storage/store.ts +333 -0
  423. package/src/deploy/build.ts +95 -16
  424. package/src/eject/provider-api-definitions.ts +1 -0
  425. package/src/eject/workspace-connections.ts +1 -0
  426. package/src/extensions/actions.ts +199 -73
  427. package/src/jobs/actions/list-recurring-jobs.ts +2 -0
  428. package/src/jobs/scheduler.ts +71 -4
  429. package/src/jobs/tools.ts +31 -1
  430. package/src/localization/default-messages.ts +1 -0
  431. package/src/mcp-client/index.ts +6 -0
  432. package/src/provider-api/actions/provider-api.ts +1 -1
  433. package/src/provider-api/index.ts +190 -5
  434. package/src/secrets/register-framework-secrets.ts +8 -0
  435. package/src/server/agent-chat/context-tools.ts +9 -0
  436. package/src/server/agent-chat/framework-prompts.ts +2 -2
  437. package/src/server/agent-chat-plugin.ts +22 -2
  438. package/src/server/core-routes-plugin.ts +1 -0
  439. package/src/server/credential-provider.ts +9 -3
  440. package/src/server/workspace-provider-oauth.ts +181 -4
  441. package/src/styles/agent-native.css +45 -2
  442. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  443. package/src/templates/chat/AGENTS.md +1 -1
  444. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  445. package/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  446. package/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  447. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  448. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  449. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  450. package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  451. package/src/triggers/actions.ts +11 -2
  452. package/src/triggers/dispatcher.ts +20 -1
  453. package/src/triggers/types.ts +5 -0
  454. package/src/vite/action-types-plugin.ts +9 -1
  455. package/corpus/templates/analytics/server/handlers/sql-query.ts +0 -36
  456. package/corpus/templates/analytics/server/routes/api/sql-query.post.ts +0 -1
@@ -623,7 +623,7 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
623
623
  "update-extension": {
624
624
  tool: {
625
625
  description:
626
- 'Update an existing sandboxed Alpine.js mini-app extension. If the user is viewing the extension, use the extensionId from <current-screen> or <current-url> directly; do not list extensions first just to find the current id. Prefer granular edits for surgical changes; full-body replacement is blocked by default to preserve existing layout, CSS, copy, and interactions during data-only fixes. Use `patches` or `edits` for targeted changes; set `allowFullReplacement=true` only when the user explicitly asks for a visual rewrite or supplies a complete replacement body. Supported edits include literal replace, insert-before/after marker, replace-between markers, replace-section/wrap-section/remove-section for <!-- agent-native:section name --> blocks, and regex-replace. Pass format=true to run Prettier on the final HTML. To replace the whole body with a large pasted file, pass contentFromAttachment (the attachment name, or "latest") instead of copying the file into `content` that avoids re-emitting thousands of tokens.',
626
+ 'Update an existing sandboxed Alpine.js mini-app extension. Pass exactly three fields: `id`, `operation`, and `payloadJson`. `payloadJson` is a JSON object encoded as a string so model gateways cannot fill its optional members with invalid empty placeholders. For operation="edit", pass {"edits":[...]} or {"patches":[...]} and optional format=true. For operation="replace", pass exactly one of content, contentFromAttachment, or contentFromWorkspaceFile; use this operation only for a user-requested broad visual rewrite or complete replacement body. For operation="metadata", pass name, description, or icon. Change sharing through set-resource-visibility instead. If the user is viewing the extension, use the extensionId from <current-screen> or <current-url> directly.',
627
627
  parameters: {
628
628
  type: "object",
629
629
  properties: {
@@ -632,72 +632,35 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
632
632
  description:
633
633
  "Extension id to update. Prefer the extensionId from <current-screen> or <current-url> for the current extension.",
634
634
  },
635
- name: {
636
- type: "string",
637
- description: "Optional new display name.",
638
- },
639
- description: {
640
- type: "string",
641
- description: "Optional new description.",
642
- },
643
- content: {
644
- type: "string",
645
- description:
646
- "Optional full replacement Alpine.js HTML body snippet.",
647
- },
648
- contentFromAttachment: {
635
+ operation: {
649
636
  type: "string",
637
+ enum: ["edit", "replace", "metadata"],
650
638
  description:
651
- 'Optional full replacement sourced from a pasted/attached file on the current turn, by attachment name (or the literal "latest" for the most recent pasted block). Use instead of `content` when replacing the whole body with a large pasted file so you do not have to re-type it. Ignored when `content` is provided.',
639
+ 'The single update mode: "edit" for focused patches/edits, "replace" for an explicitly authorized complete body replacement, or "metadata" for name/description/icon.',
652
640
  },
653
- contentFromWorkspaceFile: {
641
+ payloadJson: {
654
642
  type: "string",
643
+ minLength: 2,
655
644
  description:
656
- 'Optional full replacement sourced from a workspace/shared resource file, by resource path (e.g. "intuit-analytics-extension.html"). The server reads the full file and uses it as the replacement body. Use instead of `content` when replacing the whole body with a large file that exists as a workspace resource. Ignored when `content` is provided.',
657
- },
658
- allowFullReplacement: {
659
- type: "boolean",
660
- description:
661
- "Explicitly allow replacing the entire existing body. Omit or set false for data-only repairs so the existing visual design is protected. Use true only when the user explicitly requested a broad visual rewrite or supplied a complete replacement body.",
662
- },
663
- patches: {
664
- anyOf: [
665
- { type: "string" },
666
- { type: "array", items: { type: "object" } },
667
- ],
668
- description:
669
- 'Optional patches as a JSON-encoded string or native array of { "find": "...", "replace": "...", "all"?: true, "expectedMatches"?: 1, "required"?: true } objects. Missing required targets fail instead of silently no-oping.',
670
- },
671
- edits: {
672
- anyOf: [
673
- { type: "string" },
674
- { type: "array", items: { type: "object" } },
675
- ],
676
- description:
677
- 'Preferred optional granular edit operations as a JSON-encoded string or native array. Examples: { "op": "insert-after", "marker": "<!-- section:metrics -->", "content": "..." }, { "op": "replace-section", "section": "npm-chart", "content": "..." }, { "op": "wrap-section", "section": "charts", "before": "<div>", "after": "</div>" }, { "op": "regex-replace", "pattern": "...", "replace": "...", "expectedMatches": 1 }.',
678
- },
679
- format: {
680
- type: "boolean",
681
- description:
682
- "When true, format the final extension HTML with Prettier after applying content, patches, and edits.",
683
- },
684
- icon: {
685
- type: "string",
686
- description: "Optional icon name or short label.",
687
- },
688
- visibility: {
689
- type: "string",
690
- description:
691
- "Optional sharing visibility. Public extension sharing is not supported; use private or org.",
692
- enum: ["private", "org"],
645
+ 'A non-empty JSON object encoded as a string. edit example: {"edits":[{"op":"replace","find":"old","replace":"new"}],"format":true}. replace example: {"contentFromAttachment":"latest"}. metadata example: {"name":"New name"}.',
693
646
  },
694
647
  },
695
- required: ["id"],
648
+ required: ["id", "operation", "payloadJson"],
649
+ additionalProperties: false,
696
650
  },
697
651
  },
698
652
  run: async (args, ctx) => {
653
+ const normalizedUpdate = normalizeUpdateExtensionArgs(args);
654
+ if ("error" in normalizedUpdate) return normalizedUpdate.error;
655
+ args = normalizedUpdate.args;
699
656
  const id = String(args?.id ?? "").trim();
700
657
  if (!id) return "Error: id is required.";
658
+ if (
659
+ args?.name !== undefined &&
660
+ (typeof args.name !== "string" || args.name.trim().length === 0)
661
+ ) {
662
+ return "Error: extension name must be a non-empty string. No changes were applied.";
663
+ }
701
664
  const localMessage = await localExtensionEditMessage(id);
702
665
  if (localMessage) return localMessage;
703
666
 
@@ -722,11 +685,19 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
722
685
  });
723
686
  }
724
687
 
688
+ const attachmentRef =
689
+ typeof args?.contentFromAttachment === "string"
690
+ ? args.contentFromAttachment.trim()
691
+ : "";
692
+ const workspaceFileRef =
693
+ typeof args?.contentFromWorkspaceFile === "string"
694
+ ? args.contentFromWorkspaceFile.trim()
695
+ : "";
725
696
  const fullReplacementRequested =
726
697
  (typeof args?.content === "string" &&
727
698
  args.content.trim().length > 0) ||
728
- args?.contentFromAttachment !== undefined ||
729
- args?.contentFromWorkspaceFile !== undefined;
699
+ attachmentRef.length > 0 ||
700
+ workspaceFileRef.length > 0;
730
701
  if (
731
702
  fullReplacementRequested &&
732
703
  !coerceBoolean(args?.allowFullReplacement)
@@ -748,8 +719,7 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
748
719
  : undefined;
749
720
  if (
750
721
  replacementContent === undefined &&
751
- (args?.contentFromAttachment !== undefined ||
752
- args?.contentFromWorkspaceFile !== undefined)
722
+ (attachmentRef.length > 0 || workspaceFileRef.length > 0)
753
723
  ) {
754
724
  const resolved = await resolveExtensionContentAsync(args, ctx);
755
725
  if ("error" in resolved) return resolved.error;
@@ -757,20 +727,20 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
757
727
  }
758
728
 
759
729
  let result = null;
730
+ const patches = parsePatches((args as any).patches);
731
+ if (args?.patches !== undefined && !patches) {
732
+ return "Error: patches must be a JSON array of { find, replace } objects.";
733
+ }
734
+ const edits = parseEdits((args as any).edits);
735
+ if (args?.edits !== undefined && !edits) {
736
+ return "Error: edits must be a JSON array of supported extension edit operations.";
737
+ }
760
738
  const hasContentUpdate =
761
739
  replacementContent !== undefined ||
762
- args?.patches !== undefined ||
763
- args?.edits !== undefined ||
764
- args?.format !== undefined;
740
+ (patches?.length ?? 0) > 0 ||
741
+ (edits?.length ?? 0) > 0 ||
742
+ coerceBoolean(args?.format);
765
743
  if (hasContentUpdate) {
766
- const patches = parsePatches((args as any).patches);
767
- if (args?.patches !== undefined && !patches) {
768
- return "Error: patches must be a JSON array of { find, replace } objects.";
769
- }
770
- const edits = parseEdits((args as any).edits);
771
- if (args?.edits !== undefined && !edits) {
772
- return "Error: edits must be a JSON array of supported extension edit operations.";
773
- }
774
744
  try {
775
745
  result = await updateExtensionContent(id, {
776
746
  content: replacementContent,
@@ -806,13 +776,15 @@ export function createExtensionActionEntries(): Record<string, ActionEntry> {
806
776
  meta.description = String(args.description).trim();
807
777
  }
808
778
  if (args?.icon !== undefined) meta.icon = String(args.icon);
809
- if (args?.visibility !== undefined) {
779
+ if (args?.visibility !== undefined)
810
780
  meta.visibility = String(args.visibility);
811
- }
812
781
  if (Object.keys(meta).length > 0) {
813
782
  result = await updateExtension(id, meta as any);
814
783
  }
815
784
 
785
+ if (!result && !hasContentUpdate && Object.keys(meta).length === 0) {
786
+ return "Error: update-extension received no actual changes. Choose one operation and provide a non-empty payloadJson object; empty placeholder fields are not an update.";
787
+ }
816
788
  if (!result) result = await getExtension(id);
817
789
  if (!result) return `Error: extension not found: ${id}`;
818
790
  const hiddenIds = await getHiddenExtensionIdsForCurrentUser();
@@ -1444,7 +1416,7 @@ async function summarizeExtensionForAgentRead(
1444
1416
  reason: "unchanged-content-already-returned-this-run",
1445
1417
  contentHash: fingerprint,
1446
1418
  contentLength: row.content.length,
1447
- next: "Use the content already returned earlier in this run and call update-extension with focused edits/patches. Set forceContent=true only if you truly need the full body again.",
1419
+ next: 'Use the content already returned earlier in this run and call update-extension with operation="edit" plus focused edits/patches inside payloadJson. Set forceContent=true only if you truly need the full body again.',
1448
1420
  },
1449
1421
  };
1450
1422
  }
@@ -1746,6 +1718,160 @@ function coerceBoolean(value: unknown): boolean {
1746
1718
  return value === true || value === "true";
1747
1719
  }
1748
1720
 
1721
+ function normalizeUpdateExtensionArgs(
1722
+ args: any,
1723
+ ): { args: Record<string, unknown> } | { error: string } {
1724
+ const hasCompactContract =
1725
+ args?.operation !== undefined || args?.payloadJson !== undefined;
1726
+ if (!hasCompactContract) {
1727
+ const legacyArgs = { ...((args ?? {}) as Record<string, unknown>) };
1728
+ const hasInvalidPlaceholderSignal =
1729
+ (typeof legacyArgs.visibility === "string" &&
1730
+ legacyArgs.visibility.trim().length === 0) ||
1731
+ [legacyArgs.patches, legacyArgs.edits].some(
1732
+ (value) =>
1733
+ value !== null &&
1734
+ typeof value === "object" &&
1735
+ (Array.isArray(value)
1736
+ ? value.length > 0 &&
1737
+ value.every(
1738
+ (item) =>
1739
+ item !== null &&
1740
+ typeof item === "object" &&
1741
+ !Array.isArray(item) &&
1742
+ Object.keys(item).length === 0,
1743
+ )
1744
+ : Object.keys(value).length === 0),
1745
+ );
1746
+ if (hasInvalidPlaceholderSignal) {
1747
+ for (const [key, value] of Object.entries(legacyArgs)) {
1748
+ if (key === "id") continue;
1749
+ const empty =
1750
+ value === false ||
1751
+ value === null ||
1752
+ (typeof value === "string" && value.trim().length === 0) ||
1753
+ (Array.isArray(value) &&
1754
+ (value.length === 0 ||
1755
+ value.every(
1756
+ (item) =>
1757
+ item !== null &&
1758
+ typeof item === "object" &&
1759
+ !Array.isArray(item) &&
1760
+ Object.keys(item).length === 0,
1761
+ ))) ||
1762
+ (typeof value === "object" &&
1763
+ value !== null &&
1764
+ !Array.isArray(value) &&
1765
+ Object.keys(value).length === 0);
1766
+ if (empty) delete legacyArgs[key];
1767
+ }
1768
+ delete legacyArgs.visibility;
1769
+ }
1770
+ return { args: legacyArgs };
1771
+ }
1772
+
1773
+ const operation = String(args?.operation ?? "").trim();
1774
+ if (!(["edit", "replace", "metadata"] as const).includes(operation as any)) {
1775
+ return {
1776
+ error:
1777
+ 'Error: operation must be "edit", "replace", or "metadata". No changes were applied.',
1778
+ };
1779
+ }
1780
+
1781
+ let payload: unknown;
1782
+ try {
1783
+ payload = JSON.parse(String(args?.payloadJson ?? ""));
1784
+ } catch {
1785
+ return {
1786
+ error:
1787
+ "Error: payloadJson must be a valid JSON object encoded as a string. No changes were applied.",
1788
+ };
1789
+ }
1790
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
1791
+ return {
1792
+ error:
1793
+ "Error: payloadJson must decode to a non-empty JSON object. No changes were applied.",
1794
+ };
1795
+ }
1796
+
1797
+ const payloadRecord = payload as Record<string, unknown>;
1798
+ const allowedByOperation: Record<string, Set<string>> = {
1799
+ edit: new Set(["patches", "edits", "format"]),
1800
+ replace: new Set([
1801
+ "content",
1802
+ "contentFromAttachment",
1803
+ "contentFromWorkspaceFile",
1804
+ "format",
1805
+ ]),
1806
+ metadata: new Set(["name", "description", "icon"]),
1807
+ };
1808
+ const unexpected = Object.keys(payloadRecord).filter(
1809
+ (key) => !allowedByOperation[operation].has(key),
1810
+ );
1811
+ if (unexpected.length > 0) {
1812
+ return {
1813
+ error: `Error: operation=${operation} does not accept ${unexpected.join(", ")}. No changes were applied.`,
1814
+ };
1815
+ }
1816
+
1817
+ if (operation === "edit") {
1818
+ const patches = parsePatches(payloadRecord.patches);
1819
+ const edits = parseEdits(payloadRecord.edits);
1820
+ const hasEdit =
1821
+ (patches?.length ?? 0) > 0 ||
1822
+ (edits?.length ?? 0) > 0 ||
1823
+ coerceBoolean(payloadRecord.format);
1824
+ if (!hasEdit) {
1825
+ return {
1826
+ error:
1827
+ "Error: operation=edit requires at least one valid patch/edit or format=true. No changes were applied.",
1828
+ };
1829
+ }
1830
+ }
1831
+
1832
+ if (operation === "replace") {
1833
+ const replacementSources = [
1834
+ payloadRecord.content,
1835
+ payloadRecord.contentFromAttachment,
1836
+ payloadRecord.contentFromWorkspaceFile,
1837
+ ].filter((value) => typeof value === "string" && value.trim().length > 0);
1838
+ if (replacementSources.length !== 1) {
1839
+ return {
1840
+ error:
1841
+ "Error: operation=replace requires exactly one non-empty content, contentFromAttachment, or contentFromWorkspaceFile value. No changes were applied.",
1842
+ };
1843
+ }
1844
+ }
1845
+
1846
+ if (operation === "metadata") {
1847
+ const keys = Object.keys(payloadRecord);
1848
+ if (keys.length === 0) {
1849
+ return {
1850
+ error:
1851
+ "Error: operation=metadata requires name, description, or icon. No changes were applied.",
1852
+ };
1853
+ }
1854
+ if (
1855
+ payloadRecord.name !== undefined &&
1856
+ (typeof payloadRecord.name !== "string" ||
1857
+ payloadRecord.name.trim().length === 0)
1858
+ ) {
1859
+ return {
1860
+ error:
1861
+ "Error: extension name must be a non-empty string. No changes were applied.",
1862
+ };
1863
+ }
1864
+ }
1865
+
1866
+ return {
1867
+ args: {
1868
+ id: String(args?.id ?? "").trim(),
1869
+ ...payloadRecord,
1870
+ ...(operation === "replace" ? { allowFullReplacement: true } : {}),
1871
+ },
1872
+ };
1873
+ }
1874
+
1749
1875
  function parseInlineContext(
1750
1876
  value: unknown,
1751
1877
  ): Record<string, unknown> | undefined {
@@ -46,6 +46,7 @@ export interface RecurringJobActionItem {
46
46
  lastError: string | null;
47
47
  nextRun: string | null;
48
48
  createdBy: string | null;
49
+ mcpTools: string[];
49
50
  canUpdate: boolean;
50
51
  }
51
52
 
@@ -96,6 +97,7 @@ export default defineAction({
96
97
  lastError: meta.lastError ?? null,
97
98
  nextRun: nextRun(meta),
98
99
  createdBy: meta.createdBy ?? null,
100
+ mcpTools: meta.mcpTools ?? [],
99
101
  canUpdate,
100
102
  });
101
103
  }
@@ -42,6 +42,50 @@ export interface JobFrontmatter {
42
42
  deliveryThreadRef?: string;
43
43
  deliveryTenantId?: string;
44
44
  model?: string;
45
+ /** Explicit MCP tool capabilities available to this background run. */
46
+ mcpTools?: string[];
47
+ }
48
+
49
+ const MAX_JOB_MCP_TOOLS = 64;
50
+ const JOB_MCP_TOOL_NAME_RE = /^mcp__[^\s]+__[^\s]+$/;
51
+
52
+ /**
53
+ * Normalize the non-secret MCP capability references persisted with a job.
54
+ * Tool names are opaque framework identifiers; URLs and credentials never
55
+ * belong in job frontmatter.
56
+ */
57
+ export function normalizeJobMcpTools(value: unknown): string[] | undefined {
58
+ if (value === undefined || value === null) return undefined;
59
+ const parsed =
60
+ typeof value === "string"
61
+ ? (() => {
62
+ try {
63
+ return JSON.parse(value);
64
+ } catch {
65
+ throw new Error("mcpTools must be a JSON array of tool names.");
66
+ }
67
+ })()
68
+ : value;
69
+ if (!Array.isArray(parsed)) {
70
+ throw new Error("mcpTools must be an array of MCP tool names.");
71
+ }
72
+ if (parsed.length > MAX_JOB_MCP_TOOLS) {
73
+ throw new Error(
74
+ `mcpTools may contain at most ${MAX_JOB_MCP_TOOLS} tool names.`,
75
+ );
76
+ }
77
+ const normalized = [...new Set(parsed)];
78
+ if (
79
+ normalized.some(
80
+ (toolName) =>
81
+ typeof toolName !== "string" || !JOB_MCP_TOOL_NAME_RE.test(toolName),
82
+ )
83
+ ) {
84
+ throw new Error(
85
+ "mcpTools must contain only framework MCP tool names such as mcp__server__tool.",
86
+ );
87
+ }
88
+ return normalized;
45
89
  }
46
90
 
47
91
  const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
@@ -129,6 +173,14 @@ export function parseJobFrontmatter(content: string): {
129
173
  case "model":
130
174
  meta.model = value;
131
175
  break;
176
+ case "mcpTools":
177
+ try {
178
+ meta.mcpTools = normalizeJobMcpTools(value);
179
+ } catch {
180
+ // Ignore malformed optional capability metadata and keep the job
181
+ // readable; newly-created jobs are validated before persistence.
182
+ }
183
+ break;
132
184
  }
133
185
  }
134
186
 
@@ -166,6 +218,8 @@ export function buildJobContent(meta: JobFrontmatter, body: string): string {
166
218
  if (meta.deliveryTenantId)
167
219
  lines.push(`deliveryTenantId: ${meta.deliveryTenantId}`);
168
220
  if (meta.model) lines.push(`model: ${meta.model}`);
221
+ if (meta.mcpTools?.length)
222
+ lines.push(`mcpTools: ${JSON.stringify(meta.mcpTools)}`);
169
223
  lines.push(`---`);
170
224
  lines.push("");
171
225
  lines.push(body);
@@ -174,8 +228,15 @@ export function buildJobContent(meta: JobFrontmatter, body: string): string {
174
228
 
175
229
  // ─── Job execution ──────────────────────────────────────────────────────────
176
230
 
231
+ export interface RecurringJobContext {
232
+ name: string;
233
+ meta: JobFrontmatter;
234
+ body: string;
235
+ resource: Resource;
236
+ }
237
+
177
238
  export interface SchedulerDeps {
178
- getActions: () => Record<string, ActionEntry>;
239
+ getActions: (job?: RecurringJobContext) => Record<string, ActionEntry>;
179
240
  getSystemPrompt: (owner: string) => Promise<string>;
180
241
  /**
181
242
  * Tool names to expose on the FIRST engine request for a job run. When
@@ -188,7 +249,7 @@ export interface SchedulerDeps {
188
249
  * merged actions are the app's own vs. framework additions, so this must
189
250
  * be supplied explicitly rather than inferred here.
190
251
  */
191
- getInitialToolNames?: () => string[] | undefined;
252
+ getInitialToolNames?: (job?: RecurringJobContext) => string[] | undefined;
192
253
  /** Optional engine override. Defaults to the resolved request engine. */
193
254
  engine?: AgentEngine;
194
255
  apiKey?: string;
@@ -477,9 +538,15 @@ async function executeJob(
477
538
  },
478
539
  async () => {
479
540
  try {
480
- const baseActions = deps.getActions();
541
+ const jobContext: RecurringJobContext = {
542
+ name: jobName,
543
+ meta,
544
+ body,
545
+ resource,
546
+ };
547
+ const baseActions = deps.getActions(jobContext);
481
548
  const systemPrompt = await deps.getSystemPrompt(jobUserEmail);
482
- const initialToolNames = deps.getInitialToolNames?.();
549
+ const initialToolNames = deps.getInitialToolNames?.(jobContext);
483
550
  // Only attach tool-search (and pay its schema cost) when the caller
484
551
  // actually supplied an initial subset to filter down to — otherwise
485
552
  // this is byte-for-byte the prior unfiltered behavior.
@@ -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()