@agent-native/core 0.114.16 → 0.115.3

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 (476) hide show
  1. package/agent-native.eject.json +2 -0
  2. package/corpus/README.md +3 -3
  3. package/corpus/core/CHANGELOG.md +41 -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 +122 -3
  11. package/corpus/core/src/cli/skills-content/visual-plan-skill.ts +19 -2
  12. package/corpus/core/src/cli/templates-meta.ts +12 -0
  13. package/corpus/core/src/client/AssistantChat.tsx +53 -26
  14. package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +19 -0
  15. package/corpus/core/src/client/agent-page/use-jobs.ts +1 -0
  16. package/corpus/core/src/client/blocks/library/wireframe.tsx +3 -1
  17. package/corpus/core/src/client/chat/message-components.tsx +35 -1
  18. package/corpus/core/src/client/chat/tool-call-display.tsx +38 -3
  19. package/corpus/core/src/connections/catalog.ts +20 -1
  20. package/corpus/core/src/connections/reader.ts +65 -0
  21. package/corpus/core/src/dashboard-storage/index.ts +27 -0
  22. package/corpus/core/src/dashboard-storage/panel-source.ts +168 -0
  23. package/corpus/core/src/dashboard-storage/schema.ts +62 -0
  24. package/corpus/core/src/dashboard-storage/store.ts +333 -0
  25. package/corpus/core/src/deploy/build.ts +95 -16
  26. package/corpus/core/src/eject/provider-api-definitions.ts +1 -0
  27. package/corpus/core/src/eject/workspace-connections.ts +1 -0
  28. package/corpus/core/src/extensions/actions.ts +199 -73
  29. package/corpus/core/src/jobs/actions/list-recurring-jobs.ts +2 -0
  30. package/corpus/core/src/jobs/scheduler.ts +71 -4
  31. package/corpus/core/src/jobs/tools.ts +31 -1
  32. package/corpus/core/src/localization/default-messages.ts +1 -0
  33. package/corpus/core/src/mcp-client/index.ts +6 -0
  34. package/corpus/core/src/provider-api/actions/provider-api.ts +1 -1
  35. package/corpus/core/src/provider-api/index.ts +190 -5
  36. package/corpus/core/src/secrets/register-framework-secrets.ts +8 -0
  37. package/corpus/core/src/server/agent-chat/context-tools.ts +9 -0
  38. package/corpus/core/src/server/agent-chat/framework-prompts.ts +2 -2
  39. package/corpus/core/src/server/agent-chat-plugin.ts +22 -2
  40. package/corpus/core/src/server/core-routes-plugin.ts +1 -0
  41. package/corpus/core/src/server/credential-provider.ts +9 -3
  42. package/corpus/core/src/server/workspace-provider-oauth.ts +181 -4
  43. package/corpus/core/src/styles/agent-native.css +45 -2
  44. package/corpus/core/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  45. package/corpus/core/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  46. package/corpus/core/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  47. package/corpus/core/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  48. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  49. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  50. package/corpus/core/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  51. package/corpus/core/src/triggers/actions.ts +11 -2
  52. package/corpus/core/src/triggers/dispatcher.ts +20 -1
  53. package/corpus/core/src/triggers/types.ts +5 -0
  54. package/corpus/core/src/vite/action-types-plugin.ts +9 -1
  55. package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +115 -0
  56. package/corpus/templates/analytics/AGENTS.md +11 -11
  57. package/corpus/templates/analytics/_gitignore +39 -0
  58. package/corpus/templates/analytics/actions/query-dashboard-panel.ts +30 -0
  59. package/corpus/templates/analytics/actions/update-dashboard.ts +2 -1
  60. package/corpus/templates/analytics/app/lib/sql-query.ts +11 -25
  61. package/corpus/templates/analytics/changelog/2026-07-21-fixed-extension-updates-failing-before-changes-could-be-appl.md +6 -0
  62. package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +1 -0
  63. package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +51 -0
  64. package/corpus/templates/analytics/server/lib/prometheus.ts +1 -1
  65. package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -1
  66. package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +115 -0
  67. package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +115 -0
  68. package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +115 -0
  69. package/corpus/templates/calendar/_gitignore +39 -0
  70. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  71. package/corpus/templates/chat/AGENTS.md +1 -1
  72. package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +115 -0
  73. package/corpus/templates/clips/AGENTS.md +7 -0
  74. package/corpus/templates/clips/actions/prepare-crm-call-evidence.ts +58 -0
  75. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +88 -11
  76. package/corpus/templates/clips/changelog/2026-07-21-crm-call-evidence-handoff.md +6 -0
  77. package/corpus/templates/clips/changelog/2026-07-21-recording-retries-and-restarts-keep-their-upload-session-so-.md +6 -0
  78. package/corpus/templates/clips/chrome-extension/src/background.ts +20 -5
  79. package/corpus/templates/clips/chrome-extension/src/native-recording-state.ts +19 -0
  80. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +8 -0
  81. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +9 -0
  82. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +54 -28
  83. package/corpus/templates/clips/server/plugins/agent-chat.ts +1 -0
  84. package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +115 -0
  85. package/corpus/templates/content/_gitignore +39 -0
  86. package/corpus/templates/content/learnings.defaults.md +5 -0
  87. package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +115 -0
  88. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
  89. package/corpus/templates/crm/.agents/skills/crm/SKILL.md +128 -0
  90. package/corpus/templates/crm/.agents/skills/customizing-agent-native/SKILL.md +145 -0
  91. package/corpus/templates/crm/.agents/skills/feature-flags/SKILL.md +169 -0
  92. package/corpus/templates/crm/.agents/skills/upgrade-agent-native/SKILL.md +100 -0
  93. package/corpus/templates/crm/.env.example +5 -0
  94. package/corpus/templates/crm/AGENTS.md +120 -0
  95. package/corpus/templates/crm/CHANGELOG.md +1 -0
  96. package/corpus/templates/crm/DEVELOPING.md +66 -0
  97. package/corpus/templates/crm/README.md +106 -0
  98. package/corpus/templates/crm/_gitignore +12 -0
  99. package/corpus/templates/crm/actions/_crm-action-utils.ts +87 -0
  100. package/corpus/templates/crm/actions/_crm-dashboard.ts +69 -0
  101. package/corpus/templates/crm/actions/_crm-signal-utils.ts +79 -0
  102. package/corpus/templates/crm/actions/apply-crm-proposals.ts +203 -0
  103. package/corpus/templates/crm/actions/attach-call-evidence.ts +170 -0
  104. package/corpus/templates/crm/actions/configure-crm-connection.ts +126 -0
  105. package/corpus/templates/crm/actions/configure-native-crm.ts +44 -0
  106. package/corpus/templates/crm/actions/create-crm-record.ts +148 -0
  107. package/corpus/templates/crm/actions/create-crm-signal-tracker.ts +58 -0
  108. package/corpus/templates/crm/actions/delete-staged-dataset.ts +14 -0
  109. package/corpus/templates/crm/actions/get-crm-automation-recipe.ts +36 -0
  110. package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +33 -0
  111. package/corpus/templates/crm/actions/get-crm-dashboard.ts +14 -0
  112. package/corpus/templates/crm/actions/get-crm-overview.ts +13 -0
  113. package/corpus/templates/crm/actions/get-crm-pipeline-data.ts +61 -0
  114. package/corpus/templates/crm/actions/get-crm-record.ts +75 -0
  115. package/corpus/templates/crm/actions/install-crm-pipeline-dashboard.ts +81 -0
  116. package/corpus/templates/crm/actions/list-crm-dashboard-revisions.ts +15 -0
  117. package/corpus/templates/crm/actions/list-crm-dashboards.ts +15 -0
  118. package/corpus/templates/crm/actions/list-crm-proposals.ts +31 -0
  119. package/corpus/templates/crm/actions/list-crm-records.ts +79 -0
  120. package/corpus/templates/crm/actions/list-crm-saved-views.ts +15 -0
  121. package/corpus/templates/crm/actions/list-crm-signal-hits.ts +43 -0
  122. package/corpus/templates/crm/actions/list-crm-signal-trackers.ts +32 -0
  123. package/corpus/templates/crm/actions/list-crm-tasks.ts +22 -0
  124. package/corpus/templates/crm/actions/list-staged-datasets.ts +14 -0
  125. package/corpus/templates/crm/actions/list-workspace-connections.ts +47 -0
  126. package/corpus/templates/crm/actions/manage-crm-signal-tracker.ts +87 -0
  127. package/corpus/templates/crm/actions/manage-crm-task.ts +132 -0
  128. package/corpus/templates/crm/actions/navigate.ts +63 -0
  129. package/corpus/templates/crm/actions/provider-api-catalog.ts +22 -0
  130. package/corpus/templates/crm/actions/provider-api-docs.ts +54 -0
  131. package/corpus/templates/crm/actions/provider-api-request.ts +92 -0
  132. package/corpus/templates/crm/actions/query-staged-dataset.ts +44 -0
  133. package/corpus/templates/crm/actions/record-crm-call-insight.ts +160 -0
  134. package/corpus/templates/crm/actions/record-crm-smart-signal.ts +150 -0
  135. package/corpus/templates/crm/actions/restore-crm-dashboard-revision.ts +23 -0
  136. package/corpus/templates/crm/actions/review-crm-signal.ts +31 -0
  137. package/corpus/templates/crm/actions/run-crm-saved-view-program.ts +103 -0
  138. package/corpus/templates/crm/actions/run-crm-signal-trackers.ts +275 -0
  139. package/corpus/templates/crm/actions/run.ts +11 -0
  140. package/corpus/templates/crm/actions/save-crm-dashboard.ts +51 -0
  141. package/corpus/templates/crm/actions/save-crm-saved-view.ts +119 -0
  142. package/corpus/templates/crm/actions/sync-crm.ts +146 -0
  143. package/corpus/templates/crm/actions/update-crm-record.ts +508 -0
  144. package/corpus/templates/crm/actions/view-screen.ts +218 -0
  145. package/corpus/templates/crm/agent-native.app-skill.json +58 -0
  146. package/corpus/templates/crm/app/components/crm/CreateCrmRecordDialog.tsx +158 -0
  147. package/corpus/templates/crm/app/components/crm/CrmDashboardPanel.tsx +83 -0
  148. package/corpus/templates/crm/app/components/crm/CrmSignalsPanel.tsx +225 -0
  149. package/corpus/templates/crm/app/components/crm/IntelligenceSettings.tsx +413 -0
  150. package/corpus/templates/crm/app/components/crm/RecordActions.tsx +510 -0
  151. package/corpus/templates/crm/app/components/crm/RecordGrid.tsx +134 -0
  152. package/corpus/templates/crm/app/components/crm/RecordWorkspace.tsx +367 -0
  153. package/corpus/templates/crm/app/components/crm/SavedViewDataProgram.tsx +92 -0
  154. package/corpus/templates/crm/app/components/crm/Surface.tsx +96 -0
  155. package/corpus/templates/crm/app/components/crm/WorkOverview.tsx +180 -0
  156. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +106 -0
  157. package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +84 -0
  158. package/corpus/templates/crm/app/entry.client.tsx +16 -0
  159. package/corpus/templates/crm/app/entry.server.tsx +10 -0
  160. package/corpus/templates/crm/app/global.css +167 -0
  161. package/corpus/templates/crm/app/hooks/use-navigation-state.ts +60 -0
  162. package/corpus/templates/crm/app/i18n/en-US.ts +89 -0
  163. package/corpus/templates/crm/app/i18n/index.ts +34 -0
  164. package/corpus/templates/crm/app/lib/dashboard.ts +13 -0
  165. package/corpus/templates/crm/app/lib/navigation.ts +54 -0
  166. package/corpus/templates/crm/app/lib/tab-id.ts +1 -0
  167. package/corpus/templates/crm/app/lib/types.ts +172 -0
  168. package/corpus/templates/crm/app/lib/utils.ts +1 -0
  169. package/corpus/templates/crm/app/root.tsx +88 -0
  170. package/corpus/templates/crm/app/routes/_index.tsx +26 -0
  171. package/corpus/templates/crm/app/routes/accounts.tsx +41 -0
  172. package/corpus/templates/crm/app/routes/agent.tsx +5 -0
  173. package/corpus/templates/crm/app/routes/ask.tsx +53 -0
  174. package/corpus/templates/crm/app/routes/dashboard.tsx +118 -0
  175. package/corpus/templates/crm/app/routes/opportunities.tsx +41 -0
  176. package/corpus/templates/crm/app/routes/people.tsx +41 -0
  177. package/corpus/templates/crm/app/routes/proposals.tsx +266 -0
  178. package/corpus/templates/crm/app/routes/records.$recordId.tsx +35 -0
  179. package/corpus/templates/crm/app/routes/settings.tsx +63 -0
  180. package/corpus/templates/crm/app/routes/setup.tsx +308 -0
  181. package/corpus/templates/crm/app/routes/tasks.tsx +252 -0
  182. package/corpus/templates/crm/app/routes/views.tsx +333 -0
  183. package/corpus/templates/crm/app/routes.ts +17 -0
  184. package/corpus/templates/crm/app/vite-env.d.ts +6 -0
  185. package/corpus/templates/crm/changelog/2026-07-21-agent-native-crm.md +6 -0
  186. package/corpus/templates/crm/changelog/2026-07-21-clips-call-evidence-review-recipe.md +6 -0
  187. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-find-and-review-evidence-grounded-call-signals-w.md +6 -0
  188. package/corpus/templates/crm/changelog/2026-07-21-crm-can-now-manage-keyword-and-smart-call-signal-trackers-fr.md +6 -0
  189. package/corpus/templates/crm/changelog/2026-07-21-delegated-local-crm-automation.md +6 -0
  190. package/corpus/templates/crm/changelog/2026-07-21-native-sql.md +6 -0
  191. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboard.md +6 -0
  192. package/corpus/templates/crm/changelog/2026-07-21-pipeline-dashboards-now-install-correctly-from-the-crm-actio.md +6 -0
  193. package/corpus/templates/crm/changelog/2026-07-21-salesforce-connection.md +6 -0
  194. package/corpus/templates/crm/components.json +20 -0
  195. package/corpus/templates/crm/docs/architecture/crm-contract.md +180 -0
  196. package/corpus/templates/crm/learnings.defaults.md +5 -0
  197. package/corpus/templates/crm/package.json +59 -0
  198. package/corpus/templates/crm/public/favicon.svg +1 -0
  199. package/corpus/templates/crm/public/icon-180.svg +1 -0
  200. package/corpus/templates/crm/public/manifest.json +11 -0
  201. package/corpus/templates/crm/react-router.config.ts +7 -0
  202. package/corpus/templates/crm/server/crm/adapter.ts +32 -0
  203. package/corpus/templates/crm/server/crm/crm-field-firewall.ts +64 -0
  204. package/corpus/templates/crm/server/crm/crm-mirror.ts +711 -0
  205. package/corpus/templates/crm/server/crm/hubspot-adapter.ts +1143 -0
  206. package/corpus/templates/crm/server/crm/native-adapter.ts +1715 -0
  207. package/corpus/templates/crm/server/crm/read-through.ts +207 -0
  208. package/corpus/templates/crm/server/crm/salesforce-adapter.ts +1255 -0
  209. package/corpus/templates/crm/server/db/crm-store.ts +1170 -0
  210. package/corpus/templates/crm/server/db/index.ts +169 -0
  211. package/corpus/templates/crm/server/db/schema.ts +441 -0
  212. package/corpus/templates/crm/server/lib/intelligence/default-detectors.ts +65 -0
  213. package/corpus/templates/crm/server/lib/intelligence/evidence.ts +105 -0
  214. package/corpus/templates/crm/server/lib/intelligence/keyword-detector.ts +100 -0
  215. package/corpus/templates/crm/server/lib/intelligence/smart-detector.ts +144 -0
  216. package/corpus/templates/crm/server/lib/intelligence/summary.ts +141 -0
  217. package/corpus/templates/crm/server/lib/provider-api.ts +64 -0
  218. package/corpus/templates/crm/server/middleware/auth.ts +4 -0
  219. package/corpus/templates/crm/server/plugins/agent-chat.ts +68 -0
  220. package/corpus/templates/crm/server/plugins/auth.ts +14 -0
  221. package/corpus/templates/crm/server/plugins/core-routes.ts +17 -0
  222. package/corpus/templates/crm/server/plugins/db.ts +454 -0
  223. package/corpus/templates/crm/server/routes/[...page].get.ts +5 -0
  224. package/corpus/templates/crm/shared/crm-automation-recipes.ts +132 -0
  225. package/corpus/templates/crm/shared/crm-contract.ts +254 -0
  226. package/corpus/templates/crm/shared/crm-sales-config.ts +63 -0
  227. package/corpus/templates/crm/ssr-entry.ts +11 -0
  228. package/corpus/templates/crm/tsconfig.json +24 -0
  229. package/corpus/templates/crm/vite.config.ts +15 -0
  230. package/corpus/templates/crm/vitest.config.ts +5 -0
  231. package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +115 -0
  232. package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +115 -0
  233. package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +115 -0
  234. package/corpus/templates/forms/_gitignore +39 -0
  235. package/corpus/templates/forms/learnings.defaults.md +5 -0
  236. package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +115 -0
  237. package/corpus/templates/macros/_gitignore +39 -0
  238. package/corpus/templates/macros/learnings.defaults.md +5 -0
  239. package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +115 -0
  240. package/corpus/templates/mail/_gitignore +39 -0
  241. package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +115 -0
  242. package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +19 -2
  243. package/corpus/templates/plan/AGENTS.md +10 -0
  244. package/corpus/templates/plan/actions/create-prototype-plan.ts +27 -3
  245. package/corpus/templates/plan/actions/get-plan-blocks.ts +1 -1
  246. package/corpus/templates/plan/actions/update-visual-plan.ts +3 -2
  247. package/corpus/templates/plan/app/components/plan/PlanContentRenderer.tsx +18 -4
  248. package/corpus/templates/plan/app/components/plan/PlanVisualSurface.tsx +10 -3
  249. package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +3 -1
  250. package/corpus/templates/plan/app/i18n/en-US.ts +6 -0
  251. package/corpus/templates/plan/app/lib/create-plan-routing.ts +39 -0
  252. package/corpus/templates/plan/app/pages/PlansPage.tsx +31 -107
  253. package/corpus/templates/plan/changelog/2026-07-22-high-fidelity-mockup-requests-now-preserve-branded-css-use-d.md +6 -0
  254. package/corpus/templates/plan/shared/plan-content.ts +110 -2
  255. package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +115 -0
  256. package/corpus/templates/slides/_gitignore +39 -0
  257. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +27 -0
  258. package/corpus/templates/tasks/_gitignore +39 -0
  259. package/corpus/toolkit/CHANGELOG.md +12 -0
  260. package/corpus/toolkit/README.md +30 -0
  261. package/corpus/toolkit/agent-native.eject.json +33 -0
  262. package/corpus/toolkit/package.json +15 -1
  263. package/corpus/toolkit/src/dashboard/DataTable.tsx +273 -0
  264. package/corpus/toolkit/src/dashboard/DateRangePicker.tsx +57 -0
  265. package/corpus/toolkit/src/dashboard/GenericChartPanel.tsx +461 -0
  266. package/corpus/toolkit/src/dashboard/MetricCard.tsx +54 -0
  267. package/corpus/toolkit/src/dashboard/StatsCard.tsx +49 -0
  268. package/corpus/toolkit/src/dashboard/dashboard-layout.ts +329 -0
  269. package/corpus/toolkit/src/dashboard/index.ts +6 -0
  270. package/corpus/toolkit/src/index.ts +1 -0
  271. package/corpus/toolkit/src/ui/calendar.tsx +8 -8
  272. package/corpus/toolkit/src/ui/date-picker.tsx +4 -1
  273. package/dist/action.d.ts +14 -1
  274. package/dist/action.d.ts.map +1 -1
  275. package/dist/action.js.map +1 -1
  276. package/dist/agent/production-agent.d.ts +3 -1
  277. package/dist/agent/production-agent.d.ts.map +1 -1
  278. package/dist/agent/production-agent.js +97 -3
  279. package/dist/agent/production-agent.js.map +1 -1
  280. package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
  281. package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -1
  282. package/dist/cli/skills-content/visual-plan-skill.js +19 -2
  283. package/dist/cli/skills-content/visual-plan-skill.js.map +1 -1
  284. package/dist/cli/templates-meta.d.ts.map +1 -1
  285. package/dist/cli/templates-meta.js +12 -0
  286. package/dist/cli/templates-meta.js.map +1 -1
  287. package/dist/client/AssistantChat.d.ts +4 -0
  288. package/dist/client/AssistantChat.d.ts.map +1 -1
  289. package/dist/client/AssistantChat.js +30 -17
  290. package/dist/client/AssistantChat.js.map +1 -1
  291. package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -1
  292. package/dist/client/agent-page/AgentJobsTab.js +3 -1
  293. package/dist/client/agent-page/AgentJobsTab.js.map +1 -1
  294. package/dist/client/agent-page/use-jobs.d.ts +1 -0
  295. package/dist/client/agent-page/use-jobs.d.ts.map +1 -1
  296. package/dist/client/agent-page/use-jobs.js.map +1 -1
  297. package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
  298. package/dist/client/blocks/library/wireframe.js +3 -2
  299. package/dist/client/blocks/library/wireframe.js.map +1 -1
  300. package/dist/client/chat/message-components.d.ts +5 -0
  301. package/dist/client/chat/message-components.d.ts.map +1 -1
  302. package/dist/client/chat/message-components.js +17 -1
  303. package/dist/client/chat/message-components.js.map +1 -1
  304. package/dist/client/chat/tool-call-display.d.ts +3 -1
  305. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  306. package/dist/client/chat/tool-call-display.js +17 -7
  307. package/dist/client/chat/tool-call-display.js.map +1 -1
  308. package/dist/collab/routes.d.ts +1 -1
  309. package/dist/collab/struct-routes.d.ts +1 -1
  310. package/dist/connections/catalog.d.ts +17 -3
  311. package/dist/connections/catalog.d.ts.map +1 -1
  312. package/dist/connections/catalog.js +16 -1
  313. package/dist/connections/catalog.js.map +1 -1
  314. package/dist/connections/reader.d.ts +18 -0
  315. package/dist/connections/reader.d.ts.map +1 -1
  316. package/dist/connections/reader.js +41 -0
  317. package/dist/connections/reader.js.map +1 -1
  318. package/dist/dashboard-storage/index.d.ts +4 -0
  319. package/dist/dashboard-storage/index.d.ts.map +1 -0
  320. package/dist/dashboard-storage/index.js +4 -0
  321. package/dist/dashboard-storage/index.js.map +1 -0
  322. package/dist/dashboard-storage/panel-source.d.ts +68 -0
  323. package/dist/dashboard-storage/panel-source.d.ts.map +1 -0
  324. package/dist/dashboard-storage/panel-source.js +76 -0
  325. package/dist/dashboard-storage/panel-source.js.map +1 -0
  326. package/dist/dashboard-storage/schema.d.ts +562 -0
  327. package/dist/dashboard-storage/schema.d.ts.map +1 -0
  328. package/dist/dashboard-storage/schema.js +32 -0
  329. package/dist/dashboard-storage/schema.js.map +1 -0
  330. package/dist/dashboard-storage/store.d.ts +62 -0
  331. package/dist/dashboard-storage/store.d.ts.map +1 -0
  332. package/dist/dashboard-storage/store.js +227 -0
  333. package/dist/dashboard-storage/store.js.map +1 -0
  334. package/dist/deploy/build.d.ts +7 -0
  335. package/dist/deploy/build.d.ts.map +1 -1
  336. package/dist/deploy/build.js +78 -14
  337. package/dist/deploy/build.js.map +1 -1
  338. package/dist/eject/provider-api-definitions.d.ts +2 -1
  339. package/dist/eject/provider-api-definitions.d.ts.map +1 -1
  340. package/dist/eject/provider-api-definitions.js +1 -0
  341. package/dist/eject/provider-api-definitions.js.map +1 -1
  342. package/dist/eject/workspace-connections.d.ts.map +1 -1
  343. package/dist/eject/workspace-connections.js +1 -0
  344. package/dist/eject/workspace-connections.js.map +1 -1
  345. package/dist/extensions/actions.d.ts.map +1 -1
  346. package/dist/extensions/actions.js +165 -67
  347. package/dist/extensions/actions.js.map +1 -1
  348. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  349. package/dist/jobs/actions/list-recurring-jobs.d.ts +1 -0
  350. package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -1
  351. package/dist/jobs/actions/list-recurring-jobs.js +1 -0
  352. package/dist/jobs/actions/list-recurring-jobs.js.map +1 -1
  353. package/dist/jobs/scheduler.d.ts +17 -2
  354. package/dist/jobs/scheduler.d.ts.map +1 -1
  355. package/dist/jobs/scheduler.js +51 -2
  356. package/dist/jobs/scheduler.js.map +1 -1
  357. package/dist/jobs/tools.d.ts.map +1 -1
  358. package/dist/jobs/tools.js +32 -2
  359. package/dist/jobs/tools.js.map +1 -1
  360. package/dist/localization/default-messages.d.ts +1 -0
  361. package/dist/localization/default-messages.d.ts.map +1 -1
  362. package/dist/localization/default-messages.js +1 -0
  363. package/dist/localization/default-messages.js.map +1 -1
  364. package/dist/mcp-client/index.d.ts +2 -0
  365. package/dist/mcp-client/index.d.ts.map +1 -1
  366. package/dist/mcp-client/index.js +5 -0
  367. package/dist/mcp-client/index.js.map +1 -1
  368. package/dist/notifications/routes.d.ts +3 -3
  369. package/dist/progress/routes.d.ts +1 -1
  370. package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
  371. package/dist/provider-api/actions/provider-api.d.ts +8 -6
  372. package/dist/provider-api/actions/provider-api.d.ts.map +1 -1
  373. package/dist/provider-api/actions/provider-api.js +1 -1
  374. package/dist/provider-api/actions/provider-api.js.map +1 -1
  375. package/dist/provider-api/index.d.ts +11 -7
  376. package/dist/provider-api/index.d.ts.map +1 -1
  377. package/dist/provider-api/index.js +143 -5
  378. package/dist/provider-api/index.js.map +1 -1
  379. package/dist/resources/handlers.d.ts +1 -1
  380. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  381. package/dist/secrets/register-framework-secrets.js +7 -0
  382. package/dist/secrets/register-framework-secrets.js.map +1 -1
  383. package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
  384. package/dist/server/agent-chat/context-tools.js +9 -0
  385. package/dist/server/agent-chat/context-tools.js.map +1 -1
  386. package/dist/server/agent-chat/framework-prompts.js +2 -2
  387. package/dist/server/agent-chat/framework-prompts.js.map +1 -1
  388. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  389. package/dist/server/agent-chat-plugin.js +18 -2
  390. package/dist/server/agent-chat-plugin.js.map +1 -1
  391. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  392. package/dist/server/core-routes-plugin.js +1 -0
  393. package/dist/server/core-routes-plugin.js.map +1 -1
  394. package/dist/server/credential-provider.d.ts +4 -3
  395. package/dist/server/credential-provider.d.ts.map +1 -1
  396. package/dist/server/credential-provider.js +9 -3
  397. package/dist/server/credential-provider.js.map +1 -1
  398. package/dist/server/workspace-provider-oauth.d.ts +6 -1
  399. package/dist/server/workspace-provider-oauth.d.ts.map +1 -1
  400. package/dist/server/workspace-provider-oauth.js +141 -4
  401. package/dist/server/workspace-provider-oauth.js.map +1 -1
  402. package/dist/styles/agent-native.css +45 -2
  403. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  404. package/dist/templates/chat/AGENTS.md +1 -1
  405. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  406. package/dist/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  407. package/dist/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  408. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  409. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  410. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  411. package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  412. package/dist/triggers/actions.d.ts.map +1 -1
  413. package/dist/triggers/actions.js +10 -2
  414. package/dist/triggers/actions.js.map +1 -1
  415. package/dist/triggers/dispatcher.d.ts.map +1 -1
  416. package/dist/triggers/dispatcher.js +15 -0
  417. package/dist/triggers/dispatcher.js.map +1 -1
  418. package/dist/triggers/types.d.ts +5 -0
  419. package/dist/triggers/types.d.ts.map +1 -1
  420. package/dist/triggers/types.js.map +1 -1
  421. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  422. package/dist/vite/action-types-plugin.js +4 -1
  423. package/dist/vite/action-types-plugin.js.map +1 -1
  424. package/docs/content/agent-native-toolkit.mdx +16 -0
  425. package/docs/content/recurring-jobs.mdx +35 -6
  426. package/package.json +7 -3
  427. package/src/action.ts +22 -1
  428. package/src/agent/production-agent.ts +122 -3
  429. package/src/cli/skills-content/visual-plan-skill.ts +19 -2
  430. package/src/cli/templates-meta.ts +12 -0
  431. package/src/client/AssistantChat.tsx +53 -26
  432. package/src/client/agent-page/AgentJobsTab.tsx +19 -0
  433. package/src/client/agent-page/use-jobs.ts +1 -0
  434. package/src/client/blocks/library/wireframe.tsx +3 -1
  435. package/src/client/chat/message-components.tsx +35 -1
  436. package/src/client/chat/tool-call-display.tsx +38 -3
  437. package/src/connections/catalog.ts +20 -1
  438. package/src/connections/reader.ts +65 -0
  439. package/src/dashboard-storage/index.ts +27 -0
  440. package/src/dashboard-storage/panel-source.ts +168 -0
  441. package/src/dashboard-storage/schema.ts +62 -0
  442. package/src/dashboard-storage/store.ts +333 -0
  443. package/src/deploy/build.ts +95 -16
  444. package/src/eject/provider-api-definitions.ts +1 -0
  445. package/src/eject/workspace-connections.ts +1 -0
  446. package/src/extensions/actions.ts +199 -73
  447. package/src/jobs/actions/list-recurring-jobs.ts +2 -0
  448. package/src/jobs/scheduler.ts +71 -4
  449. package/src/jobs/tools.ts +31 -1
  450. package/src/localization/default-messages.ts +1 -0
  451. package/src/mcp-client/index.ts +6 -0
  452. package/src/provider-api/actions/provider-api.ts +1 -1
  453. package/src/provider-api/index.ts +190 -5
  454. package/src/secrets/register-framework-secrets.ts +8 -0
  455. package/src/server/agent-chat/context-tools.ts +9 -0
  456. package/src/server/agent-chat/framework-prompts.ts +2 -2
  457. package/src/server/agent-chat-plugin.ts +22 -2
  458. package/src/server/core-routes-plugin.ts +1 -0
  459. package/src/server/credential-provider.ts +9 -3
  460. package/src/server/workspace-provider-oauth.ts +181 -4
  461. package/src/styles/agent-native.css +45 -2
  462. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +27 -0
  463. package/src/templates/chat/AGENTS.md +1 -1
  464. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +27 -0
  465. package/src/templates/default/.agents/skills/app-branding/SKILL.md +159 -0
  466. package/src/templates/default/.agents/skills/app-permissions/SKILL.md +155 -0
  467. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +27 -0
  468. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +27 -0
  469. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +31 -18
  470. package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +15 -0
  471. package/src/triggers/actions.ts +11 -2
  472. package/src/triggers/dispatcher.ts +20 -1
  473. package/src/triggers/types.ts +5 -0
  474. package/src/vite/action-types-plugin.ts +9 -1
  475. package/corpus/templates/analytics/server/handlers/sql-query.ts +0 -36
  476. package/corpus/templates/analytics/server/routes/api/sql-query.post.ts +0 -1
@@ -0,0 +1,106 @@
1
+ # CRM
2
+
3
+ CRM is an agent-native CRM that runs either as a standalone Native SQL system
4
+ or as a scoped companion for connected HubSpot and Salesforce workspaces. It
5
+ provides fast record work, saved views, tasks, cadence, evidence, reviewable
6
+ call signals, and agent workflows without forcing a provider choice.
7
+
8
+ Native SQL is local-authoritative and portable across SQLite, Postgres, and D1.
9
+ The connected modes support scoped Connected and Hybrid behavior: HubSpot maps
10
+ companies, contacts, and deals; Salesforce maps Accounts, Contacts, and
11
+ Opportunities.
12
+
13
+ ## Guardrails
14
+
15
+ - Native SQL requires no external connection or provider credential.
16
+ - Provider credentials are workspace Connections only.
17
+ - The mirror contains configured cohorts and allow-listed fields, not raw
18
+ provider exports.
19
+ - Sensitive fields default to redacted and unknown fields are remote-only.
20
+ - Evidence stores a bounded quote and source reference, never transcripts or
21
+ media.
22
+ - Signal detectors produce timestamped evidence citations. Keyword matching is
23
+ local; smart moments and summaries are delegated through agent chat and saved
24
+ only after grounding validation.
25
+ - Provider mutations are revision-aware, audited, and proposed when agent risk
26
+ requires approval.
27
+
28
+ ## Start or connect CRM
29
+
30
+ 1. Open **Set up CRM** and select **Start with Native SQL** to use CRM without
31
+ HubSpot or Salesforce. Native records and fields are local-authoritative.
32
+ 2. To use CRM as a companion, in shared **Settings → Connections**, authorize
33
+ HubSpot or Salesforce and
34
+ grant the connection to CRM. OAuth and refresh tokens stay in workspace
35
+ Connections; CRM never accepts a token or key. Salesforce production is the
36
+ default. For a sandbox, use **Authorize the sandbox directly** on Set up CRM;
37
+ the selected login environment is retained for token refresh.
38
+ 3. Choose the granted connection and select a recent
39
+ history window. HubSpot may be narrowed to deal pipeline IDs; Salesforce
40
+ starts with recently updated Accounts, Contacts, and Opportunities.
41
+ 4. CRM mirrors the selected cohort and allow-listed fields only. Confirm the
42
+ connection actor's access before relying on a record in the local mirror.
43
+
44
+ ## Operating model
45
+
46
+ - **Connected**: the source CRM is authoritative. CRM is a scoped companion
47
+ for record work, saved views, tasks, call evidence, and analysis.
48
+ - **Hybrid**: the source CRM remains authoritative for remote fields; CRM may
49
+ own explicitly configured derived-local and local-authoritative fields.
50
+ - **Native SQL**: CRM is the system of record for its accounts, people,
51
+ opportunities, relationships, saved views, tasks, cadence, and local fields.
52
+ It has no upstream provider, sync job, or provider token.
53
+ - **Signals**: attach one Clips call-evidence artifact to one or more CRM
54
+ records, run the default Pricing, Competitors, Objections, Next steps,
55
+ Budget, and Timing detectors, then confirm or dismiss the grounded results.
56
+ Clips remains the owner of recording, transcript, consent, and media access.
57
+ - **Clips review recipe**: from a chosen CRM record, prepare a default-off
58
+ `clip.created` recipe. After explicit activation, its Clips-owned trigger
59
+ ignores the event media URL, resolves the clip through an access-checked
60
+ read action, and attaches only its opaque ID, durable HTTPS `/r/<id>` page,
61
+ and capture time to that exact CRM record. It never copies media or a
62
+ transcript, infers another record, or authorizes a provider write.
63
+ - **Pipeline dashboard**: install the CRM-owned Pipeline dashboard to get
64
+ action-backed stage, amount, and close-date panels. Its data program and
65
+ dashboard revisions are access-scoped CRM records; the reusable chart and
66
+ table presentation comes from the Toolkit dashboard kit.
67
+ - **Read and write safety**: provider reads use the connection's effective
68
+ permissions. Upstream changes are revision-aware, access-checked proposals
69
+ in this release; finish the approved change in HubSpot or Salesforce and do
70
+ not claim a provider write completed from CRM.
71
+
72
+ ## Review and delegation policy
73
+
74
+ CRM records the actor, expected remote revision, idempotency key, field-level
75
+ provenance, and an audit event for each mutation request. Local, reversible
76
+ routine work can execute in CRM. Agent-initiated provider changes become
77
+ reviewable proposals; destructive, bulk, and named-risk changes remain gated.
78
+ Delegated authority is narrow and stored as policy—it never expands record or
79
+ field access, bypasses the write firewall, or turns a provider result into an
80
+ unverified success.
81
+
82
+ Salesforce reads are validated against the current connection actor and field
83
+ permissions before mirrored data is returned. A service-account mirror never
84
+ proves a user's access; ambiguous or changed access fails closed until refresh.
85
+
86
+ ## Live testing
87
+
88
+ Use a shared, already-authorized workspace Connection—never copy its secret
89
+ into an environment file. Choose a small recent cohort, verify the resulting
90
+ records and access scope in CRM, then test a proposal without applying a
91
+ provider change. Record only connection labels, counts, and non-sensitive
92
+ results in test evidence.
93
+
94
+ See [the CRM contract](docs/architecture/crm-contract.md) for field policies,
95
+ identity, access scope, and write decisions.
96
+
97
+ ## Local development
98
+
99
+ ```bash
100
+ pnpm install
101
+ pnpm dev
102
+ ```
103
+
104
+ Set `DATABASE_URL` for persistent deployment storage. Native SQL works without
105
+ external credentials. Connect HubSpot or Salesforce from the workspace
106
+ Connections surface; do not add provider secrets to `.env`.
@@ -0,0 +1,12 @@
1
+ node_modules
2
+ dist
3
+ build
4
+ .output
5
+ .netlify
6
+ .react-router
7
+ .generated
8
+ data/*.db
9
+ data/*.db-shm
10
+ data/*.db-wal
11
+ .env
12
+ .env.local
@@ -0,0 +1,87 @@
1
+ import type { ActionRunContext } from "@agent-native/core/action";
2
+ import {
3
+ getRequestOrgId,
4
+ getRequestUserEmail,
5
+ } from "@agent-native/core/server";
6
+
7
+ export {
8
+ isBoundedCrmValue,
9
+ isSafeCrmMutationFieldName,
10
+ isSafeCrmMutationFields,
11
+ } from "../server/crm/crm-field-firewall.js";
12
+
13
+ export const MAX_CRM_FIELDS_PER_MUTATION = 20;
14
+
15
+ export function requireCrmScope(ctx?: ActionRunContext) {
16
+ const ownerEmail = ctx?.userEmail ?? getRequestUserEmail();
17
+ if (!ownerEmail) throw new Error("Sign in is required to manage CRM data.");
18
+ const orgId = ctx?.orgId ?? getRequestOrgId() ?? null;
19
+ return {
20
+ ownerEmail,
21
+ orgId,
22
+ visibility: orgId ? ("org" as const) : ("private" as const),
23
+ };
24
+ }
25
+
26
+ export function crmInitiatedBy(ctx?: ActionRunContext) {
27
+ if (ctx?.caller === "automation") return "automation" as const;
28
+ return ctx?.caller === "tool" ||
29
+ ctx?.caller === "mcp" ||
30
+ ctx?.caller === "a2a"
31
+ ? ("agent" as const)
32
+ : ("human" as const);
33
+ }
34
+
35
+ export function crmWriteRisk(fieldNames: string[]) {
36
+ const names = fieldNames.map((field) => field.toLowerCase());
37
+ if (names.some((field) => field.includes("owner")))
38
+ return "ownership" as const;
39
+ if (names.some((field) => field === "amount" || field.includes("amount"))) {
40
+ return "amount" as const;
41
+ }
42
+ if (
43
+ names.some((field) => field.includes("stage") || field.includes("pipeline"))
44
+ ) {
45
+ return "stage" as const;
46
+ }
47
+ return "routine" as const;
48
+ }
49
+
50
+ export async function scopedCrmIdempotencyKey(input: {
51
+ ownerEmail: string;
52
+ orgId: string | null;
53
+ recordId: string;
54
+ key: string;
55
+ }): Promise<string> {
56
+ const value = [
57
+ "crm-mutation-v1",
58
+ input.ownerEmail.toLowerCase(),
59
+ input.orgId ?? "",
60
+ input.recordId,
61
+ input.key,
62
+ ].join("\u0000");
63
+ const bytes = new TextEncoder().encode(value);
64
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
65
+ return `crm:v1:${Array.from(new Uint8Array(digest), (byte) =>
66
+ byte.toString(16).padStart(2, "0"),
67
+ ).join("")}`;
68
+ }
69
+
70
+ export function toJson(value: unknown, maxChars: number) {
71
+ const encoded = JSON.stringify(value);
72
+ if (encoded.length > maxChars) {
73
+ throw new Error(`CRM payload exceeds the ${maxChars}-character limit.`);
74
+ }
75
+ return encoded;
76
+ }
77
+
78
+ export function parseJsonRecord(value: string): Record<string, unknown> {
79
+ try {
80
+ const parsed = JSON.parse(value) as unknown;
81
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
82
+ ? (parsed as Record<string, unknown>)
83
+ : {};
84
+ } catch {
85
+ return {};
86
+ }
87
+ }
@@ -0,0 +1,69 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ import type { ActionRunContext } from "@agent-native/core/action";
4
+ import type { AccessContext } from "@agent-native/core/sharing";
5
+
6
+ import type { CrmDashboardConfig } from "../server/db/index.js";
7
+
8
+ export const CRM_PIPELINE_DASHBOARD_TITLE = "Pipeline";
9
+ export const CRM_PIPELINE_PROGRAM_NAME = "crm-pipeline-by-stage";
10
+ export const CRM_PIPELINE_PROGRAM_TITLE = "CRM pipeline by stage";
11
+ export const CRM_PIPELINE_REFRESH_TTL_MS = 5 * 60_000;
12
+
13
+ export const CRM_PIPELINE_PROGRAM_COLUMNS = [
14
+ { name: "stage", type: "string" },
15
+ { name: "pipelineValue", type: "number" },
16
+ { name: "opportunities", type: "number" },
17
+ ] as const;
18
+
19
+ export const CRM_PIPELINE_PROGRAM_CODE = `const result = await appAction("get-crm-pipeline-data");
20
+ emit(result.rows, ${JSON.stringify(CRM_PIPELINE_PROGRAM_COLUMNS, null, 2)});`;
21
+
22
+ export function requireDashboardAccess(
23
+ ctx?: ActionRunContext,
24
+ ): AccessContext & { userEmail: string } {
25
+ const userEmail = ctx?.userEmail?.trim().toLowerCase();
26
+ if (!userEmail) {
27
+ throw new Error("CRM dashboards require an authenticated user.");
28
+ }
29
+ return { userEmail, orgId: ctx?.orgId ?? undefined };
30
+ }
31
+
32
+ export function crmPipelineDashboardId(ctx: AccessContext): string {
33
+ const owner = ctx.userEmail?.trim().toLowerCase();
34
+ if (!owner) throw new Error("CRM dashboards require an authenticated user.");
35
+ const scope = `${ctx.orgId ?? "personal"}:${owner}`;
36
+ return `crm-pipeline-${createHash("sha256").update(scope).digest("hex").slice(0, 24)}`;
37
+ }
38
+
39
+ export function createPipelineDashboardConfig(
40
+ programId: string,
41
+ ): CrmDashboardConfig {
42
+ const query = JSON.stringify({ programId });
43
+ return {
44
+ version: 1,
45
+ panels: [
46
+ {
47
+ id: "pipeline-total",
48
+ title: "Pipeline value",
49
+ source: "program",
50
+ query,
51
+ chartType: "metric",
52
+ },
53
+ {
54
+ id: "pipeline-by-stage",
55
+ title: "Pipeline by stage",
56
+ source: "program",
57
+ query,
58
+ chartType: "bar",
59
+ },
60
+ {
61
+ id: "pipeline-table",
62
+ title: "Stage detail",
63
+ source: "program",
64
+ query,
65
+ chartType: "table",
66
+ },
67
+ ],
68
+ };
69
+ }
@@ -0,0 +1,79 @@
1
+ import type { ActionRunContext } from "@agent-native/core/action";
2
+ import { accessFilter, assertAccess } from "@agent-native/core/sharing";
3
+ import { and, eq, inArray } from "drizzle-orm";
4
+
5
+ import { getDb, schema } from "../server/db/index.js";
6
+ import type { CallEvidenceExcerpt } from "../server/lib/intelligence/evidence.js";
7
+ import {
8
+ requireCrmScope,
9
+ scopedCrmIdempotencyKey,
10
+ } from "./_crm-action-utils.js";
11
+
12
+ export async function loadCrmSignalEvidence(args: {
13
+ recordId: string;
14
+ evidenceIds?: string[];
15
+ role?: "viewer" | "editor";
16
+ }) {
17
+ await assertAccess("crm-record", args.recordId, args.role ?? "viewer");
18
+ const db = getDb();
19
+ const predicates = [
20
+ eq(schema.crmCallEvidence.recordId, args.recordId),
21
+ accessFilter(schema.crmCallEvidence, schema.crmCallEvidenceShares),
22
+ ];
23
+ if (args.evidenceIds?.length) {
24
+ predicates.push(inArray(schema.crmCallEvidence.id, args.evidenceIds));
25
+ }
26
+ const rows = await db
27
+ .select()
28
+ .from(schema.crmCallEvidence)
29
+ .where(and(...predicates))
30
+ .limit(20);
31
+ if (
32
+ args.evidenceIds?.length &&
33
+ rows.length !== new Set(args.evidenceIds).size
34
+ ) {
35
+ throw new Error("One or more call-evidence references are unavailable.");
36
+ }
37
+ return rows;
38
+ }
39
+
40
+ export function evidenceExcerpts(
41
+ rows: Awaited<ReturnType<typeof loadCrmSignalEvidence>>,
42
+ ): CallEvidenceExcerpt[] {
43
+ return rows.flatMap((row) => {
44
+ const quote = row.quote.trim() || row.summary.trim();
45
+ if (!quote) return [];
46
+ return [
47
+ {
48
+ evidenceRef: row.id,
49
+ quote,
50
+ ...(row.speaker ? { speaker: row.speaker } : {}),
51
+ startSeconds: row.startSeconds ?? 0,
52
+ ...(row.endSeconds !== null ? { endSeconds: row.endSeconds } : {}),
53
+ },
54
+ ];
55
+ });
56
+ }
57
+
58
+ export async function crmSignalIdempotencyKey(
59
+ ctx: ActionRunContext | undefined,
60
+ recordId: string,
61
+ key: string,
62
+ ) {
63
+ const scope = requireCrmScope(ctx);
64
+ return {
65
+ scope,
66
+ key: await scopedCrmIdempotencyKey({
67
+ ownerEmail: scope.ownerEmail,
68
+ orgId: scope.orgId,
69
+ recordId,
70
+ key: `signal:${key}`,
71
+ }),
72
+ };
73
+ }
74
+
75
+ export function signalTupleError(message: string): never {
76
+ const error = new Error(message) as Error & { statusCode?: number };
77
+ error.statusCode = 404;
78
+ throw error;
79
+ }
@@ -0,0 +1,203 @@
1
+ import { defineAction, type ActionRunContext } from "@agent-native/core/action";
2
+ import { accessFilter, assertAccess } from "@agent-native/core/sharing";
3
+ import { and, eq } from "drizzle-orm";
4
+ import { z } from "zod";
5
+
6
+ import { isConnectedCrmProvider } from "../server/crm/adapter.js";
7
+ import { getDb, schema } from "../server/db/index.js";
8
+ import {
9
+ isSafeCrmMutationFields,
10
+ parseJsonRecord,
11
+ requireCrmScope,
12
+ } from "./_crm-action-utils.js";
13
+
14
+ function conditionalMutationMessage(provider: "hubspot" | "salesforce") {
15
+ const label = provider === "hubspot" ? "HubSpot" : "Salesforce";
16
+ return `${label} did not apply this update because this connection has not proved an atomic expected-revision write path. Refresh the record and make this change in ${label}.`;
17
+ }
18
+
19
+ function updateAffectedRows(result: unknown): number {
20
+ if (!result || typeof result !== "object") return 0;
21
+ const value = result as {
22
+ rowsAffected?: unknown;
23
+ rowCount?: unknown;
24
+ count?: unknown;
25
+ changes?: unknown;
26
+ meta?: { changes?: unknown };
27
+ };
28
+ for (const count of [
29
+ value.rowsAffected,
30
+ value.rowCount,
31
+ value.count,
32
+ value.changes,
33
+ value.meta?.changes,
34
+ ]) {
35
+ if (typeof count === "number") return count;
36
+ }
37
+ return 0;
38
+ }
39
+
40
+ export default defineAction({
41
+ description:
42
+ "Review one pending HubSpot or Salesforce provider proposal. The initial release records approval and fails closed unless the connection proves an atomic expected-revision write path; otherwise make the change upstream after review.",
43
+ schema: z.object({
44
+ proposalId: z.string().trim().min(1).max(128),
45
+ }),
46
+ needsApproval: true,
47
+ audit: {
48
+ target: (_args, result) => {
49
+ const response = result as {
50
+ recordId: string;
51
+ ownerEmail: string;
52
+ orgId: string | null;
53
+ visibility: "private" | "org";
54
+ };
55
+ return {
56
+ type: "crm-record",
57
+ id: response.recordId,
58
+ ownerEmail: response.ownerEmail,
59
+ orgId: response.orgId,
60
+ visibility: response.visibility,
61
+ };
62
+ },
63
+ summary: (args) => `Reviewed CRM proposal ${args.proposalId}`,
64
+ recordInputs: false,
65
+ },
66
+ run: async (args, ctx?: ActionRunContext) => {
67
+ await assertAccess("crm-mutation", args.proposalId, "editor");
68
+ const db = getDb();
69
+ const [proposal] = await db
70
+ .select()
71
+ .from(schema.crmMutations)
72
+ .where(
73
+ and(
74
+ eq(schema.crmMutations.id, args.proposalId),
75
+ accessFilter(
76
+ schema.crmMutations,
77
+ schema.crmMutationShares,
78
+ undefined,
79
+ "editor",
80
+ ),
81
+ ),
82
+ )
83
+ .limit(1);
84
+ if (!proposal) throw new Error("CRM proposal was not found.");
85
+ if (proposal.target !== "provider" || proposal.operation !== "update") {
86
+ throw new Error(
87
+ "Only pending provider update proposals can be reviewed in this phase.",
88
+ );
89
+ }
90
+ if (proposal.status !== "pending") {
91
+ throw new Error(
92
+ `CRM proposal is ${proposal.status} and cannot be reviewed.`,
93
+ );
94
+ }
95
+ if (!proposal.recordId || !proposal.connectionId) {
96
+ throw new Error(
97
+ "CRM proposal is missing its record or connection reference.",
98
+ );
99
+ }
100
+ await assertAccess("crm-record", proposal.recordId, "editor");
101
+ await assertAccess("crm-connection", proposal.connectionId, "editor");
102
+ const [[record], [connection]] = await Promise.all([
103
+ db
104
+ .select()
105
+ .from(schema.crmRecords)
106
+ .where(
107
+ and(
108
+ eq(schema.crmRecords.id, proposal.recordId),
109
+ accessFilter(
110
+ schema.crmRecords,
111
+ schema.crmRecordShares,
112
+ undefined,
113
+ "editor",
114
+ ),
115
+ ),
116
+ )
117
+ .limit(1),
118
+ db
119
+ .select()
120
+ .from(schema.crmConnections)
121
+ .where(
122
+ and(
123
+ eq(schema.crmConnections.id, proposal.connectionId),
124
+ accessFilter(
125
+ schema.crmConnections,
126
+ schema.crmConnectionShares,
127
+ undefined,
128
+ "editor",
129
+ ),
130
+ ),
131
+ )
132
+ .limit(1),
133
+ ]);
134
+ if (!record || record.tombstone || !connection) {
135
+ throw new Error(
136
+ "CRM proposal no longer has an available record and connection.",
137
+ );
138
+ }
139
+ if (!isConnectedCrmProvider(connection.provider)) {
140
+ throw new Error(
141
+ "Only HubSpot and Salesforce provider proposals are enabled in this release.",
142
+ );
143
+ }
144
+ if (!connection.workspaceConnectionId) {
145
+ throw new Error(
146
+ "CRM connection is missing its workspace connection reference.",
147
+ );
148
+ }
149
+ if (!proposal.expectedRemoteRevision) {
150
+ throw new Error(
151
+ "CRM proposal has no remote revision and must be recreated from a refreshed record.",
152
+ );
153
+ }
154
+ const patch = parseJsonRecord(proposal.patchJson);
155
+ const fields = patch.fields;
156
+ if (!fields || typeof fields !== "object" || Array.isArray(fields)) {
157
+ throw new Error("CRM proposal has an invalid field patch.");
158
+ }
159
+ const fieldPatch = fields as Record<string, unknown>;
160
+ if (!isSafeCrmMutationFields(fieldPatch)) {
161
+ throw new Error("CRM proposal contains an unsafe field patch.");
162
+ }
163
+
164
+ const scope = requireCrmScope(ctx);
165
+ const now = new Date().toISOString();
166
+ const message = conditionalMutationMessage(connection.provider);
167
+ const claim = await db
168
+ .update(schema.crmMutations)
169
+ .set({
170
+ status: "rejected",
171
+ approvedBy: scope.ownerEmail,
172
+ approvedAt: now,
173
+ error: message,
174
+ updatedAt: now,
175
+ })
176
+ .where(
177
+ and(
178
+ eq(schema.crmMutations.id, proposal.id),
179
+ eq(schema.crmMutations.status, "pending"),
180
+ accessFilter(
181
+ schema.crmMutations,
182
+ schema.crmMutationShares,
183
+ undefined,
184
+ "editor",
185
+ ),
186
+ ),
187
+ );
188
+ if (updateAffectedRows(claim) !== 1) {
189
+ throw new Error(
190
+ "CRM proposal was already claimed by another application attempt.",
191
+ );
192
+ }
193
+ return {
194
+ proposalId: proposal.id,
195
+ recordId: record.id,
196
+ status: "rejected" as const,
197
+ message,
198
+ ownerEmail: record.ownerEmail,
199
+ orgId: record.orgId,
200
+ visibility: record.visibility,
201
+ };
202
+ },
203
+ });